Basic lyrics transform
This commit is contained in:
parent
d423a4cffc
commit
9a8d9c3e28
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -27,3 +27,4 @@ public/**/*.webp
|
||||||
|
|
||||||
# obsidian
|
# obsidian
|
||||||
.obsidian/
|
.obsidian/
|
||||||
|
.stfolder/
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
"leaflet": "^1.9.3",
|
"leaflet": "^1.9.3",
|
||||||
"leaflet.markercluster": "^1.5.3",
|
"leaflet.markercluster": "^1.5.3",
|
||||||
"lunr": "^2.3.9",
|
"lunr": "^2.3.9",
|
||||||
|
"node-html-parser": "^6.1.5",
|
||||||
"rehype-katex": "^6.0.3",
|
"rehype-katex": "^6.0.3",
|
||||||
"rehype-raw": "^6.1.1",
|
"rehype-raw": "^6.1.1",
|
||||||
"rehype-stringify": "^9.0.3",
|
"rehype-stringify": "^9.0.3",
|
||||||
|
|
|
@ -22,6 +22,9 @@ dependencies:
|
||||||
lunr:
|
lunr:
|
||||||
specifier: ^2.3.9
|
specifier: ^2.3.9
|
||||||
version: 2.3.9
|
version: 2.3.9
|
||||||
|
node-html-parser:
|
||||||
|
specifier: ^6.1.5
|
||||||
|
version: 6.1.5
|
||||||
rehype-katex:
|
rehype-katex:
|
||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: 6.0.3
|
version: 6.0.3
|
||||||
|
@ -1113,6 +1116,10 @@ packages:
|
||||||
readable-stream: 3.6.2
|
readable-stream: 3.6.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/boolbase@1.0.0:
|
||||||
|
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/boxen@6.2.1:
|
/boxen@6.2.1:
|
||||||
resolution: {integrity: sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==}
|
resolution: {integrity: sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==}
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
@ -1302,6 +1309,21 @@ packages:
|
||||||
which: 2.0.2
|
which: 2.0.2
|
||||||
dev: false
|
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:
|
/csstype@3.1.2:
|
||||||
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
|
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -1362,6 +1384,33 @@ packages:
|
||||||
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
|
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
|
||||||
dev: false
|
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:
|
/dset@3.1.2:
|
||||||
resolution: {integrity: sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==}
|
resolution: {integrity: sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
@ -1808,6 +1857,11 @@ packages:
|
||||||
space-separated-tokens: 2.0.2
|
space-separated-tokens: 2.0.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/he@1.2.0:
|
||||||
|
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
|
||||||
|
hasBin: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
/html-entities@2.3.3:
|
/html-entities@2.3.3:
|
||||||
resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==}
|
resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -2707,6 +2761,13 @@ packages:
|
||||||
lodash: 4.17.21
|
lodash: 4.17.21
|
||||||
dev: false
|
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:
|
/node-releases@2.0.10:
|
||||||
resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==}
|
resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -2722,6 +2783,12 @@ packages:
|
||||||
path-key: 4.0.0
|
path-key: 4.0.0
|
||||||
dev: false
|
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:
|
/onetime@5.1.2:
|
||||||
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
|
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
8
src/components/lyrics/Lyrics.astro
Normal file
8
src/components/lyrics/Lyrics.astro
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
import { transform } from "./transform";
|
||||||
|
|
||||||
|
const html = await Astro.slots.render('default');
|
||||||
|
const lyrics = transform(html);
|
||||||
|
---
|
||||||
|
|
||||||
|
<section class="lyrics" set:html={lyrics}></section>
|
87
src/components/lyrics/transform.ts
Normal file
87
src/components/lyrics/transform.ts
Normal file
|
@ -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 => `<th>${lang}</th>`);
|
||||||
|
const rows = verses.map(verse =>
|
||||||
|
`<tr>${keys.map(lang =>
|
||||||
|
`<td>${verse[lang].map(line =>
|
||||||
|
`<span>${line}</span><br/>`).join('')}
|
||||||
|
</td>`).join('')}
|
||||||
|
</tr>`
|
||||||
|
)
|
||||||
|
.join('');
|
||||||
|
|
||||||
|
return [
|
||||||
|
"<table>",
|
||||||
|
`<tr>${head.join('')}</tr>`,
|
||||||
|
rows,
|
||||||
|
"</table>",
|
||||||
|
].join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transform(html: string) {
|
||||||
|
return toHtml(reduceStack(toStack(html)));
|
||||||
|
}
|
33
src/content/lyrics/black-eyes.mdx
Normal file
33
src/content/lyrics/black-eyes.mdx
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
---
|
||||||
|
title: Black Eyes
|
||||||
|
date: 2023-04-25
|
||||||
|
---
|
||||||
|
import Lyrics from '../../components/lyrics/Lyrics.astro';
|
||||||
|
|
||||||
|
|
||||||
|
<Lyrics>
|
||||||
|
|
||||||
|
# Japanese
|
||||||
|
- 瞬きをして 切り取る時間
|
||||||
|
- 何気なくても 大切な今を
|
||||||
|
- 忘れないで 居られるように
|
||||||
|
- いつか 頭の中
|
||||||
|
- 掻き消して しまっても
|
||||||
|
# Romaji
|
||||||
|
- fddsfsaf
|
||||||
|
- fdsfadsf
|
||||||
|
- test
|
||||||
|
- test
|
||||||
|
---
|
||||||
|
# Japanese
|
||||||
|
- 瞬きをして 切り取る時間ff
|
||||||
|
- 何気なくても 大切な今を
|
||||||
|
- 忘れないで 居られるように
|
||||||
|
- いつか 頭の中
|
||||||
|
- 掻き消して しまっても
|
||||||
|
# Romaji
|
||||||
|
- fddsfsaf
|
||||||
|
- fdsfadsf
|
||||||
|
- test
|
||||||
|
- test
|
||||||
|
</Lyrics>
|
12
src/layouts/Lyrics.astro
Normal file
12
src/layouts/Lyrics.astro
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
import Base from "./Base.astro";
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<Base>
|
||||||
|
<main class="l_pages">
|
||||||
|
<article class="l_pages__list">
|
||||||
|
<slot/>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
</Base>
|
16
src/pages/lyrics/[...slug].astro
Normal file
16
src/pages/lyrics/[...slug].astro
Normal file
|
@ -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();
|
||||||
|
---
|
||||||
|
|
||||||
|
<Lyrics>
|
||||||
|
<Content />
|
||||||
|
</Lyrics>
|
Loading…
Reference in a new issue