diff options
-rw-r--r-- | album/alterniabound/album.txt | 2 | ||||
-rw-r--r-- | album/homestuck-vol-1-4/album.txt | 2 | ||||
-rw-r--r-- | album/mobius-trip-and-hadron-kaleido/album.txt | 21 | ||||
-rw-r--r-- | album/one-year-older/album.txt | 2 | ||||
-rw-r--r-- | flash/5426.gif | bin | 0 -> 26710 bytes | |||
-rw-r--r-- | flash/flashes.txt | 944 | ||||
-rw-r--r-- | flashes/flashes.txt | 4 | ||||
-rw-r--r-- | site.css | 76 | ||||
-rw-r--r-- | upd8.js | 523 |
9 files changed, 1419 insertions, 155 deletions
diff --git a/album/alterniabound/album.txt b/album/alterniabound/album.txt index ef296405..69285f94 100644 --- a/album/alterniabound/album.txt +++ b/album/alterniabound/album.txt @@ -58,7 +58,7 @@ Commentary: Don't tell anyone, but this is actually a remix of one of Jit's old fansongs called <a href="track/under-the-hat/index.html">Under the Hat</a>, which was a battle theme for Dad. So if your heart still pines for him... his soul and pipe are contained deep within this track. So damn catchy and sleuthy. ------------------------------------------------------------------------------- -Track: BL1ND JUST1C3 - 1NV3ST1G4T1ON !! +Track: BL1ND JUST1C3 : 1NV3ST1G4T1ON !! Artist: Malcolm Brown References: The Lemonsnout Turnabout, Sburban Jungle URLs: https://homestuck.bandcamp.com/track/bl1nd-just1c3-1nv3st1g4t1on-2 diff --git a/album/homestuck-vol-1-4/album.txt b/album/homestuck-vol-1-4/album.txt index ff5dd1f4..7516e014 100644 --- a/album/homestuck-vol-1-4/album.txt +++ b/album/homestuck-vol-1-4/album.txt @@ -290,7 +290,7 @@ Original Date: April 13, 2010 URLs: https://homestuck.bandcamp.com/track/doctor-3 Commentary: <i>Clark Powell:</i> - Doctor was originally by Buzinkai and then a now non-active member Michael Vellejo added a few bits of percussion to it. I then put together a larger mix of the tune with shinier production and a glockenspiel tag, and this was the version Andrew used in the end. + Doctor was originally by Buzinkai and then a now non-active member Michael Vallejo added a few bits of percussion to it. I then put together a larger mix of the tune with shinier production and a glockenspiel tag, and this was the version Andrew used in the end. <i>Buzinkai:</i> Doctor was written before Homestuck, actually. The only thing I can really remember was that Super Smash Bros Brawl came out right before I finished it. The original loop (which is not the one specifically heard in the comic, but was included in the album release) was directly inspired by music from Cave Story, and I was trying to at the time musically embody how I felt at the time, I think. Though it never seems to come out exactly as I plan it, I enjoyed the results. I will say that I cannot truly believe how many people have remixed it. The arpeggio part at the end goes between the left, both, and right speakers sequentially. I was too lazy to set the channel settings manually, so I did each note on a different instrument, which is set to each speaker channel. Not many people know that, and I think it actually made it a living hell for remixers who got a hold of the original file. diff --git a/album/mobius-trip-and-hadron-kaleido/album.txt b/album/mobius-trip-and-hadron-kaleido/album.txt index 3b977744..da2c42ac 100644 --- a/album/mobius-trip-and-hadron-kaleido/album.txt +++ b/album/mobius-trip-and-hadron-kaleido/album.txt @@ -4,6 +4,27 @@ Cover Art: Tavia Morra, Richard Gung Track Art: Tavia Morra, Richard Gung Date: May 31, 2011 00:00:04 FG: #eecc22 +Commentary: + <i>Michael Guy Bowman:</i> + <i>Is there a linear story to this album, or is it some other form of story telling?</i> + I've seen a good handful of questions like this and I'd be glad to clear this up. This album does have characters and a story behind it, but it is not a linear story or a rock opera. It's an eponymous album by its members Mobius Trip and Hadron Kaleido. + Back when Andrew proposed the music project in March of 2009, he made it clear that one of the things he wanted to do was create a lot of "fake bands" which would exist as actual musical entities within the Homestuck Universe in much the same light as the Gorillaz, the Monkees, or the Chipmunks (wow, those are all animal names). While we accomplished that somewhat with albums like "Squiddles Singalong", most of the concept albums have largely been musical homages to the actual characters. For example the Felt didn't "make" their album of the same name, the music team made it as program music. + <i>Mobius Trip and Hadron Kaleido</i> is meant to be literally an album that Mobius and Hadron would make together. Like the Kernelsprites, they spread their knowledge of Sburb and <u>The Ultimate Riddle</u> cryptically through overtly complex riddles rendered as rock music. They have a seemingly limitless knowledge of all things in the Homestuck universe, or do they? For all their answers they don't just give anything away, they tease you with their songs. + Hoohoohoo! + <i>How much thought did you put into connecting the album with Homestuck? Or was it just supposed to be a silly thing with a loose connection?</i> + From the very beginning I wanted to make this an album for Homestuck fans, but I also wanted this to be something which could be listened to from the outside-in. My goal was to create a solid set of songs that would revisit the basic themes of Homestuck, meaning that the fans would get a whole new dimension to the world of Homestuck and listeners unfamiliar with the comic could discover listen to it and, if so intrigued, discover the entire world of MSPA to create context for the album. Think of it as the relationship between <i>House of Leaves</i> and the band Poe - there is intertextuality between the literature and music and together they create a bigger picture. Plus, you can discover them in whatever order you like. + Personally, I believe the album is very faithful to the basic ideas of Homestuck. All the big themes are there: time, eternity, repetition, survival, the unknown, fractals, betrayal, dreams, romance, hypnosis, pumpkins, etc. While I certainly had ideas for songs already floating around before the fake band project fell in my lap, my rule of thumb was to incorporate Homestuck any time I hit a dead-end and didn't know what to do. Plus, the process of planning the art was something that Tavia and I were working on from almost the very beginning. + <i>how much of the instrumentation was synthesized and how much of it was organic? i'm thinking specifically of the fiddly guitar bits in forever</i> + I play every instrument on this record, and all the ones that aren't real instruments I either played through a synthesizer or sequenced myself. All the guitar is real guitar played by myself. I did all of the singing except for some backup vocals by Tavia. About half of the bass parts are me playing an old P-Bass and the other half are some spectacularly vintage-sounding synth basses that I sequenced. While I do play drums, I was unable to use my drum set in the making of this album and instead spent an intense amount of time laying down the drum parts as the first step in making each track. Most of the performance side of the album was really quick and just involved running through the song and playing a midi keyboard run through patches. + The "fiddly guitar bits" are played on a white Epiphone Les Paul named Glinda. + <i>Are there any intentional song similarities or specific inspirations, musically? Chain of Prospit reminds me a LOT of She Blinded Me With Science by Thomas Dolby, in a very good way.</i> + None of the songs are supposed to sound intentionally like any other song, but my style is informed by the groups I've listened to that I really enjoy. I can see the resemblance, but when I listen to my own music I always hear a demolition derby of every song I've ever liked. All the things I've seen posted about my music being a mix between groups like Daft Punk, David Bowie, or They Might Be Giants really satisfy me because those are most of the same things I listen to. + I think I listened to "She Blinded Me With Science" a lot about five years ago. Thomas Dolby is a cool guy. I really like his soundtrack to Gate to the Mind's Eye. + <i>Tavia Morra:</i> + <i>Also any fun stories you can share from taking the pictures for the graphics?</i> + For the portrait of Hadron's face, I cobbled together my little lighting and shooting rig with the following: tripod, camera, music stand, orange extension cord, nightlight, and a chair. It was super guerrilla, if you consider shooting in the comfort of your own home guerrilla. Either way, it was actually a very pleasant photoshoot that didn't require an extensive amount of time to set up. + Oh, and I kept eating cookies during one of the photoshoots. + That's all I can remember at the moment. Bowman might remember more. ------------------------------------------------------------------------------- Track: Forever URLs: https://bowman.bandcamp.com/track/forever diff --git a/album/one-year-older/album.txt b/album/one-year-older/album.txt index c88115c5..235ced6c 100644 --- a/album/one-year-older/album.txt +++ b/album/one-year-older/album.txt @@ -92,7 +92,7 @@ Track Art: Killian Ng URLs: https://erikscheele.bandcamp.com/track/unlabeled Commentary: <i>Erik Scheele:</i> - This is the second of the solo piano pieces on this album, at least in the main tracks, and a really late release as well, given that it first <a href="https://www.homestuck.com/story/3725">appeared</a> in the comic some time around a year ago. I've held it back from getting released just so it could go on this record, so I'm glad it could finally go out. + This is the second of the solo piano pieces on this album, at least in the main tracks, and a really late release as well, given that it first appeared in the comic some time around a year ago. I've held it back from getting released just so it could go on this record, so I'm glad it could finally go out. This is also the only piece on the album that doesn't have a specific event to go along with it. Instead, I went for where it appeared in the comic when placing it, and see it as more of a small interlude. The intermission between Act 1 and Act 2 of a musical, if you will. The art is meant to go along with this as well, a sort of non-canon get-together of the first set of trolls and kids we know, and I can imagine them playing this record while they chill. ------------------------------------------------------------------------------- Track: Skaian Shrapnel diff --git a/flash/5426.gif b/flash/5426.gif new file mode 100644 index 00000000..0fbd4731 --- /dev/null +++ b/flash/5426.gif Binary files differdiff --git a/flash/flashes.txt b/flash/flashes.txt new file mode 100644 index 00000000..48655f1e --- /dev/null +++ b/flash/flashes.txt @@ -0,0 +1,944 @@ +ACT: Act 1 - The Note Desolation Plays +FG: #7799ff +------------------------------------------------------------------------------ +Flash: [S] John: Play haunting piano refrain. +Page: 77 +Date: April 21, 2009 +Tracks: +- Showtime (Piano Refrain) +------------------------------------------------------------------------------ +Flash: [S] ==> +Page: 82 +Date: April 24, 2009 +Tracks: +- Foley (by Clark Powell) +------------------------------------------------------------------------------ +Flash: [S] John: Enter. +Page: 88 +Date: April 27, 2009 +Tracks: +- Harlequin +------------------------------------------------------------------------------ +Flash: [S] STRIFE! +Page: 90 +Date: April 28, 2009 +Tracks: +- Showtime (Original Mix) +------------------------------------------------------------------------------ +Flash: [S] ==> +Page: 137 +Date: May 9, 2009 +Tracks: +- Sburban Jungle +------------------------------------------------------------------------------ +Flash: [S] ==> +Page: 186 +Date: May 21, 2009 +Tracks: +- Harlequin +------------------------------------------------------------------------------ +Flash: [S] Rose: Play a haunting refrain on the violin. +Page: 222 +Date: May 29, 2009 +Tracks: +- Aggrieve (Violin Refrain) +------------------------------------------------------------------------------ +Flash: [S] John: Take bite of apple. +Page: 246 +Date: June 7, 2009 +Tracks: +- Sburban Countdown +------------------------------------------------------------------------------ +ACT: Act 2 - Raise of the Conductor's Baton +FG: #ff5555 +------------------------------------------------------------------------------ +Flash: [S] YOU THERE. BOY. +Page: 253 +Date: June 14, 2009 +Tracks: +- Showtime (Piano Refrain) +------------------------------------------------------------------------------ +Flash: [S] ==> +Page: 338 +Date: July 4, 2009 +Tracks: +- 01, 02 (by Andrew Hussie) +- 03, 04, 05, 11 (by Gabe Nezovic) +- 06, 07, 12, 13, 14, 15, 16 (by Robert J! Lake) +- 08, 09 (by xerxes333) +- 10 (by Robert Blaker) +------------------------------------------------------------------------------ +Flash: [S] Rose: Youth roll right out the front door. +Page: 388 +Date: July 19, 2009 +Tracks: +- Aggrieve +------------------------------------------------------------------------------ +Flash: [S] ==>==>==>!!!!!!!!! +Page: 393 +Date: July 22, 2009 +Tracks: +- Showtime (Imp Strife Mix) +------------------------------------------------------------------------------ +Flash: [S] GET UP JOHN, THIS IS NO TIME FOR SLUMBER. +Page: 397 +Date: July 23, 2009 +Tracks: +- Showtime (Imp Strife Mix) +------------------------------------------------------------------------------ +Flash: [S] JOHN, SALVAGE YOUR WEAPON AND FIGHT ON! +Page: 400 +Date: July 25, 2009 +Tracks: +- Showtime (Imp Strife Mix) +------------------------------------------------------------------------------ +Flash: [S] WHAT THIS IS SO OUTRAGEOUS +Page: 418 +Date: July 30, 2009 +Tracks: +- Nannaquin +------------------------------------------------------------------------------ +Flash: [S] GO ON. ==> +Page: 422 +Date: August 1, 2009 +Tracks: +- Skies of Skaia +------------------------------------------------------------------------------ +Flash: [S] ==> +Page: 476 +Date: August 15, 2009 +Tracks: +- Harlequin (Rock Version) +------------------------------------------------------------------------------ +Flash: [S] John: Sleep. +Page: 644 +Date: September 15, 2009 +Tracks: +- John Sleeps - Skaian Magicant +------------------------------------------------------------------------------ +Flash: [S] John: Wake up. +Page: 651 +Date: September 17, 2009 +Tracks: +- John Sleeps - Skaian Magicant +------------------------------------------------------------------------------ +Flash: [S] Dave: Ascend to the highest point of the building. +Page: 665 +Date: September 21, 2009 +Tracks: +- Upward Movement (Dave Owns) +------------------------------------------------------------------------------ +Flash: [S] WV: Lead your men to victory! +Page: 721 +Date: October 2, 2009 +Tracks: +- Vagabounce +------------------------------------------------------------------------------ +Flash: [S] WV: Hasten to the exit post-haste! +Page: 755 +Date: October 9, 2009 +Tracks: +- Sburban Reversal +------------------------------------------------------------------------------ +Flash: [S] WV: Ascend. +Page: 757 +Date: October 11, 2009 +Tracks: +- Explore +------------------------------------------------------------------------------ +ACT: Act 3 - Insane Corkscrew Haymakers +FG: #55ff77 +------------------------------------------------------------------------------ +Flash: [S] Jade: Play a silly flute refrain. +Page: 769 +Date: October 15, 2009 +Tracks: +- Flute performance (by Jan Van Den Hemel) +------------------------------------------------------------------------------ +Flash: [S] Jade: Play a hauntingly relaxing bassline. +Page: 822 +Date: October 27, 2009 +Tracks: +- Gardener +------------------------------------------------------------------------------ +Flash: [S] Jade: Open FreshJamz! +Page: 830 +Date: October 31, 2009 +Tracks: +- Showtime Remix +- Aggrieve Remix +- Verdancy (Bassline) +- Potential Verdancy +- Ohgodwhat +- Ohgodwhat Remix +- Rediscover Fusion +- Crystalanthemums +- Explore Remix +------------------------------------------------------------------------------ +Flash: [S] MIDNIGHT CREW: ACT 1031 +Page: 833 +Date: November 2, 2009 +Tracks: +- Dead Shuffle +------------------------------------------------------------------------------ +Flash: [S] Dave: STRIFE. +Page: 836 +Date: November 6, 2009 +Tracks: +- Beatdown (Strider Style) +------------------------------------------------------------------------------ +Flash: [S] Jade: Descend. +Page: 843 +Date: November 8, 2009 +Tracks: +- Harleboss +------------------------------------------------------------------------------ +Flash: [S] Dave: Abscond. +Page: 871 +Date: November 18, 2009 +Tracks: +- Beatdown Round 2 +------------------------------------------------------------------------------ +Flash: [S] Rose: Ascend. +Page: 879 +Date: November 20, 2009 +Tracks: +- Harleboss +------------------------------------------------------------------------------ +Flash: [S] Strife!!! +Page: 918 +Date: November 27, 2009 +Tracks: +- Dissension (Original) +------------------------------------------------------------------------------ +Flash: [S] Rose: Fast forward to now. +Page: 938 +Date: December 1, 2009 +Tracks: +- Chorale for Jaspers +------------------------------------------------------------------------------ +Flash: [S] Ride. +Page: pony +Date: December 1, 2009 +Tracks: +- Pony Chorale +------------------------------------------------------------------------------ +Flash: [S] John: Examine your dad's room. +Page: 948 +Date: December 3, 2009 +Tracks: +- Revelawesome +------------------------------------------------------------------------------ +Flash: [S] John: Mental breakdown. +Page: 979 +Date: December 6, 2009 +Tracks: +- Hardlyquin +------------------------------------------------------------------------------ +Flash: [S] Jade: Retrieve package. +Page: 980 +Date: December 8, 2009 +Tracks: +- An Unbreakable Union +- Carefree Victory +------------------------------------------------------------------------------ +Flash: [S] Jade: Dream up extra arms and play advanced bass solo. +Page: 1026 +Date: December 18, 2009 +Tracks: +- The Beginning of Something Really Excellent +------------------------------------------------------------------------------ +Flash: [S] Dave: Strife! +Page: 1070 +Date: December 24, 2009 +Tracks: +- Versus +------------------------------------------------------------------------------ +Flash: [S] Jade: Pester John. +Page: 1073 +Date: December 29, 2009 +Tracks: +- Ballad of Awakening +------------------------------------------------------------------------------ +Flash: [S] Enter. +Page: 1149 +Date: January 14, 2010 +Tracks: +- Sburban Jungle +------------------------------------------------------------------------------ +ACT: Intermission - Don't Bleed on the Suits. +FG: #22cc22 +------------------------------------------------------------------------------ +Flash: [S][I] ==> +Page: 1267 +Date: January 29, 2010 +Tracks: +- Three in the Morning +------------------------------------------------------------------------------ +ACT: Act 4 - Flight of the Paradox Clones +FG: #b536da +------------------------------------------------------------------------------ +Flash: [S] ACT 4 ==> +Page: 1358 +Date: February 10, 2010 +Tracks: +- Doctor +------------------------------------------------------------------------------ +Flash: [S] ==> +Page: 1407 +Date: February 17, 2010 +Tracks: +- Endless Climb +------------------------------------------------------------------------------ +Flash: [S] Dave: Accelerate. +Page: 1641 +Date: April 2, 2010 +Tracks: +- Atomyk Ebonpyre +------------------------------------------------------------------------------ +Flash: [S] ==> +Page: 1656 +Date: April 3, 2010 +Tracks: +- Bed of Rose's / Dreams of Derse +------------------------------------------------------------------------------ +Flash: [S] Jack: Ascend. +Page: 1668 +Date: April 13, 2010 +Tracks: +- Black +- Descend +------------------------------------------------------------------------------ +Flash: [S] Rose and Dave: Shut up and jam. +Page: 1720 +Date: April 22, 2010 +Tracks: +- Unsheath'd +- Welcome to the New Extreme +- Octoroon Rangoon +- Derse Dreamers +- Phantasmagoric Waltz +------------------------------------------------------------------------------ +Flash: [S] WV?: Rise up. +Page: 1801 +Date: May 5, 2010 +Tracks: +- Skaian Skirmish +------------------------------------------------------------------------------ +Flash: [S] John: Reunite with your loving wife and daughter. +Page: 1931 +Date: May 26, 2010 +Tracks: +- How Do I Live (Bunny Back in the Box Version) +------------------------------------------------------------------------------ +Flash: [S] Descend. +Page: 1940 +Date: May 31, 2010 +Tracks: +- Descend +------------------------------------------------------------------------------ +ACT: Act 5 Act 1 - <span style="color: #008282">MOB1US DOUBL3 R34CH4ROUND</span> +FG: #0000ff +------------------------------------------------------------------------------ +Flash: [S] Make her pay. +Page: 2578 +Date: September 8, 2010 +Tracks: +- Crystamanthequins +------------------------------------------------------------------------------ +ACT: Act 5 Act 2 - <span style="color: #2ed73a">He is already here.</span> +FG: #ff0000 +------------------------------------------------------------------------------ +Flash: [S] ACT 5 ACT 2 ==> +Page: 2626 +Date: September 19, 2010 +Tracks: +- Homestuck +------------------------------------------------------------------------------ +Flash: [S] Vriska: Watch street tough maverick with nothing to lose +Page: 2787 +Date: October 19, 2010 +Tracks: +- How Do I Live (Bunny Back in the Box Version) +------------------------------------------------------------------------------ +Flash: [S] Past Karkat: Wake up. +Page: 2792 +Date: October 25, 2010 +Tracks: +- Karkat's Theme +- Vriska's Theme +- Terezi's Theme +- AlterniaBound +- Spider's Claw +- MeGaLoVania +- A Tender Moment +- Nic Cage Song +- Secret ROM (by Toby Fox) +- Boy Skylark (Brief) +- Hero's Growth (by Solatrus) +- Phrenic Phever +- Walk-Stab-Walk (R&E) +- Horschestra +------------------------------------------------------------------------------ +Flash: [S] Jade: Wake up. +Page: 2848 +Date: November 10, 2010 +Tracks: +- Let the Squiddles Sleep (End Theme) +------------------------------------------------------------------------------ +Flash: [S] Jade: Enter. +Page: 2927 +Date: November 28, 2010 +Tracks: +- Umbral Ultimatum +------------------------------------------------------------------------------ +Flash: [S] ==> +Page: 2988 +Date: December 4, 2010 +Tracks: +- Frost:frost-vol6 +------------------------------------------------------------------------------ +Flash: [S] Jade: STRIFE!!!!!!!!!!!! +Page: 3001 +Date: December 6, 2010 +Tracks: +- Sunslammer +------------------------------------------------------------------------------ +Flash: [S] John: Enter village. +Page: 3079 +Date: December 15, 2010 +Tracks: +- Planet Healer +------------------------------------------------------------------------------ +Flash: [S] JOHN. RISE UP. +Page: 3087 +Date: December 16, 2010 +Tracks: +- Savior of the Waking World +------------------------------------------------------------------------------ +Flash: [S] Wake. +Page: 3297 +Date: January 15, 2011 +Tracks: +- MeGaLoVania +------------------------------------------------------------------------------ +Flash: [S] Kanaya: Return to the core. +Page: 3321 +Date: January 22, 2011 +Tracks: +- Darling Kanaya +- Karkat's Theme +- Eridan's Theme +- Nautical Nightmare +- Heir Conditioning +------------------------------------------------------------------------------ +Flash: [S] Equius: Seek the highb100d. +Page: 3438 +Date: February 6, 2011 +Tracks: +- Horschestra STRONG Version +- Nepeta's Theme +- Blackest Heart (With Honks) +- Midnight Calliope +- Miracles (by ICP, Toby Fox) +------------------------------------------------------------------------------ +Flash: [S] 3x SHOWDOWN COMBO. +Page: 3520 +Date: February 16, 2011 +Tracks: +- Trollian Standoff +------------------------------------------------------------------------------ +Flash: [S] All: Behold glory of Zillyhoo. +Page: 3679 +Date: March 23, 2011 +Tracks: +- Warhammer of Zillyhoo +------------------------------------------------------------------------------ +Flash: [S] Seer: Descend. +Page: 3695 +Date: March 30, 2011 +Tracks: +- Black Rose / Green Sun +------------------------------------------------------------------------------ +Flash: [S] ==> +Page: 3696 +Date: April 2, 2011 +Tracks: +- At The Price of Oblivion +------------------------------------------------------------------------------ +Flash: [S] Terezi: Read note. +Page: 3718 +Date: April 17, 2011 +Tracks: +- Secret ROM (by Toby Fox) +------------------------------------------------------------------------------ +Flash: [S] Terezi: Play records. +Page: 3725 +Date: April 19, 2011 +Tracks: +- Trollcops +- Havoc To Be Wrought +- Rumble at the Rink +- Unlabeled +- XROM (by Toby Fox) +- I'm a Member of the Midnight Crew (by Eddie Morton) +------------------------------------------------------------------------------ +Flash: [S] Seer: Ascend. +Page: 3744 +Date: April 30, 2011 +Tracks: +- Terezi Owns +------------------------------------------------------------------------------ +Flash: [S] Flip. +Page: 3760 +Date: May 15, 2011 +Tracks: +- BL1ND JUST1C3 : 1NV3ST1G4T1ON !! +------------------------------------------------------------------------------ +Flash: [S] Attempt rare and highly dangerous 5x SHOWDOWN COMBO. +Page: 4085 +Date: August 22, 2011 +Tracks: +- The Carnival +------------------------------------------------------------------------------ +Flash: [S] Cascade. +Page: 4109 +Date: October 25, 2011 +Tracks: +- Cascade (Beta) +- Flare +- Savior of the Dreaming Dead +- Black Hole / Green Sun +------------------------------------------------------------------------------ +ACT: Intermission 2 - The Man in the Cairo Overcoat. +FG: #22cc22 +------------------------------------------------------------------------------ +Flash: [S] Begin intermission 2. +Page: 4111 +Date: October 31, 2011 +Tracks: +- English +------------------------------------------------------------------------------ +ACT: Act 6 Act 1 - Through Broken Glass +FG: #7799ff +------------------------------------------------------------------------------ +Flash: [S] ACT 6 +Page: 4113 +Date: November 11, 2011 +Tracks: +- Homestuck Anthem +------------------------------------------------------------------------------ +Flash: [S] ==> +Page: 4275 +Date: December 7, 2011 +Tracks: +- Foley (by Toby Fox) +------------------------------------------------------------------------------ +Flash: [S] Jane: Get mail. +Page: 4282 +Date: December 9, 2011 +Tracks: +- Foley (by Clark Powell) +------------------------------------------------------------------------------ +ACT: Act 6 Intermission 1 - corpse party +FG: #a10000 +------------------------------------------------------------------------------ +Flash: [S][A6I1] Karkat: Mental breakdown. +Page: 4373 +Date: December 23, 2011 +Tracks: +- Frustracean +------------------------------------------------------------------------------ +Flash: [S] END OF ACT 6 INTERMISSION 1 +Page: 4390 +Date: December 29, 2011 +Tracks: +- Infinity Mechanism +------------------------------------------------------------------------------ +ACT: Act 6 Act 2 - Your shit is wrecked. +FG: #f2a400 +------------------------------------------------------------------------------ +Flash: [S] Roxy: Sleepwalk. +Page: 4486 +Date: January 21, 2011 +Tracks: +- Even in Death +------------------------------------------------------------------------------ +Flash: [S] RAP-OFF!!!!!!!!!! +Page: 4541 +Date: February 4, 2012 +Tracks: +- Anbroids:anbroids-v2 +------------------------------------------------------------------------------ +Flash: [S] Prince of Heart: Rise up. +Page: 4572 +Date: February 16, 2012 +Tracks: +- Time on My Side +------------------------------------------------------------------------------ +Flash: [S] Frigglish: Fast forward to Jaspersprite. +Page: 4617 +Date: February 26, 2012 +Tracks: +- Chorale for Jaspers +------------------------------------------------------------------------------ +Flash: [S] Jane: Enter. +Page: 4665 +Date: March 8, 2012 +Tracks: +- Another Jungle +- A Taste for Adventure +------------------------------------------------------------------------------ +ACT: Act 6 Intermission 2 - penis ouija +FG: #e00707 +------------------------------------------------------------------------------ +Flash: [S][A6I2] ??? +Page: 4815 +Date: April 3, 2012 +Tracks: +- weird moody horse shit (by Alexander Rosetti) +------------------------------------------------------------------------------ +ACT: Act 6 Act 3 - Nobles +FG: #8899cc +------------------------------------------------------------------------------ +Flash: [S] ACT 6 ACT 3 +Page: 4820 +Date: April 14, 2012 +Tracks: +- Rain +------------------------------------------------------------------------------ +Flash: [S] Jane: Proceed. +Page: 4825 +Date: April 16, 2012 +Tracks: +- Ruins (With Strings) +------------------------------------------------------------------------------ +Flash: [S] Jane: Cautiously approach. +Page: 4827 +Date: April 17, 2012 +Tracks: +- Elevatorstuck +------------------------------------------------------------------------------ +Flash: [S] DD: Ascend. +Page: 4942 +Date: May 17, 2012 +Tracks: +- Black +------------------------------------------------------------------------------ +Flash: [S] DD: Ascend more casually. +Page: 4944 +Date: May 17, 2012 +Tracks: +- I'm a Member of the Midnight Crew (Acapella) +------------------------------------------------------------------------------ +Flash: [S] Terry: Fast forward to Liv. +Page: 5027 +Date: June 12, 2012 +Tracks: +- I Don't Want to Miss a Thing +------------------------------------------------------------------------------ +Flash: [S] Dirk: Synchronize. +Page: 5238 +Date: July 9, 2012 +Tracks: +- Unite Synchronization +------------------------------------------------------------------------------ +Flash: [S] Dirk: Unite. +Page: 5252 +Date: July 9, 2012 +Tracks: +- Unite Synchronization +------------------------------------------------------------------------------ +Flash: [S] Dirk: Synchronize. +Page: 5238 +Date: July 9, 2012 +Tracks: +- Unite Synchronization +------------------------------------------------------------------------------ +Flash: [S] Caliborn: Enter. +Page: 5261 +Date: July 28, 2012 +Tracks: +- Eternity Served Cold +------------------------------------------------------------------------------ +ACT: Act 6 Intermission 3 - Ballet of the Dancestors +FG: #b536da +------------------------------------------------------------------------------ +Flash: [S] ACT 6 INTERMISSION 3 +Page: 5263 +Date: August 31, 2012 +Tracks: +- Fuchsia Ruler +- Darling Dolorosa (by Toby Fox) +- GameGrl (Original 1993 Mix) +- Iron Infidel +- Elevatorstuck +------------------------------------------------------------------------------ +Flash: [S][A6I3] ==> +Page: 5308 +Date: September 24, 2012 +Tracks: +- Hate You +- G4M3BL0RG (by Toby Fox) +- Olive Rogue +- Violet Prince +- Purple Bard +- Teal Seer +- Crab Waltz (by Toby Fox) +------------------------------------------------------------------------------ +Flash: [S][A6I3] ==> +Page: 5398 +Date: October 22, 2012 +Tracks: +- 108 Stars of Density (by Toby Fox) +- The Brave and the Bronze (by Yan Rodriguez) +- Jade Sylph +- Rust Maid +- Indigo Heir +- Orchid Horror +- Davesprite +- iRRRRRRRRECONCIA8LE +------------------------------------------------------------------------------ +Flash: [S][A6I3] ==> +Page: 5426 +Date: October 27, 2012 +Jiff: Yeah +Tracks: <span class="loading">Loading</span> +------------------------------------------------------------------------------ +Flash: [S][A6I3] MINISTRIFE!!! +Page: 5427 +Date: November 3, 2012 +Tracks: +- Killed by BR8K Spider!!!!!!!! +------------------------------------------------------------------------------ +ACT: Act 6 Act 4 - Void +FG: #cccccc +------------------------------------------------------------------------------ +Flash: [S] ACT 6 ACT 4 +Page: 5438 +Date: November 12, 2012 +Tracks: +- Even in Death (T'Morra's Belly Mix) +------------------------------------------------------------------------------ +Flash: [S] ==> +Page: 5440 +Date: November 14, 2012 +Tracks: +- English +------------------------------------------------------------------------------ +ACT: Act 6 Intermission 4 - Dead +FG: #777777 +------------------------------------------------------------------------------ +Flash: [S][A6I4] ==> +Page: 5471 +Date: November 18, 2012 +Tracks: +- Elevatorstuck +------------------------------------------------------------------------------ +Flash: [S][A6I4] ==> +Page: 5472 +Date: November 19, 2012 +Tracks: +- Elevatorstuck +------------------------------------------------------------------------------ +Flash: [S][A6I4] ==> +Page: 5473 +Date: November 19, 2012 +Tracks: +- Elevatorstuck +------------------------------------------------------------------------------ +Flash: [S][A6I4] ==> +Page: 5474 +Date: November 19, 2012 +Tracks: +- Elevatorstuck +------------------------------------------------------------------------------ +Flash: [S][A6I4] ==> +Page: 5485 +Date: November 21, 2012 +Tracks: +- Elevatorstuck +------------------------------------------------------------------------------ +Flash: [S!][A6I4] ==> +Page: 5494 +Date: November 25, 2012 +Tracks: +- Elevatorstuck +------------------------------------------------------------------------------ +Flash: [!!!][A6I4] ==> +Page: 5495 +Date: November 25, 2012 +Tracks: +- Elevatorstuck +------------------------------------------------------------------------------ +ACT: Act 6 Act 5 - Of Gods and Tricksters +FG: #ffee00 +------------------------------------------------------------------------------ +Flash: [S] ACT 6 ACT 5 +Page: 5512 +Date: November 28, 2012 +Tracks: +- A Taste for Adventure +------------------------------------------------------------------------------ +Flash: [S] Ride. +Page: 5655 +Date: December 26, 2012 +Tracks: +- Horschestra STRONG Version +------------------------------------------------------------------------------ +Flash: [S] Jane: Engage. +Page: 5711 +Date: January 9, 2013 +Tracks: +- Trickster Mode (by Toby Fox) +------------------------------------------------------------------------------ +Flash: [S] Jane: Blast off. +Page: 5712 +Date: January 10, 2013 +Tracks: +- Trickster Mode (by Toby Fox) +------------------------------------------------------------------------------ +Flash: [S] ACT 6 ACT 5 ACT 2 +Page: 5714 +Date: January 11, 2013 +Tracks: +- Kazoostuck (by Toby Fox) +- (I'm not going through the rest of the Trickster flashes, sorry.) +------------------------------------------------------------------------------ +ACT: Act 6 Intermission 5 - <span style="color: #929292">I'M PUTTING YOU ON SPEAKER CRAB.</span> +FG: #77ff88 +------------------------------------------------------------------------------ +Flash: [S][A6I5] BEGIN INTERFISHIN +Page: 5981 +Date: March 10, 2013 +Tracks: +- Elevatorstuck +------------------------------------------------------------------------------ +Flash: [S][A6I5] END OF ACT 6 INTERMISSION 5 INTERMISSION 4 +Page: 6066 +Date: April 1, 2013 +Tracks: +- Blackest Heart (With Honks) +------------------------------------------------------------------------------ +Flash: [S][A6I5] ==> +Page: 6231 +Date: April 13, 2013 +Tracks: +- A Taste for Adventure +------------------------------------------------------------------------------ +ACT: Act 6 Act 6 Act 1 - HOMOSUCK +FG: #2ed73a +------------------------------------------------------------------------------ +Flash: [S] ACT 6 ACT 6 +Page: 6243 +Date: June 12, 2013 +Tracks: +- Homosuck Anthem (by Toby Fox) +------------------------------------------------------------------------------ +ACT: Act 6 Act 6 Intermission 1 - Stardust +FG: #dddddd +------------------------------------------------------------------------------ +Flash: [S] ACT 6 ACT 6 INTERMISSION 1 +Page: 6278 +Date: June 14, 2013 +Tracks: +- Gold Pilot +------------------------------------------------------------------------------ +ACT: Act 6 Act 6 Intermission 3 - GAME OVER +FG: #ffffff +------------------------------------------------------------------------------ +Flash: [S] GAME OVER. +Page: 6901 +Date: October 25, 2014 +Tracks: +- Carne Vale +------------------------------------------------------------------------------ +ACT: Act 6 Act 6 Intermission 4 - <span style="color: #008282">F1X TH1S</span> +FG: #4466ff +------------------------------------------------------------------------------ +Flash: [S][A6A6I4] ====> +Page: 7098 +Date: November 28, 2014 +Tracks: +- Pipeorgankind +------------------------------------------------------------------------------ +Flash: [S][A6A6I4] ====> +Page: 7101 +Date: December 1, 2014 +Tracks: +- Elevatorstuck, with Meows (by Toby Fox) +------------------------------------------------------------------------------ +Flash: [S][A6A6I4] ====> +Page: 7405 +Date: January 19, 2015 +Tracks: +- Not a creature was stirring (by Alexander Rosetti) +------------------------------------------------------------------------------ +ACT: Act 6 Act 6 Act 5 - MASTERPIECE +FG: #55ff00 +------------------------------------------------------------------------------ +Flash: [S] ACT 6 ACT 6 ACT 5 +Page: 7409 +Date: April 13, 2015 +Tracks: +- Homosuck Swan Song (by Toby Fox) +------------------------------------------------------------------------------ +Flash: [S] MSPA Reader: Mental breakdown. +Page: 7448 +Date: April 22, 2015 +Tracks: +- Hello Zepp - Saw Theme (by Charlie Clouser) +------------------------------------------------------------------------------ +ACT: Act 6 Act 6 Intermission 5 - <span style="color: #1076a2">She's 8ack</span> +FG: #00ffff +------------------------------------------------------------------------------ +Flash: [S] ACT 6 ACT 6 INTERMISSION 5 +Page: 7449 +Date: April 26, 2015 +Tracks: +- Moonsetter +------------------------------------------------------------------------------ +Flash: [S][A6A6I5] ====> +Page: 7928 +Date: July 23, 2015 +Tracks: +- Horsecatska (by James Roach) +------------------------------------------------------------------------------ +Flash: [S] Terezi: Remem8er. +Page: 7959 +Date: July 27, 2015 +Tracks: +- Do You Remem8er Me +------------------------------------------------------------------------------ +ACT: Act 6 Act 6 Act 6 - <span style="color: #ff0000">Collide.</span> +FG: #ee1100 +------------------------------------------------------------------------------ +Flash: [S] Collide. +Page: 8087 +Date: April 6, 2016 +Tracks: +- Creata (Canon Edit) +- Oppa Toby Style +- Eternity, Served Cold (Canon Edit) +- Heir of Grief +------------------------------------------------------------------------------ +ACT: Act 7 - <span style="color: #c7ff43">The Rapture</span><br><i>& Post Canon</i> +FG: #ffffff +------------------------------------------------------------------------------ +Flash: [S] ACT 7 +Page: 8127 +Date: April 13, 2016 +Tracks: +- Overture (Canon Edit) +------------------------------------------------------------------------------ +Flash: [S] ==> +Page: 8129 +Date: October 25, 2016 +Tracks: +- Foley (by Clark Powell) +------------------------------------------------------------------------------ +Flash: [S] ==> +Page: 8130 +Date: October 25, 2016 +Tracks: +- Ascend diff --git a/flashes/flashes.txt b/flashes/flashes.txt deleted file mode 100644 index 39ca1635..00000000 --- a/flashes/flashes.txt +++ /dev/null @@ -1,4 +0,0 @@ -Flash: [S] John: Play haunting piano refrain. -Page: 77 -Tracks: -- Showtime (Piano Refrain) diff --git a/site.css b/site.css index dc065850..9ec544d8 100644 --- a/site.css +++ b/site.css @@ -72,11 +72,38 @@ a:hover { margin: 10px 5px; } -#sidebar ol { +#sidebar > ol, #sidebar > ul { padding-left: 30px; padding-right: 15px; } +#sidebar > dl { + padding-right: 15px; + padding-left: 0; +} + +#sidebar > dl dt { + padding-left: 15px; + margin-top: 0.5em; +} + +#sidebar > dl dt.current { + font-weight: 800; +} + +#sidebar > dl dd { + margin-left: 0; +} + +#sidebar > dl dd ul { + padding-left: 30px; + margin-left: 0; +} + +#sidebar > dl .side { + padding-left: 10px; +} + #sidebar li.current { font-weight: 800; } @@ -140,6 +167,11 @@ h1 { margin-bottom: 10px; } +.grid-listing h2 { + text-align: center; + width: 100%; +} + #top-index #content h1 { text-align: center; font-size: 2em; @@ -197,3 +229,45 @@ dl dt { dl dd { margin-bottom: 1em; } + +.new { + animation: new 1s infinite; +} + +@keyframes new { + 0% { + color: #bbdd00; + } + + 50% { + color: #eeff22; + } + + 100% { + color: #bbdd00; + } +} + +/* fake :P */ +.loading::after { + content: '.'; + animation: loading 6s infinite; +} + +@keyframes loading { + 0 { + content: '.'; + } + + 33% { + content: '..'; + } + + 66% { + content: '...'; + } + + 100% { + content: '.'; + } +} diff --git a/upd8.js b/upd8.js index 2cb15fe9..70b3a981 100644 --- a/upd8.js +++ b/upd8.js @@ -97,10 +97,11 @@ const SITE_ABOUT = ` <ul> <li>Florrie: that's me! I programmed most of the site, and put the whole thing together. Say hi to me on twitter (<a href="https://twitter.com/florriestuck">@florriestuck</a>) or reddit (<a href="https://reddit.com/u/towerofnix/">/u/towerofnix</a>)!</li> <li><a href="https://homestuck.bandcamp.com/">Homestuck's Bandcamp</a>, the official host of Homestuck's music: I got almost all the album listings and basic track info from here.</li> - <li>GiovanH's <a href="https://www.reddit.com/r/homestuck/comments/dn2s69/i_was_prepared_for_this_eventuality_and_also/">complete track art archive</a>: track art! A million thanks for putting this together and sharing this with me. (Prior to this, I used the <a href="https://web.archive.org/web/20190720035022/https://homestuck.bandcamp.com/music">Web Archive</a> to gather track art.)</li> + <li>GiovanH's <a href="https://my.pcloud.com/publink/show?code=kZdJQ8kZNyIwh0Hn1ime6Ty7L2J87BE3E2ak">complete track art archive</a>: track art! A million thanks for putting this together and sharing this with me. (Prior to this, I used the <a href="https://web.archive.org/web/20190720035022/https://homestuck.bandcamp.com/music">Web Archive</a> to gather track art.)</li> <li><a href="https://recordcrash.com/nsnd.html">NSND</a>: leitmotifs! Thanks to this site in combination with credits on the bandcamp and artists' own commentary, this wiki is a rather comprehensive resource for leitmotifs and other track references.</li> + <li><a href="https://www.bgreco.net/hsflash.html">bgreco.net (HQ Audio Flashes)</a>: thumbnail captures for the individual Flash animations! There were a couple captures missing that I took myself, but most Flash thumbnails are from here.</a></li> <li>The <a href="https://homestuck-and-mspa-music.fandom.com/wiki/Homestuck_and_MSPA_Music_Wiki">Homestuck and MSPA Music Wiki</a> on Fandom: the inspiration for this wiki! I've wanted to make a more complete and explorable wiki ever since seeing it. The Fandom wiki has also been a very handy reference in putting this together, so much thanks to everyone who's worked on it!</li> - <li>All comments on the site, <a href="https://www.reddit.com/r/homestuck/comments/dwtc4w/i_made_a_wiki_for_homestuck_albums_including/">especially from /r/homestuck</a>: I appreciate all feedback a lot! People have shared a ton of ideas and suggestions with me, and I <i>cannot</i> emphasize enough how motivating it is to share a project with like-minded folx interested in making it better with you. Extra thanks to the subreddit mods for pinning the discussion post and keeping it there so long - I received a ton of feedback I've loved working with and talking about the project with other people there has been a joy. :)</li> + <li>All comments on the site: I appreciate all feedback a lot! People have shared a ton of ideas and suggestions with me, and I <i>cannot</i> emphasize enough how motivating it is to share a project with like-minded folx interested in making it better with you.</li> </ul> `; @@ -124,6 +125,7 @@ const ARTIST_DIRECTORY = 'artist'; const ARTIST_AVATAR_DIRECTORY = 'artist-avatar'; const LISTING_DIRECTORY = 'list'; const ABOUT_DIRECTORY = 'about'; +const FLASH_DIRECTORY = 'flash'; // Might ena8le this later... we'll see! Eventually. May8e. const ENABLE_ARTIST_AVATARS = false; @@ -169,6 +171,114 @@ async function findAlbumDataFiles() { return paths.filter(Boolean); } +function* getSections(lines) { + // ::::) + const isSeparatorLine = line => /^-{8,}$/.test(line); + yield* splitArray(lines, isSeparatorLine); +} + +function getBasicField(lines, name) { + const line = lines.find(line => line.startsWith(name + ':')); + return line && line.slice(name.length + 1).trim(); +}; + +function getListField(lines, name) { + let startIndex = lines.findIndex(line => line.startsWith(name + ':')); + // If callers want to default to an empty array, they should stick + // "|| []" after the call. + if (startIndex === -1) { + return null; + } + // We increment startIndex 8ecause we don't want to include the + // "heading" line (e.g. "URLs:") in the actual data. + startIndex++; + let endIndex = lines.findIndex((line, index) => index >= startIndex && !line.startsWith('- ')); + if (endIndex === -1) { + endIndex = lines.length; + } + if (endIndex === startIndex) { + // If there is no list that comes after the heading line, treat the + // heading line itself as the comma-separ8ted array value, using + // the 8asic field function to do that. (It's l8 and my 8rain is + // sleepy. Please excuse any unhelpful comments I may write, or may + // have already written, in this st8. Thanks!) + const value = getBasicField(lines, name); + return value && value.split(',').map(val => val.trim()); + } + const listLines = lines.slice(startIndex, endIndex); + return listLines.map(line => line.slice(2)); +}; + +function getContributionField(section, name) { + let contributors = getListField(section, name); + + if (!contributors) { + return null; + } + + contributors = contributors.map(contrib => { + // 8asically, the format is "Who (What)", or just "Who". 8e sure to + // keep in mind that "what" doesn't necessarily have a value! + const match = contrib.match(/^(.*?)( \((.*)\))?$/); + if (!match) { + return contrib; + } + const who = match[1]; + const what = match[3] || null; + return {who, what}; + }); + + const badContributor = contributors.find(val => typeof val === 'string'); + if (badContributor) { + return {error: `An entry has an incorrectly formatted contributor, "${badContributor}".`}; + } + + if (contributors.length === 1 && contributors[0].who === 'none') { + return null; + } + + return contributors; +}; + +function getMultilineField(lines, name) { + // All this code is 8asically the same as the getListText - just with a + // different line prefix (four spaces instead of a dash and a space). + let startIndex = lines.findIndex(line => line.startsWith(name + ':')); + if (startIndex === -1) { + return null; + } + startIndex++; + let endIndex = lines.findIndex((line, index) => index >= startIndex && !line.startsWith(' ')); + if (endIndex === -1) { + endIndex = lines.length; + } + // If there aren't any content lines, don't return anything! + if (endIndex === startIndex) { + return null; + } + // We also join the lines instead of returning an array. + const listLines = lines.slice(startIndex, endIndex); + return listLines.map(line => line.slice(4)).join('\n'); +}; + +function getMultilineHTMLField(lines, name) { + const text = getMultilineField(lines, name); + return text && text.split('\n').map(line => line.startsWith('<ul>') ? line : `<p>${line}</p>`).join('\n'); +}; + +function getCommentaryField(lines) { + const text = getMultilineHTMLField(lines, 'Commentary'); + if (text) { + const lines = text.split('\n'); + if (!lines[0].includes(':</i>')) { + return {error: `An entry is missing commentary citation: "${lines[0].slice(0, 40)}..."`}; + } + return text; + } else { + return null; + } +}; + async function processAlbumDataFile(file) { let contents; try { @@ -190,118 +300,11 @@ async function processAlbumDataFile(file) { // We'll just return more specific errors if it's missing necessary data // fields. - // ::::) - const isSeparatorLine = line => /^-{8,}$/.test(line); - const contentLines = contents.split('\n'); // In this line of code I defeat the purpose of using a generator in the // first place. Sorry!!!!!!!! - const sections = Array.from(splitArray(contentLines, isSeparatorLine)); - - const initialLines = contentLines.slice(0, contentLines.findIndex(isSeparatorLine)); - - const getBasicField = (lines, name) => { - const line = lines.find(line => line.startsWith(name + ':')); - return line && line.slice(name.length + 1).trim(); - }; - - const getListField = (lines, name) => { - let startIndex = lines.findIndex(line => line.startsWith(name + ':')); - // If callers want to default to an empty array, they should stick - // "|| []" after the call. - if (startIndex === -1) { - return null; - } - // We increment startIndex 8ecause we don't want to include the - // "heading" line (e.g. "URLs:") in the actual data. - startIndex++; - let endIndex = lines.findIndex((line, index) => index >= startIndex && !line.startsWith('- ')); - if (endIndex === -1) { - endIndex = lines.length; - } - if (endIndex === startIndex) { - // If there is no list that comes after the heading line, treat the - // heading line itself as the comma-separ8ted array value, using - // the 8asic field function to do that. (It's l8 and my 8rain is - // sleepy. Please excuse any unhelpful comments I may write, or may - // have already written, in this st8. Thanks!) - const value = getBasicField(lines, name); - return value && value.split(',').map(val => val.trim()); - } - const listLines = lines.slice(startIndex, endIndex); - return listLines.map(line => line.slice(2)); - }; - - const getContributionField = (section, name) => { - let contributors = getListField(section, name); - - if (!contributors) { - return null; - } - - contributors = contributors.map(contrib => { - // 8asically, the format is "Who (What)", or just "Who". 8e sure to - // keep in mind that "what" doesn't necessarily have a value! - const match = contrib.match(/^(.*?)( \((.*)\))?$/); - if (!match) { - return contrib; - } - const who = match[1]; - const what = match[3] || null; - return {who, what}; - }); - - const badContributor = contributors.find(val => typeof val === 'string'); - if (badContributor) { - return {error: `An entry has an incorrectly formatted contributor, "${badContributor}".`}; - } - - if (contributors.length === 1 && contributors[0].who === 'none') { - return null; - } - - return contributors; - }; - - const getMultilineField = (lines, name) => { - // All this code is 8asically the same as the getListText - just with a - // different line prefix (four spaces instead of a dash and a space). - let startIndex = lines.findIndex(line => line.startsWith(name + ':')); - if (startIndex === -1) { - return null; - } - startIndex++; - let endIndex = lines.findIndex((line, index) => index >= startIndex && !line.startsWith(' ')); - if (endIndex === -1) { - endIndex = lines.length; - } - // If there aren't any content lines, don't return anything! - if (endIndex === startIndex) { - return null; - } - // We also join the lines instead of returning an array. - const listLines = lines.slice(startIndex, endIndex); - return listLines.map(line => line.slice(4)).join('\n'); - }; - - const getMultilineHTMLField = (lines, name) => { - const text = getMultilineField(lines, name); - return text && text.split('\n').map(line => line.startsWith('<ul>') ? line : `<p>${line}</p>`).join('\n'); - }; - - const getCommentaryField = lines => { - const text = getMultilineHTMLField(lines, 'Commentary'); - if (text) { - const lines = text.split('\n'); - if (!lines[0].includes(':</i>')) { - return {error: `An entry is missing commentary citation: "${lines[0].slice(0, 40)}..."`}; - } - return text; - } else { - return null; - } - }; + const sections = Array.from(getSections(contentLines)); const albumSection = sections[0]; const albumName = getBasicField(albumSection, 'Album'); @@ -474,6 +477,59 @@ async function processAlbumDataFile(file) { return albumData; } +async function processFlashDataFile(file) { + let contents; + try { + contents = await readFile(file, 'utf-8'); + } catch (error) { + return {error: `Could not read ${file} (${error.code}).`}; + } + + const contentLines = contents.split('\n'); + const sections = Array.from(getSections(contentLines)); + + let act, theme; + return sections.map(section => { + if (getBasicField(section, 'ACT')) { + act = getBasicField(section, 'ACT'); + theme = { + fg: getBasicField(section, 'FG') + }; + return {act8r8k: true, act, theme}; + } + + const name = getBasicField(section, 'Flash'); + let page = getBasicField(section, 'Page'); + let date = getBasicField(section, 'Date'); + const jiff = getBasicField(section, 'Jiff'); + const tracks = getListField(section, 'Tracks'); + + if (!name) { + return {error: 'Expected "Flash" (name) field!'}; + } + + if (!page) { + return {error: 'Expected "Page" field!'}; + } + + if (!date) { + return {error: 'Expected "Date" field!'}; + } + + if (isNaN(Date.parse(date))) { + return {error: `Invalid Date field: "${date}"`}; + } + + date = new Date(date); + + if (!tracks) { + return {error: 'Expected "Tracks" field!'}; + } + + return {name, page, date, tracks, act, theme, jiff}; + }); +} + // This gets all the track o8jects defined in every al8um, and sorts them 8y // date released. Generally, albumData will pro8a8ly already 8e sorted 8efore // you pass it to this function, 8ut individual tracks can have their own @@ -543,7 +599,7 @@ async function writePage(directoryParts, title, body) { `); } -function writeMiscellaneousPages(albumData) { +function writeMiscellaneousPages(albumData, flashData) { return progressPromiseAll('Writing miscellaneous pages.', [ writePage([], SITE_TITLE, fixWS` <body id="top-index"> @@ -553,6 +609,7 @@ function writeMiscellaneousPages(albumData) { <p>Explore the site!</p> <a href="${LISTING_DIRECTORY}/index.html">Listings</a> <a href="about/index.html">About & Credits</a> + <a href="${FLASH_DIRECTORY}/index.html">Flashes <span class="new">(New!)</span></a> <p>...or choose an album:</p> </div> <div class="grid-listing"> @@ -566,6 +623,35 @@ function writeMiscellaneousPages(albumData) { </div> </body> `), + writePage([FLASH_DIRECTORY], `Flashes`, fixWS` + <body id="top-index"> + <div id="content"> + <h1>Flashes</h1> + <div id="intro-menu"> + <a href="index.html">Home</a> + <a href="${LISTING_DIRECTORY}/index.html">Listings</a> + <a href="about/index.html">About & Credits</a> + </div> + <div class="long-content"> + <p>Also check out:</p> + <ul> + <li>Bambosh's <a href="https://www.youtube.com/watch?v=AEIOQN3YmNc">[S]Homestuck - All flashes</a>: an excellently polished compilation of all Flash animations in Homestuck.</li> + <li>bgreco.net's <a href="https://www.bgreco.net/hsflash.html">Homestuck HQ Audio Flashes</a>: an index of all HS Flash animations with Bandcamp-quality audio built in. (Also the source for many thumbnails below!)</li> + </ul> + </div> + <div class="grid-listing"> + ${flashData.map(flash => flash.act8r8k ? fixWS` + <h2 style="${getThemeString(flash.theme)}"><a href="${FLASH_DIRECTORY}/${getFlashDirectory(flashData.find(f => f.page && f.act === flash.act))}/index.html">${flash.act}</a></h2> + ` : fixWS` + <a class="grid-item" href="${FLASH_DIRECTORY}/${getFlashDirectory(flash)}/index.html" style="${getThemeString(flash.theme)}"> + <img src="${getFlashCover(flash)}"> + <span>${flash.name}</span> + </a> + `).join('\n')} + </div> + </div> + </body> + `), writePage([ABOUT_DIRECTORY], 'About & Credits', fixWS` <body> <div id="content"> @@ -581,9 +667,11 @@ function writeMiscellaneousPages(albumData) { } // This function title is my gr8test work of art. -async function writeIndexAndTrackPagesForAlbum(album, albumData) { - await writeAlbumPage(album, albumData); - await Promise.all(album.tracks.map(track => writeTrackPage(track, albumData))); +function writeIndexAndTrackPagesForAlbum(album, albumData, flashData) { + return [ + writeAlbumPage(album, albumData), + ...album.tracks.map(track => writeTrackPage(track, albumData, flashData)) + ]; } async function writeAlbumPage(album, albumData) { @@ -597,7 +685,7 @@ async function writeAlbumPage(album, albumData) { <a id="cover-art" href="${getAlbumCover(album)}"><img src="${getAlbumCover(album)}"></a> <h1>${album.name}</h1> <p> - ${album.artists && `By ${getArtistString(album.artists)}.<br>`} + ${album.artists && `By ${getArtistString(album.artists, albumData)}.<br>`} ${album.coverArtists && `Cover art by ${joinNoOxford(album.coverArtists.map(({ who, what }) => fixWS` <a href="${ARTIST_DIRECTORY}/${getArtistDirectory(who)}/index.html">${who}</a>${what && ` (${getContributionString({what}, allTracks)})`} `))}.<br>`} @@ -608,7 +696,7 @@ async function writeAlbumPage(album, albumData) { <li> <a href="${TRACK_DIRECTORY}/${track.directory}/index.html">${track.name}</a> ${track.artists !== album.artists && fixWS` - <span class="by">by ${getArtistString(track.artists)}</span> + <span class="by">by ${getArtistString(track.artists, albumData)}</span> `} </li> `).join('\n')} @@ -624,11 +712,12 @@ async function writeAlbumPage(album, albumData) { `); } -async function writeTrackPage(track, albumData) { +async function writeTrackPage(track, albumData, flashData) { const artistNames = getArtistNames(albumData); const allTracks = getAllTracks(albumData); const tracksThatReference = getTracksThatReference(track, allTracks); const tracksReferenced = getTracksReferencedBy(track, allTracks); + const flashesThatFeature = getFlashesThatFeature(track, allTracks, flashData); await writePage([TRACK_DIRECTORY, track.directory], track.name, fixWS` <body style="${getThemeString(track.album.theme)}"> <div id="sidebar"> @@ -638,7 +727,7 @@ async function writeTrackPage(track, albumData) { <a href="${getTrackCover(track)}" id="cover-art"><img src="${getTrackCover(track)}"></a> <h1>${track.name}</h1> <p> - By ${getArtistString(track.artists)}.<br> + By ${getArtistString(track.artists, albumData)}.<br> ${track.coverArtists && `Cover art by ${joinNoOxford(track.coverArtists.map(({ who, what }) => fixWS` <a href="${ARTIST_DIRECTORY}/${getArtistDirectory(who)}/index.html">${who}</a>${what && ` (${getContributionString({what}, allTracks)})`} `))}.<br>`} @@ -669,7 +758,7 @@ async function writeTrackPage(track, albumData) { ${tracksReferenced.map(track => fixWS` <li> <a href="${TRACK_DIRECTORY}/${track.directory}/index.html" style="${getThemeString(track.album.theme)}">${track.name}</a> - <span class="by">by ${getArtistString(track.artists)}</span> + <span class="by">by ${getArtistString(track.artists, albumData)}</span> </li> `).join('\n')} </ul> @@ -680,11 +769,17 @@ async function writeTrackPage(track, albumData) { ${tracksThatReference.map(track => fixWS` <li> <a href="${TRACK_DIRECTORY}/${track.directory}/index.html" style="${getThemeString(track.album.theme)}">${track.name}</a> - <span class="by">by ${getArtistString(track.artists)}</span> + <span class="by">by ${getArtistString(track.artists, albumData)}</span> </li> `).join('\n')} </ul> `} + ${flashesThatFeature.length && fixWS` + <p>Flashes that feature <i>${track.name}</i>:</p> + <ul> + ${flashesThatFeature.map(flash => `<li>${getFlashLinkHTML(flash)}</li>`).join('\n')} + </ul> + `} ${track.lyrics && fixWS` <p>Lyrics:</p> <blockquote> @@ -702,11 +797,11 @@ async function writeTrackPage(track, albumData) { `); } -async function writeArtistPages(albumData) { - await progressPromiseAll('Writing artist pages.', getArtistNames(albumData).map(artistName => writeArtistPage(artistName, albumData))); +async function writeArtistPages(albumData, flashData) { + await progressPromiseAll('Writing artist pages.', getArtistNames(albumData).map(artistName => writeArtistPage(artistName, albumData, flashData))); } -async function writeArtistPage(artistName, albumData) { +async function writeArtistPage(artistName, albumData, flashData) { const allTracks = getAllTracks(albumData); const tracks = sortByDate(allTracks.filter(track => ( track.artists.includes(artistName) || @@ -737,11 +832,13 @@ async function writeArtistPage(artistName, albumData) { who: artistName, what: track.contributors.filter(({ who }) => who === artistName).map(({ what }) => what).join(', ') }; + const flashes = getFlashesThatFeature(track, allTracks, flashData); return fixWS` <li title="${th(i + 1)} track by ${artistName}; ${th(track.album.tracks.indexOf(track) + 1)} in ${track.album.name}"> <a href="${TRACK_DIRECTORY}/${track.directory}/index.html" style="${getThemeString(track.album.theme)}">${track.name}</a> - ${track.artists.includes(artistName) && track.artists.length > 1 && `<span class="contributed">(with ${getArtistString(track.artists.filter(a => a !== artistName))})</span>`} + ${track.artists.includes(artistName) && track.artists.length > 1 && `<span class="contributed">(with ${getArtistString(track.artists.filter(a => a !== artistName), albumData)})</span>`} ${contrib.what && `<span class="contributed">(${getContributionString(contrib, tracks) || 'contributed'})</span>`} + ${flashes.length && `<br><span class="flashes">(Featured in ${joinNoOxford(flashes.map(getFlashLinkHTML))})</span></br>`} </li> `; })} @@ -762,13 +859,17 @@ async function writeArtistPage(artistName, albumData) { `} ${commentaryThings.length && fixWS` <h2 id="commentary">Commentary</h2> - ${albumChunkedList(commentaryThings, thing => fixWS` - <li> - ${thing.album ? fixWS` - <a href="${TRACK_DIRECTORY}/${thing.directory}/index.html" style="${getThemeString(thing.album.theme)}">${thing.name}</a> - ` : '(album commentary)'} - </li> - `, false)} + ${albumChunkedList(commentaryThings, thing => { + const flashes = getFlashesThatFeature(thing, allTracks, flashData); + return fixWS` + <li> + ${thing.album ? fixWS` + <a href="${TRACK_DIRECTORY}/${thing.directory}/index.html" style="${getThemeString(thing.album.theme)}">${thing.name}</a> + ` : '(album commentary)'} + ${flashes.length && `<br><span class="flashes">(Featured in ${joinNoOxford(flashes.map(getFlashLinkHTML))})</span></br>`} + </li> + ` + }, false)} </ul> `} </div> @@ -804,6 +905,77 @@ function albumChunkedList(tracks, getLI, showDate = true) { `; } +async function writeFlashPages(albumData, flashData) { + await progressPromiseAll('Writing Flash pages.', flashData.map(flash => flash.page && writeFlashPage(flash, albumData, flashData)).filter(Boolean)); +} + +async function writeFlashPage(flash, albumData, flashData) { + const allTracks = getAllTracks(albumData); + const kebab = getFlashDirectory(flash); + const index = `${FLASH_DIRECTORY}/${kebab}/index.html`; + const act6 = flashData.findIndex(f => f.act.startsWith('Act 6')) + const side = (flashData.indexOf(flash) < act6) ? 1 : 2 + await writePage([FLASH_DIRECTORY, kebab], flash.name, fixWS` + <body style="${getThemeString(flash.theme)}"> + <div id="sidebar"> + <h2><a href="index.html">(Home)</a></h2> + <hr> + <h1><a href="${FLASH_DIRECTORY}/index.html">Flashes</a></h1> + <dl> + ${flashData.filter(f => f.act8r8k).map(({ act, theme }) => fixWS` + ${act.startsWith('Act 1') && fixWS` + <dt class="side ${side === 1 && 'current'}"><a href="${FLASH_DIRECTORY}/${getFlashDirectory(flashData.find(f => f.page && f.act.startsWith('Act 1')))}/index.html" style="--fg-color: #4ac925">Side 1 (Acts 1-5)</a></dt> + `} + ${act.startsWith('Act 6 Act 1') && fixWS` + <dt class="side ${side === 2 && 'current'}"><a href="${FLASH_DIRECTORY}/${getFlashDirectory(flashData.find(f => f.page && f.act.startsWith('Act 6')))}/index.html" style="--fg-color: #1076a2">Side 2 (Acts 6-7)</a></dt> + `} + ${(flashData.findIndex(f => f.act === act) < act6 ? (side === 1) : (side === 2)) && `<dt class="${act === flash.act ? 'current' : ''}"><a href="${FLASH_DIRECTORY}/${getFlashDirectory(flashData.find(f => f.page && f.act === act))}/index.html" style="${getThemeString(theme)}">${act}</a></dt>`} + ${act === flash.act && fixWS` + <dd><ul> + ${flashData.filter(f => f.page && f.act === act).map(f => fixWS` + <li class="${f === flash ? 'current' : ''}"> + <a href="${FLASH_DIRECTORY}/${getFlashDirectory(f)}/index.html" style="${getThemeString(f.theme)}">${f.name}</a> + </li> + `).join('\n')} + </ul></dd> + `} + `).join('\n')} + </dl> + </div> + <div id="content"> + <h1>${flash.name}</h1> + <a id="cover-art" href="${getFlashCover(flash)}"><img src="${getFlashCover(flash)}"></a> + <p>Released ${getDateString(flash)}.</p> + <p>Play on <a href="${getFlashLink(flash)}">Homestuck</a> (${isNaN(Number(flash.page)) ? 'secret page' : `page ${flash.page}`}).</p> + <p>Tracks featured in <i>${flash.name.replace(/\.$/, '')}</i>:</p> + <ul> + ${flash.tracks.map(ref => { + const track = getLinkedTrack(ref, allTracks); + const neighm = ref.match(/(.*?\S):/) || [ref, ref]; + if (track) { + return fixWS` + <li> + <a href="${TRACK_DIRECTORY}/${track.directory}/index.html" style="${getThemeString(track.album.theme)}">${neighm[1]}</a> + <span class="by">by ${getArtistString(track.artists, albumData)}</span> + </li> + `; + } else { + const by = ref.match(/\(by .*\)/); + if (by) { + const name = ref.replace(by, '').trim(); + const who = by[0].replace(/\(by |\)/g, '').split(',').map(w => w.trim()); + return `<li>${name} <span class="by">by ${getArtistString(who, albumData)}</span></li>`; + } else { + return `<li>${ref}</li>`; + } + } + }).join('\n')} + </ul> + </div> + </body> + `); +} + function writeListingPages(albumData) { const allArtists = getArtistNames(albumData).sort(); const allTracks = getAllTracks(albumData); @@ -1012,24 +1184,42 @@ function getTracksThatReference(track, allTracks) { } function getTracksReferencedBy(track, allTracks) { - return track.references.map(ref => { - if (ref.includes(':')) { - const dir = ref.split(':')[1]; - return allTracks.find(track => track.directory === dir); - } else { - return allTracks.find(track => track.name === ref); - } - }).filter(Boolean); + return track.references.map(ref => getLinkedTrack(ref, allTracks)).filter(Boolean); +} + +function getLinkedTrack(ref, allTracks) { + const match = ref.match(/\S:(.*)/); + if (match) { + const dir = match[1]; + return allTracks.find(track => track.directory === dir); + } else { + return allTracks.find(track => track.name === ref); + } } -function getArtistString(artists) { - return joinNoOxford(artists.map(artist => fixWS` - <a href="${ARTIST_DIRECTORY}/${getArtistDirectory(artist)}/index.html">${artist}</a> - `)); +function getFlashesThatFeature(track, allTracks, flashData) { + return flashData.filter(flash => flash.tracks && flash.tracks.map(t => getLinkedTrack(t, allTracks)).includes(track)); +} + +function getArtistString(artists, albumData) { + const artistNames = getArtistNames(albumData); + return joinNoOxford(artists.map(artist => { + if (artistNames.includes(artist)) { + return fixWS` + <a href="${ARTIST_DIRECTORY}/${getArtistDirectory(artist)}/index.html">${artist}</a> + `; + } else { + return artist; + } + })); } function getThemeString({fg, bg, theme}) { - return `--fg-color: ${fg}; --bg-color: ${bg}; --theme: ${theme + ''}`; + return [ + [fg, `--fg-color: ${fg}`], + [bg, `--bg-color: ${bg}`], + [theme, `--theme: ${theme + ''}`] + ].filter(pair => pair[0] !== undefined).map(pair => pair[1]).join('; '); } // Terri8le hack: since artists aren't really o8jects and don't have proper @@ -1038,6 +1228,12 @@ function getArtistDirectory(artistName) { return getKebabCase(artistName); } +function getFlashDirectory(flash) { + // const kebab = getKebabCase(flash.name.replace('[S] ', '')); + // return flash.page + (kebab ? '-' + kebab : ''); + return '' + flash.page; +} + function getKebabCase(name) { return name.split(' ').join('-').replace(/&/g, 'and').replace(/[^a-zA-Z0-9\-]/g, '').replace(/-{2,}/g, '-').replace(/^-+|-+$/g, '').toLowerCase(); } @@ -1096,6 +1292,17 @@ function getTrackCover(track) { return `${ALBUM_DIRECTORY}/${track.album.directory}/${track.directory}.jpg`; } } +function getFlashCover(flash) { + return `${FLASH_DIRECTORY}/${flash.page}.${flash.jiff === 'Yeah' ? 'gif' : 'png'}`; +} + +function getFlashLink(flash) { + return `https://homestuck.com/story/${flash.page}`; +} + +function getFlashLinkHTML(flash) { + return `<a href="${FLASH_DIRECTORY}/${getFlashDirectory(flash)}/index.html" title="Page ${flash.page}" style="${getThemeString(flash.theme)}">${flash.name}</a>`; +} async function main() { // 8ut wait, you might say, how do we know which al8um these data files @@ -1139,10 +1346,32 @@ async function main() { return; } - await writeMiscellaneousPages(albumData); - await progressPromiseAll(`Writing album & track pages.`, albumData.map(album => writeIndexAndTrackPagesForAlbum(album, albumData))); - await writeArtistPages(albumData); + const flashData = await processFlashDataFile(path.join(FLASH_DIRECTORY, 'flashes.txt')); + if (flashData.error) { + console.log(`\x1b[31;1m${flashData.error}\x1b[0m`); + return; + } + + const flashErrors = flashData.filter(obj => obj.error); + if (flashErrors.length) { + for (const error of flashErrors) { + console.log(`\x1b[31;1m${error.error}\x1b[0m`); + } + return; + } + + await writeMiscellaneousPages(albumData, flashData); + await progressPromiseAll(`Writing album & track pages.`, albumData.map(album => writeIndexAndTrackPagesForAlbum(album, albumData, flashData)).reduce((a, b) => a.concat(b))); + await writeArtistPages(albumData, flashData); await writeListingPages(albumData); + await writeFlashPages(albumData, flashData); + + /* + const allTracks = getAllTracks(albumData) + const track = albumData.find(album => album.name === 'Homestuck Vol. 6: Heir Transparent').tracks[0]; + console.log(getFlashesThatFeature(track, allTracks, flashData)); + console.log(getLinkedTrack('Frost:frost-vol6', allTracks)); + */ // The single most important step. console.log('Written!'); |