mirror of
https://github.com/ThaUnknown/miru.git
synced 2026-04-19 01:02:05 +00:00
fix: improve subtitle parsing state handling
This commit is contained in:
parent
fb81cb9367
commit
800eba7a48
3 changed files with 109 additions and 90 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "Miru",
|
||||
"version": "4.3.5",
|
||||
"version": "4.3.6",
|
||||
"author": "ThaUnknown_ <ThaUnknown@users.noreply.github.com>",
|
||||
"description": "Stream anime torrents, real-time with no waiting for downloads.",
|
||||
"main": "build/main.js",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import WebTorrent from 'webtorrent'
|
||||
import { SubtitleParser, SubtitleStream } from 'matroska-subtitles'
|
||||
import { ipcRenderer } from 'electron'
|
||||
import { pipeline } from 'streamx'
|
||||
import HTTPTracker from 'bittorrent-tracker/lib/client/http-tracker.js'
|
||||
import { hex2bin, arr2hex, text2arr } from 'uint8-util'
|
||||
import Parser from './parser.js'
|
||||
|
||||
class TorrentClient extends WebTorrent {
|
||||
constructor (settings) {
|
||||
|
|
@ -19,7 +18,6 @@ class TorrentClient extends WebTorrent {
|
|||
|
||||
this.current = null
|
||||
this.parsed = false
|
||||
this.boundParse = this.parseSubtitles.bind(this)
|
||||
|
||||
setInterval(() => {
|
||||
this.dispatch('stats', {
|
||||
|
|
@ -84,25 +82,12 @@ class TorrentClient extends WebTorrent {
|
|||
if (data.data) {
|
||||
const found = (await this.get(data.data.infoHash))?.files.find(file => file.path === data.data.path)
|
||||
if (this.current) {
|
||||
this.current.removeListener('done', this.boundParse)
|
||||
this.current.removeAllListeners('stream')
|
||||
}
|
||||
this.cancelParse()
|
||||
this.parsed = false
|
||||
this.parser?.destroy()
|
||||
this.current = found
|
||||
if (this.current?.name.endsWith('.mkv')) {
|
||||
// if (this.current.done) this.parseSubtitles()
|
||||
// this.current.once('done', this.boundParse)
|
||||
this.parseFonts(this.current)
|
||||
this.current.on('stream', (_, cb) => {
|
||||
if (!this.parsed) {
|
||||
this.stream = new SubtitleStream(this.stream)
|
||||
this.handleSubtitleParser(this.stream, true)
|
||||
cb(this.stream)
|
||||
}
|
||||
})
|
||||
}
|
||||
// TODO: findSubtitleFiles(current)
|
||||
this.parser = new Parser(this, found)
|
||||
// TODO: parser.findSubtitleFiles(found)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
|
@ -138,79 +123,9 @@ class TorrentClient extends WebTorrent {
|
|||
message({ type, data }, transfer)
|
||||
}
|
||||
|
||||
parseSubtitles () {
|
||||
if (this.current.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)
|
||||
console.log('Sub parsing started')
|
||||
const fileStream = this.current.createReadStream()
|
||||
this.parser = fileStream.pipe(parser)
|
||||
}
|
||||
}
|
||||
|
||||
cancelParse () {
|
||||
this.parser?.destroy()
|
||||
this.stream?.destroy()
|
||||
this.metadata?.destroy()
|
||||
this.metadata = undefined
|
||||
this.parser = undefined
|
||||
this.stream = undefined
|
||||
}
|
||||
|
||||
parseFonts (file) {
|
||||
this.metadata = pipeline(file.createReadStream(), new SubtitleParser())
|
||||
this.handleSubtitleParser(this.metadata)
|
||||
this.metadata.once('tracks', tracks => {
|
||||
if (!tracks.length) {
|
||||
this.parsed = true
|
||||
this.metadata.destroy()
|
||||
}
|
||||
})
|
||||
this.metadata.once('subtitle', () => {
|
||||
this.metadata.destroy()
|
||||
})
|
||||
}
|
||||
|
||||
handleSubtitleParser (parser, skipFile) {
|
||||
parser.once('tracks', tracks => {
|
||||
if (!tracks.length) {
|
||||
this.parsed = true
|
||||
parser?.destroy()
|
||||
} else {
|
||||
this.dispatch('tracks', tracks)
|
||||
}
|
||||
})
|
||||
parser.on('subtitle', (subtitle, trackNumber) => {
|
||||
this.dispatch('subtitle', { subtitle, trackNumber })
|
||||
})
|
||||
if (!skipFile) {
|
||||
parser.once('chapters', chapters => {
|
||||
this.dispatch('chapters', chapters)
|
||||
})
|
||||
parser.on('file', file => {
|
||||
if (file.mimetype === 'application/x-truetype-font' || file.mimetype === 'application/font-woff' || file.mimetype === 'application/vnd.ms-opentype' || file.mimetype === 'font/sfnt' || file.mimetype.startsWith('font/') || file.filename.toLowerCase().endsWith('.ttf')) {
|
||||
const data = Buffer.from(file.data)
|
||||
this.dispatch('file', { mimetype: file.mimetype, data }, [data.buffer])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
predestroy () {
|
||||
this.destroy()
|
||||
this.server.close()
|
||||
this.cancelParse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
104
src/background/parser.js
Normal file
104
src/background/parser.js
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
import { pipeline } from 'streamx'
|
||||
import { SubtitleParser, SubtitleStream } from 'matroska-subtitles'
|
||||
|
||||
export default class Parser {
|
||||
parsed = false
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
console.log('Sub parsing started')
|
||||
const fileStream = this.file.createReadStream()
|
||||
this.parser = fileStream.pipe(parser)
|
||||
}
|
||||
}
|
||||
|
||||
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 (file.mimetype.toLowerCase().includes('font') || file.filename.toLowerCase().endsWith('.ttf')) {
|
||||
const data = Buffer.from(file.data)
|
||||
this.client.dispatch('file', { mimetype: file.mimetype, data }, [data.buffer])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue