final touches to interface to include album covers, and more

This commit is contained in:
suroh 2023-10-11 18:06:52 +02:00
parent 1fedcdf92b
commit a1b0439bd0
25 changed files with 1840 additions and 668 deletions

View File

@ -15,6 +15,7 @@
"urlpattern-polyfill": "^9.0.0"
},
"devDependencies": {
"chokidar": "^3.5.3",
"eslint": "^8.49.0",
"eslint-plugin-lit": "^1.9.1",
"sass": "^1.67.0",

View File

@ -1,50 +1,51 @@
[
{
"title": "Late Junction",
"details": "BBC, 2019",
"title": "Fireside Chat",
"details": "Mark \"Frosty\" McNeil, Red Bull Radio, 2019",
"parent_dir": "documentaries_interviews_audio",
"media": "-21 08_Late Junction_2019 - Meredith Monk v2 BBC"
"media": "Fireside Chat_Mark \"Frosty\" McNeil, Red Bull Radio, 2019.mp3",
"image": "Fireside Chat_Mark \"Frosty\" McNeil, Red Bull Radio, 2019.png"
},
{
"title": "Speaking of Music",
"details": "Meredith Monk, 1984 Part 1 of 2",
"title": "Irene Ferchl, Bayerischer Rundfunk",
"details": "Kulturjournal, 1986",
"parent_dir": "documentaries_interviews_audio",
"media": "-22 02_Speaking of Music Meredith Monk 1984 Part 1 of 2"
},
{
"title": "Speaking of Music",
"details": "Meredith Monk, 1984 Part 2 of 2",
"parent_dir": "documentaries_interviews_audio",
"media": "-23 03_Speaking of Music_ Meredith Monk 1984 Part 2 of 2"
},
{
"title": "Interview with I Frechl-Bayn Rundfunk",
"details": "1986",
"parent_dir": "documentaries_interviews_audio",
"media": "-24 04 Meredith Monk Interview with I Ferchl_Bayn Rundfunk 1986"
},
{
"title": "Terry Gross Interview",
"details": "1987",
"parent_dir": "documentaries_interviews_audio",
"media": "-25 05 Terry Gross interview_1987"
},
{
"title": "Interview with David Garland",
"details": "WNYC, Sacred Sundays, 2008",
"parent_dir": "documentaries_interviews_audio",
"media": "-26 06 WNYC Interview w_ David Garland_SacredSundays_2008"
},
{
"title": "Frosty McNeil and Meredith Monk",
"details": "Fireside Chat, Red Bull Radio",
"parent_dir": "documentaries_interviews_audio",
"media": "-27 07_Red Bull Radio_Fireside Chat_M frosty McNeil and MM_41119"
"media": "Irene Ferchl, Bayerischer Rundfunk_Kulturjournal, 1986.mp3",
"image": "Irene Ferchl, Bayerischer Rundfunk_Kulturjournal, 1986.png"
},
{
"title": "Late Junction",
"details": "BBC, 2019",
"details": "Jennifer Lucy Allan, BBC Radio 3, 2019",
"parent_dir": "documentaries_interviews_audio",
"media": "-28 08_Late Junction_2019 - Meredith Monk v2 BBC"
"media": "Late Junction_Jennifer Lucy Allan, BBC Radio 3, 2019.mp3",
"image": "Late Junction_Jennifer Lucy Allan, BBC Radio 3, 2019.png"
},
{
"title": "Sacred Sundays",
"details": "David Garland, WNYC, 2008",
"parent_dir": "documentaries_interviews_audio",
"media": "Sacred Sundays_David Garland, WNYC, 2008.mp3",
"image": "Sacred Sundays_David Garland, WNYC, 2008.png"
},
{
"title": "Speaking of Music",
"details": "Charles Amirkhanian, Other Minds, 1984. Part 1 of 2",
"parent_dir": "documentaries_interviews_audio",
"media": "Speaking of Music_Charles Amirkhanian, Other Minds, 1984. Part 1 of 2..mp3",
"image": "Speaking of Music_Charles Amirkhanian, Other Minds, 1984. Part 1 of 2..png"
},
{
"title": "Speaking of Music",
"details": "Charles Amirkhanian, Other Minds, 1984. Part 2 of 2",
"parent_dir": "documentaries_interviews_audio",
"media": "Speaking of Music_Charles Amirkhanian, Other Minds, 1984. Part 2 of 2..mp3",
"image": "Speaking of Music_Charles Amirkhanian, Other Minds, 1984. Part 2 of 2..png"
},
{
"title": "Terry Gross",
"details": "unedited, 1987",
"parent_dir": "documentaries_interviews_audio",
"media": "Terry Gross_unedited, 1987.mp3",
"image": "Terry Gross_unedited, 1987.png"
}
]
]

View File

