Fix some regressions and add CSP headers to suppress some noise
This commit is contained in:
parent
2494ae7483
commit
5987ff95c6
1
Pipfile
1
Pipfile
|
@ -8,6 +8,7 @@ fugashi = "*"
|
||||||
unidic = "*"
|
unidic = "*"
|
||||||
pykakasi = "*"
|
pykakasi = "*"
|
||||||
django = "*"
|
django = "*"
|
||||||
|
django-csp = "*"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ ALLOWED_HOSTS = ['topcez-lhw', '127.0.0.1']
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
'lyrics',
|
'lyrics',
|
||||||
|
'csp',
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
|
@ -41,6 +42,7 @@ INSTALLED_APPS = [
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
'csp.middleware.CSPMiddleware',
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
@ -122,3 +124,10 @@ STATIC_URL = 'static/'
|
||||||
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
|
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
|
# CSP
|
||||||
|
# CSP_REPORT_ONLY = True
|
||||||
|
CSP_DEFAULT_SRC = ["'self'", '*', "'unsafe-inline'", 'blob:']
|
||||||
|
CSP_STYLE_SRC = ["'self'", "'unsafe-inline'"]
|
||||||
|
CSP_REPORT_URI = ["'http://127.0.0.1'"]
|
||||||
|
CSP_WORKER_SRC = ["'self'", '*', "'unsafe-inline'"]
|
||||||
|
|
|
@ -3,9 +3,11 @@ const css_font_sizes = ['0%', 'xx-small', 'x-small', 'small', 'medium', 'large',
|
||||||
const string_replacements_element = document.querySelector('#word_replacements_pre');
|
const string_replacements_element = document.querySelector('#word_replacements_pre');
|
||||||
const word_overrides_element = document.querySelector('#word_replacements_post');
|
const word_overrides_element = document.querySelector('#word_replacements_post');
|
||||||
const lyrics_input_element = document.querySelector('#lyrics_input_textarea');
|
const lyrics_input_element = document.querySelector('#lyrics_input_textarea');
|
||||||
|
const lyrics_tl_input_element = document.querySelector('#lyrics_tl_input_textarea');
|
||||||
const lyrics_output_element = document.querySelector('#lyrics_output');
|
const lyrics_output_element = document.querySelector('#lyrics_output');
|
||||||
const arrangement_input_element = document.querySelector('#arrangement_input_textarea');
|
const arrangement_input_element = document.querySelector('#arrangement_input_textarea');
|
||||||
const arrangement_output_element = document.querySelector('#arrangement_output');
|
const arrangement_output_element = document.querySelector('#arrangement_output');
|
||||||
|
const lyrics_output_show_tl_element = document.querySelector('#lyrics_output_show_tl');
|
||||||
const lyrics_output_show_romaji_element = document.querySelector('#lyrics_output_show_romaji');
|
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 lyrics_output_show_kanji_element = document.querySelector('#lyrics_output_show_kanji');
|
||||||
const req_tokenization_url = './tokenize';
|
const req_tokenization_url = './tokenize';
|
||||||
|
@ -38,11 +40,11 @@ function format_parsed_line(line) {
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_lyrics_output(data) {
|
function update_lyrics_output() {
|
||||||
tokenized_lyric_lines = data.parsed_lines;
|
|
||||||
var html = '';
|
var html = '';
|
||||||
|
|
||||||
lyric_section_ranges = {};
|
lyric_section_ranges = {};
|
||||||
|
const tl_lines = lyrics_tl_input_element.value.split('\n');
|
||||||
var current_lyric_section
|
var current_lyric_section
|
||||||
var line_counter = 0
|
var line_counter = 0
|
||||||
tokenized_lyric_lines.forEach(line => {
|
tokenized_lyric_lines.forEach(line => {
|
||||||
|
@ -57,6 +59,8 @@ function update_lyrics_output(data) {
|
||||||
current_lyric_section = section_match[1];
|
current_lyric_section = section_match[1];
|
||||||
lyric_section_ranges[current_lyric_section] = [line_counter];
|
lyric_section_ranges[current_lyric_section] = [line_counter];
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (line_counter < tl_lines.length) html += `<span class="lyrics-tl">${tl_lines[line_counter]}<br></span>`;
|
||||||
}
|
}
|
||||||
html += format_parsed_line(line);
|
html += format_parsed_line(line);
|
||||||
line_counter++;
|
line_counter++;
|
||||||
|
@ -70,10 +74,14 @@ function update_lyrics_output(data) {
|
||||||
|
|
||||||
update_arrangement_output();
|
update_arrangement_output();
|
||||||
}
|
}
|
||||||
|
function on_receive_tokenized_lyrics(data) {
|
||||||
|
tokenized_lyric_lines = data.parsed_lines;
|
||||||
|
update_lyrics_output();
|
||||||
|
}
|
||||||
|
|
||||||
function update_arrangement_output() {
|
function update_arrangement_output() {
|
||||||
console.log('Updating arrangement output');
|
console.log('Updating arrangement output');
|
||||||
|
const tl_lines = lyrics_tl_input_element.value.split('\n');
|
||||||
const arrangement_str = arrangement_input_element.value;
|
const arrangement_str = arrangement_input_element.value;
|
||||||
var html = '';
|
var html = '';
|
||||||
arrangement_str.split(',').forEach(section => {
|
arrangement_str.split(',').forEach(section => {
|
||||||
|
@ -84,6 +92,9 @@ function update_arrangement_output() {
|
||||||
// html += `[${s}]<br>`; // Section name is already in the line range :)
|
// html += `[${s}]<br>`; // Section name is already in the line range :)
|
||||||
const [i0, i1] = lyric_section_ranges[s];
|
const [i0, i1] = lyric_section_ranges[s];
|
||||||
for (let i = i0; i < i1; i++) {
|
for (let i = i0; i < i1; i++) {
|
||||||
|
if ((typeof tokenized_lyric_lines[i]) != "string") {
|
||||||
|
if (i < tl_lines.length) html += `<span class="lyrics-tl">${tl_lines[i]}<br></span>`;
|
||||||
|
}
|
||||||
html += format_parsed_line(tokenized_lyric_lines[i]);
|
html += format_parsed_line(tokenized_lyric_lines[i]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -121,29 +132,41 @@ function lyrics_input_updated() {
|
||||||
})
|
})
|
||||||
.then((rsp) => {
|
.then((rsp) => {
|
||||||
console.debug(rsp);
|
console.debug(rsp);
|
||||||
update_lyrics_output(rsp);
|
on_receive_tokenized_lyrics(rsp);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
function update_outputs() {
|
||||||
|
update_lyrics_output();
|
||||||
|
update_arrangement_output();
|
||||||
|
}
|
||||||
// lyrics_input_element.addEventListener('keyup', (event) => {if (update_lyrics_keys.has(event.key)) lyrics_input_updated();});
|
// lyrics_input_element.addEventListener('keyup', (event) => {if (update_lyrics_keys.has(event.key)) lyrics_input_updated();});
|
||||||
lyrics_input_element.addEventListener('change', lyrics_input_updated);
|
lyrics_input_element.addEventListener('change', lyrics_input_updated);
|
||||||
|
lyrics_tl_input_element.addEventListener('change', update_outputs);
|
||||||
arrangement_input_element.addEventListener('change', update_arrangement_output);
|
arrangement_input_element.addEventListener('change', update_arrangement_output);
|
||||||
|
|
||||||
function update_output_styles() {
|
function update_output_styles() {
|
||||||
style_lyrics_kanji.style.display = lyrics_output_show_kanji_element.value > 0 ? "inline" : "none";
|
style_lyrics_kanji.style.display = lyrics_output_show_kanji_element.value > 0 ? "inline" : "none";
|
||||||
style_lyrics_romaji.style.display = lyrics_output_show_romaji_element.value > 0 ? "inline" : "none";
|
style_lyrics_romaji.style.display = lyrics_output_show_romaji_element.value > 0 ? "inline" : "none";
|
||||||
|
style_lyrics_tl.style.display = lyrics_output_show_tl_element.value > 0 ? "inline" : "none";
|
||||||
style_lyrics_kanji.style.fontSize = css_font_sizes[lyrics_output_show_kanji_element.value];
|
style_lyrics_kanji.style.fontSize = css_font_sizes[lyrics_output_show_kanji_element.value];
|
||||||
style_lyrics_romaji.style.fontSize = css_font_sizes[lyrics_output_show_romaji_element.value];
|
style_lyrics_romaji.style.fontSize = css_font_sizes[lyrics_output_show_romaji_element.value];
|
||||||
|
style_lyrics_tl.style.fontSize = css_font_sizes[lyrics_output_show_tl_element.value];
|
||||||
}
|
}
|
||||||
|
|
||||||
const stylesheet = document.styleSheets[0];
|
const stylesheet = document.styleSheets[0];
|
||||||
console.log(stylesheet.cssRules)
|
// console.log(stylesheet.cssRules)
|
||||||
const style_lyrics_kanji = stylesheet.cssRules[stylesheet.insertRule('.lyrics-kanji {display: inline}')];
|
const style_lyrics_kanji = stylesheet.cssRules[stylesheet.insertRule('.lyrics-kanji {display: inline}')];
|
||||||
const style_lyrics_romaji = stylesheet.cssRules[stylesheet.insertRule('.lyrics-romaji {display: inline}')];
|
const style_lyrics_romaji = stylesheet.cssRules[stylesheet.insertRule('.lyrics-romaji {display: inline}')];
|
||||||
console.log(style_lyrics_kanji)
|
const style_lyrics_tl = stylesheet.cssRules[stylesheet.insertRule('.lyrics-tl {display: inline}')];
|
||||||
console.log(style_lyrics_romaji)
|
// console.log(style_lyrics_kanji)
|
||||||
|
// console.log(style_lyrics_romaji)
|
||||||
lyrics_output_show_kanji_element.addEventListener('change', update_output_styles);
|
lyrics_output_show_kanji_element.addEventListener('change', update_output_styles);
|
||||||
lyrics_output_show_romaji_element.addEventListener('change', update_output_styles);
|
lyrics_output_show_romaji_element.addEventListener('change', update_output_styles);
|
||||||
|
lyrics_output_show_tl_element.addEventListener('change', update_output_styles);
|
||||||
update_output_styles();
|
update_output_styles();
|
||||||
|
|
||||||
|
document.getElementById('btn_syllable').addEventListener('click', () => {console.log(`Syllable button clicked! ${performance.now()}ms`)});
|
||||||
|
document.getElementById('btn_metronome').addEventListener('click', () => {console.log(`Metronome button clicked! ${performance.now()}ms`)});
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
function noteDurationToMs (bpm, dur, type) {
|
||||||
|
return 60000 * 4 * dur * type / bpm
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleNote(ac, time, dur) {
|
||||||
|
var osc = ac.createOscillator();
|
||||||
|
osc.connect( ac.destination );
|
||||||
|
osc.start(time);
|
||||||
|
osc.stop(time + dur);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ac = new AudioContext();
|
||||||
|
let lastNote= ac.currentTime;
|
||||||
|
const step = noteDurationToMs(120, 1 / 4, 1) / 1000;
|
||||||
|
const lookAhead = step / 2;
|
||||||
|
|
||||||
|
setInterval(()=> {
|
||||||
|
const diff = ac.currentTime - lastNote;
|
||||||
|
if (diff >= lookAhead) {
|
||||||
|
const nextNote = lastNote + step;
|
||||||
|
scheduleNote(ac, nextNote, 0.025)
|
||||||
|
lastNote = nextNote;
|
||||||
|
}
|
||||||
|
},15)
|
|
@ -1,10 +1,11 @@
|
||||||
video, input {
|
video {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
/* input {
|
||||||
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
} */
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
background-color: aqua;
|
background-color: aqua;
|
||||||
|
@ -41,6 +42,15 @@ input {
|
||||||
#arrangement_input {
|
#arrangement_input {
|
||||||
max-width: 260px;
|
max-width: 260px;
|
||||||
}
|
}
|
||||||
|
#line_timer {
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
#syllable_timer {
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
#syllable_timer input {
|
||||||
|
max-width: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
.flex-container {
|
.flex-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -70,3 +80,6 @@ input {
|
||||||
.lyrics-kanji {
|
.lyrics-kanji {
|
||||||
font-family: Droid Sans Japanese;
|
font-family: Droid Sans Japanese;
|
||||||
}
|
}
|
||||||
|
.lyrics-tl {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
// This is mostly a port of the python code. It might desync from that over time.
|
||||||
|
function generate_subtitles() {
|
||||||
|
const format_defaults = {
|
||||||
|
'PlayResX': 1280,
|
||||||
|
'PlayResY': 720,
|
||||||
|
'LatinFont': 'Droid Sans',
|
||||||
|
'JapaneseFont': 'Droid Sans Japanese',
|
||||||
|
'TranslationSize': 36,
|
||||||
|
'RomajiSize': 48,
|
||||||
|
'KanjiSize': 72,
|
||||||
|
'KanjiVMargin': 20,
|
||||||
|
'FuriSize': 36,
|
||||||
|
'FuriVMargin': 85,
|
||||||
|
'KaraokeColourFuture': '000019FF',
|
||||||
|
'KaraokeColourPast': 'E02A0A00',
|
||||||
|
}
|
||||||
|
const f = format_defaults;
|
||||||
|
s = `[Script Info]
|
||||||
|
ScriptType: v4.00+
|
||||||
|
WrapStyle: 0
|
||||||
|
ScaledBorderAndShadow: yes
|
||||||
|
YCbCr Matrix: TV.709
|
||||||
|
PlayResX: ${f.PlayResX}
|
||||||
|
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
|
||||||
|
|
||||||
|
[Events]
|
||||||
|
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text`
|
||||||
|
// TODO: add the lines
|
||||||
|
return s;
|
||||||
|
}
|
|
@ -4,11 +4,12 @@ import JASSUB from '../jass/jassub.es.js'
|
||||||
'use strict'
|
'use strict'
|
||||||
var URL = window.URL || window.webkitURL
|
var URL = window.URL || window.webkitURL
|
||||||
var displayMessage = function (message, isError) {
|
var displayMessage = function (message, isError) {
|
||||||
var element = document.querySelector('#message')
|
var element = document.querySelector('#video_message')
|
||||||
element.innerHTML = message
|
element.innerHTML = message
|
||||||
element.className = isError ? 'error' : 'info'
|
element.className = isError ? 'error' : 'info'
|
||||||
}
|
}
|
||||||
var playSelectedFile = function (event) {
|
var playSelectedFile = function (event) {
|
||||||
|
console.log('Attempting to play video file');
|
||||||
var file = this.files[0]
|
var file = this.files[0]
|
||||||
var type = file.type
|
var type = file.type
|
||||||
var videoNode = document.querySelector('video')
|
var videoNode = document.querySelector('video')
|
||||||
|
@ -25,13 +26,13 @@ import JASSUB from '../jass/jassub.es.js'
|
||||||
var fileURL = URL.createObjectURL(file)
|
var fileURL = URL.createObjectURL(file)
|
||||||
videoNode.src = fileURL
|
videoNode.src = fileURL
|
||||||
}
|
}
|
||||||
var inputNode = document.querySelector('input')
|
var inputNode = document.querySelector('#video_selector_input')
|
||||||
inputNode.addEventListener('change', playSelectedFile, false)
|
inputNode.addEventListener('change', playSelectedFile, false)
|
||||||
})()
|
})()
|
||||||
|
|
||||||
// import font from '../jass/DroidSansJapanese.ttf'
|
// import font from '../jass/DroidSansJapanese.ttf'
|
||||||
const renderer = new JASSUB({
|
const renderer = new JASSUB({
|
||||||
video: document.querySelector('video'),
|
video: document.querySelector('#local_video'),
|
||||||
subUrl: '../test.ass',
|
subUrl: '../test.ass',
|
||||||
fonts: [],
|
fonts: [],
|
||||||
// fallbackFont: 'liberation sans',
|
// fallbackFont: 'liberation sans',
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
[Script Info]
|
||||||
|
ScriptType: v4.00+
|
||||||
|
WrapStyle: 0
|
||||||
|
ScaledBorderAndShadow: yes
|
||||||
|
YCbCr Matrix: TV.709
|
||||||
|
PlayResX: 1280
|
||||||
|
PlayResY: 720
|
||||||
|
|
||||||
|
[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,Droid Sans,72,&H002A0A00,&H000019FF,&H00FFFFFF,&H00000000,0,0,0,0,100,100,0,0,1,2.5,0,8,30,30,25,1
|
||||||
|
Style: Kanji,Droid Sans Japanese,72,&HE02A0A00,&H000019FF,&H00FFFFFF,&H00000000,0,0,0,0,100,100,0,0,1,4.0,0,2,30,30,20,1
|
||||||
|
Style: Furigana,Droid Sans Japanese,36,&HE02A0A00,&H000019FF,&H00FFFFFF,&H00000000,0,0,0,0,100,100,0,0,1,2.5,0,2,0,0,85,1
|
||||||
|
Style: Romaji,Droid Sans,48,&HE02A0A00,&H000019FF,&H00FFFFFF,&H00000000,0,0,0,0,100,100,0,0,1,2.5,0,8,30,30,20,1
|
||||||
|
Style: Translation,Droid Sans,36,&H00FFFFFF,&H000019FF,&H00000000,&H00000000,0,1,0,0,100,100,0,0,1,1.0,3,8,30,30,20,1
|
||||||
|
|
||||||
|
[Events]
|
||||||
|
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
|
||||||
|
Dialogue: 0,00:01:08.00,00:01:20.50,Translation,,,,,,Rain and snow fall from the heavens. Moisten the earth and make it sprout
|
||||||
|
Dialogue: 0,00:01:08.00,00:01:20.50,Romaji,,,,,,{\k0}{\K50}a{\K50}me{\k0} {\K50}ya{\k0} {\K50}yu{\K50}ki{\k0} {\K50}ga{\k0} {\K50}ten{\k0} {\K50}ka{\K50}ra{\k0} {\K50}fu{\K50}tte{\k0} {\K50}chi{\k0} {\K50}wo{\k0} {\K50}u{\K50}ru{\K50}o{\K50}shi{\k0} {\K50}me{\k0} {\K50}wo{\k0} {\K50}da{\K50}sa{\k0} {\K50}se{\K50}ru
|
||||||
|
Dialogue: 0,00:01:08.00,00:01:20.50,Kanji,,,,,,{\k0}{\K100}雨{\K50}や{\K100}雪{\K50}が{\K50}天{\K50}か{\K50}ら{\K50}降{\K50}って{\K50}地{\K50}を{\K150}潤{\K50}し{\k0} {\K50}芽{\K50}を{\K50}出{\K50}さ{\K50}せ{\K50}る
|
||||||
|
Dialogue: 1,00:01:08.00,00:01:20.50,Furigana,,90,1190,,,{\k0}{\K50}あ{\K50}め
|
||||||
|
Dialogue: 1,00:01:08.00,00:01:20.50,Furigana,,200,1080,,,{\k150}{\K50}ゆ{\K50}き
|
||||||
|
Dialogue: 1,00:01:08.00,00:01:20.50,Furigana,,310,970,,,{\k300}{\K50}てん
|
||||||
|
Dialogue: 1,00:01:08.00,00:01:20.50,Furigana,,475,805,,,{\k450}{\K50}ふ
|
||||||
|
Dialogue: 1,00:01:08.00,00:01:20.50,Furigana,,640,640,,,{\k550}{\K50}ち
|
||||||
|
Dialogue: 1,00:01:08.00,00:01:20.50,Furigana,,750,530,,,{\k650}{\K50}う{\K50}る{\K50}お
|
||||||
|
Dialogue: 1,00:01:08.00,00:01:20.50,Furigana,,915,365,,,{\k850}{\K50}め
|
||||||
|
Dialogue: 1,00:01:08.00,00:01:20.50,Furigana,,1025,255,,,{\k950}{\K50}だ
|
||||||
|
Dialogue: 0,00:01:20.50,00:01:33.50,Translation,,,,,,Seed to those who sow. And bread to those who eat.
|
||||||
|
Dialogue: 0,00:01:20.50,00:01:33.50,Romaji,,,,,,{\k0}{\K50}ta{\K50}ne{\K50}ma{\K50}ki{\k0} {\K50}ku{\k0} {\K50}nin{\k0} {\K50}ni{\k0} {\K50}shu{\k0} {\K50}wo{\k0} {\K50}a{\K50}ta{\K50}e{\k0} {\K50}ta{\K50}be{\K50}ru{\k0} {\K50}hi{\K50}to{\k0} {\K50}ni{\k0} {\K50}pan{\k0} {\K50}wo{\k0} {\K50}a{\K50}ta{\K50}e{\K50}ru
|
||||||
|
Dialogue: 0,00:01:20.50,00:01:33.50,Kanji,,,,,,{\k0}{\K200}種蒔{\K50}く{\K50}人{\K50}に{\k0} {\K50}種{\K50}を{\K100}与{\K50}え{\k0} {\K50}食{\K50}べ{\K50}る{\K100}人{\K50}に{\k0} {\K50}パン{\K50}を{\K100}与{\K50}え{\K50}る
|
||||||
|
Dialogue: 1,00:01:20.50,00:01:33.50,Furigana,,62,1217,,,{\k0}{\K50}た{\K50}ね{\K50}ま{\K50}き
|
||||||
|
Dialogue: 1,00:01:20.50,00:01:33.50,Furigana,,200,1080,,,{\k250}{\K50}にん
|
||||||
|
Dialogue: 1,00:01:20.50,00:01:33.50,Furigana,,365,915,,,{\k350}{\K50}しゅ
|
||||||
|
Dialogue: 1,00:01:20.50,00:01:33.50,Furigana,,475,805,,,{\k450}{\K50}あ{\K50}た
|
||||||
|
Dialogue: 1,00:01:20.50,00:01:33.50,Furigana,,640,640,,,{\k600}{\K50}た
|
||||||
|
Dialogue: 1,00:01:20.50,00:01:33.50,Furigana,,805,475,,,{\k750}{\K50}ひ{\K50}と
|
||||||
|
Dialogue: 1,00:01:20.50,00:01:33.50,Furigana,,1135,145,,,{\k1000}{\K50}あ{\K50}た
|
||||||
|
Dialogue: 0,00:01:33.50,00:01:46.00,Translation,,,,,,The Lord's thoughts always go beyond my thoughts
|
||||||
|
Dialogue: 0,00:01:33.50,00:01:46.00,Romaji,,,,,,{\k0}{\K50}shu{\k0} {\K50}no{\k0} {\K50}o{\K50}mo{\K50}i{\k0} {\K50}ha{\k0} {\K50}i{\K50}tsu{\k0} {\K50}de{\k0} {\K50}mo{\k0} {\K50}wa{\K50}ta{\K50}shi{\k0} {\K50}no{\k0} {\K50}o{\K50}mo{\K50}i{\k0} {\K50}wo{\k0} {\K50}ko{\K50}e{\k0} {\K50}te{\k0} {\K50}i{\K50}ku
|
||||||
|
Dialogue: 0,00:01:33.50,00:01:46.00,Kanji,,,,,,{\k0}{\K50}主{\K50}の{\K100}思{\K50}い{\K50}は{\K50}い{\K50}つ{\K50}で{\K50}も{\k0} {\K150}私{\K50}の{\K100}思{\K50}い{\K50}を{\K50}超{\K50}え{\K50}て{\K50}い{\K50}く
|
||||||
|
Dialogue: 1,00:01:33.50,00:01:46.00,Furigana,,117,1162,,,{\k0}{\K50}しゅ
|
||||||
|
Dialogue: 1,00:01:33.50,00:01:46.00,Furigana,,227,1052,,,{\k100}{\K50}お{\K50}も
|
||||||
|
Dialogue: 1,00:01:33.50,00:01:46.00,Furigana,,667,612,,,{\k500}{\K50}わ{\K50}た{\K50}し
|
||||||
|
Dialogue: 1,00:01:33.50,00:01:46.00,Furigana,,777,502,,,{\k700}{\K50}お{\K50}も
|
||||||
|
Dialogue: 1,00:01:33.50,00:01:46.00,Furigana,,942,337,,,{\k900}{\K50}こ
|
||||||
|
Dialogue: 0,00:01:46.00,00:01:58.50,Translation,,,,,,The words you have spoken Will not return in vain. And I will see it done.
|
||||||
|
Dialogue: 0,00:01:46.00,00:01:58.50,Romaji,,,,,,{\k0}{\K50}a{\K50}na{\K50}ta{\k0} {\K50}ga{\k0} {\K50}tsu{\K50}ge{\k0} {\K50}ta{\k0} {\K50}ko{\K50}to{\K50}ba{\k0} {\K50}ha{\k0} {\K50}mu{\K50}na{\K50}shi{\K50}ku{\k0} {\K50}ka{\K50}e{\K50}ru{\k0} {\K50}ko{\K50}to{\k0} {\K50}ha{\k0} {\K50}na{\K50}i
|
||||||
|
Dialogue: 0,00:01:46.00,00:01:58.50,Kanji,,,,,,{\k0}{\K50}あ{\K50}な{\K50}た{\K50}が{\K50}告{\K50}げ{\K50}た{\K150}言葉{\K50}は{\k0} {\K100}空{\K50}し{\K50}く{\K100}帰{\K50}る{\K50}こ{\K50}と{\K50}は{\K50}な{\K50}い
|
||||||
|
Dialogue: 1,00:01:46.00,00:01:58.50,Furigana,,310,970,,,{\k200}{\K50}つ
|
||||||
|
Dialogue: 1,00:01:46.00,00:01:58.50,Furigana,,502,777,,,{\k350}{\K50}こ{\K50}と{\K50}ば
|
||||||
|
Dialogue: 1,00:01:46.00,00:01:58.50,Furigana,,695,585,,,{\k550}{\K50}む{\K50}な
|
||||||
|
Dialogue: 1,00:01:46.00,00:01:58.50,Furigana,,860,420,,,{\k750}{\K50}か{\K50}え
|
||||||
|
Dialogue: 0,00:01:58.50,00:02:12.00,Translation,,,,,,You will succeed in the mission you have given.
|
||||||
|
Dialogue: 0,00:01:58.50,00:02:12.00,Romaji,,,,,,{\k0}{\K50}ka{\K50}na{\K50}ra{\K50}zu{\k0} {\K50}so{\K50}re{\k0} {\K50}wo{\k0} {\K50}na{\K50}shi{\K50}to{\K50}ge{\k0} {\K50}a{\K50}ta{\K50}e{\k0} {\K50}ta{\k0} {\K50}shi{\K50}me{\K50}i{\k0} {\K50}se{\K50}i{\K50}ko{\K50}u{\k0} {\K50}sa{\k0} {\K50}se{\K50}ru
|
||||||
|
Dialogue: 0,00:01:58.50,00:02:12.00,Kanji,,,,,,{\k0}{\K150}必{\K50}ず{\K50}そ{\K50}れ{\K50}を{\k0} {\K50}成{\K50}し{\K50}遂{\K50}げ{\k0} {\K100}与{\K50}え{\K50}た{\K150}使命{\k0} {\K200}成功{\K50}さ{\K50}せ{\K50}る
|
||||||
|
Dialogue: 1,00:01:58.50,00:02:12.00,Furigana,,62,1217,,,{\k0}{\K50}か{\K50}な{\K50}ら
|
||||||
|
Dialogue: 1,00:01:58.50,00:02:12.00,Furigana,,392,887,,,{\k350}{\K50}な
|
||||||
|
Dialogue: 1,00:01:58.50,00:02:12.00,Furigana,,502,777,,,{\k450}{\K50}と
|
||||||
|
Dialogue: 1,00:01:58.50,00:02:12.00,Furigana,,667,612,,,{\k550}{\K50}あ{\K50}た
|
||||||
|
Dialogue: 1,00:01:58.50,00:02:12.00,Furigana,,860,420,,,{\k750}{\K50}し{\K50}め{\K50}い
|
||||||
|
Dialogue: 1,00:01:58.50,00:02:12.00,Furigana,,1025,255,,,{\k900}{\K50}せ{\K50}い{\K50}こ{\K50}う
|
||||||
|
Dialogue: 0,00:02:12.00,00:02:26.50,Translation,,,,,,Praise the Lord, my soul. Rejoice and be glad, and see what the Lord has done.
|
||||||
|
Dialogue: 0,00:02:12.00,00:02:26.50,Romaji,,,,,,{\k0}{\K50}ho{\K50}me{\K50}ta{\K50}ta{\K50}e{\K50}yo{\k0} {\K50}wa{\K50}ga{\k0} {\K50}ta{\K50}ma{\K50}shi{\K50}i{\k0} {\K50}yo{\k0} {\K50}yo{\K50}ro{\K50}ko{\K50}bi{\k0} {\K50}mo{\K50}te{\k0} {\K50}shu{\k0} {\K50}no{\k0} {\K50}mi{\k0} {\K50}wa{\K50}sa{\k0} {\K50}wo{\k0} {\K50}mi{\K50}yo
|
||||||
|
Dialogue: 0,00:02:12.00,00:02:26.50,Kanji,,,,,,{\k0}{\K50}褒{\K50}め{\K50}た{\K50}た{\K50}え{\K50}よ{\k0} {\K50}我{\K50}が{\K200}魂{\K50}よ{\k0} {\K150}喜{\K50}び{\K50}持{\K50}て{\k0} {\K50}主{\K50}の{\K50}み{\K50}わ{\K50}さ{\K50}を{\K50}見{\K50}よ
|
||||||
|
Dialogue: 1,00:02:12.00,00:02:26.50,Furigana,,-20,1300,,,{\k0}{\K50}ほ
|
||||||
|
Dialogue: 1,00:02:12.00,00:02:26.50,Furigana,,365,915,,,{\k300}{\K50}わ
|
||||||
|
Dialogue: 1,00:02:12.00,00:02:26.50,Furigana,,475,805,,,{\k400}{\K50}た{\K50}ま{\K50}し{\K50}い
|
||||||
|
Dialogue: 1,00:02:12.00,00:02:26.50,Furigana,,640,640,,,{\k650}{\K50}よ{\K50}ろ{\K50}こ
|
||||||
|
Dialogue: 1,00:02:12.00,00:02:26.50,Furigana,,750,530,,,{\k850}{\K50}も
|
||||||
|
Dialogue: 1,00:02:12.00,00:02:26.50,Furigana,,915,365,,,{\k950}{\K50}しゅ
|
||||||
|
Dialogue: 1,00:02:12.00,00:02:26.50,Furigana,,1245,35,,,{\k1250}{\K50}み
|
||||||
|
Dialogue: 0,00:02:26.50,00:02:40.00,Translation,,,,,,Hallelujah. Glory to the Lord.
|
||||||
|
Dialogue: 0,00:02:26.50,00:02:40.00,Romaji,,,,,,{\k0}{\K50}ha{\K50}re{\K50}ru{\K50}ya{\k0} {\K50}shu{\k0} {\K50}ni{\k0} {\K50}e{\K50}i{\K50}ko{\K50}u{\k0} {\K50}a{\K50}re{\k0} {\K50}i{\K50}ke{\K50}ru{\k0} {\K50}ka{\K50}mi{\k0} {\K50}ni{\k0} {\K50}yu{\K50}da{\K50}ne{\k0} {\K50}te{\k0} {\K50}i{\K50}ki{\K50}ru
|
||||||
|
Dialogue: 0,00:02:26.50,00:02:40.00,Kanji,,,,,,{\k0}{\K50}ハ{\K50}レ{\K50}ル{\K50}ヤ{\k0} {\K50}主{\K50}に{\K200}栄光{\K50}あ{\K50}れ{\k0} {\K50}生{\K50}け{\K50}る{\K100}神{\K50}に{\k0} {\K100}委{\K50}ね{\K50}て{\K50}生{\K50}き{\K50}る
|
||||||
|
Dialogue: 1,00:02:26.50,00:02:40.00,Furigana,,282,997,,,{\k200}{\K50}しゅ
|
||||||
|
Dialogue: 1,00:02:26.50,00:02:40.00,Furigana,,420,860,,,{\k300}{\K50}え{\K50}い{\K50}こ{\K50}う
|
||||||
|
Dialogue: 1,00:02:26.50,00:02:40.00,Furigana,,667,612,,,{\k600}{\K50}い
|
||||||
|
Dialogue: 1,00:02:26.50,00:02:40.00,Furigana,,832,447,,,{\k750}{\K50}か{\K50}み
|
||||||
|
Dialogue: 1,00:02:26.50,00:02:40.00,Furigana,,997,282,,,{\k900}{\K50}ゆ{\K50}だ
|
||||||
|
Dialogue: 1,00:02:26.50,00:02:40.00,Furigana,,1162,117,,,{\k1100}{\K50}い
|
||||||
|
Dialogue: 0,00:02:40.00,00:02:47.50,Translation,,,,,,I entrust my life to the living God. The living God is with us.
|
||||||
|
Dialogue: 0,00:02:40.00,00:02:47.50,Romaji,,,,,,{\k0}{\K50}i{\K50}ke{\K50}ru{\k0} {\K50}ka{\K50}mi{\k0} {\K50}ga{\k0} {\K50}to{\K50}mo{\k0} {\K50}ni{\k0} {\K50}o{\K50}sa{\k0} {\K50}re{\K50}ru
|
||||||
|
Dialogue: 0,00:02:40.00,00:02:47.50,Kanji,,,,,,{\k0}{\K50}生{\K50}け{\K50}る{\K100}神{\K50}が{\k0} {\K100}共{\K50}に{\K50}お{\K50}さ{\K50}れ{\K50}る
|
||||||
|
Dialogue: 1,00:02:40.00,00:02:47.50,Furigana,,337,942,,,{\k0}{\K50}い
|
||||||
|
Dialogue: 1,00:02:40.00,00:02:47.50,Furigana,,502,777,,,{\k150}{\K50}か{\K50}み
|
||||||
|
Dialogue: 1,00:02:40.00,00:02:47.50,Furigana,,667,612,,,{\k300}{\K50}と{\K50}も
|
|
@ -64,12 +64,17 @@
|
||||||
<!-- Lyrics input -->
|
<!-- Lyrics input -->
|
||||||
<div id="lyrics_input">
|
<div id="lyrics_input">
|
||||||
<h2>Lyrics Input</h2>
|
<h2>Lyrics Input</h2>
|
||||||
<textarea id="lyrics_input_textarea" rows="40" cols="80" placeholder="[v1] おはよう世界"></textarea>
|
<h3>Japanese</h3>
|
||||||
|
<textarea id="lyrics_input_textarea" rows="20" cols="80" placeholder="[v1] おはよう世界"></textarea>
|
||||||
|
<h3>Translation</h3>
|
||||||
|
<textarea id="lyrics_tl_input_textarea" rows="20" cols="80" placeholder="[v1] Hello world"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<!-- Lyrics output -->
|
<!-- Lyrics output -->
|
||||||
<div id="lyrics_output_outer">
|
<div id="lyrics_output_outer">
|
||||||
<table><tr>
|
<table><tr>
|
||||||
<td><h2>Lyrics Output</h2></td>
|
<td><h2>Lyrics Output</h2></td>
|
||||||
|
<td><input type="number" min="0" max="7" id="lyrics_output_show_tl" value="4"></td>
|
||||||
|
<td><label for="lyrics_output_show_tl">Translation</label></td>
|
||||||
<td><input type="number" min="0" max="7" id="lyrics_output_show_romaji" value="4"></td>
|
<td><input type="number" min="0" max="7" id="lyrics_output_show_romaji" value="4"></td>
|
||||||
<td><label for="lyrics_output_show_romaji">Romaji</label></td>
|
<td><label for="lyrics_output_show_romaji">Romaji</label></td>
|
||||||
<td><input type="number" min="0" max="7" id="lyrics_output_show_kanji" value="6"></td>
|
<td><input type="number" min="0" max="7" id="lyrics_output_show_kanji" value="6"></td>
|
||||||
|
@ -84,13 +89,31 @@
|
||||||
<div id="arrangement_output">
|
<div id="arrangement_output">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Syllable Timer -->
|
||||||
|
<div id="syllable_timer">
|
||||||
|
<h2>Syllable Timer</h2>
|
||||||
|
This will have a metronome and a button for tapping out the rhythm of a given line.<br>
|
||||||
|
<span>
|
||||||
|
<input type="number" id="metronome_bpm" min="10" max="500" value="120" maxlength="4">
|
||||||
|
<label for="metronome_bpm">BPM</label>
|
||||||
|
</span>
|
||||||
|
<button id="btn_metronome">Metronome</button>
|
||||||
|
<button id="btn_syllable">Syllable</button>
|
||||||
|
</div>
|
||||||
|
<!-- Line Timer -->
|
||||||
|
<div id="line_timer">
|
||||||
|
<h2>Line Timer</h2>
|
||||||
|
Tap the start of each line along with the video to record timing information.<br>
|
||||||
|
<button id="btn_start_of_line">Start of Line</button>
|
||||||
|
<button id="btn_p_video">Play/Pause Video</button>
|
||||||
|
</div>
|
||||||
<!-- Embedded video player for subtitle timing and preview -->
|
<!-- Embedded video player for subtitle timing and preview -->
|
||||||
<div id="embedded_video">
|
<div id="embedded_video">
|
||||||
<h2>Video</h2>
|
<h2>Video</h2>
|
||||||
You may select a local video file for subtitle timing and preview. It will not be uploaded anywhere.
|
You may select a local video file for subtitle timing and preview. It will not be uploaded anywhere.
|
||||||
<div id="message"></div>
|
<div id="video_message"></div>
|
||||||
<input type="file" accept="video/*"/>
|
<input id="video_selector_input" type="file" accept="video/*"/>
|
||||||
<video controls autoplay width="640"></video>
|
<video id="local_video" controls autoplay width="640"></video>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
Loading…
Reference in New Issue