mirror of
https://github.com/ThaUnknown/miru.git
synced 2026-05-17 02:51:45 +00:00
204 lines
5.9 KiB
JavaScript
204 lines
5.9 KiB
JavaScript
const { app, ipcMain } = require('electron')
|
|
const WebTorrent = require('webtorrent')
|
|
const http = require('http')
|
|
const pump = require('pump')
|
|
const rangeParser = require('range-parser')
|
|
const mime = require('mime')
|
|
const { SubtitleParser, SubtitleStream } = require('matroska-subtitles')
|
|
|
|
let window = null
|
|
app.on('browser-window-created', (event, data) => {
|
|
window = data
|
|
window.on('closed', () => {
|
|
window = null
|
|
})
|
|
})
|
|
|
|
let client = null
|
|
|
|
let settings = {}
|
|
|
|
const server = http.createServer((request, response) => {
|
|
if (!request.url) return null
|
|
let [infoHash, ...filePath] = request.url.slice(request.url.indexOf('/webtorrent/') + 12).split('/')
|
|
filePath = decodeURI(filePath.join('/'))
|
|
if (!infoHash || !filePath) return null
|
|
|
|
const file = client?.get(infoHash)?.files.find(file => file.path === filePath)
|
|
if (!file) return null
|
|
|
|
response.setHeader('Access-Control-Allow-Origin', '*')
|
|
response.setHeader('Content-Type', mime.getType(file.name) || 'application/octet-stream')
|
|
|
|
response.setHeader('Accept-Ranges', 'bytes')
|
|
|
|
let range = rangeParser(file.length, request.headers.range || '')
|
|
|
|
if (Array.isArray(range)) {
|
|
response.statusCode = 206
|
|
range = range[0]
|
|
|
|
response.setHeader(
|
|
'Content-Range',
|
|
`bytes ${range.start}-${range.end}/${file.length}`
|
|
)
|
|
response.setHeader('Content-Length', range.end - range.start + 1)
|
|
} else {
|
|
response.statusCode = 200
|
|
range = null
|
|
response.setHeader('Content-Length', file.length)
|
|
}
|
|
|
|
if (response.method === 'HEAD') {
|
|
return response.end()
|
|
}
|
|
|
|
let stream = file.createReadStream(range)
|
|
|
|
if (stream && !parsed) {
|
|
if (file.name.endsWith('.mkv')) {
|
|
parserInstance = new SubtitleStream(parserInstance)
|
|
handleSubtitleParser(parserInstance, true)
|
|
stream = pump(stream, parserInstance)
|
|
}
|
|
}
|
|
|
|
pump(stream, response)
|
|
})
|
|
|
|
server.on('error', console.log)
|
|
|
|
server.listen(41785)
|
|
|
|
let current = null
|
|
let parsed = false
|
|
let parserInstance = null
|
|
|
|
function parseSubtitles () {
|
|
if (current.name.endsWith('.mkv')) {
|
|
const parser = new SubtitleParser()
|
|
handleSubtitleParser(parser, true)
|
|
const finish = () => {
|
|
console.log('Sub parsing finished')
|
|
parsed = true
|
|
fileStream?.destroy()
|
|
stream?.destroy()
|
|
stream = undefined
|
|
}
|
|
parser.once('tracks', tracks => {
|
|
if (!tracks.length) finish()
|
|
})
|
|
parser.once('finish', finish)
|
|
console.log('Sub parsing started')
|
|
const fileStream = current.createReadStream()
|
|
let stream = fileStream.pipe(parser)
|
|
}
|
|
}
|
|
|
|
function parseFonts (file) {
|
|
const stream = new SubtitleParser()
|
|
handleSubtitleParser(stream)
|
|
stream.once('tracks', tracks => {
|
|
if (!tracks.length) {
|
|
parsed = true
|
|
stream.destroy()
|
|
fileStreamStream.destroy()
|
|
}
|
|
})
|
|
stream.once('subtitle', () => {
|
|
fileStreamStream.destroy()
|
|
stream.destroy()
|
|
window?.webContents.send('fonts')
|
|
})
|
|
const fileStreamStream = file.createReadStream()
|
|
fileStreamStream.pipe(stream)
|
|
}
|
|
|
|
function handleSubtitleParser (parser, skipFile) {
|
|
parser.once('tracks', tracks => {
|
|
if (!tracks.length) {
|
|
parsed = true
|
|
parser?.destroy()
|
|
} else {
|
|
window?.webContents.send('tracks', tracks)
|
|
}
|
|
})
|
|
parser.on('subtitle', (subtitle, trackNumber) => {
|
|
window?.webContents.send('subtitle', { subtitle, trackNumber })
|
|
})
|
|
if (!skipFile) {
|
|
parser.on('file', file => {
|
|
if (file.mimetype === 'application/x-truetype-font' || file.mimetype === 'application/font-woff' || file.mimetype === 'application/vnd.ms-opentype') {
|
|
window?.webContents.send('file', { mimetype: file.mimetype, data: Array.from(file.data) })
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
ipcMain.on('current', (event, data) => {
|
|
current?.removeListener('done', parseSubtitles)
|
|
parserInstance?.destroy()
|
|
parserInstance = null
|
|
current = null
|
|
parsed = false
|
|
if (data) {
|
|
current = client?.get(data.infoHash)?.files.find(file => file.path === data.path)
|
|
if (current.name.endsWith('.mkv')) {
|
|
if (current.done) parseSubtitles()
|
|
current.on('done', parseSubtitles)
|
|
parseFonts(current)
|
|
}
|
|
// findSubtitleFiles(current) TODO:
|
|
}
|
|
})
|
|
|
|
ipcMain.on('settings', (event, data) => {
|
|
if (!client) {
|
|
settings = data
|
|
client = new WebTorrent({
|
|
dht: !settings.torrentDHT,
|
|
downloadLimit: settings.torrentSpeed * 1048576 || 0,
|
|
uploadLimit: settings.torrentSpeed * 1572864 || 0 // :trolled:
|
|
})
|
|
setInterval(() => {
|
|
window?.webContents?.send('stats', {
|
|
numPeers: (client?.torrents.length && client?.torrents[0].numPeers) || 0,
|
|
uploadSpeed: (client?.torrents.length && client?.torrents[0].uploadSpeed) || 0,
|
|
downloadSpeed: (client?.torrents.length && client?.torrents[0].downloadSpeed) || 0
|
|
})
|
|
}, 200)
|
|
setInterval(() => {
|
|
if (client?.torrents[0]?.pieces) window?.webContents?.send('pieces', [...client?.torrents[0]?.pieces.map(piece => piece === null ? 77 : 33)])
|
|
}, 2000)
|
|
client.on('torrent', torrent => {
|
|
const files = torrent.files.map(file => {
|
|
return {
|
|
infoHash: torrent.infoHash,
|
|
name: file.name,
|
|
type: file._getMimeType(),
|
|
size: file.size,
|
|
path: file.path,
|
|
url: encodeURI('http://localhost:41785/webtorrent/' + torrent.infoHash + '/' + file.path)
|
|
}
|
|
})
|
|
window?.webContents.send('files', files)
|
|
window?.webContents.send('pieces', torrent.pieces.length)
|
|
window?.webContents.send('torrent', Array.from(torrent.torrentFile))
|
|
})
|
|
}
|
|
})
|
|
|
|
ipcMain.on('torrent', (event, data) => {
|
|
if (client.torrents.length) client.remove(client.torrents[0].infoHash)
|
|
if (typeof data !== 'string') data = Buffer.from(data)
|
|
client.add(data, {
|
|
private: settings.torrentPeX,
|
|
path: settings.torrentPath,
|
|
destroyStoreOnDestroy: !settings.torrentPersist,
|
|
announce: [
|
|
'wss://tracker.openwebtorrent.com',
|
|
'wss://spacetradersapi-chatbox.herokuapp.com:443/announce',
|
|
'wss://peertube.cpy.re:443/tracker/socket'
|
|
]
|
|
})
|
|
})
|