@ -1,92 +1,114 @@
[
{
"title": "Michael Blackwood Making Dances",
"details": "",
"title": "4 American Composers",
"details": "documentary by Peter Greenaway, 1983",
"parent_dir": "documentaries_interviews_video",
"media": "--2 MichaelBlackwoodMakingDances.m4v"
},
{
"title": "ECM 1981",
"details": "2019",
"parent_dir": "documentaries_interviews_video",
"media": "--3 ECM1981 Video Meredith Monk V2_2019.m4v"
"media": "4 American Composers_documentary by Peter Greenaway, 1983.m4v",
"image": "4 American Composers_documentary by Peter Greenaway, 1983.jpg"
},
{
"title": "Andere Avantgarde",
"details": "TV Interview 1982",
"details": "television documentary by Peter Greenaway, 1983",
"parent_dir": "documentaries_interviews_video",
"media": "--4 Meredith Monk_Andere Avantgarde_TV Interview_1982_.m4v"
},
{
"title": "New Sounds for a New World",
"details": "1982",
"parent_dir": "documentaries_interviews_video",
"media": "--5 New Sounds for a New World_1982.m4v"
},
{
"title": "Four American Composers",
"details": "PeterGreenaway",
"parent_dir": "documentaries_interviews_video",
"media": "--6 Four American Composers_Peter Greenaway.m4v"
"media": "Andere Avantgarde_television documentary by Peter Greenaway, 1983.m4v",
"image": "Andere Avantgarde_television documentary by Peter Greenaway, 1983.jpg"
},
{
"title": "BBC Late Show",
"details": "",
"details": "television interview, 1991",
"parent_dir": "documentaries_interviews_video",
"media": "--7 bbc_late_show (Original).m4v"
"media": "BBC Late Show_television interview, 1991.m4v",
"image": "BBC Late Show_television interview, 1991.jpg"
},
{
"title": "Documentary by Sidsel Mundal",
"details": "Norwegian Television, 1994",
"title": "Coffee and Composition",
"details": "Meredith Monk and Robert Kyr, online, 2021",
"parent_dir": "documentaries_interviews_video",
"media": "--8 1994 documentary by Sidsel Mundal_for Norwegian Telev.m4v"
"media": "Coffee and Composition_Meredith Monk and Robert Kyr, online, 2021.m4v",
"image": "Coffee and Composition_Meredith Monk and Robert Kyr, online, 2021.jpg"
},
{
"title": "Television Documentary",
"details": "Polish Television, 1995",
"title": "Dorothy and Lillian Gish Award",
"details": "portrait interview with Meredith Monk, 2017",
"parent_dir": "documentaries_interviews_video",
"media": "--9 Meredith Monk - Polish Television Documentary (1995).m4v"
"media": "Dorothy and Lillian Gish Award_portrait interview with Meredith Monk, 2017.m4v",
"image": "Dorothy and Lillian Gish Award_portrait interview with Meredith Monk, 2017.jpg"
},
{
"title": "Inner Voice",
"details": "",
"title": "ECM 50 | 1981 Meredith Monk",
"details": "documentary by Ingo Berhman for ECM Records' 50th Anniversary, 2019",
"parent_dir": "documentaries_interviews_video",
"media": "-12 MeredithMonk_Inner Voice.m4v"
"media": "ECM 50 | 1981 Meredith Monk_documentary by Ingo Berhman for ECM Records' 50th Anniversary, 2019.m4v",
"image": "ECM 50 | 1981 Meredith Monk_documentary by Ingo Berhman for ECM Records' 50th Anniversary, 2019.jpg"
},
{
"title": "Lecutre Performance",
"details": "Bennington College, 11 March 2011",
"title": "Girlchild Diary",
"details": "documentary on Education of the Girlchild, ed. Joëlle Schon, 2015",
"parent_dir": "documentaries_interviews_video",
"media": "-13 Bennington College lecture performance 3.11.11.m4v"
"media": "Girlchild Diary_documentary on Education of the Girlchild, ed. Joëlle Schon, 2015.m4v",
"image": "Girlchild Diary_documentary on Education of the Girlchild, ed. Joëlle Schon, 2015.jpg"
},
{
"title": "",
"title": "MMonk",
"details": "TheSoulsMessenger",
"parent_dir": "documentaries_interviews_video",
"media": "-14 MMonk_TheSoulsMessenger_Lublin_2012.m4v"
"media": "MMonk_TheSoulsMessenger_Lublin_2012.m4v",
"image": "MMonk_TheSoulsMessenger_Lublin_2012.jpg"
},
{
"title": "",
"title": "Making Dances",
"details": "documentary by Michael Blackwood, 1980",
"parent_dir": "documentaries_interviews_video",
"media": "-15 Girlchild Diary_61116.m4v"
"media": "Making Dances_documentary by Michael Blackwood, 1980.m4v",
"image": "Making Dances_documentary by Michael Blackwood, 1980.jpg"
},
{
"title": "",
"title": "Meredith Monk and Adam Shatz",
"details": "conversation on Book of Days, online, 2020",
"parent_dir": "documentaries_interviews_video",
"media": "-16 Q2 Spaces_Meredith Monk_2014.m4v"
"media": "Meredith Monk and Adam Shatz_conversation on Book of Days, online, 2020.m4v",
"image": "Meredith Monk and Adam Shatz_conversation on Book of Days, online, 2020.jpg"
},
{
"title": "",
"title": "Meredith Monk lecture",
"details": "Bennington College, Vermont, 2011",
"parent_dir": "documentaries_interviews_video",
"media": "-17 Gish Prize Ceremony Camera A.m4v"
"media": "Meredith Monk lecture_Bennington College, Vermont, 2011.m4v",
"image": "Meredith Monk lecture_Bennington College, Vermont, 2011.jpg"
},
{
"title": "",
"title": "Meredith Monk: Inner Voice",
"details": "documentary by Babeth M. VanLoo, Buddhist Broadcasting Foundation, 2009",
"parent_dir": "documentaries_interviews_video",
"media": "-18 MM and Adam Shatz - Book of Days conversation_2020.m4v"
"media": "Meredith Monk: Inner Voice_documentary by Babeth M. VanLoo, Buddhist Broadcasting Foundation, 2009.m4v",
"image": "Meredith Monk: Inner Voice_documentary by Babeth M. VanLoo, Buddhist Broadcasting Foundation, 2009.jpg"
},
{
"title": "",
"title": "Meredith Monk",
"details": "documentary by Sidsel Mundal for Norwegian Television, 1994",
"parent_dir": "documentaries_interviews_video",
"media": "-19 Coffee and Composition with Meredith Monk_2021.m4v"
"media": "Meredith Monk_documentary by Sidsel Mundal for Norwegian Television, 1994.m4v",
"image": "Meredith Monk_documentary by Sidsel Mundal for Norwegian Television, 1994.jpg"
},
{
"title": "Meredith",
"details": "documentary by Mariusz Grzegorzeki for Polish Television, 1995",
"parent_dir": "documentaries_interviews_video",
"media": "Meredith_documentary by Mariusz Grzegorzeki for Polish Television, 1995.m4v",
"image": "Meredith_documentary by Mariusz Grzegorzeki for Polish Television, 1995.jpg"
},
{
"title": "Neue Töne aus der Neuen Welt",
"details": "(New Sounds for a New World) documentary by Birgitta Ashoff for German Telelvision (in German), 1983",
"parent_dir": "documentaries_interviews_video",
"media": "Neue Töne aus der Neuen Welt_(New Sounds for a New World) documentary by Birgitta Ashoff for German Telelvision (in German), 1983.m4v",
"image": "Neue Töne aus der Neuen Welt_(New Sounds for a New World) documentary by Birgitta Ashoff for German Telelvision (in German), 1983.jpg"
},
{
"title": "Q2 Spaces: Meredith Monk",
"details": "documentary, 2014",
"parent_dir": "documentaries_interviews_video",
"media": "Q2 Spaces: Meredith Monk_documentary, 2014.m4v",
"image": "Q2 Spaces: Meredith Monk_documentary, 2014.jpg"
}
]
]

View File

@ -1,27 +1,44 @@
[
{
"title": "",
"parent_dir": "films",
"media": "_72 01 16_Millimeter_Earrings_1980_Color_IN_HD_23-98_ProRes4444_Pillar Scan GOOD copy v4 2023 0812.m4v"
"title": "16 Millimeter Earrings",
"details": "Robert S. Withers, 1979",
"parent_dir": "Films",
"media": "16 Millimeter Earrings_Robert S. Withers, 1979.m4v",
"image": "16 Millimeter Earrings_Robert S. Withers, 1979.jpg"
},
{
"title": "",
"parent_dir": "films",
"media": "_74 Ellis Island.m4v"
"title": "Book of Days",
"details": "Meredith Monk, 1988",
"parent_dir": "Films",
"media": "Book of Days_Meredith Monk, 1988.m4v",
"image": "Book of Days_Meredith Monk, 1988.jpg"
},
{
"title": "",
"parent_dir": "films",
"media": "_75 Book of Days.m4v"
"title": "Ellis Island",
"details": "Meredith Monk and Bob Rosen, 1981",
"parent_dir": "Films",
"media": "Ellis Island_Meredith Monk and Bob Rosen, 1981.m4v",
"image": "Ellis Island_Meredith Monk and Bob Rosen, 1981.jpg"
},
{
"title": "",
"parent_dir": "films",
"media": "_76 1982 Paris KTCA (full).m4v"
"title": "Paris",
"details": "Meredith Monk and Ping Chong, 1982",
"parent_dir": "Films",
"media": "Paris_Meredith Monk and Ping Chong, 1982.m4v",
"image": "Paris_Meredith Monk and Ping Chong, 1982.jpg"
},
{
"title": "",
"parent_dir": "films",
"media": "_77 TurtleDreams(Waltz)_Stereo_Tranfer1inchApril2018.m4v"
"title": "Quarry",
"details": "1977",
"parent_dir": "Films",
"media": "Quarry_1977.m4v",
"image": "Quarry_1977.jpg"
},
{
"title": "Turtle Dreams (Waltz)",
"details": "Meredith Monk, 1983",
"parent_dir": "Films",
"media": "Turtle Dreams (Waltz)_Meredith Monk, 1983.m4v",
"image": "Turtle Dreams (Waltz)_Meredith Monk, 1983.jpg"
}
]
]

View File

@ -1,18 +1 @@
[
{
"title": "Photo One",
"media": "photo_one.jpg"
},
{
"title": "Photo Two",
"media": "photo_two.jpg"
},
{
"title": "Photo Three",
"media": "photo_three.jpg"
},
{
"title": "Photo Four",
"media": "photo_four.jpg"
}
]
[]

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1 @@
[
{
"title": "",
"parent_dir": "music_sound_unpublished",
"media": "no content recieved",
"tracks": []
}
]
[]

View File

