From afffffbfe521464d5d9623663f4139a02cc2ff18 Mon Sep 17 00:00:00 2001 From: ThaUnknown Date: Tue, 2 Feb 2021 01:11:04 +0100 Subject: [PATCH] full offline video playback, VTT subtitle fixes, post-download improvements, minor fixes --- app/index.html | 10 +++------- app/js/animeHandler.js | 4 ++-- app/js/playerHandler.js | 2 +- app/js/subtitleOctopus.js | 13 +++++++++---- app/js/subtitles-octopus.js | 2 +- app/js/torrentHandler.js | 18 ++++++++++++------ 6 files changed, 28 insertions(+), 21 deletions(-) diff --git a/app/index.html b/app/index.html index bf94f63..ccaeb8a 100644 --- a/app/index.html +++ b/app/index.html @@ -665,12 +665,8 @@ - - + +
- + diff --git a/app/js/animeHandler.js b/app/js/animeHandler.js index bb1febf..1612e21 100644 --- a/app/js/animeHandler.js +++ b/app/js/animeHandler.js @@ -625,11 +625,11 @@ async function resolveFileMedia(opts) { tempMedia = opts.media.relations.edges.filter(edge => edge.relationType == "SEQUEL" && (edge.node.format == "TV" || "TV_SHORT"))[0].node increment = true } - if (tempMedia.episodes && epMax - (opts.offset + tempMedia.episodes) > (media.episodes || media.nextAiringEpisode.episode)) { + if (tempMedia?.episodes && epMax - (opts.offset + tempMedia.episodes) > (media.episodes || media.nextAiringEpisode.episode)) { // episode is still out of bounds let nextEdge = await alRequest({ method: "SearchIDSingle", id: tempMedia.id }) await resolveSeason({ media: nextEdge.data.Media, episode: opts.episode, offset: opts.offset + nextEdge.data.Media.episodes, increment: increment }) - } else if (tempMedia.episodes && epMax - (opts.offset + tempMedia.episodes) < (media.episodes || media.nextAiringEpisode.episode) && epMin - (opts.offset + tempMedia.episodes) > 0) { + } else if (tempMedia?.episodes && epMax - (opts.offset + tempMedia.episodes) < (media.episodes || media.nextAiringEpisode.episode) && epMin - (opts.offset + tempMedia.episodes) > 0) { // episode is in range, seems good! overwriting media to count up "seasons" if (opts.episode.constructor == Array) { episode = `${elems.episode_number[0] - (opts.offset + tempMedia.episodes)} - ${elems.episode_number[elems.episode_number.length - 1] - (opts.offset + tempMedia.episodes)}` diff --git a/app/js/playerHandler.js b/app/js/playerHandler.js index 4a472c3..9be9212 100644 --- a/app/js/playerHandler.js +++ b/app/js/playerHandler.js @@ -154,7 +154,7 @@ async function buildVideo(torrent, opts) { // sets video source and creates a bu if (playerData.nowPlaying[0].streamingEpisodes.length >= Number(playerData.nowPlaying[1])) { let streamingEpisode = playerData.nowPlaying[0].streamingEpisodes.filter(episode => episodeRx.exec(episode.title) && episodeRx.exec(episode.title)[1] == Number(playerData.nowPlaying[1]))[0] video.poster = streamingEpisode.thumbnail - document.title = `${playerData.nowPlaying[0].title.userPreferred} - ${Number(playerData.nowPlaying[1])} - EP ${episodeRx.exec(streamingEpisode.title)[2]} - Miru` + document.title = `${playerData.nowPlaying[0].title.userPreferred} - EP ${Number(playerData.nowPlaying[1])} - ${episodeRx.exec(streamingEpisode.title)[2]} - Miru` mediaMetadata.artist = `Episode ${Number(playerData.nowPlaying[1])} - ${episodeRx.exec(streamingEpisode.title)[2]}` mediaMetadata.artwork = [{ src: streamingEpisode.thumbnail, diff --git a/app/js/subtitleOctopus.js b/app/js/subtitleOctopus.js index a14b26b..c24b6ac 100644 --- a/app/js/subtitleOctopus.js +++ b/app/js/subtitleOctopus.js @@ -14,6 +14,8 @@ function subStream(stream) { // subtitle parsing with seeking support track.header = `[V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: Default,${Object.values(subtitle1list.options).filter(item => item.value == settings.subtitle1)[0].innerText} +[Events] + ` } playerData.headers[track.number] = track @@ -28,8 +30,7 @@ Style: Default,${Object.values(subtitle1list.options).filter(item => item.value let formatSub = "Dialogue: " + (subtitle.layer || 0) + "," + new Date(subtitle.time).toISOString().slice(12, -1).slice(0, -1) + "," + new Date(subtitle.time + subtitle.duration).toISOString().slice(12, -1).slice(0, -1) + "," + (subtitle.style || "Default") + "," + (subtitle.name || "") + "," + (subtitle.marginL || "0") + "," + (subtitle.marginR || "0") + "," + (subtitle.marginV || "0") + "," + (subtitle.effect || "") + "," + subtitle.text if (!playerData.subtitles[trackNumber].has(formatSub)) { playerData.subtitles[trackNumber].add(formatSub) - if (playerData.selectedHeader == trackNumber) - renderSubs.call(null, trackNumber) + if (playerData.selectedHeader == trackNumber) renderSubs(trackNumber) } } @@ -46,7 +47,7 @@ function renderSubs(trackNumber) { video: video, subContent: trackNumber ? playerData.headers[trackNumber].header.slice(0, -1) + Array.from(playerData.subtitles[trackNumber]).join("\n") : playerData.headers[3].header.slice(0, -1), lossyRender: true, - fonts: playerData.fonts.length == 0 ? ["https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fBBc4.woff2"] : playerData.fonts, + fonts: playerData.fonts?.length != 0 ? playerData.fonts : ["https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fBBc4.woff2"] , workerUrl: 'js/subtitles-octopus-worker.js', timeOffset: 0 }; @@ -84,6 +85,8 @@ function postDownload(file) { // parse subtitles fully after a download is finis track.header = `[V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: Default,${Object.values(subtitle1list.options).filter(item => item.value == settings.subtitle1)[0].innerText} +[Events] + ` } headers[track.number] = track @@ -99,8 +102,10 @@ Style: Default,${Object.values(subtitle1list.options).filter(item => item.value playerData.headers = headers playerData.parsed = 1 playerData.subtitleStream = undefined - renderSubs.call(null, playerData.selectedHeader) + renderSubs(playerData.selectedHeader) parser = undefined + video.pause(); + playVideo(); }); file.createReadStream().pipe(parser) } diff --git a/app/js/subtitles-octopus.js b/app/js/subtitles-octopus.js index 35b22f1..9069147 100644 --- a/app/js/subtitles-octopus.js +++ b/app/js/subtitles-octopus.js @@ -19,7 +19,7 @@ var SubtitlesOctopus = function (options) { self.dropAllAnimations = options.dropAllAnimations || false; self.libassMemoryLimit = options.libassMemoryLimit || 0; // set libass bitmap cache memory limit in MiB (approximate) self.libassGlyphLimit = options.libassGlyphLimit || 0; // set libass glyph cache memory limit in MiB (approximate) - self.targetFps = options.targetFps || 60; + self.targetFps = options.targetFps || 30; self.prescaleTradeoff = options.prescaleTradeoff || null; // render subtitles less than viewport when less than 1.0 to improve speed, render to more than 1.0 to improve quality; set to null to disable scaling self.softHeightLimit = options.softHeightLimit || 1080; // don't apply prescaleTradeoff < 1 when viewport height is less that this limit self.hardHeightLimit = options.hardHeightLimit || 2160; // don't ever go above this limit diff --git a/app/js/torrentHandler.js b/app/js/torrentHandler.js index 9d9a60d..f06575f 100644 --- a/app/js/torrentHandler.js +++ b/app/js/torrentHandler.js @@ -55,8 +55,8 @@ function t(a) { // offline storage initial load let offlineTorrents async function loadOfflineStorage() { - offlineTorrents = new Set([...await indexedDB.databases()].map(object => { return object.name })); - [...offlineTorrents].forEach(torrentID => offlineDownload(torrentID, true)) // adds all offline store torrents to the client + offlineTorrents = JSON.parse(localStorage.getItem("offlineTorrents")) || {}; + Object.values(offlineTorrents).forEach(torrentID => offlineDownload(new Blob([new Uint8Array(torrentID)]), true)) // adds all offline store torrents to the client } // add torrent for offline download @@ -66,12 +66,16 @@ function offlineDownload(torrentID, skipVerify) { skipVerify: skipVerify }) torrent.on("metadata", async () => { - offlineTorrents.add(torrent.infoHash) + console.log(torrent) + if (!offlineTorrents[torrent.infoHash]) { + offlineTorrents[torrent.infoHash] = Array.from(torrent.torrentFile); + localStorage.setItem("offlineTorrents", JSON.stringify(offlineTorrents)) + } let mediaInformation = await resolveFileMedia({ fileName: torrent.name, method: "SearchName" }) template = cardCreator(mediaInformation) template.onclick = async () => { addTorrent(torrent, { media: mediaInformation.media, episode: mediaInformation.parseObject.episode }) - store[mediaInformation.parseObject.anime_title] = await alRequest({ id: mediaInformation.media?.id, method: "SearchIDSingle" }).then(res => res.data.Media) + store[mediaInformation.parseObject.anime_title] = await alRequest({ id: mediaInformation.media?.id, method: "SearchIDSingle" }).then(res => res.data.Media) // force updates entry data on play in case its outdated, needs to be made cleaner and somewhere else... } document.querySelector(".downloads").appendChild(template) @@ -83,7 +87,7 @@ loadOfflineStorage() // cleanup torrent and store function cleanupTorrents() { client.torrents.filter(torrent => { - return !offlineTorrents.has(torrent.infoHash) || torrent.progress != 1 // creates an array of all non-offline store torrents and removes them + return !(offlineTorrents[torrent.infoHash] || torrent.progress == 1) // creates an array of all non-offline store torrents and removes them }).forEach(torrent => torrent.destroy({ destroyStore: true })) } @@ -122,7 +126,9 @@ function addTorrent(torrentID, opts) { document.location.hash = "#player" cleanupVideo() cleanupTorrents() - if (client.get(torrentID)) { + if (torrentID instanceof Object) { + playTorrent(torrentID, opts) + } else if (client.get(torrentID)) { playTorrent(client.get(torrentID), opts) } else { client.add(torrentID, settings.torrent5 ? { store: IdbChunkStore } : {}, function (torrent) {