feat: new mkv parsing backend

This commit is contained in:
ThaUnknown 2023-10-21 12:17:23 +02:00
parent 995c8a621a
commit 12a47c17e1
4 changed files with 81 additions and 109 deletions

View file

@ -1,6 +1,6 @@
{
"name": "Miru",
"version": "4.4.15",
"version": "4.4.16",
"author": "ThaUnknown_ <ThaUnknown@users.noreply.github.com>",
"description": "Stream anime torrents, real-time with no waiting for downloads.",
"main": "build/main.js",
@ -37,7 +37,7 @@
"html-webpack-plugin": "^5.5.3",
"jassub": "1.7.8",
"js-levenshtein": "^1.1.6",
"matroska-subtitles": "github:ThaUnknown/matroska-subtitles#446d0628ff0bcf13eb95184777615f3a0e6d8ae8",
"matroska-metadata": "^1.0.1",
"mini-css-extract-plugin": "^2.7.6",
"p2pt": "github:ThaUnknown/p2pt#modernise",
"perfect-seekbar": "^1.1.0",

View file

@ -79,9 +79,9 @@ devDependencies:
js-levenshtein:
specifier: ^1.1.6
version: 1.1.6
matroska-subtitles:
specifier: github:ThaUnknown/matroska-subtitles#446d0628ff0bcf13eb95184777615f3a0e6d8ae8
version: github.com/ThaUnknown/matroska-subtitles/446d0628ff0bcf13eb95184777615f3a0e6d8ae8
matroska-metadata:
specifier: ^1.0.1
version: 1.0.1
mini-css-extract-plugin:
specifier: ^2.7.6
version: 2.7.6(webpack@5.88.2)
@ -437,7 +437,7 @@ packages:
get-browser-rtc: 1.1.0
queue-microtask: 1.2.3
streamx: 2.15.1
uint8-util: 2.2.3
uint8-util: 2.2.4
transitivePeerDependencies:
- supports-color
dev: true
@ -448,7 +448,7 @@ packages:
debug: 4.3.4
queue-microtask: 1.2.3
streamx: 2.15.1
uint8-util: 2.2.3
uint8-util: 2.2.4
ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)
transitivePeerDependencies:
- bufferutil
@ -460,7 +460,7 @@ packages:
resolution: {integrity: sha512-bD6PvWbaf53JC04O7WnGDjqZBDgja/KT2Jd/6I2vJBIy+DLmQfQJZZ/G+16nAkVq1yGTIkO4rfc4RlH0DmEEqA==}
engines: {node: '>=0.2.6'}
dependencies:
uint8-util: 2.2.3
uint8-util: 2.2.4
dev: true
/@tootallnate/once@2.0.0:
@ -1225,7 +1225,7 @@ packages:
resolution: {integrity: sha512-AERXw18df0pF3ziGOCyUjqKZBVNH8HV3lBxnx5w0qtgMIk4a1wb9BkcCQbkp9Zstfrn/dzRwl7MmUHHocX3sRQ==}
engines: {node: '>=12.20.0'}
dependencies:
uint8-util: 2.2.3
uint8-util: 2.2.4
dev: true
/bep53-range@2.0.0:
@ -1294,7 +1294,7 @@ packages:
rc4: 0.1.5
streamx: 2.15.1
throughput: 1.0.1
uint8-util: 2.2.3
uint8-util: 2.2.4
unordered-array-remove: 1.0.2
transitivePeerDependencies:
- supports-color
@ -1324,7 +1324,7 @@ packages:
simple-get: 4.0.1
socks: 2.7.1
string2compact: 2.0.1
uint8-util: 2.2.3
uint8-util: 2.2.4
unordered-array-remove: 1.0.2
ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)
optionalDependencies:
@ -1857,7 +1857,7 @@ packages:
piece-length: 2.0.1
queue-microtask: 1.2.3
run-parallel: 1.2.0
uint8-util: 2.2.3
uint8-util: 2.2.4
dev: true
/cross-env@7.0.3:
@ -2183,9 +2183,10 @@ packages:
engines: {node: '>=10'}
dev: true
/ebml-stream@1.0.3:
resolution: {integrity: sha512-A+jCBY5NNAH/CQlcjLWN9txgv3uNiz+UAmMqDHPxFxoMNnuerV0RLhkE0YI9aNhdS3JVfcEQ9jFWq39fAR2W5g==}
engines: {node: '>= 10.10.0'}
/ebml-iterator@1.0.4:
resolution: {integrity: sha512-sTksd9ZKki/uWlbXPpvKg63AEEZpLYw+SrQjaY3L//inmtLSl20gowa9Umr0qpdtzPq6V6IkRjMgXg6JBFbZ0g==}
dependencies:
uint8-util: 2.2.4
dev: true
/ee-first@1.1.1:
@ -4029,7 +4030,7 @@ packages:
dependencies:
'@thaunknown/thirty-two': 1.0.3
bep53-range: 2.0.0
uint8-util: 2.2.3
uint8-util: 2.2.4
dev: true
/matcher@3.0.0:
@ -4040,6 +4041,15 @@ packages:
dev: true
optional: true
/matroska-metadata@1.0.1:
resolution: {integrity: sha512-McJiL+uX1ftPvJtpyifLs8BHAAGGnGfzXwIYoz8wymT3Ks1cC+q4OZstjtWRm8X5zZSBolLoABTVi6QtiDZ4HA==}
dependencies:
ebml-iterator: 1.0.4
fast-readable-async-iterator: 1.1.1
pako: 2.1.0
uint8-util: 2.2.4
dev: true
/mdn-data@2.0.30:
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
dev: true
@ -4481,7 +4491,7 @@ packages:
get-stdin: 9.0.0
magnet-uri: 7.0.5
queue-microtask: 1.2.3
uint8-util: 2.2.3
uint8-util: 2.2.4
dev: true
/parseurl@1.3.3:
@ -5635,7 +5645,7 @@ packages:
resolution: {integrity: sha512-j0tRX7qq22nIuVFF57Tg/wAvFq79F1eM9pcMxY+b0qCCe7yXJnIrqF+Q5YEJ94tNisDnJzcqDHNrPmD9X/yAIg==}
engines: {node: '>=12.20.0'}
dependencies:
uint8-util: 2.2.3
uint8-util: 2.2.4
dev: true
/tr46@0.0.3:
@ -5763,6 +5773,12 @@ packages:
base64-arraybuffer: 1.0.2
dev: true
/uint8-util@2.2.4:
resolution: {integrity: sha512-uEI5lLozmKQPYEevfEhP9LY3Je5ZmrQhaWXrzTVqrLNQl36xsRh8NiAxYwB9J+2BAt99TRbmCkROQB2ZKhx4UA==}
dependencies:
base64-arraybuffer: 1.0.2
dev: true
/unbox-primitive@1.0.2:
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
dependencies:
@ -5818,7 +5834,7 @@ packages:
bencode: 4.0.0
bitfield: 4.1.0
debug: 4.3.4
uint8-util: 2.2.3
uint8-util: 2.2.4
transitivePeerDependencies:
- supports-color
dev: true
@ -6296,22 +6312,13 @@ packages:
version: 2.0.5
dev: true
github.com/ThaUnknown/matroska-subtitles/446d0628ff0bcf13eb95184777615f3a0e6d8ae8:
resolution: {tarball: https://codeload.github.com/ThaUnknown/matroska-subtitles/tar.gz/446d0628ff0bcf13eb95184777615f3a0e6d8ae8}
name: matroska-subtitles
version: 3.3.3
dependencies:
ebml-stream: 1.0.3
pako: 2.1.0
dev: true
github.com/ThaUnknown/p2pt/3b191bd83998d0f28b022f4e3b871a7030ff6f6d:
resolution: {tarball: https://codeload.github.com/ThaUnknown/p2pt/tar.gz/3b191bd83998d0f28b022f4e3b871a7030ff6f6d}
name: p2pt
version: 1.5.1
dependencies:
bittorrent-tracker: 10.0.12
uint8-util: 2.2.3
uint8-util: 2.2.4
optionalDependencies:
wrtc: 0.4.7
transitivePeerDependencies:

View file

@ -1,105 +1,70 @@
import { pipeline } from 'streamx'
import { SubtitleParser, SubtitleStream } from 'matroska-subtitles'
import { fontRx } from '../common/util.js'
import Metadata from 'matroska-metadata'
export default class Parser {
parsed = false
/** @type {Metadata} */
metadata = null
client = null
file = null
parser = null
stream = null
destroyed = false
constructor (client, file) {
this.client = client
this.file = file
if (this.file.name.endsWith('.mkv')) {
// if (this.file.done) this.parseSubtitles()
// this.file.once('done', this.boundParse)
this.parseFonts(this.file)
this.file.on('stream', (_, cb) => {
if (!this.parsed) {
this.stream = new SubtitleStream(this.metadata || this.stream)
this.handleSubtitleParser(this.stream, true)
cb(this.stream)
this.metadata = new Metadata(file)
this.metadata.getTracks().then(tracks => {
console.log({ tracks })
if (this.destroyed) return
if (!tracks.length) {
this.parsed = true
this.destroy()
} else {
this.client.dispatch('tracks', tracks)
}
})
this.metadata.getChapters().then(chapters => {
console.log({ chapters })
if (this.destroyed) return
this.client.dispatch('chapters', chapters)
})
this.metadata.getAttachments().then(files => {
console.log({ files })
if (this.destroyed) return
for (const file of files) {
if (fontRx.test(file.filename) || file.mimetype.toLowerCase().includes('font')) {
const data = new Uint8Array(file.data)
this.client.dispatch('file', { data }, [data.buffer])
}
}
})
this.metadata.on('subtitle', (subtitle, trackNumber) => {
if (this.destroyed) return
this.client.dispatch('subtitle', { subtitle, trackNumber })
})
if (this.file.name.endsWith('.mkv') || this.file.name.endsWith('.webm')) {
this.file.on('iterator', ({ iterator }, cb) => {
if (this.destroyed) cb(iterator)
cb(this.metadata.parseStream(iterator))
})
}
}
parseSubtitles () {
if (this.file.name.endsWith('.mkv')) {
const parser = new SubtitleParser()
this.handleSubtitleParser(parser, true)
const finish = () => {
console.log('Sub parsing finished')
this.parsed = true
this.parser?.destroy()
this.parser = undefined
fileStream?.destroy()
}
parser.once('tracks', tracks => {
if (!tracks.length) finish()
})
parser.once('finish', finish)
async parseSubtitles () {
if (this.file.name.endsWith('.mkv') || this.file.name.endsWith('.webm')) {
console.log('Sub parsing started')
const fileStream = this.file.createReadStream()
this.parser = fileStream.pipe(parser)
await this.metadata.parseFile()
console.log('Sub parsing finished')
}
}
destroy () {
this.destroyed = true
this.parser?.destroy()
this.stream?.destroy()
this.metadata?.destroy()
this.metadata = undefined
this.parser = undefined
this.stream = undefined
}
parseFonts (file) {
const metadata = pipeline(file.createReadStream(), new SubtitleParser())
this.handleSubtitleParser(metadata)
metadata.once('tracks', tracks => {
if (!tracks.length) {
this.parsed = true
metadata.destroy()
}
})
metadata.once('subtitle', () => {
metadata.destroy()
if (this.destroyed) return
this.metadata = metadata
})
}
handleSubtitleParser (parser, skipFile) {
parser.once('tracks', tracks => {
if (!tracks.length) {
this.parsed = true
parser?.destroy()
} else {
if (this.destroyed) return
this.client.dispatch('tracks', tracks)
}
})
parser.on('subtitle', (subtitle, trackNumber) => {
if (this.destroyed) return
this.client.dispatch('subtitle', { subtitle, trackNumber })
})
if (!skipFile) {
parser.once('chapters', chapters => {
if (this.destroyed) return
this.client.dispatch('chapters', chapters)
})
parser.on('file', file => {
if (this.destroyed) return
if (fontRx.test(file.filename) || file.mimetype.toLowerCase().includes('font')) {
const data = new Uint8Array(file.data)
this.client.dispatch('file', { data }, [data.buffer])
}
})
}
}
}

View file

@ -14,7 +14,7 @@ let webtorrentWindow
function createWindow () {
// Create the browser window.
webtorrentWindow = new BrowserWindow({
show: false,
show: development,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,