Lastest releases doesnt re-build if the feed hasnt changed, subtitle renderer now uses embedded fonts, only create missing thumbnails, hardsubbed PiP, minor fixes

This commit is contained in:
ThaUnknown 2020-10-26 20:22:14 +01:00
parent 5d644589ad
commit 8d9edc8c99
7 changed files with 134 additions and 51 deletions

View file

@ -58,6 +58,9 @@
#player:target .player { #player:target .player {
display: flex !important display: flex !important
} }
#player.pip{
background: #000
}
.controls { .controls {
background: linear-gradient(to top, rgba(0, 0, 0, .8), rgba(0, 0, 0, .4) 25%, rgba(0, 0, 0, .2) 50%, rgba(0, 0, 0, .1) 75%, transparent); background: linear-gradient(to top, rgba(0, 0, 0, .8), rgba(0, 0, 0, .4) 25%, rgba(0, 0, 0, .2) 50%, rgba(0, 0, 0, .1) 75%, transparent);
@ -212,8 +215,10 @@
#player:fullscreen #btheatre, #player:fullscreen #btheatre,
#player:target>a, #player:target>a,
#progress+img[src=" "], #progress+img[src=" "],
video[src=""] { video[src=""],
display: none #player.pip video,
#player.pip canvas {
display: none !important
} }
video::cue { video::cue {

View file

@ -304,11 +304,17 @@
<option value="Roboto,Arial,Helvetica,sans-serif">Roboto</option> <option value="Roboto,Arial,Helvetica,sans-serif">Roboto</option>
</select> </select>
</div> </div>
<div class="custom-switch mb-20"> <div class="custom-switch mb-10">
<input type="checkbox" id="subtitle2"> <input type="checkbox" id="subtitle2">
<label for="subtitle2">Async Rendering [Might cause desync on low end devices but greatly <label for="subtitle2">Async Rendering [Might cause desync on low end devices but greatly
improves performance]</label> improves performance]</label>
</div> </div>
<div class="custom-switch mb-20">
<input type="checkbox" id="subtitle3">
<label for="subtitle3">Video Canvas Merging [Displays subtitles in PiP and ChromeCast, requires
<a href="chrome://flags/#disable-accelerated-2d-canvas"
target="_blank">chrome://flags/#disable-accelerated-2d-canvas</a> set to Disabled]</label>
</div>
<h1 class="content-title font-size-22"> <h1 class="content-title font-size-22">
@ -360,7 +366,7 @@
<script src="https://cdn.jsdelivr.net/npm/webtorrent@latest/webtorrent.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/webtorrent@latest/webtorrent.min.js"></script>
<script src="js/rangeParser.js"></script> <script src="js/rangeParser.js"></script>
<script src="js/torrentHandler.js"></script> <script src="js/torrentHandler.js"></script>
<script src="https://cdn.jsdelivr.net/npm/matroska-subtitles@3.1.0/dist/matroska-subtitles.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/matroska-subtitles@3.2.0/dist/matroska-subtitles.min.js"></script>
<script src="js/subtitles-octopus.js"></script> <script src="js/subtitles-octopus.js"></script>
<script src="js/subtitleOctopus.js"></script> <script src="js/subtitleOctopus.js"></script>
</body> </body>

View file

@ -319,41 +319,45 @@ async function nyaaRss(url) {
const regex = /((?:\[[^\]]*\])*)?\s*((?:[^\d\[\.](?!S\d))*)?\s*((?:S\d+[^\w\[]*E?)?[\d\-]*)\s*(.*)?/i, const regex = /((?:\[[^\]]*\])*)?\s*((?:[^\d\[\.](?!S\d))*)?\s*((?:S\d+[^\w\[]*E?)?[\d\-]*)\s*(.*)?/i,
eregex = /(\[.*\]\ ?)?(.+?(?=\ \\ \d))?(\ \\ )?(\d+)?/i, eregex = /(\[.*\]\ ?)?(.+?(?=\ \\ \d))?(\ \\ )?(\d+)?/i,
plsregex = /(\[.[^\]]*\]\ ?)?(.+?(?=\ \-\ \d))?(\ \-\ )?(\d+)?(.*)?/i plsregex = /(\[.[^\]]*\]\ ?)?(.+?(?=\ \-\ \d))?(\ \-\ )?(\d+)?(.*)?/i
let store = {}; let store = {},
lastResult
async function hsRss() { async function hsRss() {
if (document.location.href.endsWith("#releases")) { if (document.location.href.endsWith("#releases")) {
let frag = document.createDocumentFragment(), let frag = document.createDocumentFragment(),
releases = document.querySelector(".releases"), releases = document.querySelector(".releases"),
url = settings.torrent4 == "https://miru.kirdow.com/request/?url=https://www.erai-raws.info/rss-" ? settings.torrent4 + settings.torrent1 + "-magnet" : settings.torrent4 + settings.torrent1 url = settings.torrent4 == "https://miru.kirdow.com/request/?url=https://www.erai-raws.info/rss-" ? settings.torrent4 + settings.torrent1 + "-magnet" : settings.torrent4 + settings.torrent1
releases.textContent = '';
releases.appendChild(skeletonCard)
res = await fetch(url) res = await fetch(url)
await res.text().then(async (xmlTxt) => { await res.text().then(async (xmlTxt) => {
try { try {
let doc = DOMPARSER(xmlTxt, "text/xml") let doc = DOMPARSER(xmlTxt, "text/xml")
let items = doc.querySelectorAll("item") if (lastResult != doc) {
for (let item of items) { releases.textContent = '';
let i = item.querySelector.bind(item), releases.appendChild(skeletonCard)
regexParse = plsregex.exec(i("title").textContent) lastResult = doc
if (!store.hasOwnProperty(regexParse[2]) && !alResponse.data.Page.media.some(media => (Object.values(media.title).concat(media.synonyms).filter(name => name != null).includes(regexParse[2]) && ((store[regexParse[2]] = media) && true)))) { let items = doc.querySelectorAll("item")
//shit not found, lookup for (let item of items) {
let res = await alRequest(regexParse[2], 1) let i = item.querySelector.bind(item),
if (!res.data.Page.media[0]) { regexParse = plsregex.exec(i("title").textContent)
res = await alRequest(regexParse[2].replace(" (TV)", "").replace(` (${new Date().getFullYear()})`, ""), 1) if (!store.hasOwnProperty(regexParse[2]) && !alResponse.data.Page.media.some(media => (Object.values(media.title).concat(media.synonyms).filter(name => name != null).includes(regexParse[2]) && ((store[regexParse[2]] = media) && true)))) {
//shit not found, lookup
let res = await alRequest(regexParse[2], 1)
if (!res.data.Page.media[0]) {
res = await alRequest(regexParse[2].replace(" (TV)", "").replace(` (${new Date().getFullYear()})`, ""), 1)
}
store[regexParse[2]] = res.data.Page.media[0]
} }
store[regexParse[2]] = res.data.Page.media[0] let media = store[regexParse[2]],
template = cardCreator(media, regexParse)
template.onclick = () => {
playerData.selected = [regexParse[2], regexParse[4]]
addTorrent(i('link').textContent)
}
frag.appendChild(template)
} }
let media = store[regexParse[2]], releases.textContent = '';
template = cardCreator(media, regexParse) releases.appendChild(frag)
template.onclick = () => {
playerData.selected = [regexParse[2], regexParse[4]]
addTorrent(i('link').textContent)
}
frag.appendChild(template)
} }
releases.textContent = '';
releases.appendChild(frag)
} catch (e) { } catch (e) {
console.error(e) console.error(e)
} }

View file

@ -24,6 +24,9 @@ let playerData = {
function resetVideo() { function resetVideo() {
!!playerData.octopusInstance ? playerData.octopusInstance.dispose() : "" !!playerData.octopusInstance ? playerData.octopusInstance.dispose() : ""
!!playerData.fonts ? playerData.fonts.forEach(file => {
URL.revokeObjectURL(file)
}) : ""
playerData = { playerData = {
tracks: [], tracks: [],
headers: undefined, headers: undefined,
@ -31,6 +34,7 @@ function resetVideo() {
subtitles: [], subtitles: [],
subtitleStream: undefined, subtitleStream: undefined,
octopusInstance: undefined, octopusInstance: undefined,
fonts: [],
nowPlaying: undefined, nowPlaying: undefined,
selected: undefined, selected: undefined,
thumbnails: [] thumbnails: []
@ -132,7 +136,8 @@ function createThumbnail(vid) {
function finishThumbnails(url) { function finishThumbnails(url) {
if (settings.player5 && settings.player8) { if (settings.player5 && settings.player8) {
let thumbVid = document.createElement("video") let thumbVid = document.createElement("video"),
index = 0
thumbVid.src = url thumbVid.src = url
thumbVid.addEventListener('loadeddata', () => { thumbVid.addEventListener('loadeddata', () => {
@ -145,11 +150,15 @@ function finishThumbnails(url) {
}) })
function loadTime() { function loadTime() {
while (playerData.thumbnails[index] && index <= Math.floor(thumbVid.duration / 5)) {
index++
}
if (thumbVid.currentTime != thumbVid.duration) { if (thumbVid.currentTime != thumbVid.duration) {
thumbVid.currentTime = thumbVid.currentTime + 5; thumbVid.currentTime = index * 5
} else { } else {
thumbVid.remove() thumbVid.remove()
} }
index++
} }
} }
} }
@ -276,7 +285,53 @@ updateVolume(parseInt(settings.player1))
// PiP // PiP
async function btnpip() { async function btnpip() {
video !== document.pictureInPictureElement ? await video.requestPictureInPicture() : await document.exitPictureInPicture(); if (!playerData.octopusInstance) {
video !== document.pictureInPictureElement ? await video.requestPictureInPicture() : await document.exitPictureInPicture();
} else {
if (document.pictureInPictureElement) {
await document.exitPictureInPicture()
} else {
let canvas = document.createElement("canvas"),
subtitleCanvas = document.querySelector(".libassjs-canvas"),
canvasVideo = document.createElement("video"),
context = canvas.getContext("2d", { alpha: false }),
running = true
canvas.width = subtitleCanvas.width
canvas.height = subtitleCanvas.height
player.classList.add("pip")
function renderFrame() {
if (running) {
context.drawImage(video, 0, 0, canvas.width, canvas.height)
context.drawImage(subtitleCanvas, 0, 0)
window.requestAnimationFrame(renderFrame)
}
}
window.requestAnimationFrame(renderFrame)
canvasVideo.srcObject = canvas.captureStream()
canvasVideo.onloadeddata = async function () {
canvasVideo.play()
await canvasVideo.requestPictureInPicture()
}
canvasVideo.onleavepictureinpicture = () => {
running = false
canvasVideo.remove()
canvas.remove()
player.classList.remove("pip")
}
}
}
}
function hardSub() {
let c1 = document.createElement("canvas"),
sub = document.querySelector(".libassjs-canvas")
c1.width = sub.width
c1.height = sub.height
let ctx1 = c1.getContext("2d")
ctx1.drawImage(video, 0, 0, c1.width, c1.height)
ctx1.drawImage(sub, 0, 0)
console.log(c1.toDataURL("image/jpeg"))
} }
//miniplayer //miniplayer
@ -422,7 +477,7 @@ function selPlaying(sel) {
} }
function updatePositionState() { function updatePositionState() {
if ('setPositionState' in navigator.mediaSession) { if ('setPositionState' in navigator.mediaSession && video.duration) {
navigator.mediaSession.setPositionState({ navigator.mediaSession.setPositionState({
duration: video.duration || 0, duration: video.duration || 0,
playbackRate: video.playbackRate || 0, playbackRate: video.playbackRate || 0,

View file

@ -9,6 +9,7 @@ const settingsElements = {
player8: player8, player8: player8,
subtitle1: subtitle1, subtitle1: subtitle1,
subtitle2: subtitle2, subtitle2: subtitle2,
subtitle3: subtitle3,
torrent1: torrent1, torrent1: torrent1,
torrent2: torrent2, torrent2: torrent2,
torrent3: torrent3, torrent3: torrent3,
@ -28,6 +29,7 @@ function restoreDefaults() {
player8: true, player8: true,
subtitle1: "'Open Sans', sans-serif", subtitle1: "'Open Sans', sans-serif",
subtitle2: true, subtitle2: true,
subtitle3: true,
torrent1: "1080", torrent1: "1080",
torrent2: false, torrent2: false,
torrent3: true, torrent3: true,

View file

@ -27,7 +27,7 @@ function subStream(stream) {
} }
}) })
} }
playerData.subtitleStream.on('subtitle', function (subtitle, trackNumber) { playerData.subtitleStream.on('subtitle', (subtitle, trackNumber) => {
if (playerData.headers) { if (playerData.headers) {
let formatSub = "Dialogue: " + subtitle.layer + "," + 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 + "," + subtitle.name + "," + subtitle.marginL + "," + subtitle.marginR + "," + subtitle.marginV + "," + subtitle.effect + "," + subtitle.text let formatSub = "Dialogue: " + subtitle.layer + "," + 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 + "," + subtitle.name + "," + subtitle.marginL + "," + subtitle.marginR + "," + subtitle.marginV + "," + subtitle.effect + "," + subtitle.text
if (!playerData.subtitles[trackNumber].includes(formatSub)) { if (!playerData.subtitles[trackNumber].includes(formatSub)) {
@ -41,6 +41,9 @@ function subStream(stream) {
} }
} }
}) })
playerData.subtitleStream.on('file', file => {
file.mimetype == ("application/x-truetype-font" || "application/font-woff") ? playerData.fonts.push(window.URL.createObjectURL(new Blob([file.data],{type: file.mimetype}))) : ""
})
stream.pipe(playerData.subtitleStream) stream.pipe(playerData.subtitleStream)
} }
} }
@ -51,7 +54,7 @@ function renderSubs(trackNumber) {
video: video, video: video,
subContent: trackContent, subContent: trackContent,
lossyRender: settings.subtitle2, lossyRender: settings.subtitle2,
fonts: ["https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fBBc4.woff2"], fonts: playerData.fonts.length == 0 ? ["https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fBBc4.woff2"] : playerData.fonts,
workerUrl: 'js/subtitles-octopus-worker.js' workerUrl: 'js/subtitles-octopus-worker.js'
}; };
playerData.octopusInstance = new SubtitlesOctopus(options); playerData.octopusInstance = new SubtitlesOctopus(options);

View file

@ -99,31 +99,39 @@ async function addTorrent(magnet) {
} }
function postDownload(url, file) { function postDownload(url, file) {
if (settings.player8) { if (settings.player8) {
let parser = new SubtitleParser(), if (playerData.subtitleStream) {
subtitles = [] let parser = new SubtitleParser(),
parser.once('tracks', pTracks => { subtitles = []
pTracks.forEach(track => { parser.once('tracks', pTracks => {
subtitles[track.number] = [] pTracks.forEach(track => {
subtitles[track.number] = []
})
}) })
}) parser.on('subtitle', function (subtitle, trackNumber) {
parser.on('subtitle', function (subtitle, trackNumber) { if (playerData.headers) {
if (playerData.headers) { subtitles[trackNumber].push("Dialogue: " + subtitle.layer + "," + 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 + "," + subtitle.name + "," + subtitle.marginL + "," + subtitle.marginR + "," + subtitle.marginV + "," + subtitle.effect + "," + subtitle.text)
subtitles[trackNumber].push("Dialogue: " + subtitle.layer + "," + 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 + "," + subtitle.name + "," + subtitle.marginL + "," + subtitle.marginR + "," + subtitle.marginV + "," + subtitle.effect + "," + subtitle.text) } else if (!Object.values(playerData.tracks[trackNumber].cues).some(c => c.text == subtitle.text && c.startTime == subtitle.time / 1000 && c.endTime == (subtitle.time + subtitle.duration) / 1000)) {
} else if (!Object.values(playerData.tracks[trackNumber].cues).some(c => c.text == subtitle.text && c.startTime == subtitle.time / 1000 && c.endTime == (subtitle.time + subtitle.duration) / 1000)) { let cue = new VTTCue(subtitle.time / 1000, (subtitle.time + subtitle.duration) / 1000, subtitle.text)
let cue = new VTTCue(subtitle.time / 1000, (subtitle.time + subtitle.duration) / 1000, subtitle.text) playerData.tracks[trackNumber].addCue(cue)
playerData.tracks[trackNumber].addCue(cue) }
} })
}) parser.on('finish', () => {
parser.on('finish', () => { playerData.subtitles = subtitles
playerData.subtitles = subtitles renderSubs.call(null, 3)
renderSubs.call(null, 3) let time = video.currentTime,
playState = !video.paused
video.src = url
video.currentTime = time
playState ? video.play() : ""
});
file.createReadStream().pipe(parser)
} else {
let time = video.currentTime, let time = video.currentTime,
playState = !video.paused playState = !video.paused
video.src = url video.src = url
video.currentTime = time video.currentTime = time
playState ? video.play() : "" playState ? video.play() : ""
}); }
file.createReadStream().pipe(parser)
} }
} }
function onProgress() { function onProgress() {