mirror of
https://github.com/ThaUnknown/miru.git
synced 2026-04-06 21:19:25 +00:00
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:
parent
5d644589ad
commit
8d9edc8c99
7 changed files with 134 additions and 51 deletions
|
|
@ -58,6 +58,9 @@
|
|||
#player:target .player {
|
||||
display: flex !important
|
||||
}
|
||||
#player.pip{
|
||||
background: #000
|
||||
}
|
||||
|
||||
.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);
|
||||
|
|
@ -212,8 +215,10 @@
|
|||
#player:fullscreen #btheatre,
|
||||
#player:target>a,
|
||||
#progress+img[src=" "],
|
||||
video[src=""] {
|
||||
display: none
|
||||
video[src=""],
|
||||
#player.pip video,
|
||||
#player.pip canvas {
|
||||
display: none !important
|
||||
}
|
||||
|
||||
video::cue {
|
||||
|
|
|
|||
|
|
@ -304,11 +304,17 @@
|
|||
<option value="Roboto,Arial,Helvetica,sans-serif">Roboto</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="custom-switch mb-20">
|
||||
<div class="custom-switch mb-10">
|
||||
<input type="checkbox" id="subtitle2">
|
||||
<label for="subtitle2">Async Rendering [Might cause desync on low end devices but greatly
|
||||
improves performance]</label>
|
||||
</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">
|
||||
|
|
@ -360,7 +366,7 @@
|
|||
<script src="https://cdn.jsdelivr.net/npm/webtorrent@latest/webtorrent.min.js"></script>
|
||||
<script src="js/rangeParser.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/subtitleOctopus.js"></script>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -319,41 +319,45 @@ async function nyaaRss(url) {
|
|||
const regex = /((?:\[[^\]]*\])*)?\s*((?:[^\d\[\.](?!S\d))*)?\s*((?:S\d+[^\w\[]*E?)?[\d\-]*)\s*(.*)?/i,
|
||||
eregex = /(\[.*\]\ ?)?(.+?(?=\ \–\ \d))?(\ \–\ )?(\d+)?/i,
|
||||
plsregex = /(\[.[^\]]*\]\ ?)?(.+?(?=\ \-\ \d))?(\ \-\ )?(\d+)?(.*)?/i
|
||||
let store = {};
|
||||
let store = {},
|
||||
lastResult
|
||||
|
||||
async function hsRss() {
|
||||
if (document.location.href.endsWith("#releases")) {
|
||||
let frag = document.createDocumentFragment(),
|
||||
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
|
||||
releases.textContent = '';
|
||||
releases.appendChild(skeletonCard)
|
||||
res = await fetch(url)
|
||||
await res.text().then(async (xmlTxt) => {
|
||||
try {
|
||||
let doc = DOMPARSER(xmlTxt, "text/xml")
|
||||
let items = doc.querySelectorAll("item")
|
||||
for (let item of items) {
|
||||
let i = item.querySelector.bind(item),
|
||||
regexParse = plsregex.exec(i("title").textContent)
|
||||
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)
|
||||
if (lastResult != doc) {
|
||||
releases.textContent = '';
|
||||
releases.appendChild(skeletonCard)
|
||||
lastResult = doc
|
||||
let items = doc.querySelectorAll("item")
|
||||
for (let item of items) {
|
||||
let i = item.querySelector.bind(item),
|
||||
regexParse = plsregex.exec(i("title").textContent)
|
||||
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]],
|
||||
template = cardCreator(media, regexParse)
|
||||
template.onclick = () => {
|
||||
playerData.selected = [regexParse[2], regexParse[4]]
|
||||
addTorrent(i('link').textContent)
|
||||
}
|
||||
frag.appendChild(template)
|
||||
releases.textContent = '';
|
||||
releases.appendChild(frag)
|
||||
}
|
||||
releases.textContent = '';
|
||||
releases.appendChild(frag)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ let playerData = {
|
|||
|
||||
function resetVideo() {
|
||||
!!playerData.octopusInstance ? playerData.octopusInstance.dispose() : ""
|
||||
!!playerData.fonts ? playerData.fonts.forEach(file => {
|
||||
URL.revokeObjectURL(file)
|
||||
}) : ""
|
||||
playerData = {
|
||||
tracks: [],
|
||||
headers: undefined,
|
||||
|
|
@ -31,6 +34,7 @@ function resetVideo() {
|
|||
subtitles: [],
|
||||
subtitleStream: undefined,
|
||||
octopusInstance: undefined,
|
||||
fonts: [],
|
||||
nowPlaying: undefined,
|
||||
selected: undefined,
|
||||
thumbnails: []
|
||||
|
|
@ -132,7 +136,8 @@ function createThumbnail(vid) {
|
|||
|
||||
function finishThumbnails(url) {
|
||||
if (settings.player5 && settings.player8) {
|
||||
let thumbVid = document.createElement("video")
|
||||
let thumbVid = document.createElement("video"),
|
||||
index = 0
|
||||
thumbVid.src = url
|
||||
|
||||
thumbVid.addEventListener('loadeddata', () => {
|
||||
|
|
@ -145,11 +150,15 @@ function finishThumbnails(url) {
|
|||
})
|
||||
|
||||
function loadTime() {
|
||||
while (playerData.thumbnails[index] && index <= Math.floor(thumbVid.duration / 5)) {
|
||||
index++
|
||||
}
|
||||
if (thumbVid.currentTime != thumbVid.duration) {
|
||||
thumbVid.currentTime = thumbVid.currentTime + 5;
|
||||
thumbVid.currentTime = index * 5
|
||||
} else {
|
||||
thumbVid.remove()
|
||||
}
|
||||
index++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -276,7 +285,53 @@ updateVolume(parseInt(settings.player1))
|
|||
// PiP
|
||||
|
||||
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
|
||||
|
|
@ -422,7 +477,7 @@ function selPlaying(sel) {
|
|||
}
|
||||
|
||||
function updatePositionState() {
|
||||
if ('setPositionState' in navigator.mediaSession) {
|
||||
if ('setPositionState' in navigator.mediaSession && video.duration) {
|
||||
navigator.mediaSession.setPositionState({
|
||||
duration: video.duration || 0,
|
||||
playbackRate: video.playbackRate || 0,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ const settingsElements = {
|
|||
player8: player8,
|
||||
subtitle1: subtitle1,
|
||||
subtitle2: subtitle2,
|
||||
subtitle3: subtitle3,
|
||||
torrent1: torrent1,
|
||||
torrent2: torrent2,
|
||||
torrent3: torrent3,
|
||||
|
|
@ -28,6 +29,7 @@ function restoreDefaults() {
|
|||
player8: true,
|
||||
subtitle1: "'Open Sans', sans-serif",
|
||||
subtitle2: true,
|
||||
subtitle3: true,
|
||||
torrent1: "1080",
|
||||
torrent2: false,
|
||||
torrent3: true,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ function subStream(stream) {
|
|||
}
|
||||
})
|
||||
}
|
||||
playerData.subtitleStream.on('subtitle', function (subtitle, trackNumber) {
|
||||
playerData.subtitleStream.on('subtitle', (subtitle, trackNumber) => {
|
||||
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
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -51,7 +54,7 @@ function renderSubs(trackNumber) {
|
|||
video: video,
|
||||
subContent: trackContent,
|
||||
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'
|
||||
};
|
||||
playerData.octopusInstance = new SubtitlesOctopus(options);
|
||||
|
|
|
|||
|
|
@ -99,31 +99,39 @@ async function addTorrent(magnet) {
|
|||
}
|
||||
function postDownload(url, file) {
|
||||
if (settings.player8) {
|
||||
let parser = new SubtitleParser(),
|
||||
subtitles = []
|
||||
parser.once('tracks', pTracks => {
|
||||
pTracks.forEach(track => {
|
||||
subtitles[track.number] = []
|
||||
if (playerData.subtitleStream) {
|
||||
let parser = new SubtitleParser(),
|
||||
subtitles = []
|
||||
parser.once('tracks', pTracks => {
|
||||
pTracks.forEach(track => {
|
||||
subtitles[track.number] = []
|
||||
})
|
||||
})
|
||||
})
|
||||
parser.on('subtitle', function (subtitle, trackNumber) {
|
||||
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)
|
||||
} 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)
|
||||
playerData.tracks[trackNumber].addCue(cue)
|
||||
}
|
||||
})
|
||||
parser.on('finish', () => {
|
||||
playerData.subtitles = subtitles
|
||||
renderSubs.call(null, 3)
|
||||
parser.on('subtitle', function (subtitle, trackNumber) {
|
||||
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)
|
||||
} 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)
|
||||
playerData.tracks[trackNumber].addCue(cue)
|
||||
}
|
||||
})
|
||||
parser.on('finish', () => {
|
||||
playerData.subtitles = subtitles
|
||||
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,
|
||||
playState = !video.paused
|
||||
video.src = url
|
||||
video.currentTime = time
|
||||
playState ? video.play() : ""
|
||||
});
|
||||
file.createReadStream().pipe(parser)
|
||||
}
|
||||
}
|
||||
}
|
||||
function onProgress() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue