From 9a8d9c3e2847c62f07051bc91f52d6e91155f8d5 Mon Sep 17 00:00:00 2001 From: Maciej Jur Date: Wed, 26 Apr 2023 00:26:45 +0200 Subject: [PATCH] Basic lyrics transform --- .gitignore | 1 + package.json | 1 + pnpm-lock.yaml | 67 +++++++++++++++++++++++ src/components/lyrics/Lyrics.astro | 8 +++ src/components/lyrics/transform.ts | 87 ++++++++++++++++++++++++++++++ src/content/lyrics/black-eyes.mdx | 33 ++++++++++++ src/layouts/Lyrics.astro | 12 +++++ src/pages/lyrics/[...slug].astro | 16 ++++++ 8 files changed, 225 insertions(+) create mode 100644 src/components/lyrics/Lyrics.astro create mode 100644 src/components/lyrics/transform.ts create mode 100644 src/content/lyrics/black-eyes.mdx create mode 100644 src/layouts/Lyrics.astro create mode 100644 src/pages/lyrics/[...slug].astro diff --git a/.gitignore b/.gitignore index bd76842..d6ede8a 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ public/**/*.webp # obsidian .obsidian/ +.stfolder/ diff --git a/package.json b/package.json index e2e4bcf..b235f88 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "leaflet": "^1.9.3", "leaflet.markercluster": "^1.5.3", "lunr": "^2.3.9", + "node-html-parser": "^6.1.5", "rehype-katex": "^6.0.3", "rehype-raw": "^6.1.1", "rehype-stringify": "^9.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 037ad93..54c0a16 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,6 +22,9 @@ dependencies: lunr: specifier: ^2.3.9 version: 2.3.9 + node-html-parser: + specifier: ^6.1.5 + version: 6.1.5 rehype-katex: specifier: ^6.0.3 version: 6.0.3 @@ -1113,6 +1116,10 @@ packages: readable-stream: 3.6.2 dev: false + /boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: false + /boxen@6.2.1: resolution: {integrity: sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1302,6 +1309,21 @@ packages: which: 2.0.2 dev: false + /css-select@5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.0.1 + nth-check: 2.1.1 + dev: false + + /css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + dev: false + /csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} dev: false @@ -1362,6 +1384,33 @@ packages: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} dev: false + /dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + dev: false + + /domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: false + + /domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: false + + /domutils@3.0.1: + resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: false + /dset@3.1.2: resolution: {integrity: sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==} engines: {node: '>=4'} @@ -1808,6 +1857,11 @@ packages: space-separated-tokens: 2.0.2 dev: false + /he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + dev: false + /html-entities@2.3.3: resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==} dev: false @@ -2707,6 +2761,13 @@ packages: lodash: 4.17.21 dev: false + /node-html-parser@6.1.5: + resolution: {integrity: sha512-fAaM511feX++/Chnhe475a0NHD8M7AxDInsqQpz6x63GRF7xYNdS8Vo5dKsIVPgsOvG7eioRRTZQnWBrhDHBSg==} + dependencies: + css-select: 5.1.0 + he: 1.2.0 + dev: false + /node-releases@2.0.10: resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} dev: false @@ -2722,6 +2783,12 @@ packages: path-key: 4.0.0 dev: false + /nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: false + /onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} diff --git a/src/components/lyrics/Lyrics.astro b/src/components/lyrics/Lyrics.astro new file mode 100644 index 0000000..5902357 --- /dev/null +++ b/src/components/lyrics/Lyrics.astro @@ -0,0 +1,8 @@ +--- +import { transform } from "./transform"; + +const html = await Astro.slots.render('default'); +const lyrics = transform(html); +--- + +
diff --git a/src/components/lyrics/transform.ts b/src/components/lyrics/transform.ts new file mode 100644 index 0000000..3a76656 --- /dev/null +++ b/src/components/lyrics/transform.ts @@ -0,0 +1,87 @@ +import { Node, HTMLElement, parse } from 'node-html-parser'; + + +interface Stack { + [key: string]: string[][]; +} + +interface Verse { + [key: string]: string[]; +} + + +function extractLines(nodes: Node[]): string[] { + return nodes + .map(node => node.text) + .filter(text => text != '\n'); +} + +function createVerse(data: Stack, lang: string) { + (lang in data) + ? data[lang].push([]) + : data[lang] = [[]]; +} + +function toStack(html: string): Stack { + const root = parse(html); + const stack: Stack = {}; + + const nodes = root.childNodes as HTMLElement[]; + nodes.reduce((lang, node) => { + switch (node.rawTagName) { + case 'h1': { + const lang: string = node.id.replace(/-.+/, ''); + createVerse(stack, lang); + return lang; + } + case 'ul': { + const lines = extractLines(node.childNodes); + stack[lang].at(-1)!.push(...lines); + return lang; + } + } + return lang; + }, ''); + + return stack; +} + +function reduceStack(stack: Stack): Verse[] { + const langs = Object.keys(stack); + const length = langs.map(lang => stack[lang].length).reduce((a, b) => Math.max(a, b)); + const verses: Verse[] = []; + + for (const _ of Array(length)) { + const verse: Verse = {}; + for (const lang of langs) { + const lines = stack[lang].pop(); + verse[lang] = lines ? lines : []; + } + verses.push(verse); + } + return verses.reverse(); +} + +function toHtml(verses: Verse[]): string { + const keys = Object.keys(verses[0]); + const head = keys.map(lang => `${lang}`); + const rows = verses.map(verse => + `${keys.map(lang => + `${verse[lang].map(line => + `${line}
`).join('')} + `).join('')} + ` + ) + .join(''); + + return [ + "", + `${head.join('')}`, + rows, + "
", + ].join(''); +} + +export function transform(html: string) { + return toHtml(reduceStack(toStack(html))); +} diff --git a/src/content/lyrics/black-eyes.mdx b/src/content/lyrics/black-eyes.mdx new file mode 100644 index 0000000..ad27900 --- /dev/null +++ b/src/content/lyrics/black-eyes.mdx @@ -0,0 +1,33 @@ +--- +title: Black Eyes +date: 2023-04-25 +--- +import Lyrics from '../../components/lyrics/Lyrics.astro'; + + + + +# Japanese +- 瞬きをして 切り取る時間 +- 何気なくても 大切な今を +- 忘れないで 居られるように +- いつか 頭の中 +- 掻き消して しまっても +# Romaji +- fddsfsaf +- fdsfadsf +- test +- test +--- +# Japanese +- 瞬きをして 切り取る時間ff +- 何気なくても 大切な今を +- 忘れないで 居られるように +- いつか 頭の中 +- 掻き消して しまっても +# Romaji +- fddsfsaf +- fdsfadsf +- test +- test + diff --git a/src/layouts/Lyrics.astro b/src/layouts/Lyrics.astro new file mode 100644 index 0000000..fd3f922 --- /dev/null +++ b/src/layouts/Lyrics.astro @@ -0,0 +1,12 @@ +--- +import Base from "./Base.astro"; + +--- + + +
+
+ +
+
+ diff --git a/src/pages/lyrics/[...slug].astro b/src/pages/lyrics/[...slug].astro new file mode 100644 index 0000000..98d0991 --- /dev/null +++ b/src/pages/lyrics/[...slug].astro @@ -0,0 +1,16 @@ +--- +import Lyrics from "../../layouts/Lyrics.astro"; +import { getCollection } from "astro:content"; + +export async function getStaticPaths() { + return (await getCollection('lyrics')) + .map(entry => ({params: {slug: entry.slug}, props: {entry}})); +} + +const { entry } = Astro.props; +const { Content } = await entry.render(); +--- + + + +