mirror of
https://github.com/NoCrypt/migu.git
synced 2026-03-20 17:47:31 +00:00
fix: memory leaks
This commit is contained in:
parent
68c05a71f9
commit
5e5aa7b6ab
4 changed files with 393 additions and 329 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "Miru",
|
||||
"version": "4.0.8",
|
||||
"version": "4.0.9",
|
||||
"author": "ThaUnknown_ <ThaUnknown@users.noreply.github.com>",
|
||||
"description": "Stream anime torrents, real-time with no waiting for downloads.",
|
||||
"main": "build/main.js",
|
||||
|
|
@ -43,7 +43,7 @@
|
|||
"webpack": "^5.85.0",
|
||||
"webpack-cli": "^5.1.3",
|
||||
"webpack-dev-server": "^4.15.0",
|
||||
"webtorrent": "^2.0.37"
|
||||
"webtorrent": "^2.1.0"
|
||||
},
|
||||
"standard": {
|
||||
"ignore": [
|
||||
|
|
|
|||
595
pnpm-lock.yaml
595
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -51,13 +51,19 @@ class TorrentClient extends WebTorrent {
|
|||
async handleMessage ({ data }) {
|
||||
switch (data.type) {
|
||||
case 'current': {
|
||||
this.current?.removeListener('done', this.boundParse)
|
||||
this.cancelParse()
|
||||
this.current = null
|
||||
this.metadata = null
|
||||
this.parsed = false
|
||||
if (data.data) {
|
||||
this.current = (await this.get(data.data.infoHash))?.files.find(file => file.path === data.data.path)
|
||||
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('iterator')
|
||||
// this is a patch, idfk why these leak
|
||||
for (const iterator of this.current._iterators) {
|
||||
iterator.destroy()
|
||||
}
|
||||
}
|
||||
this.cancelParse()
|
||||
this.parsed = false
|
||||
this.current = found
|
||||
if (this.current?.name.endsWith('.mkv')) {
|
||||
// if (this.current.done) this.parseSubtitles()
|
||||
// this.current.once('done', this.boundParse)
|
||||
|
|
@ -125,22 +131,23 @@ class TorrentClient extends WebTorrent {
|
|||
|
||||
cancelParse () {
|
||||
this.parser?.destroy()
|
||||
this.metadata?.destroy()
|
||||
this.metadata = undefined
|
||||
this.parser = undefined
|
||||
}
|
||||
|
||||
parseFonts (file) {
|
||||
const stream = new SubtitleParser(file)
|
||||
this.handleSubtitleParser(stream)
|
||||
stream.once('tracks', tracks => {
|
||||
this.metadata = new SubtitleParser(file)
|
||||
this.handleSubtitleParser(this.metadata)
|
||||
this.metadata.once('tracks', tracks => {
|
||||
if (!tracks.length) {
|
||||
this.parsed = true
|
||||
stream.destroy()
|
||||
this.metadata.destroy()
|
||||
}
|
||||
})
|
||||
stream.once('subtitle', () => {
|
||||
stream.destroy()
|
||||
this.metadata.once('subtitle', () => {
|
||||
this.metadata.destroy()
|
||||
})
|
||||
this.metadata = stream
|
||||
}
|
||||
|
||||
handleSubtitleParser (parser, skipFile) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { EbmlIteratorDecoder, EbmlTagId } from 'ebml-iterator'
|
||||
import { EventEmitter } from 'events'
|
||||
import join from 'join-async-iterator'
|
||||
import { inflate } from 'pako'
|
||||
|
||||
const SSA_TYPES = new Set(['ssa', 'ass'])
|
||||
|
|
@ -53,10 +52,7 @@ export class SubtitleParserBase extends EventEmitter {
|
|||
[EbmlTagId.BlockGroup]: this.handleBlockGroup.bind(this),
|
||||
[EbmlTagId.Chapters]: this.handleChapters.bind(this)
|
||||
}
|
||||
}
|
||||
|
||||
async * [Symbol.asyncIterator] (stream) {
|
||||
const decoder = new EbmlIteratorDecoder({
|
||||
this.decoder = new EbmlIteratorDecoder({
|
||||
bufferTagIds: [
|
||||
EbmlTagId.TimecodeScale,
|
||||
EbmlTagId.Tracks,
|
||||
|
|
@ -64,20 +60,17 @@ export class SubtitleParserBase extends EventEmitter {
|
|||
EbmlTagId.AttachedFile,
|
||||
EbmlTagId.Chapters,
|
||||
EbmlTagId.Duration
|
||||
],
|
||||
stream
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
for await (const chunk of stream) {
|
||||
if (this.destroyed) return null
|
||||
const tags = decoder.parseTags(chunk)
|
||||
for (const tag of tags) {
|
||||
this._tagMap[tag.id]?.(tag)
|
||||
if (tag.id === EbmlTagId.Tracks) {
|
||||
if (!tag.Children.some(({ id }) => id === EbmlTagId.TrackEntry)) return this.destroy()
|
||||
}
|
||||
decoderWrite (chunk) {
|
||||
const tags = this.decoder.parseTags(chunk)
|
||||
for (const tag of tags) {
|
||||
this._tagMap[tag.id]?.(tag)
|
||||
if (tag.id === EbmlTagId.Tracks) {
|
||||
if (!tag.Children.some(({ id }) => id === EbmlTagId.TrackEntry)) return this.destroy()
|
||||
}
|
||||
yield chunk
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -200,12 +193,16 @@ export class SubtitleParser extends SubtitleParserBase {
|
|||
super()
|
||||
|
||||
;(async () => {
|
||||
const iterator = stream[Symbol.asyncIterator]()
|
||||
try {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
for await (const _ of super[Symbol.asyncIterator](stream)) {
|
||||
if (this.destroyed) break
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
for await (const chunk of iterator) {
|
||||
if (this.destroyed) return iterator.return()
|
||||
this.decoderWrite(chunk)
|
||||
}
|
||||
} catch (e) {}
|
||||
} catch (e) {
|
||||
iterator.return()
|
||||
}
|
||||
this.emit('finish')
|
||||
})()
|
||||
}
|
||||
|
|
@ -227,35 +224,40 @@ export class SubtitleStream extends SubtitleParserBase {
|
|||
}
|
||||
}
|
||||
|
||||
async * [Symbol.asyncIterator] (stream = this._stream) {
|
||||
while (true) {
|
||||
if (this.destroyed) return
|
||||
if (this.unstable) {
|
||||
const iterator = stream[Symbol.asyncIterator]()
|
||||
const { value: chunk } = await iterator.next()
|
||||
if (!chunk) return
|
||||
// the ebml decoder expects to see a tag, so we won't use it until we find a cluster
|
||||
for (let i = 0; i < chunk.length - 12; i++) {
|
||||
// cluster id 0x1F43B675
|
||||
// https://matroska.org/technical/elements.html#LevelCluster
|
||||
if (chunk[i] === 0x1f && chunk[i + 1] === 0x43 && chunk[i + 2] === 0xb6 && chunk[i + 3] === 0x75) {
|
||||
// length of cluster size tag
|
||||
const len = 8 - Math.floor(Math.log2(chunk[i + 4]))
|
||||
// first tag in cluster is a valid EbmlTag
|
||||
if (EbmlTagId[chunk[i + 4 + len]]) {
|
||||
// okay this is probably a cluster
|
||||
this.unstable = false
|
||||
yield chunk.slice(0, i)
|
||||
yield * super[Symbol.asyncIterator](join([[chunk.slice(i)], iterator]))
|
||||
return
|
||||
destroy () {
|
||||
this.destroyed = true
|
||||
this.emit('finish')
|
||||
this._stream.return()
|
||||
}
|
||||
|
||||
async * [Symbol.asyncIterator] () {
|
||||
try {
|
||||
for await (const chunk of this._stream) {
|
||||
if (this.destroyed) return this._stream.return()
|
||||
if (this.unstable) {
|
||||
// the ebml decoder expects to see a tag, so we won't use it until we find a cluster
|
||||
for (let i = 0; i < chunk.length - 12; i++) {
|
||||
// cluster id 0x1F43B675
|
||||
// https://matroska.org/technical/elements.html#LevelCluster
|
||||
if (chunk[i] === 0x1f && chunk[i + 1] === 0x43 && chunk[i + 2] === 0xb6 && chunk[i + 3] === 0x75) {
|
||||
// length of cluster size tag
|
||||
const len = 8 - Math.floor(Math.log2(chunk[i + 4]))
|
||||
// first tag in cluster is a valid EbmlTag
|
||||
if (EbmlTagId[chunk[i + 4 + len]]) {
|
||||
// okay this is probably a cluster
|
||||
this.unstable = false
|
||||
this.decoderWrite(chunk.slice(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.decoderWrite(chunk)
|
||||
}
|
||||
yield chunk
|
||||
} else {
|
||||
yield * super[Symbol.asyncIterator](stream)
|
||||
return
|
||||
}
|
||||
} finally {
|
||||
this._stream.return()
|
||||
}
|
||||
this._stream.return()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue