improved ass resampler

This commit is contained in:
Daniel Haller 2024-04-24 05:25:39 +02:00
parent 17de9416d0
commit 76d8ab5f39
2 changed files with 75 additions and 48 deletions

View File

@ -404,7 +404,7 @@ export async function downloadCrunchyrollPlaylist(
const subDownload = async () => { const subDownload = async () => {
const sbs: Array<string> = [] const sbs: Array<string> = []
for (const sub of subDownloadList) { for (const sub of subDownloadList) {
const name = await downloadCRSub(sub, subFolder) const name = await downloadCRSub(sub, subFolder, quality)
sbs.push(name) sbs.push(name)
} }
return sbs return sbs

View File

@ -11,34 +11,59 @@ export async function downloadCRSub(
url: string url: string
isDub: boolean isDub: boolean
}, },
dir: string dir: string,
qual: 1080 | 720 | 480 | 360 | 240
) { ) {
const path = `${dir}/${sub.language}${sub.isDub ? `-FORCED` : ''}.${sub.format}` const path = `${dir}/${sub.language}${sub.isDub ? `-FORCED` : ''}.${sub.format}`
var qualX;
var qualY;
switch (qual) {
case 1080:
qualX = 1920
qualY = 1080
break;
case 720:
qualX = 1280
qualY = 720
break;
case 480:
qualX = 720
qualY = 480
break;
case 360:
qualX = 640
qualY = 360
break;
case 240:
qualX = 426
qualY = 240
break;
}
const stream = fs.createWriteStream(path) const stream = fs.createWriteStream(path)
const response = await fetch(sub.url) const response = await fetch(sub.url)
var resampledSubs = resamplePOSSubtitle(await response.text()) var parsedASS = parse(await response.text())
var parsedASS = parse(resampledSubs)
parsedASS.info['Original Script'] = 'crd [https://github.com/stratuma/]' parsedASS.info['Original Script'] = 'crd [https://github.com/stratuma/]'
parsedASS.info.PlayResX = "1920";
parsedASS.info.PlayResY = "1080";
for (const s of parsedASS.styles.style) { for (const s of parsedASS.styles.style) {
if (s.Fontname === 'Arial') { ;(s.Fontsize = String(Math.round((parseInt(s.Fontsize) / parseInt(parsedASS.info.PlayResY)) * qualY))),
(s.Fontsize = "54"), (s.Outline = "4"), (s.MarginV = "60"); (s.Outline = String(Math.round((parseInt(s.Outline) / parseInt(parsedASS.info.PlayResY)) * qualY))),
} (s.MarginL = String(Math.round((parseInt(s.MarginL) / parseInt(parsedASS.info.PlayResY)) * qualY))),
if (s.Name === 'TypePlaceholder') { (s.MarginR = String(Math.round((parseInt(s.MarginR) / parseInt(parsedASS.info.PlayResY)) * qualY))),
(s.Fontsize = "57"), (s.Outline = "4"), (s.MarginL = "30"), (s.MarginR = "30"), (s.MarginV = "60"); (s.MarginV = String(Math.round((parseInt(s.MarginV) / parseInt(parsedASS.info.PlayResY)) * qualY)))
}
} }
parsedASS.info.PlayResX = String(qualX)
parsedASS.info.PlayResY = String(qualY)
const fixed = stringify(parsedASS) const fixed = stringify(parsedASS)
const readableStream = Readable.from([fixed]) const resampledSubs = resamplePOSSubtitle(fixed,parseInt(parsedASS.info.PlayResX), parseInt(parsedASS.info.PlayResY), qualX, qualY)
const readableStream = Readable.from([resampledSubs])
await finished(readableStream.pipe(stream)) await finished(readableStream.pipe(stream))
console.log(`Sub ${sub.language}.${sub.format} downloaded`) console.log(`Sub ${sub.language}.${sub.format} downloaded`)
@ -46,30 +71,30 @@ export async function downloadCRSub(
return path return path
} }
function resamplePOSSubtitle(subtitle: string) { function resamplePOSSubtitle(subtitle: string, ox: number, oy: number, nx: number, ny: number) {
let lines = subtitle.split('\n'); let lines = subtitle.split('\n')
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
let line = lines[i]; let line = lines[i]
if (line.includes("\\pos(")) { if (line.includes('\\pos(')) {
let posMatch = line.match(/\\pos\((\d+),(\d+)\)/); let posMatch = line.match(/\\pos\((\d+),(\d+)\)/)
if (posMatch) { if (posMatch) {
let oldX = parseInt(posMatch[1]); let oldX = parseInt(posMatch[1])
let oldY = parseInt(posMatch[2]); let oldY = parseInt(posMatch[2])
let newX = Math.round((oldX / 640) * 1920); let newX = Math.round((oldX / ox) * nx)
let newY = Math.round((oldY / 360) * 1080); let newY = Math.round((oldY / oy) * ny)
let newPos = `\\pos(${newX},${newY})`; let newPos = `\\pos(${newX},${newY})`
line = line.replace(/\\pos\(\d+,\d+\)/, newPos); line = line.replace(/\\pos\(\d+,\d+\)/, newPos)
lines[i] = line; lines[i] = line
}
} }
}
} }
return lines.join('\n'); return lines.join('\n')
} }
export async function downloadADNSub(link: string, dir: string, secret: string) { export async function downloadADNSub(link: string, dir: string, secret: string) {
@ -118,14 +143,14 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\
positionAligh: string positionAligh: string
lineAlign: string lineAlign: string
text: string text: string
}>, }>
vostde: Array<{ vostde: Array<{
startTime: number startTime: number
endTime: number endTime: number
positionAligh: string positionAligh: string
lineAlign: string lineAlign: string
text: string text: string
}>, }>
} = await JSON.parse(subs) } = await JSON.parse(subs)
if (parsedSubs.vde) { if (parsedSubs.vde) {
@ -133,7 +158,8 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\
const convertedStart = convertToTimeFormat(s.startTime) const convertedStart = convertToTimeFormat(s.startTime)
const convertedEnd = convertToTimeFormat(s.endTime) const convertedEnd = convertToTimeFormat(s.endTime)
templateASS = templateASS + `Dialogue: 0,${convertedStart},${convertedEnd},Default,,0,0,0,,${s.text.replace('\n', '\\N').replace('<i>', '{\\i1}').replace('</i>', '{\\i0}')}\n` templateASS =
templateASS + `Dialogue: 0,${convertedStart},${convertedEnd},Default,,0,0,0,,${s.text.replace('\n', '\\N').replace('<i>', '{\\i1}').replace('</i>', '{\\i0}')}\n`
} }
} }
@ -142,7 +168,8 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\
const convertedStart = convertToTimeFormat(s.startTime) const convertedStart = convertToTimeFormat(s.startTime)
const convertedEnd = convertToTimeFormat(s.endTime) const convertedEnd = convertToTimeFormat(s.endTime)
templateASS = templateASS + `Dialogue: 0,${convertedStart},${convertedEnd},Default,,0,0,0,,${s.text.replace('\n', '\\N').replace('<i>', '{\\i1}').replace('</i>', '{\\i0}')}\n` templateASS =
templateASS + `Dialogue: 0,${convertedStart},${convertedEnd},Default,,0,0,0,,${s.text.replace('\n', '\\N').replace('<i>', '{\\i1}').replace('</i>', '{\\i0}')}\n`
} }
} }
@ -166,23 +193,23 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\
} }
function convertToTimeFormat(time: number) { function convertToTimeFormat(time: number) {
var seconds: number | string = Math.floor(time); var seconds: number | string = Math.floor(time)
var milliseconds = Math.round((time - seconds) * 1000); var milliseconds = Math.round((time - seconds) * 1000)
var hours: number | string = Math.floor(seconds / 3600); var hours: number | string = Math.floor(seconds / 3600)
var minutes: number | string = Math.floor((seconds % 3600) / 60); var minutes: number | string = Math.floor((seconds % 3600) / 60)
seconds = seconds % 60; seconds = seconds % 60
hours = String(hours).padStart(2, '0'); hours = String(hours).padStart(2, '0')
minutes = String(minutes).padStart(2, '0'); minutes = String(minutes).padStart(2, '0')
seconds = String(seconds).padStart(2, '0'); seconds = String(seconds).padStart(2, '0')
milliseconds = Math.round(milliseconds / 10); milliseconds = Math.round(milliseconds / 10)
var formattedMilliseconds = milliseconds < 10 ? '0' + milliseconds : milliseconds; var formattedMilliseconds = milliseconds < 10 ? '0' + milliseconds : milliseconds
var formattedTime = hours + ':' + minutes + ':' + seconds + '.' + formattedMilliseconds; var formattedTime = hours + ':' + minutes + ':' + seconds + '.' + formattedMilliseconds
return formattedTime; return formattedTime
} }
export async function ADNparseSub(raw: string, secret: string) { export async function ADNparseSub(raw: string, secret: string) {