@ -1,184 +1,510 @@
[
{
"title": "",
"title": "Beginnings",
"details": "Tzadik, 2009",
"parent_dir": "music_sound_various",
"media": "MONK MIX Remixes and Interpretations of Music by Meredith Monk CD1",
"media": "Beginnings_Tzadik, 2009",
"image": "Beginnings_Tzadik, 2009.jpg",
"album": true,
"tracks": [
"01 Gotham Lullaby (Featuring Björk With The Brodsky Quartet).mp3",
"02 Caldera Chimera (Featuring Gabriel Prokofiev Remix).mp3",
"03 Click Song #1 (Featuring Don Byron).mp3",
"04 Double Fiesta (Featuring Meredith Monk & Bang On A Can).mp3",
"05 Astronaut Anthem (Featuring Sakamoto Remix).mp3",
"06 Shaking (Featuring Lukas Ligeti) [Pyrolator Remix].mp3",
"07 Last Song (Featuring Caetano Veloso).mp3",
"08 Fat Stream (Featuring Nico_s Piano Homage).mp3",
"09 Wheel (Featuring John Hollenbeck & Theo Bleckmann).mp3",
"10 Scared Song (Featuring Pamela Z).mp3",
"11 Boat Song (Featuring Rubin Kodheli).mp3",
"12 Gathering (Featuring Lee Ranaldo Remix).mp3",
"13 Evening (Featuring Henry Grimes Remix).mp3"
{
"title": "_60_01 Greensleeves",
"media": "_60_01 Greensleeves.mp3"
},
{
"title": "_60_02 Nota",
"media": "_60_02 Nota.mp3"
},
{
"title": "_60_03 Duet For Voice And Echoplex",
"media": "_60_03 Duet For Voice And Echoplex.mp3"
},
{
"title": "_60_04 Candy Bullets And Moon",
"media": "_60_04 Candy Bullets And Moon.mp3"
},
{
"title": "_60_05 Trance",
"media": "_60_05 Trance.mp3"
},
{
"title": "_60_06 Epic I",
"media": "_60_06 Epic I.mp3"
},
{
"title": "_60_07 Paris",
"media": "_60_07 Paris.mp3"
},
{
"title": "_60_08 Biography",
"media": "_60_08 Biography.mp3"
},
{
"title": "_60_09 Mill",
"media": "_60_09 Mill.mp3"
},
{
"title": "_60_10 The Tale",
"media": "_60_10 The Tale.mp3"
},
{
"title": "_60_11 Quarry Weave",
"media": "_60_11 Quarry Weave.mp3"
},
{
"title": "_60_12 Epic II",
"media": "_60_12 Epic II.mp3"
},
{
"title": "_60_13 Tower",
"media": "_60_13 Tower.mp3"
},
{
"title": "_60_14 Mill",
"media": "_60_14 Mill.mp3"
},
{
"title": "_60_15 Do You Be_",
"media": "_60_15 Do You Be_.mp3"
},
{
"title": "_60_16 Quarry Procession",
"media": "_60_16 Quarry Procession.mp3"
},
{
"title": "_60_17 Porch",
"media": "_60_17 Porch.mp3"
}
]
},
{
"title": "",
"title": "Biography (from Education of the Girlchild)",
"details": "Big Ego Records, 1978",
"parent_dir": "music_sound_various",
"media": "MONK MIX Remixes and Interpretations of Music by Meredith Monk CD2",
"media": "Biography (from Education of the Girlchild)_Big Ego Records, 1978",
"image": "Biography (from Education of the Girlchild)_Big Ego Records, 1978.jpg",
"album": true,
"tracks": [
"01 Dawn (feat. Dj Spooky Remix).mp3",
"02 Rain (feat. Vijay Iyer Revelation Mix Featuring Latasha N. Nevada Diggs).mp3",
"03 Atlas Ascending (feat. Todd Reynolds Remix).mp3",
"04 Epic (feat. Dj Rekha & Raj Star Remix).mp3",
"05 Memory Song (feat. Miho Hatori Remix).mp3",
"06 Travellers (feat. King Britt Idm Mix).mp3",
"07 Night Vs. Lullaby (feat. Matt Marks Remix).mp3",
"08 Double Fiesta (feat. Arto Lindsay Remix).mp3",
"09 Long Shadows (feat. Scanner Entwine Mix).mp3",
"10 Dolmen Music, Part 1 (feat. Shodekeh's Embody & Continuums Remix).mp3",
"11 Braid (feat. High Priest _ Hprizm Ghostlover Remix).mp3",
"12 Vocal_ Mill Feuille (feat. Sussan Deyhim Remix).mp3"
{
"title": "_63_13 Biography_Big Ego album",
"media": "_63_13 Biography_Big Ego album.m4a"
}
]
},
{
"title": "",
"title": "KEY: an albm of invisible theater",
"details": "Lovely Music, 1971",
"parent_dir": "music_sound_various",
"media": "_55 Songs from the Hill-Tablet",
"media": "KEY: an albm of invisible theater_Lovely Music, 1971",
"image": "KEY: an albm of invisible theater_Lovely Music, 1971.jpg",
"album": true,
"tracks": [
"_55_01 Lullaby.mp3",
"_55_02 Mesa.mp3",
"_55_03 Jade (old woman's song).mp3",
"_55_04 Wa-lie-oh.mp3",
"_55_05 Insect.mp3",
"_55_06 Descending.mp3",
"_55_07 Silo.mp3",
"_55_08 Bird Code.mp3",
"_55_09 Jew's Harp.mp3",
"_55_10 Prairie Ghost.mp3",
"_55_11 Tablet.mp3"
{
"title": "_57_01 Porch",
"media": "_57_01 Porch.mp3"
},
{
"title": "_57_02 Understreet",
"media": "_57_02 Understreet.mp3"
},
{
"title": "_57_03 What Does It Mean_",
"media": "_57_03 What Does It Mean_.mp3"
},
{
"title": "_57_04 Vision #1",
"media": "_57_04 Vision #1.mp3"
},
{
"title": "_57_05 Fat Stream",
"media": "_57_05 Fat Stream.mp3"
},
{
"title": "_57_06 Vision #2",
"media": "_57_06 Vision #2.mp3"
},
{
"title": "_57_07 Do You Be_",
"media": "_57_07 Do You Be_.mp3"
},
{
"title": "_57_08 Vision (#3)",
"media": "_57_08 Vision (#3).mp3"
},
{
"title": "_57_09 Change",
"media": "_57_09 Change.mp3"
},
{
"title": "_57_10 Dungeon",
"media": "_57_10 Dungeon.mp3"
}
]
},
{
"title": "",
"title": "MEMORY GAME",
"details": "Cantaloupe Music, 2020",
"parent_dir": "music_sound_various",
"media": "_56 Our Lady of Late",
"media": "MEMORY GAME_Cantaloupe Music, 2020",
"image": "MEMORY GAME_Cantaloupe Music, 2020.jpg",
"album": true,
"tracks": [
"_56_01 Prologue.mp3",
"_56_02 Unison.mp3",
"_56_03 Knee.mp3",
"_56_04 Hey Rhythm.mp3",
"_56_05 Cow Song.mp3",
"_56_06 Sigh.mp3",
"_56_07 Morning.mp3",
"_56_08 Slide.mp3",
"_56_09 Waltz.mp3",
"_56_10 Prophecy.mp3",
"_56_11 Dumb.mp3",
"_56_12 Conversation.mp3",
"_56_13 Low Ring.mp3",
"_56_14 High Ring.mp3",
"_56_15 Free.mp3",
"_56_16 Edge.mp3",
"_56_17 Scale Down.mp3",
"_56_18 Epilogue.mp3"
{
"title": "_58_01 Spaceship",
"media": "_58_01 Spaceship.mp3"
},
{
"title": "_58_02 Gamemaster's Song",
"media": "_58_02 Gamemaster's Song.mp3"
},
{
"title": "_58_03 Migration",
"media": "_58_03 Migration.mp3"
},
{
"title": "_58_04 Memory Song",
"media": "_58_04 Memory Song.mp3"
},
{
"title": "_58_05 Downfall",
"media": "_58_05 Downfall.mp3"
},
{
"title": "_58_06 Waltz In 5s",
"media": "_58_06 Waltz In 5s.mp3"
},
{
"title": "_58_07 Tokyo CHa Cha",
"media": "_58_07 Tokyo CHa Cha.mp3"
},
{
"title": "_58_08 Totentanz",
"media": "_58_08 Totentanz.mp3"
},
{
"title": "_58_09 Double Fiesta",
"media": "_58_09 Double Fiesta.mp3"
}
]
},
{
"title": "",
"title": "MONK MIX Remixes and Interpretations of Music by Meredith Monk (CD1)",
"details": "The House Foundation for the Arts, 2012",
"parent_dir": "music_sound_various",
"media": "_57 KEY-an album of invisible theater",
"media": "MONK MIX Remixes and Interpretations of Music by Meredith Monk (CD1)_The House Foundation for the Arts, 2012",
"image": "MONK MIX Remixes and Interpretations of Music by Meredith Monk (CD1)_The House Foundation for the Arts, 2012.jpg",
"album": true,
"tracks": [
"_57_01 Porch.mp3",
"_57_02 Understreet.mp3",
"_57_03 What Does It Mean_.mp3",
"_57_04 Vision #1.mp3",
"_57_05 Fat Stream.mp3",
"_57_06 Vision #2.mp3",
"_57_07 Do You Be_.mp3",
"_57_08 Vision (#3).mp3",
"_57_09 Change.mp3",
"_57_10 Dungeon.mp3"
{
"title": "01 Gotham Lullaby (Featuring Björk With The Brodsky Quartet)",
"media": "01 Gotham Lullaby (Featuring Björk With The Brodsky Quartet).mp3"
},
{
"title": "02 Caldera Chimera (Featuring Gabriel Prokofiev Remix)",
"media": "02 Caldera Chimera (Featuring Gabriel Prokofiev Remix).mp3"
},
{
"title": "03 Click Song #1 (Featuring Don Byron)",
"media": "03 Click Song #1 (Featuring Don Byron).mp3"
},
{
"title": "04 Double Fiesta (Featuring Meredith Monk & Bang On A Can)",
"media": "04 Double Fiesta (Featuring Meredith Monk & Bang On A Can).mp3"
},
{
"title": "05 Astronaut Anthem (Featuring Sakamoto Remix)",
"media": "05 Astronaut Anthem (Featuring Sakamoto Remix).mp3"
},
{
"title": "06 Shaking (Featuring Lukas Ligeti) [Pyrolator Remix]",
"media": "06 Shaking (Featuring Lukas Ligeti) [Pyrolator Remix].mp3"
},
{
"title": "07 Last Song (Featuring Caetano Veloso)",
"media": "07 Last Song (Featuring Caetano Veloso).mp3"
},
{
"title": "08 Fat Stream (Featuring Nico_s Piano Homage)",
"media": "08 Fat Stream (Featuring Nico_s Piano Homage).mp3"
},
{
"title": "09 Wheel (Featuring John Hollenbeck & Theo Bleckmann)",
"media": "09 Wheel (Featuring John Hollenbeck & Theo Bleckmann).mp3"
},
{
"title": "10 Scared Song (Featuring Pamela Z)",
"media": "10 Scared Song (Featuring Pamela Z).mp3"
},
{
"title": "11 Boat Song (Featuring Rubin Kodheli)",
"media": "11 Boat Song (Featuring Rubin Kodheli).mp3"
},
{
"title": "12 Gathering (Featuring Lee Ranaldo Remix)",
"media": "12 Gathering (Featuring Lee Ranaldo Remix).mp3"
},
{
"title": "13 Evening (Featuring Henry Grimes Remix)",
"media": "13 Evening (Featuring Henry Grimes Remix).mp3"
}
]
},
{
"title": "",
"title": "MONK MIX Remixes and Interpretations of Music by Meredith Monk (CD2)",
"details": "The House Foundation for the Arts, 2012",
"parent_dir": "music_sound_various",
"media": "_58 MEMORY GAME",
"media": "MONK MIX Remixes and Interpretations of Music by Meredith Monk (CD2)_The House Foundation for the Arts, 2012",
"image": "MONK MIX Remixes and Interpretations of Music by Meredith Monk (CD2)_The House Foundation for the Arts, 2012.jpg",
"album": true,
"tracks": [
"_58_01 Spaceship.mp3",
"_58_02 Gamemaster's Song.mp3",
"_58_03 Migration.mp3",
"_58_04 Memory Song.mp3",
"_58_05 Downfall.mp3",
"_58_06 Waltz In 5s.mp3",
"_58_07 Tokyo CHa Cha.mp3",
"_58_08 Totentanz.mp3",
"_58_09 Double Fiesta.mp3"
{
"title": "01 Dawn (feat. Dj Spooky Remix)",
"media": "01 Dawn (feat. Dj Spooky Remix).mp3"
},
{
"title": "02 Rain (feat. Vijay Iyer Revelation Mix Featuring Latasha N. Nevada Diggs)",
"media": "02 Rain (feat. Vijay Iyer Revelation Mix Featuring Latasha N. Nevada Diggs).mp3"
},
{
"title": "03 Atlas Ascending (feat. Todd Reynolds Remix)",
"media": "03 Atlas Ascending (feat. Todd Reynolds Remix).mp3"
},
{
"title": "04 Epic (feat. Dj Rekha & Raj Star Remix)",
"media": "04 Epic (feat. Dj Rekha & Raj Star Remix).mp3"
},
{
"title": "05 Memory Song (feat. Miho Hatori Remix)",
"media": "05 Memory Song (feat. Miho Hatori Remix).mp3"
},
{
"title": "06 Travellers (feat. King Britt Idm Mix)",
"media": "06 Travellers (feat. King Britt Idm Mix).mp3"
},
{
"title": "07 Night Vs. Lullaby (feat. Matt Marks Remix)",
"media": "07 Night Vs. Lullaby (feat. Matt Marks Remix).mp3"
},
{
"title": "08 Double Fiesta (feat. Arto Lindsay Remix)",
"media": "08 Double Fiesta (feat. Arto Lindsay Remix).mp3"
},
{
"title": "09 Long Shadows (feat. Scanner Entwine Mix)",
"media": "09 Long Shadows (feat. Scanner Entwine Mix).mp3"
},
{
"title": "10 Dolmen Music, Part 1 (feat. Shodekeh's Embody & Continuums Remix)",
"media": "10 Dolmen Music, Part 1 (feat. Shodekeh's Embody & Continuums Remix).mp3"
},
{
"title": "11 Braid (feat. High Priest _ Hprizm Ghostlover Remix)",
"media": "11 Braid (feat. High Priest _ Hprizm Ghostlover Remix).mp3"
},
{
"title": "12 Vocal_ Mill Feuille (feat. Sussan Deyhim Remix)",
"media": "12 Vocal_ Mill Feuille (feat. Sussan Deyhim Remix).mp3"
}
]
},
{
"title": "",
"title": "Monk and the Abbess",
"details": "BMG, 1996",
"parent_dir": "music_sound_various",
"media": "_60 Beginnings",
"media": "Monk and the Abbess_BMG, 1996",
"image": "Monk and the Abbess_BMG, 1996.jpg",
"album": true,
"tracks": [
"_60_01 Greensleeves.mp3",
"_60_02 Nota.mp3",
"_60_03 Duet For Voice And Echoplex.mp3",
"_60_04 Candy Bullets And Moon.mp3",
"_60_05 Trance.mp3",
"_60_06 Epic I.mp3",
"_60_07 Paris.mp3",
"_60_08 Biography.mp3",
"_60_09 Mill.mp3",
"_60_10 The Tale.mp3",
"_60_11 Quarry Weave.mp3",
"_60_12 Epic II.mp3",
"_60_13 Tower.mp3",
"_60_14 Mill.mp3",
"_60_15 Do You Be_.mp3",
"_60_16 Quarry Procession.mp3",
"_60_17 Porch.mp3"
{
"title": "_62_05 Dawn (1985)",
"media": "_62_05 Dawn (1985).mp3"
},
{
"title": "_62_06 Quarry weave 1 (1976)",
"media": "_62_06 Quarry weave 1 (1976).mp3"
},
{
"title": "_62_07 Quarry lullaby (1976)",
"media": "_62_07 Quarry lullaby (1976).mp3"
},
{
"title": "_62_08 Quarry weave 2 (1976)",
"media": "_62_08 Quarry weave 2 (1976).mp3"
},
{
"title": "_62_09 Farmer's song (1974)",
"media": "_62_09 Farmer's song (1974).mp3"
},
{
"title": "_62_10 Astronaut anthem (1983)",
"media": "_62_10 Astronaut anthem (1983).mp3"
},
{
"title": "_62_11 Nightfall (1995)",
"media": "_62_11 Nightfall (1995).mp3"
}
]
},
{
"title": "",
"title": "Our Lady of Late",
"details": "Minona Records, 1974 and Wergo, 1986",
"parent_dir": "music_sound_various",
"media": "_61 Radio Songs",
"media": "Our Lady of Late_Minona Records, 1974 and Wergo, 1986",
"image": "Our Lady of Late_Minona Records, 1974 and Wergo, 1986.jpg",
"album": true,
"tracks": [
"_61_01 Quarry Radio.mp3",
"_61_02 Gotham Blues.mp3",
"_61_03 Quarry Waltz.mp3",
"_61_04 Gotham Lullaby.mp3"
{
"title": "_56_01 Prologue",
"media": "_56_01 Prologue.mp3"
},
{
"title": "_56_02 Unison",
"media": "_56_02 Unison.mp3"
},
{
"title": "_56_03 Knee",
"media": "_56_03 Knee.mp3"
},
{
"title": "_56_04 Hey Rhythm",
"media": "_56_04 Hey Rhythm.mp3"
},
{
"title": "_56_05 Cow Song",
"media": "_56_05 Cow Song.mp3"
},
{
"title": "_56_06 Sigh",
"media": "_56_06 Sigh.mp3"
},
{
"title": "_56_07 Morning",
"media": "_56_07 Morning.mp3"
},
{
"title": "_56_08 Slide",
"media": "_56_08 Slide.mp3"
},
{
"title": "_56_09 Waltz",
"media": "_56_09 Waltz.mp3"
},
{
"title": "_56_10 Prophecy",
"media": "_56_10 Prophecy.mp3"
},
{
"title": "_56_11 Dumb",
"media": "_56_11 Dumb.mp3"
},
{
"title": "_56_12 Conversation",
"media": "_56_12 Conversation.mp3"
},
{
"title": "_56_13 Low Ring",
"media": "_56_13 Low Ring.mp3"
},
{
"title": "_56_14 High Ring",
"media": "_56_14 High Ring.mp3"
},
{
"title": "_56_15 Free",
"media": "_56_15 Free.mp3"
},
{
"title": "_56_16 Edge",
"media": "_56_16 Edge.mp3"
},
{
"title": "_56_17 Scale Down",
"media": "_56_17 Scale Down.mp3"
},
{
"title": "_56_18 Epilogue",
"media": "_56_18 Epilogue.mp3"
}
]
},
{
"title": "",
"title": "Radio Songs",
"details": "The sound of White Columns, 2014",
"parent_dir": "music_sound_various",
"media": "_62 Monk and the Abbiss",
"media": "Radio Songs_The sound of White Columns, 2014",
"image": "Radio Songs_The sound of White Columns, 2014.jpg",
"album": true,
"tracks": [
"_62_05 Dawn (1985).mp3",
"_62_06 Quarry weave 1 (1976).mp3",
"_62_07 Quarry lullaby (1976).mp3",
"_62_08 Quarry weave 2 (1976).mp3",
"_62_09 Farmer's song (1974).mp3",
"_62_10 Astronaut anthem (1983).mp3",
"_62_11 Nightfall (1995).mp3"
{
"title": "_61_01 Quarry Radio",
"media": "_61_01 Quarry Radio.mp3"
},
{
"title": "_61_02 Gotham Blues",
"media": "_61_02 Gotham Blues.mp3"
},
{
"title": "_61_03 Quarry Waltz",
"media": "_61_03 Quarry Waltz.mp3"
},
{
"title": "_61_04 Gotham Lullaby",
"media": "_61_04 Gotham Lullaby.mp3"
}
]
},
{
"title": "",
"title": "Songs from the Hill-Tablet",
"details": "Wergo, 1979",
"parent_dir": "music_sound_various",
"media": "_63 Biography (from Education of the Girlchild)",
"media": "Songs from the Hill-Tablet_Wergo, 1979",
"image": "Songs from the Hill-Tablet_Wergo, 1979.jpg",
"album": true,
"tracks": [
"_63_13 Biography_Big Ego album.m4a"
{
"title": "_55_01 Lullaby",
"media": "_55_01 Lullaby.mp3"
},
{
"title": "_55_02 Mesa",
"media": "_55_02 Mesa.mp3"
},
{
"title": "_55_03 Jade (old woman's song)",
"media": "_55_03 Jade (old woman's song).mp3"
},
{
"title": "_55_04 Wa-lie-oh",
"media": "_55_04 Wa-lie-oh.mp3"
},
{
"title": "_55_05 Insect",
"media": "_55_05 Insect.mp3"
},
{
"title": "_55_06 Descending",
"media": "_55_06 Descending.mp3"
},
{
"title": "_55_07 Silo",
"media": "_55_07 Silo.mp3"
},
{
"title": "_55_08 Bird Code",
"media": "_55_08 Bird Code.mp3"
},
{
"title": "_55_09 Jew's Harp",
"media": "_55_09 Jew's Harp.mp3"
},
{
"title": "_55_10 Prairie Ghost",
"media": "_55_10 Prairie Ghost.mp3"
},
{
"title": "_55_11 Tablet",
"media": "_55_11 Tablet.mp3"
}
]
}
]

