mirror of
https://github.com/ThaUnknown/miru.git
synced 2026-04-04 22:19:44 +00:00
comments, minor fixes
This commit is contained in:
parent
f9a7e3eea0
commit
9523fd3d03
7 changed files with 253 additions and 248 deletions
|
|
@ -494,7 +494,7 @@
|
|||
<script src="js/rangeParser.js"></script>
|
||||
<script src="js/idbkv-chunk-store.js"></script>
|
||||
<script src="js/torrentHandler.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/matroska-subtitles@3/dist/matroska-subtitles.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/matroska-subtitles@latest/dist/matroska-subtitles.min.js"></script>
|
||||
<script src="js/subtitles-octopus.js"></script>
|
||||
<script src="js/subtitleOctopus.js"></script>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const torrentRx = /(magnet:){1}|(^[A-F\d]{8,40}$){1}|(.*\.torrent){1}/i,
|
||||
imageRx = /\.(jpeg|jpg|gif|png|webp)/
|
||||
window.addEventListener("paste", async e => {
|
||||
window.addEventListener("paste", async e => { //WAIT image lookup on paste, or add torrent on paste
|
||||
let item = e.clipboardData.items[0];
|
||||
if (item && item.type.indexOf("image") === 0) {
|
||||
e.preventDefault();
|
||||
|
|
@ -37,7 +37,7 @@ window.addEventListener("paste", async e => {
|
|||
}
|
||||
|
||||
})
|
||||
function traceAnime(image, type) {
|
||||
function traceAnime(image, type) { //WAIT lookup logic
|
||||
halfmoon.initStickyAlert({
|
||||
content: `Looking Up Anime ${type == "uri" ? "" : `For <span class="text-break">${image}</span>`}`
|
||||
})
|
||||
|
|
@ -62,16 +62,17 @@ function traceAnime(image, type) {
|
|||
});
|
||||
|
||||
}
|
||||
function searchBox() {
|
||||
function searchBox() { // make searchbox behave nicely
|
||||
search.placeholder = search.value
|
||||
searchAnime(search.value)
|
||||
search.value = ""
|
||||
document.location.hash = "#browse"
|
||||
}
|
||||
//events
|
||||
navNew.onclick = () => { releasesRss() }
|
||||
navTrending.onclick = () => { searchAnime() }
|
||||
navNowPlaying.onclick = () => { viewAnime(playerData.nowPlaying[0]) }
|
||||
navList.onclick = async () => {
|
||||
navList.onclick = async () => { //user watchlist
|
||||
let browse = document.querySelector(".browse")
|
||||
browse.textContent = '';
|
||||
browse.appendChild(skeletonCard)
|
||||
|
|
@ -92,6 +93,7 @@ navList.onclick = async () => {
|
|||
browse.textContent = '';
|
||||
browse.appendChild(frag)
|
||||
}
|
||||
//AL lookup logic
|
||||
async function alRequest(searchName, method) {
|
||||
let query,
|
||||
variables = {
|
||||
|
|
@ -290,7 +292,7 @@ mutation ($id: Int, $status: MediaListStatus, $episode: Int) {
|
|||
}
|
||||
}
|
||||
let alResponse
|
||||
async function searchAnime(a) {
|
||||
async function searchAnime(a) { //search bar functionality
|
||||
let frag = document.createDocumentFragment(),
|
||||
browse = document.querySelector(".browse")
|
||||
browse.textContent = '';
|
||||
|
|
@ -311,7 +313,7 @@ async function searchAnime(a) {
|
|||
browse.appendChild(frag)
|
||||
}
|
||||
|
||||
|
||||
//these really shouldnt be global
|
||||
let detailsfrag = document.createDocumentFragment()
|
||||
let details = {
|
||||
averageScore: "Average Score",
|
||||
|
|
@ -328,6 +330,7 @@ let details = {
|
|||
synonyms: "Synonyms"
|
||||
}
|
||||
const episodeRx = /Episode (\d+) - (.*)/;
|
||||
// this is fucked beyond belief, this is why you use frameworks
|
||||
function viewAnime(media) {
|
||||
halfmoon.showModal("view")
|
||||
view.setAttribute("style", `background-image: url(${media.bannerImage}) !important`)
|
||||
|
|
@ -436,6 +439,7 @@ function trailerPopup(trailer) {
|
|||
}
|
||||
|
||||
}
|
||||
//details list factory
|
||||
function detailsCreator(entry) {
|
||||
if (entry) {
|
||||
Object.entries(entry).forEach(value => {
|
||||
|
|
@ -562,6 +566,7 @@ async function nyaaRss(media, episode) {
|
|||
})
|
||||
return frag
|
||||
}
|
||||
//resolve anime name based on torrent name and store it
|
||||
async function resolveName(name, method) {
|
||||
if (!store.hasOwnProperty(name) && !alResponse.data.Page.media.some(media => (Object.values(media.title).concat(media.synonyms).filter(name => name != null).includes(name) && ((store[name] = media) && true)))) {
|
||||
let res = await alRequest(name, method)
|
||||
|
|
@ -588,9 +593,10 @@ async function releasesRss() {
|
|||
releases = document.querySelector(".releases"),
|
||||
url
|
||||
if (Object.values(torrent4list.options).filter(item => item.value == settings.torrent4)[0]) {
|
||||
//add my own cors proxy for erai
|
||||
url = settings.torrent4 == "Erai-raws" ? new URL(Object.values(torrent4list.options).filter(item => item.value == settings.torrent4)[0].innerText + settings.torrent1 + "-magnet") : new URL(Object.values(torrent4list.options).filter(item => item.value == settings.torrent4)[0].innerText + settings.torrent1)
|
||||
} else {
|
||||
url = settings.torrent4 + settings.torrent1
|
||||
url = settings.torrent4 + settings.torrent1 // add custom RSS
|
||||
}
|
||||
let res = await fetch(url)
|
||||
await res.text().then(async (xmlTxt) => {
|
||||
|
|
@ -631,10 +637,7 @@ async function releasesRss() {
|
|||
|
||||
localStorage.setItem("store", JSON.stringify(store))
|
||||
}
|
||||
clearRelCache.onclick = () => {
|
||||
localStorage.removeItem("store")
|
||||
store = {}
|
||||
}
|
||||
//latest releases auto-update
|
||||
setInterval(() => {
|
||||
if (document.location.hash == "#releases") {
|
||||
releasesRss()
|
||||
|
|
@ -646,7 +649,7 @@ async function loadAnime() {
|
|||
}
|
||||
loadAnime()
|
||||
|
||||
let alID
|
||||
let alID // login icon
|
||||
if (localStorage.getItem("ALtoken")) {
|
||||
alRequest(undefined, "Viewer").then(result => {
|
||||
oauth.removeAttribute("href")
|
||||
|
|
|
|||
|
|
@ -34,9 +34,8 @@ function cleanupVideo() { // cleans up objects, attemps to clear as much video c
|
|||
if (dl.href) {
|
||||
URL.revokeObjectURL(dl.href)
|
||||
}
|
||||
|
||||
dl.setAttribute("disabled", "")
|
||||
dl.onclick = null
|
||||
dl.onclick = undefined
|
||||
if (typeof video !== 'undefined' && typeof client !== 'undefined') {
|
||||
video.pause()
|
||||
video.src = "";
|
||||
|
|
@ -66,7 +65,8 @@ function cleanupVideo() { // cleans up objects, attemps to clear as much video c
|
|||
if ('mediaSession' in navigator)
|
||||
navigator.mediaSession.metadata = null
|
||||
}
|
||||
async function buildVideo(file, nowPlaying) {
|
||||
|
||||
async function buildVideo(file, nowPlaying) { //creates a new video element and adds listeners... this needs to go
|
||||
video = document.createElement("video")
|
||||
if (!settings.player7 || !'pictureInPictureEnabled' in document) {
|
||||
video.setAttribute("disablePictureInPicture", "")
|
||||
|
|
@ -136,13 +136,14 @@ async function buildVideo(file, nowPlaying) {
|
|||
if (nowPlaying && nowPlaying[0]) {
|
||||
playerData.nowPlaying = nowPlaying
|
||||
navNowPlaying.classList.remove("d-none")
|
||||
} else if (settings.torrent7) {
|
||||
} else if (settings.torrent7) { // try to resolve name
|
||||
let regexParse = nameParseRegex.simple.exec(file.name)
|
||||
playerData.nowPlaying = [await resolveName(regexParse[2], "SearchAnySingle"), regexParse[4]]
|
||||
navNowPlaying.classList.remove("d-none")
|
||||
console.log(regexParse)
|
||||
}
|
||||
let mediaMetadata
|
||||
// only set mediasession and other shit if the playerdata is parsed correctly
|
||||
if (playerData.nowPlaying && playerData.nowPlaying[0] && playerData.nowPlaying[1]) {
|
||||
mediaMetadata = new MediaMetadata({
|
||||
title: playerData.nowPlaying[0].title.userPreferred,
|
||||
|
|
@ -176,13 +177,13 @@ async function buildVideo(file, nowPlaying) {
|
|||
// download progress and status
|
||||
let onProgress
|
||||
|
||||
// visibility loss
|
||||
// visibility loss pause
|
||||
document.addEventListener("visibilitychange", () => {
|
||||
if (settings.player10 && typeof video !== 'undefined' && !video.ended)
|
||||
document.visibilityState === "hidden" ? video.pause() : playVideo();
|
||||
})
|
||||
|
||||
// progress bar and display
|
||||
// progress seek bar and display
|
||||
|
||||
function updateDisplay() {
|
||||
if (typeof video !== 'undefined') {
|
||||
|
|
@ -232,7 +233,7 @@ function updateBar(progressPercent) {
|
|||
}
|
||||
}
|
||||
|
||||
// dynamic thumbnails
|
||||
// dynamic thumbnail previews
|
||||
let canvas = document.createElement("canvas")
|
||||
let context = canvas.getContext('2d')
|
||||
let h
|
||||
|
|
@ -275,7 +276,7 @@ function finishThumbnails(file) {
|
|||
})
|
||||
|
||||
function loadTime() {
|
||||
while (playerData.thumbnails[index] && index <= Math.floor(thumbVid.duration / 5)) {
|
||||
while (playerData.thumbnails[index] && index <= Math.floor(thumbVid.duration / 5)) { // only create thumbnails that are missing
|
||||
index++
|
||||
}
|
||||
if (thumbVid.currentTime != thumbVid.duration) {
|
||||
|
|
@ -364,7 +365,7 @@ function toTS(sec) {
|
|||
} else {
|
||||
return `${minutes}:${seconds}`;
|
||||
}
|
||||
// return new Date(sec*1000).toISOString().slice(12, -1).slice(0, -4).replace(/^0:/,"")
|
||||
// return new Date(sec*1000).toISOString().slice(12, -1).slice(0, -4).replace(/^0:/,"") // laggy :/
|
||||
}
|
||||
|
||||
// play/pause button
|
||||
|
|
@ -387,6 +388,7 @@ function btnpp() {
|
|||
}
|
||||
}
|
||||
}
|
||||
// next video button
|
||||
let nextCooldown
|
||||
function btnnext() {
|
||||
clearTimeout(nextCooldown)
|
||||
|
|
@ -455,7 +457,7 @@ async function btnpip() {
|
|||
if (!playerData.octopusInstance) {
|
||||
video !== document.pictureInPictureElement ? await video.requestPictureInPicture() : await document.exitPictureInPicture();
|
||||
} else {
|
||||
if (document.pictureInPictureElement && !document.pictureInPictureElement.id) {
|
||||
if (document.pictureInPictureElement && !document.pictureInPictureElement.id) { //only exit if pip is the custom one, else overwrite existing pip with custom
|
||||
await document.exitPictureInPicture()
|
||||
} else {
|
||||
let canvas = document.createElement("canvas"),
|
||||
|
|
@ -529,7 +531,7 @@ function seek(a) {
|
|||
updateBar(video.currentTime / video.duration * 100)
|
||||
}
|
||||
// subtitles, generates content every single time its opened because fuck knows when the parser will find new shit
|
||||
|
||||
// this needs to go.... really badly
|
||||
let off
|
||||
function btncap() {
|
||||
if (video.textTracks.length) {
|
||||
|
|
@ -696,6 +698,7 @@ document.onkeydown = (a) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
//media session shit
|
||||
|
||||
function updatePositionState() {
|
||||
if (typeof video !== 'undefined' && video.duration)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ function registerProtocol() {
|
|||
if ('registerProtocolHandler' in navigator) {
|
||||
navigator.registerProtocolHandler(
|
||||
'magnet',
|
||||
`${location.href.replace(location.hash, '')}#&m=%s`,
|
||||
`${location.href.replace(location.hash, '')}#&file=%s`,
|
||||
'Miru'
|
||||
);
|
||||
}
|
||||
|
|
@ -48,6 +48,10 @@ if (!localStorage.getItem("settings")) {
|
|||
} else {
|
||||
settings = JSON.parse(localStorage.getItem("settings"))
|
||||
}
|
||||
clearRelCache.onclick = () => {
|
||||
localStorage.removeItem("store")
|
||||
store = {}
|
||||
}
|
||||
renderSettings()
|
||||
setRes.addEventListener("click", restoreDefaults)
|
||||
settingsTab.addEventListener("click", applySettingsTimeout)
|
||||
|
|
|
|||
|
|
@ -1,211 +1,211 @@
|
|||
let tracks = [],
|
||||
headers = [],
|
||||
subtitleStream
|
||||
const { SubtitleStream } = MatroskaSubtitles
|
||||
// let tracks = [],
|
||||
// headers = [],
|
||||
// subtitleStream
|
||||
// const { SubtitleStream } = MatroskaSubtitles
|
||||
|
||||
function parseSubs(stream) {
|
||||
if (video.src.endsWith(".mkv")) {
|
||||
if (subtitleStream) {
|
||||
subtitleStream = new SubtitleStream(subtitleStream)
|
||||
} else {
|
||||
subtitleStream = new SubtitleStream()
|
||||
// subtitleStream.once('tracks', pTracks => {
|
||||
// pTracks.forEach(track => {
|
||||
// tracks[track.number] = video.addTextTrack('captions', track.type, track.language);
|
||||
// parseHeader(track.header, track.number);
|
||||
// let spacerCue = new VTTCue(0.1, 9999, " ")
|
||||
// spacerCue.line = -1
|
||||
// tracks[track.number].addCue(spacerCue)
|
||||
// })
|
||||
// if (video.textTracks[0]) {
|
||||
// video.textTracks[0].mode = "showing"
|
||||
// displayHeader(headers[3])
|
||||
// }
|
||||
// })
|
||||
}
|
||||
subtitleStream.on('subtitle', function (subtitle, trackNumber) {
|
||||
// subConvt(subtitle, trackNumber)
|
||||
console.log(subtitle)
|
||||
})
|
||||
stream.pipe(subtitleStream)
|
||||
}
|
||||
}
|
||||
const re_newline = /\\N/g, // replace \N with newline
|
||||
re_softbreak = /\\n/g, // There's no equivalent function in WebVTT.
|
||||
re_hardspace = /\\h/g, // Replace with
|
||||
re_style = /\{([^}]+)\}/, // replace style
|
||||
re_header_format = /(?<=\[V4\+? Styles\][\s\S]*Format: [^\n]*)(.+)/i,
|
||||
re_header_style = /(?<=\[V4\+? Styles\][\s\S]*Style: [^\n]*)(.+)/ig;
|
||||
function subConvt(result, trackNumber) {
|
||||
let cue = new VTTCue(result.time / 1000, (result.time + result.duration) / 1000, ""),
|
||||
text = result.text,
|
||||
positioned
|
||||
result.style = result.style.replace(/\ /g, "")
|
||||
if (tracks[trackNumber].label == "ass") {
|
||||
// Support for special characters in WebVTT.
|
||||
// For obvious reasons, the ampersand one *must* be first.
|
||||
text = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
||||
let style, tagsToClose = []; // Places to stash style info.
|
||||
// Subtitles may contain any number of override tags, so we'll loop through
|
||||
// to find them all.
|
||||
while ((style = text.match(re_style))) {
|
||||
let tagsToOpen = [], replaceString = '';
|
||||
if (style[1] && style[1].split) { // Stop throwing errors on empty tags.
|
||||
style = style[1].split("\\"); // Get an array of override commands.
|
||||
for (let j = 1; j < style.length; j++) {
|
||||
// Extract the current tag name.
|
||||
if (style[j]) {
|
||||
let tagCommand = style[j].match(/[a-zA-Z]+/)[0]
|
||||
// Give special reckognition to one-letter tags.
|
||||
let oneLetter = (tagCommand.length == 1) ? tagCommand : "";
|
||||
// "New" position commands. It is assumed that bottom center position is the default.
|
||||
if (tagCommand === "an") {
|
||||
let posNum = Number(style[j].substring(2, 3))
|
||||
positioned = 1
|
||||
if (Math.floor((posNum - 1) / 3) == 1) {
|
||||
cue.line = 8;
|
||||
} else if (Math.floor((posNum - 1) / 3) == 2) {
|
||||
cue.line = 1;
|
||||
} else {
|
||||
cue.line = -1;
|
||||
}
|
||||
if (posNum % 3 == 1) {
|
||||
cue.align = "start";
|
||||
} else if (posNum % 3 == 0) {
|
||||
cue.align = "end";
|
||||
}
|
||||
// Legacy position commands.
|
||||
} else if (oneLetter === "a" && !Number.isNaN(Number(style[j].substring(1, 2)))) {
|
||||
let posNum = Number(style[j].substring(1, 2));
|
||||
positioned = 1
|
||||
if (posNum > 8) {
|
||||
cue.line = 8;
|
||||
} else if (posNum > 4) {
|
||||
cue.line = 1;
|
||||
} else {
|
||||
cue.line = -1;
|
||||
}
|
||||
if ((posNum - 1) % 4 == 0) {
|
||||
cue.align = "start";
|
||||
} else if ((posNum - 1) % 4 == 2) {
|
||||
cue.align = "end";
|
||||
}
|
||||
// Map simple text decoration commands to equivalent WebVTT text tags.
|
||||
// NOTE: Strikethrough (the 's' tag) is not supported in WebVTT.
|
||||
} else if (['b', 'i', 'u', 's'].includes(oneLetter)) {
|
||||
if (Number(style[j].substring(1, 2)) === 0
|
||||
// The more elaborate 'b-tag', which we will treat as an on-off selector.
|
||||
|| (style[j].match(/b\d{3}/)
|
||||
&& Number(style[j].match(/b(\d{3})/)[1]) < 500)
|
||||
) {
|
||||
// Closing a tag.
|
||||
if (tagsToClose.includes(oneLetter)) {
|
||||
// Nothing needs to be done if this tag isn't already open.
|
||||
// HTML tags must be nested, so we must ensure that any tag nested inside
|
||||
// the tag being closed are also closed, and then opened again once the
|
||||
// current tag is closed.
|
||||
while (tagsToClose.length > 0) {
|
||||
let nowClosing = tagsToClose.pop();
|
||||
replaceString += '</' + nowClosing + '>';
|
||||
if (nowClosing !== oneLetter) {
|
||||
tagsToOpen.push(nowClosing);
|
||||
} else {
|
||||
// There's no need to close the tags that the current tag
|
||||
// is nested within.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Opening a tag.
|
||||
if (!tagsToClose.includes(oneLetter)) {
|
||||
// Nothing needs to be done if the tag is already open.
|
||||
// If no, place the tag on the bottom of the stack of tags being opened.
|
||||
tagsToOpen.splice(0, 0, oneLetter);
|
||||
}
|
||||
}
|
||||
} else if (oneLetter === 'r') {
|
||||
// Resetting override tags, by closing all open tags.
|
||||
// TODO: The 'r' tag can also be used to switch to a different named style,
|
||||
// however, named styles haven't been implemented.
|
||||
while (tagsToClose.length > 0) {
|
||||
replaceString += '</' + tagsToClose.pop() + '>';
|
||||
}
|
||||
}
|
||||
// Insert open-tags for tags in the to-open list.
|
||||
while (tagsToOpen.length > 0) {
|
||||
let nowOpening = tagsToOpen.pop();
|
||||
replaceString += '<' + nowOpening + '>';
|
||||
tagsToClose.push(nowOpening);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
text = text.replace(re_style, replaceString); // Replace override tag.
|
||||
}
|
||||
text = text.replace(re_newline, "\r\n").replace(re_softbreak, " ").replace(
|
||||
re_hardspace, " ");
|
||||
let content = "<v." + result.style + ">" + text
|
||||
while (tagsToClose.length > 0) {
|
||||
content += '</' + tagsToClose.pop() + '>';
|
||||
}
|
||||
if (!positioned && headers[trackNumber].styles[result.style][headers[trackNumber].format.indexOf("Alignment")]) {
|
||||
let posNum = Number(headers[trackNumber].styles[result.style][headers[trackNumber].format.indexOf("Alignment")]);
|
||||
if (Math.floor((posNum - 1) / 3) == 1) {
|
||||
cue.line = 8;
|
||||
} else if (Math.floor((posNum - 1) / 3) == 2) {
|
||||
cue.line = 1;
|
||||
} else {
|
||||
cue.line = -1
|
||||
}
|
||||
if (posNum % 3 == 1) {
|
||||
cue.align = "start";
|
||||
} else if (posNum % 3 == 0) {
|
||||
cue.align = "end";
|
||||
}
|
||||
}
|
||||
cue.text = content;
|
||||
} else {
|
||||
cue.text = text;
|
||||
cue.line = -1
|
||||
}
|
||||
if (!Object.values(tracks[trackNumber].cues).some(c => c.text == cue.text && c.startTime == cue.startTime && c.endTime == cue.endTime)) {
|
||||
tracks[trackNumber].addCue(cue)
|
||||
}
|
||||
}
|
||||
function parseHeader(header, number) {
|
||||
headers[number] = {
|
||||
format: re_header_format.exec(header)[1].replace(/\ /g, "").split(","),
|
||||
styles: {
|
||||
}
|
||||
}
|
||||
header.match(re_header_style).forEach((item, index) => {
|
||||
item = item.replace(/\&h/gi, "").replace(/\ /g, "").split(",")
|
||||
headers[number].styles[item[headers[number].format.indexOf("Name")]] = item
|
||||
})
|
||||
}
|
||||
function displayHeader(header) {
|
||||
substyles.innerHTML = ""
|
||||
for (let style of Object.values(header.styles)) {
|
||||
let bordCol
|
||||
style[header.format.indexOf("OutlineColour")] ? bordCol = style[header.format.indexOf("OutlineColour")].match(/[\s\S]{1,2}/g).reverse().join("").slice(0, -2) : "#000"
|
||||
substyles.innerHTML += `
|
||||
video::cue(.${style[header.format.indexOf("Name")]}) {
|
||||
color: #${style[header.format.indexOf("PrimaryColour")] ? style[header.format.indexOf("PrimaryColour")].match(/[\s\S]{1,2}/g).reverse().join("").slice(0, -2) : ""} !important;
|
||||
text-shadow: 2px 2px 0 #${bordCol},
|
||||
2px -2px 0 #${bordCol},
|
||||
-2px 2px 0 #${bordCol},
|
||||
-2px -2px 0 #${bordCol},
|
||||
2px 0px 0 #${bordCol},
|
||||
0px 2px 0 #${bordCol},
|
||||
-2px 0px 0 #${bordCol},
|
||||
0px -2px 0 #${bordCol},
|
||||
2px 2px 2px #${bordCol};
|
||||
font-weight: ${style[header.format.indexOf("Bold")] ? style[header.format.indexOf("Bold")] * -1 ? "400" : "300" : ""} !important;
|
||||
font-style: ${style[header.format.indexOf("Italic")] ? style[header.format.indexOf("Italic")] * -1 ? "italic" : "normal" : ""} !important;
|
||||
background: ${style[header.format.indexOf("BorderStyle")] ? style[header.format.indexOf("BorderStyle")] != 3 ? "none" : `#${bordCol}` : ""} !important;
|
||||
}`
|
||||
}
|
||||
}
|
||||
// function parseSubs(stream) {
|
||||
// if (video.src.endsWith(".mkv")) {
|
||||
// if (subtitleStream) {
|
||||
// subtitleStream = new SubtitleStream(subtitleStream)
|
||||
// } else {
|
||||
// subtitleStream = new SubtitleStream()
|
||||
// // subtitleStream.once('tracks', pTracks => {
|
||||
// // pTracks.forEach(track => {
|
||||
// // tracks[track.number] = video.addTextTrack('captions', track.type, track.language);
|
||||
// // parseHeader(track.header, track.number);
|
||||
// // let spacerCue = new VTTCue(0.1, 9999, " ")
|
||||
// // spacerCue.line = -1
|
||||
// // tracks[track.number].addCue(spacerCue)
|
||||
// // })
|
||||
// // if (video.textTracks[0]) {
|
||||
// // video.textTracks[0].mode = "showing"
|
||||
// // displayHeader(headers[3])
|
||||
// // }
|
||||
// // })
|
||||
// }
|
||||
// subtitleStream.on('subtitle', function (subtitle, trackNumber) {
|
||||
// // subConvt(subtitle, trackNumber)
|
||||
// console.log(subtitle)
|
||||
// })
|
||||
// stream.pipe(subtitleStream)
|
||||
// }
|
||||
// }
|
||||
// const re_newline = /\\N/g, // replace \N with newline
|
||||
// re_softbreak = /\\n/g, // There's no equivalent function in WebVTT.
|
||||
// re_hardspace = /\\h/g, // Replace with
|
||||
// re_style = /\{([^}]+)\}/, // replace style
|
||||
// re_header_format = /(?<=\[V4\+? Styles\][\s\S]*Format: [^\n]*)(.+)/i,
|
||||
// re_header_style = /(?<=\[V4\+? Styles\][\s\S]*Style: [^\n]*)(.+)/ig;
|
||||
// function subConvt(result, trackNumber) {
|
||||
// let cue = new VTTCue(result.time / 1000, (result.time + result.duration) / 1000, ""),
|
||||
// text = result.text,
|
||||
// positioned
|
||||
// result.style = result.style.replace(/\ /g, "")
|
||||
// if (tracks[trackNumber].label == "ass") {
|
||||
// // Support for special characters in WebVTT.
|
||||
// // For obvious reasons, the ampersand one *must* be first.
|
||||
// text = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
||||
// let style, tagsToClose = []; // Places to stash style info.
|
||||
// // Subtitles may contain any number of override tags, so we'll loop through
|
||||
// // to find them all.
|
||||
// while ((style = text.match(re_style))) {
|
||||
// let tagsToOpen = [], replaceString = '';
|
||||
// if (style[1] && style[1].split) { // Stop throwing errors on empty tags.
|
||||
// style = style[1].split("\\"); // Get an array of override commands.
|
||||
// for (let j = 1; j < style.length; j++) {
|
||||
// // Extract the current tag name.
|
||||
// if (style[j]) {
|
||||
// let tagCommand = style[j].match(/[a-zA-Z]+/)[0]
|
||||
// // Give special reckognition to one-letter tags.
|
||||
// let oneLetter = (tagCommand.length == 1) ? tagCommand : "";
|
||||
// // "New" position commands. It is assumed that bottom center position is the default.
|
||||
// if (tagCommand === "an") {
|
||||
// let posNum = Number(style[j].substring(2, 3))
|
||||
// positioned = 1
|
||||
// if (Math.floor((posNum - 1) / 3) == 1) {
|
||||
// cue.line = 8;
|
||||
// } else if (Math.floor((posNum - 1) / 3) == 2) {
|
||||
// cue.line = 1;
|
||||
// } else {
|
||||
// cue.line = -1;
|
||||
// }
|
||||
// if (posNum % 3 == 1) {
|
||||
// cue.align = "start";
|
||||
// } else if (posNum % 3 == 0) {
|
||||
// cue.align = "end";
|
||||
// }
|
||||
// // Legacy position commands.
|
||||
// } else if (oneLetter === "a" && !Number.isNaN(Number(style[j].substring(1, 2)))) {
|
||||
// let posNum = Number(style[j].substring(1, 2));
|
||||
// positioned = 1
|
||||
// if (posNum > 8) {
|
||||
// cue.line = 8;
|
||||
// } else if (posNum > 4) {
|
||||
// cue.line = 1;
|
||||
// } else {
|
||||
// cue.line = -1;
|
||||
// }
|
||||
// if ((posNum - 1) % 4 == 0) {
|
||||
// cue.align = "start";
|
||||
// } else if ((posNum - 1) % 4 == 2) {
|
||||
// cue.align = "end";
|
||||
// }
|
||||
// // Map simple text decoration commands to equivalent WebVTT text tags.
|
||||
// // NOTE: Strikethrough (the 's' tag) is not supported in WebVTT.
|
||||
// } else if (['b', 'i', 'u', 's'].includes(oneLetter)) {
|
||||
// if (Number(style[j].substring(1, 2)) === 0
|
||||
// // The more elaborate 'b-tag', which we will treat as an on-off selector.
|
||||
// || (style[j].match(/b\d{3}/)
|
||||
// && Number(style[j].match(/b(\d{3})/)[1]) < 500)
|
||||
// ) {
|
||||
// // Closing a tag.
|
||||
// if (tagsToClose.includes(oneLetter)) {
|
||||
// // Nothing needs to be done if this tag isn't already open.
|
||||
// // HTML tags must be nested, so we must ensure that any tag nested inside
|
||||
// // the tag being closed are also closed, and then opened again once the
|
||||
// // current tag is closed.
|
||||
// while (tagsToClose.length > 0) {
|
||||
// let nowClosing = tagsToClose.pop();
|
||||
// replaceString += '</' + nowClosing + '>';
|
||||
// if (nowClosing !== oneLetter) {
|
||||
// tagsToOpen.push(nowClosing);
|
||||
// } else {
|
||||
// // There's no need to close the tags that the current tag
|
||||
// // is nested within.
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // Opening a tag.
|
||||
// if (!tagsToClose.includes(oneLetter)) {
|
||||
// // Nothing needs to be done if the tag is already open.
|
||||
// // If no, place the tag on the bottom of the stack of tags being opened.
|
||||
// tagsToOpen.splice(0, 0, oneLetter);
|
||||
// }
|
||||
// }
|
||||
// } else if (oneLetter === 'r') {
|
||||
// // Resetting override tags, by closing all open tags.
|
||||
// // TODO: The 'r' tag can also be used to switch to a different named style,
|
||||
// // however, named styles haven't been implemented.
|
||||
// while (tagsToClose.length > 0) {
|
||||
// replaceString += '</' + tagsToClose.pop() + '>';
|
||||
// }
|
||||
// }
|
||||
// // Insert open-tags for tags in the to-open list.
|
||||
// while (tagsToOpen.length > 0) {
|
||||
// let nowOpening = tagsToOpen.pop();
|
||||
// replaceString += '<' + nowOpening + '>';
|
||||
// tagsToClose.push(nowOpening);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// text = text.replace(re_style, replaceString); // Replace override tag.
|
||||
// }
|
||||
// text = text.replace(re_newline, "\r\n").replace(re_softbreak, " ").replace(
|
||||
// re_hardspace, " ");
|
||||
// let content = "<v." + result.style + ">" + text
|
||||
// while (tagsToClose.length > 0) {
|
||||
// content += '</' + tagsToClose.pop() + '>';
|
||||
// }
|
||||
// if (!positioned && headers[trackNumber].styles[result.style][headers[trackNumber].format.indexOf("Alignment")]) {
|
||||
// let posNum = Number(headers[trackNumber].styles[result.style][headers[trackNumber].format.indexOf("Alignment")]);
|
||||
// if (Math.floor((posNum - 1) / 3) == 1) {
|
||||
// cue.line = 8;
|
||||
// } else if (Math.floor((posNum - 1) / 3) == 2) {
|
||||
// cue.line = 1;
|
||||
// } else {
|
||||
// cue.line = -1
|
||||
// }
|
||||
// if (posNum % 3 == 1) {
|
||||
// cue.align = "start";
|
||||
// } else if (posNum % 3 == 0) {
|
||||
// cue.align = "end";
|
||||
// }
|
||||
// }
|
||||
// cue.text = content;
|
||||
// } else {
|
||||
// cue.text = text;
|
||||
// cue.line = -1
|
||||
// }
|
||||
// if (!Object.values(tracks[trackNumber].cues).some(c => c.text == cue.text && c.startTime == cue.startTime && c.endTime == cue.endTime)) {
|
||||
// tracks[trackNumber].addCue(cue)
|
||||
// }
|
||||
// }
|
||||
// function parseHeader(header, number) {
|
||||
// headers[number] = {
|
||||
// format: re_header_format.exec(header)[1].replace(/\ /g, "").split(","),
|
||||
// styles: {
|
||||
// }
|
||||
// }
|
||||
// header.match(re_header_style).forEach((item, index) => {
|
||||
// item = item.replace(/\&h/gi, "").replace(/\ /g, "").split(",")
|
||||
// headers[number].styles[item[headers[number].format.indexOf("Name")]] = item
|
||||
// })
|
||||
// }
|
||||
// function displayHeader(header) {
|
||||
// substyles.innerHTML = ""
|
||||
// for (let style of Object.values(header.styles)) {
|
||||
// let bordCol
|
||||
// style[header.format.indexOf("OutlineColour")] ? bordCol = style[header.format.indexOf("OutlineColour")].match(/[\s\S]{1,2}/g).reverse().join("").slice(0, -2) : "#000"
|
||||
// substyles.innerHTML += `
|
||||
// video::cue(.${style[header.format.indexOf("Name")]}) {
|
||||
// color: #${style[header.format.indexOf("PrimaryColour")] ? style[header.format.indexOf("PrimaryColour")].match(/[\s\S]{1,2}/g).reverse().join("").slice(0, -2) : ""} !important;
|
||||
// text-shadow: 2px 2px 0 #${bordCol},
|
||||
// 2px -2px 0 #${bordCol},
|
||||
// -2px 2px 0 #${bordCol},
|
||||
// -2px -2px 0 #${bordCol},
|
||||
// 2px 0px 0 #${bordCol},
|
||||
// 0px 2px 0 #${bordCol},
|
||||
// -2px 0px 0 #${bordCol},
|
||||
// 0px -2px 0 #${bordCol},
|
||||
// 2px 2px 2px #${bordCol};
|
||||
// font-weight: ${style[header.format.indexOf("Bold")] ? style[header.format.indexOf("Bold")] * -1 ? "400" : "300" : ""} !important;
|
||||
// font-style: ${style[header.format.indexOf("Italic")] ? style[header.format.indexOf("Italic")] * -1 ? "italic" : "normal" : ""} !important;
|
||||
// background: ${style[header.format.indexOf("BorderStyle")] ? style[header.format.indexOf("BorderStyle")] != 3 ? "none" : `#${bordCol}` : ""} !important;
|
||||
// }`
|
||||
// }
|
||||
// }
|
||||
|
||||
// font-weight: ${style[header.format.indexOf("Bold")] ? style[header.format.indexOf("Bold")] * -1 ? "bold" : "normal" : ""} !important;
|
||||
// // font-weight: ${style[header.format.indexOf("Bold")] ? style[header.format.indexOf("Bold")] * -1 ? "bold" : "normal" : ""} !important;
|
||||
|
|
@ -30,6 +30,7 @@ function subStream(stream) {
|
|||
})
|
||||
}
|
||||
playerData.subtitleStream.on('subtitle', (subtitle, trackNumber) => {
|
||||
console.log(subtitle)
|
||||
if (!playerData.parsed) {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ let client = new WebTorrent({ maxConns: settings.torrent6 }),
|
|||
super(len, { ...opts, batchInterval: 1000 });
|
||||
}
|
||||
}
|
||||
window.onbeforeunload = () => {
|
||||
window.onbeforeunload = () => { //cleanup shit before unloading to free RAM/drive
|
||||
if (!settings.torrent8) {
|
||||
client.torrents[0] ? client.torrents[0].store.destroy() : ""
|
||||
}
|
||||
|
|
@ -45,12 +45,12 @@ const announceList = [
|
|||
],
|
||||
scope = window.location.pathname,
|
||||
sw = navigator.serviceWorker.register('sw.js', { scope }).then(e => {
|
||||
if (searchParams.get("m")) {
|
||||
addTorrent(searchParams.get("m"))
|
||||
if (searchParams.get("file")) {
|
||||
addTorrent(searchParams.get("file")) // add a torrent if its in the link params
|
||||
}
|
||||
}).catch(e => {
|
||||
if (String(e) == "InvalidStateError: Failed to register a ServiceWorker: The document is in an invalid state.") {
|
||||
location.reload()
|
||||
location.reload() // weird workaround for a weird bug
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
|
|
@ -80,7 +80,7 @@ WEBTORRENT_ANNOUNCE = announceList
|
|||
let maxTorrents = 1,
|
||||
videoFiles
|
||||
async function addTorrent(magnet, media, episode) {
|
||||
if (client.torrents.length >= maxTorrents) {
|
||||
if (client.torrents.length >= maxTorrents) { // remove old torrents
|
||||
if (settings.torrent8 && settings.torrent5) {
|
||||
client.remove(client.torrents[0].infoHash)
|
||||
} else {
|
||||
|
|
@ -107,7 +107,7 @@ async function addTorrent(magnet, media, episode) {
|
|||
});
|
||||
}
|
||||
})
|
||||
videoFiles = torrent.files.filter(file => videoExtensions.some(ext => file.name.endsWith(ext)))
|
||||
videoFiles = torrent.files.filter(file => videoExtensions.some(ext => file.name.endsWith(ext))) //only allow playable video files
|
||||
if (videoFiles.length) {
|
||||
videoFiles.sort((a, b) => {
|
||||
return parseInt(nameParseRegex.simple.exec(a.name)[4]) - parseInt(nameParseRegex.simple.exec(b.name)[4])
|
||||
|
|
@ -117,16 +117,10 @@ async function addTorrent(magnet, media, episode) {
|
|||
bpl.removeAttribute("disabled")
|
||||
videoFile = videoFiles.filter(file => { parseInt(nameParseRegex.simple.exec(file.name)[4]) == parseInt(episode) })
|
||||
} else {
|
||||
bpl.setAttribute("disabled", "")
|
||||
bpl.setAttribute("disabled", "")//playlist button hiding
|
||||
videofile = videoFiles[0]
|
||||
}
|
||||
|
||||
if (media && episode) {
|
||||
(videoFile && videoFile.length) ? buildVideo(videoFile[0], [media, episode]) : buildVideo(videoFiles[0], [media, episode])
|
||||
}
|
||||
else {
|
||||
(videoFile && videoFile.length) ? buildVideo(videoFile[0], [media, episode]) : buildVideo(videoFiles[0], [media, episode])
|
||||
}
|
||||
buildVideo(videoFile[0], [media, episode])
|
||||
} else {
|
||||
halfmoon.initStickyAlert({
|
||||
content: `Couldn't find video file for <span class="text-break">${torrent.infoHash}</span>!`,
|
||||
|
|
|
|||
Loading…
Reference in a new issue