From af3ab162d41e7f594ac4ccb0adaff7ad0a570e62 Mon Sep 17 00:00:00 2001 From: Luke Hubmayer-Werner Date: Thu, 19 Dec 2024 18:35:45 +1030 Subject: [PATCH] Generate Title Card subtitles --- lyrics/static/lyrics/input.js | 23 +++++++++--- lyrics/static/lyrics/subtitle_generator.js | 42 +++++++++++++++++----- lyrics/templates/lyrics/index.html | 4 +-- 3 files changed, 53 insertions(+), 16 deletions(-) diff --git a/lyrics/static/lyrics/input.js b/lyrics/static/lyrics/input.js index c6b9e35..c2bc87b 100644 --- a/lyrics/static/lyrics/input.js +++ b/lyrics/static/lyrics/input.js @@ -11,8 +11,8 @@ const lyrics_output_show_tl_element = document.querySelector('#lyrics_output_sho const lyrics_output_show_romaji_element = document.querySelector('#lyrics_output_show_romaji'); const lyrics_output_show_kanji_element = document.querySelector('#lyrics_output_show_kanji'); const subtitle_editor_textarea = document.getElementById('subtitle_editor_textarea'); -const generate_subtitles = document.getElementById('generate_subtitles'); -const download_subtitles = document.getElementById('download_subtitles'); +const btn_generate_subtitles = document.getElementById('btn_generate_subtitles'); +const btn_download_subtitles = document.getElementById('btn_download_subtitles'); const req_tokenization_url = './tokenize'; // let has_lyrics_changed = false let tokenized_lyric_lines = []; @@ -223,12 +223,25 @@ document.getElementById('load_song').addEventListener('change', event => { reader.readAsText(file); }, false) -download_subtitles.addEventListener('click', () => { +btn_download_subtitles.addEventListener('click', () => { const song_title_en = document.getElementById('song_title_en').value; save_text_file(`${song_title_en}.ass`, subtitle_editor_textarea.value); }); -generate_subtitles.addEventListener('click', () => { +import generate_subtitles_from_data from './subtitle_generator.js' +function generate_subtitles() { + console.log('Attempting to generate subtitles'); // TODO: Do something to generate subtitles + const subtitles = generate_subtitles_from_data({ + song_title: document.getElementById('song_title').value, + song_title_en: document.getElementById('song_title_en').value, + song_lyricist: document.getElementById('song_lyricist').value, + song_lyricist_en: document.getElementById('song_lyricist_en').value, + song_composer: document.getElementById('song_composer').value, + song_composer_en: document.getElementById('song_composer_en').value, + title_fade_duration_ms: 2500, + }); + subtitle_editor_textarea.value = subtitles; subtitle_editor_textarea.dispatchEvent(new Event('change', {})); // This triggers a reload in the player -}); +} +btn_generate_subtitles.addEventListener('click', generate_subtitles); diff --git a/lyrics/static/lyrics/subtitle_generator.js b/lyrics/static/lyrics/subtitle_generator.js index 33b54a3..8eafbf9 100644 --- a/lyrics/static/lyrics/subtitle_generator.js +++ b/lyrics/static/lyrics/subtitle_generator.js @@ -1,5 +1,9 @@ // This is mostly a port of the python code. It might desync from that over time. -function generate_subtitles() { +function timecode(s) { + return new Date(s*1000).toISOString().substring(11, 22); // This can overflow at 24 hours. Who cares? +} + +export default function generate_subtitles_from_data(data) { const format_defaults = { 'PlayResX': 1280, 'PlayResY': 720, @@ -13,9 +17,10 @@ function generate_subtitles() { 'FuriVMargin': 85, 'KaraokeColourFuture': '000019FF', 'KaraokeColourPast': 'E02A0A00', + 'KaraokeColourOutline': 'FFFFFF', } const f = format_defaults; - s = `[Script Info] + let s = `[Script Info] ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes @@ -25,14 +30,33 @@ PlayResY: ${f.PlayResY} [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding -Style: Default,${f.LatinFont},72,&H002A0A00,&H000019FF,&H00FFFFFF,&H00000000,0,0,0,0,100,100,0,0,1,2.5,0,8,30,30,25,1 -Style: Kanji,${f.JapaneseFont},${f.KanjiSize},&H${f.KaraokeColourPast},&H${f.KaraokeColourFuture},&H00FFFFFF,&H00000000,0,0,0,0,100,100,0,0,1,4.0,0,2,30,30,${f.KanjiVMargin},1 -Style: Furigana,${f.JapaneseFont},${f.FuriSize},&H${f.KaraokeColourPast},&H${f.KaraokeColourFuture},&H00FFFFFF,&H00000000,0,0,0,0,100,100,0,0,1,2.5,0,2,0,0,${f.FuriVMargin},1 -Style: Romaji,${f.LatinFont},${f.RomajiSize},&H${f.KaraokeColourPast},&H${f.KaraokeColourFuture},&H00FFFFFF,&H00000000,0,0,0,0,100,100,0,0,1,2.5,0,8,30,30,20,1 -Style: Translation,${f.LatinFont},${f.TranslationSize},&H00FFFFFF,&H000019FF,&H00000000,&H00000000,0,1,0,0,100,100,0,0,1,1.0,3,8,30,30,20,1 +Style: Default,${f.LatinFont},72,&H2A0A00,&H0019FF,&HFFFFFF,&H000000,0,0,0,0,100,100,0,0,1,2.5,0,8,30,30,25,1 +Style: Kanji,${f.JapaneseFont},${f.KanjiSize},&H${f.KaraokeColourPast},&H${f.KaraokeColourFuture},&H${f.KaraokeColourOutline},&H000000,0,0,0,0,100,100,0,0,1,4.0,0,2,30,30,${f.KanjiVMargin},1 +Style: Furigana,${f.JapaneseFont},${f.FuriSize},&H${f.KaraokeColourPast},&H${f.KaraokeColourFuture},&H${f.KaraokeColourOutline},&H000000,0,0,0,0,100,100,0,0,1,2.5,0,2,0,0,${f.FuriVMargin},1 +Style: Romaji,${f.LatinFont},${f.RomajiSize},&H${f.KaraokeColourPast},&H${f.KaraokeColourFuture},&H${f.KaraokeColourOutline},&H000000,0,0,0,0,100,100,0,0,1,2.5,0,8,30,30,20,1 +Style: Translation,${f.LatinFont},${f.TranslationSize},&HFFFFFF,&H0019FF,&H000000,&H000000,0,1,0,0,100,100,0,0,1,1.0,3,8,30,30,20,1 +Style: Title,Droid Sans,72,&HFFFFFF,&H0019FF,&H000000,&H000000,0,0,0,0,100,100,0,0,1,2.5,0,3,30,30,25,1 +Style: TitleJP,Droid Sans Japanese,72,&HFFFFFF,&H0019FF,&H000000,&H000000,0,0,0,0,100,100,0,0,1,2.5,0,1,30,30,25,1 [Events] -Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text` +Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text`; + // Title card + const t0 = 0.0; + const t1 = 80.0; // TODO: tie this to the first line time + const t0s = timecode(t0); + const t1s = timecode(t1); + const duration_seconds = t1-t0; + const duration_ms = Math.floor(duration_seconds * 1000); + const fade_duration_ms = data.title_fade_duration_ms ?? 1000; + const fade = `{\\fade(255,0,255,0,${fade_duration_ms},${duration_ms-fade_duration_ms},${duration_ms})}`; + s += ` +Comment: 0,00:00:00.00,00:01:20.00,,,,,,,Title Card +Dialogue: 0,${t0s},${t1s},TitleJP,,,,,,${fade}作曲 ${data.song_composer} +Dialogue: 0,${t0s},${t1s},TitleJP,,,,,,${fade}作詞 ${data.song_lyricist} +Dialogue: 0,${t0s},${t1s},TitleJP,,,,,,${fade}曲名 ${data.song_title} +Dialogue: 0,${t0s},${t1s},Title,,,,,,${fade}Music: ${data.song_composer_en} +Dialogue: 0,${t0s},${t1s},Title,,,,,,${fade}Lyrics: ${data.song_lyricist_en} +Dialogue: 0,${t0s},${t1s},Title,,,,,,${fade}${data.song_title_en}`; // TODO: add the lines return s; -} \ No newline at end of file +} diff --git a/lyrics/templates/lyrics/index.html b/lyrics/templates/lyrics/index.html index df0ab24..50c5203 100644 --- a/lyrics/templates/lyrics/index.html +++ b/lyrics/templates/lyrics/index.html @@ -136,8 +136,8 @@

Subtitle Editor

- - + +