View File

@ -1 +0,0 @@
[]

View File

@ -1,63 +1,65 @@
[
{
"title": "Specimen Days",
"details": "The Public Theater, New York, 1981. 1:26:17",
"media": "-34 Specimen Days.m4v",
"title": "Cellular Songs",
"details": "UCLA, Los Angeles, California, 2019",
"parent_dir": "theatre",
"media": "Cellular Songs_UCLA, Los Angeles, California, 2019.mp4",
"image": "Cellular Songs_UCLA, Los Angeles, California, 2019.jpg"
},
{
"title": "The Games: a science fiction opera",
"details": "Brooklyn Academy of Music (BAM), New York, 1984. 2:00:35",
"media": "-37 MMonk_TheGames_BAM1984.m4v",
"title": "Education of the Girlchild",
"details": "solo, Common Ground, NYC, 1973",
"parent_dir": "theatre",
"media": "Education of the Girlchild_solo, Common Ground, NYC, 1973..m4v",
"image": "Education of the Girlchild_solo, Common Ground, NYC, 1973..jpg"
},
{
"title": "Facing North",
"details": "George Washington University, Washington, DC, 1992. 54:32",
},
{
"title": "The Politics of Quiet",
"details": "Brooklyn Academy of Music, BAM, New York, 1996. 1:43:46",
"media": "-36 The Politics of Quiet at BAM - 10.13.96.m4v",
"details": "George Washington University, Washington, DC, 1992",
"parent_dir": "theatre",
"media": "Facing North_George Washington University, Washington, DC, 1992.mp4",
"image": "Facing North_George Washington University, Washington, DC, 1992.jpg"
},
{
"title": "Magic Frequencies (excerpts)",
"details": "Muffathalle, Munich, Germany, 1998. 25:49",
"media": "-42 1998 Magic Frequencies (excerpts) BetaCamSP transfer 2021.m4v"
"details": "Muffathalle, Munich, Germany, 1998",
"parent_dir": "theatre",
"media": "Magic Frequencies (excerpts)_Muffathalle, Munich, Germany, 1998.m4v",
"image": "Magic Frequencies (excerpts)_Muffathalle, Munich, Germany, 1998.jpg"
},
{
"title":"A Celebration Service",
"details": "St. Marks Church, NYC, 1999. 55:02",
"media": "-35 Meredith Monk - A Celebration Service_ Danspace at St. Mark's Church_1999.m4v",
"title": "Meredith Monk",
"details": "A Celebration Service",
"parent_dir": "theatre",
"media": "Meredith Monk_A Celebration Service_ Danspace at St. Mark's Church_1999.m4v",
"image": "Meredith Monk_A Celebration Service_ Danspace at St. Mark's Church_1999.jpg"
},
{
impermanence, Brooklyn Academy of Music (BAM), New York, 2006. 1:22:03
"title": "Songs of Ascension",
"details": "Brooklyn Academy of Music (BAM), New York, 2009",
"parent_dir": "theatre",
"media": "Songs of Ascension_Brooklyn Academy of Music (BAM), New York, 2009.mp4",
"image": "Songs of Ascension_Brooklyn Academy of Music (BAM), New York, 2009.jpg"
},
{
Songs of Ascension, Brooklyn Academy of Music (BAM), New York, 2009. 1:17:29
"title": "Specimen Days",
"details": "The Public Theater, New York, 1981",
"parent_dir": "theatre",
"media": "Specimen Days_The Public Theater, New York, 1981.m4v",
"image": "Specimen Days_The Public Theater, New York, 1981.jpg"
},
{
"title": "On Behalf of Nature",
"details": "UCLA, Los Angeles, California, 2013. 1:14:55"
"media": ""
"title": "The Games",
"details": "a science fiction opera, Brooklyn Academy of Music (BAM), New York, 1984",
"parent_dir": "theatre",
"media": "The Games_a science fiction opera, Brooklyn Academy of Music (BAM), New York, 1984.m4v",
"image": "The Games_a science fiction opera, Brooklyn Academy of Music (BAM), New York, 1984.jpg"
},
{
"title": "impermanence",
"details": "Brooklyn Academy of Music (BAM), New York, 2006",
"parent_dir": "theatre",
"media": "impermanence_Brooklyn Academy of Music (BAM), New York, 2006.mp4",
"image": "impermanence_Brooklyn Academy of Music (BAM), New York, 2006.jpg"
}
{
Cellular Songs, UCLA, Los Angeles, California, 2019. 1:24:07
}
"media": "-29 Education of the Gildchild solo_Common Ground_1973.m4v",
"media": "-30 Quarry_full film_1977_FINAL_20200127_added to dropbox.m4v",
"media": "-33 MEREDITH_MONK_SOLO_CONCERT_1980.m4v",
"media": "-38 MeredithMonk_SoloConcert_College des Bernadins Paris_20120516.m4v",
"media": "-39 Meredith Monk with Katie Geissinger in Concert, Haus der Kunst, Munich, Germany (2012).m4v",
"media": "-40 Candy_Bullets_and_Moon.m4v",
"media": "-41 Monk_Anthem_Final.m4v",
]

View File

@ -1,6 +1,29 @@
import fs from 'fs/promises'
import path from 'path'
import { exec } from 'child_process'
// WAVEFORM GENERATION
// TODO@mx use node-js library
async function generateWaveform(audioFile, outputDir) {
const inputFile = path.join(outputDir, audioFile)
audioFile = audioFile.replace(/\.[^/.]+$/, '.png')
const outputPath = path.join(outputDir || '.', audioFile)
return new Promise((resolve, reject) => {
exec(
`audiowaveform -i '${inputFile}' -o '${outputPath}' --output-format png -z auto -w 640 -h 180 --background-color 00000000 --waveform-color FFFFFF50 --waveform-style bars --bar-style rounded --border-color 00000000 --bar-width 4 --bar-gap 6 --no-axis-labels`,
(error, stdOut) => {
if (error) {
console.error(error)
reject(error)
} else {
resolve(audioFile)
}
})
})
}
// MAIN FUNCTION
async function main() {
// variable for incoming variable
let mediaDir = ''
@ -8,90 +31,189 @@ async function main() {
let recurse = false
let imagesOnly = false
let dryRun = false
let formatted = null
let waveform = false
let update = []
// get command line arguments
process.argv.forEach(function (val, index) {
// console.log(index + ': ' + val)
if (val == '-dir') {
// console.log(process.argv[index + 1])
mediaDir = process.argv[index + 1] || ''
}
switch (val) {
case '-dir':
mediaDir = process.argv[index + 1] || ''
break
case '-o':
outputDir = process.argv[index + 1] || ''
break
case '-u':
update = process.argv[index + 1].match(/(title|details|media|image[s]*|tracks|)/i)
? process.argv[index + 1]
.split(',')
.filter(a => [
'title',
'details',
'media',
'image',
'tracks',
'images'
].includes(a))
: true
break
case '-r':
recurse = true
break
case '--images-only':
imagesOnly = true
break
case '--dry-run':
dryRun = true
break
case '--formatted':
formatted = ['parent', 'recurse', 'both' ].includes(process.argv[index + 1]) ? process.argv[index + 1] : 'both'
break
case '--gen-waveform':
waveform = true
break
if (val == '--dry-run') {
dryRun = true
}
if (val == '--images') {
imagesOnly = true
}
if (val == '-r' || val == '-R') {
recurse = true
}
if (val == '-o') {
outputDir = process.argv[index + 1]
default:
break
}
})
// if no media dir jump out
// if no media dir passed jump out
if (!mediaDir) {
console.log('no directory passed to script')
return 0
}
//
// read directory
const dirList = await fs.readdir(mediaDir)
// variable to hold media
let media = []
let images = []
// read directory
const dirList = await fs.readdir(mediaDir)
if (!recurse) {
// If recursing we are making the "media" the directories where we will find the
// acutal media to playback or see
if (recurse) {
media = dirList.filter(i => !i.match(/\.[^/.]+$/))
} else {
media = dirList.filter(i => i.match(/.(mp\d|m\d\w)$/i))
images = dirList.filter(i => i.match(/.(jp\w*g|png)$/i))
}
// create an array of images found in the directory as well
images = dirList.filter(i => i.match(/.(jp\w*g|png)$/i))
// clean up directory for json
// clean up passed directory for json
let parent_dir = mediaDir
.match(/(?<=\/)(\w|\d)+\/*$/i)[0]
.replace(/\/$/i, '')
// set an output directory if not set by flags
if (!outputDir) {
outputDir = '.'
}
const obj = await Promise.all(media.map(async (m, i) => {
// THE MAIN EVENT
const obj = await Promise.all(media.map(async m => {
// setup structure
const _r = {
title: '',
details: '',
...genMetadata(m, formatted == 'parent' || formatted == 'both'),
parent_dir,
media: m,
image: images[i],
image: ''
}
// if we are scanning for images only, remove the 'image' property
// as it will be saved in the media property
if (imagesOnly) {
delete _r.image
} else {
if (waveform) {
// if waveform generate waveform
_r.image = await generateWaveform(m, mediaDir)
} else {
// if not compare the media name with the image name
// and if a match assign it to 'image' variable from earlier
_r.image = linkImage(m.replace(/\.[^/.]+$/, ''), images)
}
}
// if recurse (again) now we are looking for the media in the folders
if (recurse) {
// create full path from the passed dir, and the recuring dir
const rDir = path.join(mediaDir, m)
const files = await fs.readdir(rDir)
// read the dir
let files = await fs.readdir(rDir)
// filterout any rogue folders
// generate the metadata for each file
files = files.filter(f => f.match(/\.[^/.]+$/))
files = files.map(f => {
const { title, details } = genMetadata(f, formatted == 'recurse' || formatted == 'both')
return { title, details, media: f }
})
_r.album = true
_r.tracks = files
// if images only
if (imagesOnly) {
// setup object per image in array
_r.images = files
} else {
_r.album = true
_r.tracks = files
}
}
// return the result to the 'obj' variable
return _r
}))
const json = JSON.stringify(obj, null, 2)
let output = `${parent_dir}.json`
// turn the obj variable into JSON
const json = JSON.stringify(obj, null, 2)
// set the output filename
let outputFile = `${parent_dir}.json`
// check if file already exists at location
// const dataFile = await fs.readFile(path.join(outputDir, outputFile), 'utf8')
// console.log(JSON.parse(dataFile) || 'no data file exists')
// update only new fields
// if dryrun
if (dryRun) {
// just console it out
console.log(json)
} else {
fs.writeFile(path.join(outputDir, output), json)
// write it to a file
fs.writeFile(path.join(outputDir, outputFile), json)
}
}
function genMetadata(dir, formatted) {
let title, details
// if formatted flag set
if (formatted) {
// split the incoming name from the map on the '_'
// and set the first element to title, and the second to details
let [ t, d ] = dir.split('_')
// assign to return object
title = t
details = d ? d.replace(/\.+(mp\d|m\dv)$/i, '') : ''
} else {
// else just set title to filename without extensions
title = dir.replace(/\.[^/.]+$/, '')
}
return { title, details }
}
function linkImage(name, images) {
return images.find(i => {
return i.replace(/\.[^/.]+$/, '') == name
})
}
main()

View File

@ -1,5 +1,6 @@
import { LitElement, css, html, unsafeCSS } from 'lit'
import Router from './api/Router.js'
import { Task } from '@lit-labs/task'
import MainCSS from './assets/styles/main.scss?inline'
@ -10,13 +11,17 @@ import './components/Footer.js'
import './assets/styles/main.scss'
export class App extends LitElement {
static properties = {}
static properties = {
dialogEl: { state: true }
}
constructor() {
super()
}
firstUpdated() {
this.dialogEl = this.shadowRoot.querySelector('dialog')
Router.addEventListener('route-changed', () => {
if ('startViewTransition' in document) {
return document.startViewTransition(() => {
@ -28,6 +33,27 @@ export class App extends LitElement {
}
})
this.addEventListener('single-fullscreen-image', ({ detail }) => {
const { src, details } = detail
const img = new Image()
img.src = src
this.dialogEl.appendChild(img)
if (detail.details) {
const div = document.createElement('div')
const p = document.createElement('p')
p.textContent = details
div.appendChild(p)
this.dialogEl.appendChild(div)
}
this.dialogEl.showModal()
this.dialogEl.addEventListener('click', () => {
this.dialogEl.close()
this.dialogEl.innerHTML = ''
}, { once: true })
})
}
render() {
@ -35,6 +61,8 @@ export class App extends LitElement {
${Router.route.path == '/' ? '' : html`<mm-header title=${Router.route.title}></mm-header>`}
${Router.render()}
${Router.route.path == '/' ? '' : html`<mm-footer path=${Router.route.path}></mm-footer>`}
<dialog class="popup">
</dialog>
`
}
@ -45,6 +73,26 @@ export class App extends LitElement {
flex-direction: column;
height: 100vh;
}
dialog {
margin: auto;
border: none;
& div {
padding-block-start: 1em;
font-size: 1.25em;
}
& img {
display: block;
max-height: calc(100vmin - 2em);
max-width: calc(100vmin - 2em);
}
}
dialog::backdrop {
background-color: #00000090;
}
` ]
}

View File

@ -74,6 +74,7 @@ export default new Router({
short: 'Unpublished',
icon: 'headphones',
group: 'Music & Sound',
disabled: true,
plugins: [
lazy(() => import('../views/audio.js'))
],
@ -81,23 +82,23 @@ export default new Router({
},
{
path: resolveRouterPath('theatre'),
title: 'Music - Theatre Works',
short: 'Theatre Works',
icon: 'headphones',
title: 'Music-Theatre Works',
short: 'Music-Theatre',
icon: 'film',
plugins: [
lazy(() => import('../views/audio.js'))
lazy(() => import('../views/videos.js'))
],
render: () => html`<mm-audio></mm-audio>`
render: () => html`<mm-videos></mm-videos>`
},
{
path: resolveRouterPath('concerts'),
title: 'Concert Recordings',
short: 'Concerts',
icon: 'headphones',
icon: 'film',
plugins: [
lazy(() => import('../views/audio.js'))
lazy(() => import('../views/videos.js'))
],
render: () => html`<mm-audio></mm-audio>`
render: () => html`<mm-videos></mm-videos>`
},
{
path: resolveRouterPath('films'),
@ -114,6 +115,7 @@ export default new Router({
title: 'Scores, Posters, Ephemera',
short: 'images',
icon: 'camera',
disabled: true,
plugins: [
lazy(() => import('../views/images.js'))
],

View File

@ -6,7 +6,6 @@ body {
line-height: 1;
font-size: 16px;
--neutral-900: hsl(0 0% 0%);
--neutral-700: hsl(220 10% 44%);
--neutral-400: hsl(220 10% 88%);
@ -18,6 +17,7 @@ body {
--green-400: hsl(147 100% 34%);
--green-200: hsl(147 100% 50%);
--neutral-gradient-600: linear-gradient(to top,rgba(208,210,214,1) 0%, rgba(141,142,145,1) 100%);
--neutral-gradient-400: linear-gradient(to bottom, hsl(228, 5%, 82%) 0%, var(--neutral-400) 100%);
--green-gradient-400: linear-gradient(to bottom, var(--green-400) 0%, var(--green-500) 100%);
--green-inside-gradient-400: linear-gradient(to bottom, rgba(0, 154, 69, 1) 0%,rgba(177, 178, 181, 0) 100%), linear-gradient(rgba(0, 173, 78, 1),rgba(0, 173, 78, 1));

View File

@ -19,18 +19,26 @@ class AudioCard extends LitElement {
}
clickHandler() {
const event = new CustomEvent('select-audio', {
bubbles: true, composed: true,
detail: { ...this.details, idx: this.idx }
})
if (!this.selected) {
const event = new CustomEvent('select-audio', {
bubbles: true, composed: true,
detail: { ...this.details, idx: this.idx }
})
this.dispatchEvent(event)
this.dispatchEvent(event)
}
}
render() {
return html`
<div class="card ${this.selected ? 'selected' : ''}" @click=${this.clickHandler}>
<mm-icon name=${this.icon}></mm-icon>
${this.details.album && this.details.image
? html`<img
class="albumCover"
src=${this.details.image}
/>`
: html`<mm-icon name=${this.icon}></mm-icon>`
}
<main>
<p class="heading">${this.details?.title}</p>
@ -54,10 +62,18 @@ class AudioCard extends LitElement {
font-size: 3em;
}
.albumCover {
display: block;
height: 3em;
aspect-ratio: 1 / 1;
object-fit: cover;
background: lightgrey;
}
.card {
display: grid;
grid-auto-flow: column;
grid-template-columns: min-content 1fr;
grid-template-columns: auto 1fr;
gap: 1em;
align-items: center;
padding-inline: 0.75em;
@ -73,6 +89,10 @@ class AudioCard extends LitElement {
.card.selected {
outline: 2px solid var(--green-400, black);
}
.info {
max-width: 30ch;
}
` ]
}

View File

@ -43,13 +43,13 @@ class Footer extends LitElement {
renderLink(r, first = false) {
return html`
${first ? html`<span class="break"></span>` : '' }
<a href=${r.path} class="${r.path == this.path ? 'selected' : ''}">
${first && !r.disabled ? html`<span class="break"></span>` : '' }
${!r.disabled ? html`<a href=${r.path} class="${r.path == this.path ? 'selected' : ''}">
<mm-icon name=${r.icon}></mm-icon>
<span>
${r.short}
</span>
</a>
</a>` : '' }
`
}

View File

@ -18,9 +18,8 @@ class HorizontalScroller extends LitElement {
static styles = css`
:host {
--col-width: 10em;
--gap: 1em;
--gap: 0.75em;
display: flex;
padding-block-end: 0.5em;
}
.scroller {

View File

@ -39,6 +39,7 @@ class ImageCarousel extends LitElement {
padding-inline-end: 0.5em;
padding-block-start: 0.25em;
padding-block-end: 0.75em;
background: black;
}
mm-image {

View File

@ -37,15 +37,19 @@ class ModularPlayer extends LitElement {
this._initAudio()
}
firstUpdated() {
console.log(this.details)
}
_getTrack = new Task(
this,
async () => {
try {
if (this.details) {
if (this.details?.tracks) {
this.audio.src = `/media${this.details.media}/${this.details.tracks[this.track]}`
this.audio.src = `${this.details.media}/${this.details.tracks[this.track].media}`
} else {
this.audio.src = `/media${this.details.media}.mp3`
this.audio.src = `${this.details.media}`
}
this.audio.load()
if (this.playing && this.audio.paused) {
@ -95,7 +99,7 @@ class ModularPlayer extends LitElement {
this.track = 0
}
this.audio.src = `/media${this.details.media}/${this.details.tracks[this.track]}`
this.audio.src = `${this.details.media}/${this.details.tracks[this.track].media}`
this.audio.load()
}
})
@ -170,20 +174,35 @@ class ModularPlayer extends LitElement {
return `${percentage}%`
}
showImage() {
const event = new CustomEvent('single-fullscreen-image', {
bubbles: true, composed: true,
detail: { src: this.details.image }
})
this.dispatchEvent(event)
}
render() {
return html`
${ this.details ?
html`<div class="player">
${this.details.tracks ? html`
<div class="tracklist">
<h2>${this.details.title}</h2>
<header>
<img src=${this.details.image}
@click=${this.showImage}
/>
<h2>${this.details.title}</h2>
</header>
<div class="list">
<ul>
${this.details.tracks.map((t, i) => html`
<li class="${this.track === i ? 'selected' : ''}" data-track-number=${i} @click=${this._selectTrack}>
<mm-icon name="notes" class=${this.playing ? 'playing' : ''}></mm-icon>
<span>${t}</span>
<span>${t.title}</span>
</li>`)}
</ul>
</div>
@ -191,7 +210,7 @@ ${ this.details ?
` : html``}
<header>
<h2>${this.details.tracks ? this.details?.tracks[this.track] : this.details.title}</h2>
<h2>${this.details.tracks ? this.details?.tracks[this.track].title : this.details.title}</h2>
${this.details.tracks ? '' : html`<p class="details">${this.details.details}</p>`}
</header>
@ -216,7 +235,7 @@ ${ this.details ?
@input=${this._seekTrack}
class="progress"
></mm-range>
<img class="wav-img" loading="eager" src="/media${this.details.media}.png">
<img class="wav-img" loading="eager" src="${this.details.image}">
</div>
`
}
@ -263,11 +282,11 @@ ${ this.details ?
}
.player:has(.tracklist) {
grid-template-rows: 60% 0.5fr 0.3fr 1fr;
grid-template-rows: 67% 0.5fr 0.3fr 1fr;
padding-block-end: 2em;
gap: 0;
& header {
& > header {
margin-block-start: 1.5em;
margin-block-end: 2em;
}
@ -300,23 +319,36 @@ ${ this.details ?
.tracklist {
--tracklist-padding: calc(var(--padding) * 2);
position: relative;
display: flex;
flex-direction: column;
background: var(--neutral-gradient-400);
height: 100%;
> h2 {
& header {
margin-inline: var(--tracklist-padding);
margin-block-start: 0.75em;
margin-block-start: 1em;
margin-block-end: 0.75em;
padding-block-start: 0.75em;
border-block-start: thin solid var(--green-400);
display: flex;
gap: 0.5em;
align-items: end;
color: black;
& img {
height: 4em;
aspect-ratio: 1 / 1;
}
& > h2 {
line-height: 1;
max-width: 15ch;
}
}
> .list {
position: absolute;
bottom: 0;
top: calc(var(--tracklist-padding) * 2.5);
right: var(--tracklist-padding);
left: var(--tracklist-padding);
& .list {
flex-grow: 1;
margin-inline: var(--tracklist-padding);
overflow-x: hidden;
overflow-y: auto;
border-radius: 0.75em 0.75em 0 0;
@ -391,6 +423,7 @@ ${ this.details ?
}
.info:has(.waveform) {
& .time_pos,
& .time_dur {
position: absolute;

View File

@ -18,34 +18,42 @@ class NavCard extends LitElement {
firstUpdated() {
console.log(this.route)
this.shadowRoot.host.addEventListener('click', () => {
Router.navigate(this.route.path)
if (!this.route.disabled) {
Router.navigate(this.route.path)
}
})
}
navigate(path) {
path = path || this.route.path
Router.navigate(path)
if (!this.route.disabled) {
path = path || this.route.path
Router.navigate(path)
}
}
render() {
return html`
<div class="card">
${Array.isArray(this.route) ? html`
<p class="title">${this.route[0].group}</p>
<header class="title">
<span>${this.route[0].group}</span>
</header>
${this.route.map(r =>
html`
!r.disabled ? html`
<button @click=${() => this.navigate(r.path)}>
<mm-icon name=${r.icon}></mm-icon>
${r.title}
</button>
`
` : ''
)}
`
:
html`
<p class="title">${this.route?.title}</p>
<button class="iconOnly" @click=${() => this.navigate()}>
<mm-icon name=${this.route.icon}></mm-icon>
<header class="title">
<span>${this.route?.title}</span>
</header>
<button class="iconOnly" @click=${this.navigate}>
${!this.route.disabled ? html`<mm-icon name=${this.route.icon}></mm-icon>` : html`<span>coming soon...</span>`}
</button>
`
}
@ -88,6 +96,15 @@ class NavCard extends LitElement {
font-size: 0.75em;
text-align: center;
border-bottom: thin solid var(--highlight-color);
display: flex;
align-items: center;
min-height: 2.5em;
& > span {
display: block;
max-width: 18ch;
margin-inline: auto;
}
}
button {
@ -105,6 +122,10 @@ class NavCard extends LitElement {
text-shadow: 0 0 5px #ffffff;
margin: 0;
&:has(span) {
background: var(--neutral-gradient-600);
}
&.iconOnly {
display: flex;
gap: 0;
@ -112,6 +133,10 @@ class NavCard extends LitElement {
justify-content: center;
font-size: 1.5em;
padding: 1em;
& > span {
font-size: 0.5em;
}
}
& mm-icon {

View File

@ -13,6 +13,7 @@ class VerticalCard extends LitElement {
super()
this.details = {}
this.selected = false
}
select() {
@ -30,7 +31,7 @@ class VerticalCard extends LitElement {
return html`
<div @click=${this.select} class=${this.selected ? 'selected' : ''}>
<picture>
<img src="/media/${Router.route.path}/thumbs/${this.details.media}">
<img src="/media/${Router.route.path}/${this.details.image}">
</picture>
<aside>
<p class="title">${this.details?.title}</p>
@ -51,7 +52,7 @@ class VerticalCard extends LitElement {
div {
height: 100%;
display: grid;
grid-template-rows: 75% 25%;
grid-template-rows: 72% 28%;
background: lightgrey;
line-height: 1;
overflow: hidden;
@ -59,10 +60,11 @@ class VerticalCard extends LitElement {
background: var(--background-color);
color: var(--font-color);
align-content: start;
font-size: 1em;
}
.selected {
outline: 2px solid var(--color);
outline: 1px solid var(--color);
}
picture {

View File

@ -1,8 +1,6 @@
import { LitElement, css, html } from 'lit'
import { Task } from '@lit-labs/task'
import Photo from '/images/Meredith Monk (1974) Photo Lauretta Harris.jpg'
// components
import '../components/Loading.js'
import '../components/AudioCard.js'
@ -27,7 +25,9 @@ class AudioView extends LitElement {
const div = this.shadowRoot.querySelector('mm-audio-player')
div.addEventListener('transitionend', () => {
this.selected = { ...detail, media: `${Router.route.path}/${detail.media}` }
this.selected = {
...detail
}
div.classList.remove('unloading')
})
@ -49,10 +49,19 @@ class AudioView extends LitElement {
const res = await fetch(`/data${Router.route.path}.json`)
const json = await res.json()
this.tracks = json
// start track (0 is not currently available)
const idx = 1
this.selected = { ...this.tracks[idx], idx, media: `${Router.route.path}/${this.tracks[idx].media}` }
this.tracks = json.map(i => {
i.media = `/media${Router.route.path}/${i.media}`
i.image = i.image ? `/media${Router.route.path}/${i.image}` : ''
return i
})
if (this.tracks.length > 0) {
const idx = 0
this.selected = {
...this.tracks[idx], idx,
}
}
},
() => []
)
@ -70,21 +79,20 @@ class AudioView extends LitElement {
<div class="scroll-items">
${this._getAudio.render({
pending: () => html`<mm-loading style="--fill-color: grey"></mm-loading>`,
complete: () => html`${this.tracks.map((t, i) => html`
complete: () => html`${this.tracks.length > 0 ? this.tracks.map((t, i) => html`
<mm-acard
idx=${i}
icon=${t.album ? 'album' : 'play-circle'}
?selected=${t.title == this.selected.title && t.details == this.selected.details}
.details=${t}
></mm-acard>`)}`,
></mm-acard>`) : 'No tracks added for this category' }`,
error: (err) => html`Error: ${err}`
})}
</div>
</nav>
<div class="player">
<div class="player ${this.selected.tracks ? '' : 'single'}">
<div>
${this.selected?.tracks ? '' : html`<img class="bg-img" src=${Photo} />` }
<mm-audio-player .details=${this.selected}></mm-audio-player>
</div>
</div>
@ -126,6 +134,13 @@ class AudioView extends LitElement {
.player {
position: relative;
&.single > div {
background-image: url('/images/Meredith Monk (1974) Photo Lauretta Harris.jpg'), var(--green-gradient-400);
background-position: center;
background-size: 110%, 110%, cover;
background-blend-mode: soft-light, screen;
}
> div {
position: absolute;
inset: 0;

View File

@ -30,10 +30,6 @@ class ImageView extends LitElement {
json.forEach(i => i.path = `/media${Router.route.path}/${i.media}`)
this.images = json
this.selected = this.images[0]
console.log(this.selected)
} catch (err) {
console.error(err)
}
@ -42,30 +38,54 @@ class ImageView extends LitElement {
)
selectImage({ target }) {
const { details } = target
if (details?.title != this.selected?.title) {
this.selected = details
}
console.log(target.details)
const event = new CustomEvent('single-fullscreen-image', {
bubbles: true, composed: true,
detail: { ...target.details, src: `/media${Router.route.path}/${target.details.section}/${target.details.media}` }
})
this.dispatchEvent(event)
}
render() {
return html`
<mm-img-carousel .images=${this.images}></mm-img-carousel>
<!-- <mm-img-carousel .images=${this.images}></mm-img-carousel> -->
<mm-hscroller>
${this._getImages.render({ complete: () => this.images.map(i => html`
<mm-vcard @click=${this.selectImage} .details=${i} ?selected=${i.title == this.selected?.title}></mm-vcard>
`) })}
</mm-hscroller>
${this.images.length > 0 ?
html`
<div class="gallery">
${this._getImages.render({ complete: () => this.images.map(
section => html`
<header class="section-header">
<h3>${section.title}</h3>
</header>
<main>
${section.images.map(
i => html`
<mm-vcard
@click=${this.selectImage}
.details=${ { ...i, section: section.media } }
?selected=${i.title == this.selected?.title}
>
</mm-vcard>
`)}
</main>
`
) })}
</div>
` :
html`<h2>No images added to the gallery</h2>`
}
`
}
static styles = [ css`${unsafeCSS(MainCSS)}`, css`
:host {
flex-grow: 1;
display: grid;
grid-template-rows: 1fr auto;
gap: 0.5em;
height: 100%;
overflow: auto;
padding-inline: 1em;
padding-block: 1em;
}
mm-hscroller {
@ -77,12 +97,34 @@ class ImageView extends LitElement {
--color: var(--green-400, lime);
}
header {
padding-block-start: 1.5em;
padding-block-end: 1em;
font-size: 1.25em;
border-bottom: 1px solid var(--green-400);
margin-block-end: 1em;
}
main {
display: grid;
gap: 0.75em;
grid-template-columns: repeat(7, 1fr);
grid-auto-rows: 10em;
}
.image {
position: relative;
inline-margin: auto;
height: 100%;
}
mm-image-carousel {
position: absolute;
inset: 0;
}
` ]
}
customElements.define('mm-images', ImageView)

View File

@ -44,7 +44,7 @@ class VideoView extends LitElement {
<main>
<aside>
<h2>${this.selected.title}</h2>
<p class="detail">${this.selected.detail}</p>
<p class="details">${this.selected.details}</p>
</aside>
<mm-vplayer media='/media/${this.selected.media}' ?autoplay=${this.selected.autoplay}></mm-vplayer>
</main>
@ -55,7 +55,7 @@ class VideoView extends LitElement {
complete: () => html`${this.films.map(t => html`
<mm-vcard
.details=${t}
?selected=${t.title == this.selected.title && t.detail == this.selected.detail}
?selected=${t.title == this.selected.title && t.details == this.selected.details}
></mm-vcard>`
)}`
})}
@ -68,7 +68,7 @@ class VideoView extends LitElement {
flex-grow: 1;
height: 100%;
display: grid;
grid-template-rows: 70% 30%;
grid-template-rows: 1fr 0.55fr;
gap: 0.25em;
}
@ -95,7 +95,7 @@ class VideoView extends LitElement {
margin-block-end: 0.2em;
}
> .detail {
> .details {
line-height: 1.1;
}
}

View File

@ -5,6 +5,12 @@ export default defineConfig({
build: {
sourcemap: true,
target: [ 'esnext', 'edge100', 'firefox100', 'chrome100', 'safari18' ],
rollupOptions: {
external: [
'scripts',
'public/media'
],
},
},
server: {
host: '0.0.0.0'