mirror of
https://github.com/ThaUnknown/miru.git
synced 2026-03-31 06:38:37 +00:00
subtitle parser fixes, PWA fixes & work, sw caching
This commit is contained in:
parent
add74eccd1
commit
1a25ff1ccb
12 changed files with 199 additions and 176 deletions
29
app/app.html
29
app/app.html
|
|
@ -1,16 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en" class="auto-scaling-disabled">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="Miru">
|
||||
<meta name="description" content="Anime torrent streaming, ad free in a simple solution.">
|
||||
<meta name="theme-color" content="#111417" />
|
||||
<link rel="icon" href="logo.png">
|
||||
<title>Miru</title>
|
||||
<link rel="apple-touch-icon" href="logo.png">
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>Miru - Torrent streaming made simple!</title>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/gh/halfmoonui/halfmoon@1.0.4/css/halfmoon.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/halfmoon@1.1.0/css/halfmoon-variables.min.css" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link href="css/misc.css" rel="stylesheet">
|
||||
<link href="css/player.css" rel="stylesheet">
|
||||
|
|
@ -126,7 +131,7 @@
|
|||
<div class="overflow-y-hidden content-wrapper">
|
||||
<section id="player">
|
||||
<a href="#player" class="w-full h-full"></a>
|
||||
<video id="video" class="w-full" autoPictureInPicture>
|
||||
<video id="video" class="w-full" autoPictureInPicture src="">
|
||||
</video>
|
||||
<div class="player d-none flex-column justify-content-between w-full h-full">
|
||||
<div class="h-full w-full d-flex flex-column justify-content-between" id="ptoggle">
|
||||
|
|
@ -191,7 +196,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="browse">
|
||||
<section id="browse" class="d-flex flex-column">
|
||||
<div class="text-center pt-20">
|
||||
<div class="container">
|
||||
<form class="input-group mb-15" action="javascript:search()">
|
||||
|
|
@ -207,13 +212,13 @@
|
|||
<div class="gallery browse h-full overflow-y-scroll">
|
||||
</div>
|
||||
</section>
|
||||
<section id="releases">
|
||||
<section id="releases" class="d-flex flex-column">
|
||||
<div class="gallery releases h-full overflow-y-scroll">
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/gh/halfmoonui/halfmoon@1.0.4/js/halfmoon.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/gh/halfmoonui/halfmoon@1.1.0/js/halfmoon.min.js"></script>
|
||||
<script src="js/util.js"></script>
|
||||
<script src="js/animeHandler.js"></script>
|
||||
<script src="js/playerHandler.js"></script>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
--buffer: 0%;
|
||||
--height: 0;
|
||||
color: #b6b6b6;
|
||||
font-size: 62.5%;
|
||||
--nav-size: 19rem;
|
||||
--ts: "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -292,10 +292,8 @@ async function nyaaRss(url) {
|
|||
}
|
||||
|
||||
|
||||
let regex = /((?:\[[^\]]*\])*)?\s*((?:[^\d\[\.](?!S\d))*)?\s*((?:S\d+[^\w\[]*E?)?[\d\-]*)\s*(.*)?/,
|
||||
str = `[HorribleSubs] Black Clover - 143 [1080p].mkv`,
|
||||
m,
|
||||
store = {};
|
||||
const regex = /((?:\[[^\]]*\])*)?\s*((?:[^\d\[\.](?!S\d))*)?\s*((?:S\d+[^\w\[]*E?)?[\d\-]*)\s*(.*)?/;
|
||||
let store = {};
|
||||
async function regtest() {
|
||||
if ((m = regex.exec(str)) !== null) {
|
||||
if (m[2].endsWith(" - ")) {
|
||||
|
|
@ -312,7 +310,7 @@ async function regtest() {
|
|||
}
|
||||
}
|
||||
async function hsRss(url) {
|
||||
let frag = document.createDocumentFragment()
|
||||
document.querySelector(".releases").innerHTML = ""
|
||||
res = await fetch(url)
|
||||
await res.text().then(async (xmlTxt) => {
|
||||
try {
|
||||
|
|
@ -320,7 +318,7 @@ async function hsRss(url) {
|
|||
let items = doc.querySelectorAll("item")
|
||||
for (let item of items) {
|
||||
let i = item.querySelector.bind(item),
|
||||
regexParse = regex.exec(i("title").textContent)
|
||||
regexParse = regex.exec(i("title").textContent)
|
||||
if (regexParse[2].endsWith(" - ")) {
|
||||
regexParse[2] = regexParse[2].slice(0, -3)
|
||||
}
|
||||
|
|
@ -332,10 +330,11 @@ async function hsRss(url) {
|
|||
let media = store[regexParse[2]]
|
||||
let template = document.createElement("div")
|
||||
template.classList.add("card", "m-0", "p-0")
|
||||
template.innerHTML = `
|
||||
if (media) {
|
||||
template.innerHTML = `
|
||||
<div class="row h-full">
|
||||
<div class="col-4">
|
||||
<img src="${media.coverImage.extraLarge}"
|
||||
<img src="${media.coverImage.extraLarge || ""}"
|
||||
class="cover-img w-full h-full">
|
||||
</div>
|
||||
<div class="col-8 h-full card-grid">
|
||||
|
|
@ -357,15 +356,36 @@ async function hsRss(url) {
|
|||
</div>
|
||||
</div>
|
||||
`
|
||||
} else {
|
||||
template.innerHTML = `
|
||||
<div class="row h-full">
|
||||
<div class="col-4">
|
||||
<img src=""
|
||||
class="cover-img w-full h-full">
|
||||
</div>
|
||||
<div class="col-8 h-full card-grid">
|
||||
<div class="px-15 py-10">
|
||||
<h5 class="m-0 text-capitalize font-weight-bold">${regexParse[2]} - ${regexParse[3]}</h5>
|
||||
</div>
|
||||
<div class="overflow-y-scroll px-15 py-10 bg-very-dark card-desc">
|
||||
</div>
|
||||
<div class="px-15 pb-10 pt-5">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
template.onclick = function () {
|
||||
selected = [store[regexParse[2]], regexParse[3]]
|
||||
addTorrent(i('link').textContent)
|
||||
}
|
||||
frag.appendChild(template)
|
||||
document.querySelector(".releases").appendChild(template)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
})
|
||||
document.querySelector(".releases").appendChild(frag)
|
||||
}
|
||||
}
|
||||
// setTimeout(() => {
|
||||
// hsRss("http://www.horriblesubs.info/rss.php?res=1080")
|
||||
// }, 4000);
|
||||
|
|
@ -208,7 +208,7 @@ function bpp() {
|
|||
}
|
||||
|
||||
function bnext() {
|
||||
nyaaSearch(nowPlaying[0], nowPlaying[1] + 1)
|
||||
nyaaSearch(nowPlaying[0], parseInt(nowPlaying[1]) + 1)
|
||||
}
|
||||
|
||||
// volume shit
|
||||
|
|
|
|||
|
|
@ -1,15 +1,12 @@
|
|||
let tracks = [],
|
||||
parser
|
||||
|
||||
|
||||
function parseSubs(range, stream) {
|
||||
if (video.src.endsWith(".mkv")) {
|
||||
console.log('set parser', range)
|
||||
|
||||
parser = new MatroskaSubtitles({ prevInstance: parser, offset: range.start })
|
||||
|
||||
parser.once('tracks', function (pTracks) {
|
||||
tracks = []
|
||||
video.textTracks = {}
|
||||
pTracks.forEach(track => {
|
||||
tracks[track.number] = video.addTextTrack('captions', track.type, track.language || track.number)
|
||||
})
|
||||
|
|
@ -17,11 +14,9 @@ function parseSubs(range, stream) {
|
|||
video.textTracks[0].mode = "showing"
|
||||
}
|
||||
})
|
||||
|
||||
parser.once('cues', function () {
|
||||
console.log('seeking ready')
|
||||
})
|
||||
|
||||
parser.on('subtitle', function (subtitle, trackNumber) {
|
||||
subConvt(subtitle, trackNumber)
|
||||
})
|
||||
|
|
@ -58,10 +53,10 @@ function subConvt(result, trackNumber) {
|
|||
cue.line = 0.5;
|
||||
} else if (Math.floor((posNum - 1) / 3) == 2) {
|
||||
cue.line = 0;
|
||||
cue.text = " \r\n"
|
||||
}
|
||||
if (posNum % 3 == 1) {
|
||||
cue.align = "start";
|
||||
cue.text = " \r\n"
|
||||
} else if (posNum % 3 == 0) {
|
||||
cue.align = "end";
|
||||
}
|
||||
|
|
@ -72,10 +67,10 @@ function subConvt(result, trackNumber) {
|
|||
cue.line = 0.5;
|
||||
} else if (posNum > 4) {
|
||||
cue.line = 0;
|
||||
cue.text = " \r\n"
|
||||
}
|
||||
if ((posNum - 1) % 4 == 0) {
|
||||
cue.align = "start";
|
||||
cue.text = " \r\n"
|
||||
} else if ((posNum - 1) % 4 == 2) {
|
||||
cue.align = "end";
|
||||
}
|
||||
|
|
|
|||
55
app/js/sw.js
55
app/js/sw.js
|
|
@ -1,55 +0,0 @@
|
|||
self.addEventListener('activate', evt => {
|
||||
return self.clients.claim()
|
||||
})
|
||||
|
||||
self.addEventListener('fetch', evt => {
|
||||
const { request } = evt
|
||||
const { url, method, headers } = request
|
||||
if (!url.includes(self.registration.scope + 'webtorrent/')) return null
|
||||
|
||||
function getConsumer(clients) {
|
||||
return new Promise(rs => {
|
||||
// Use race condition for whoever controls the response stream
|
||||
for (const client of clients) {
|
||||
const mc = new MessageChannel()
|
||||
const {port1, port2} = mc
|
||||
port1.onmessage = evt => {
|
||||
rs([evt.data, mc])
|
||||
}
|
||||
client.postMessage({
|
||||
url,
|
||||
method,
|
||||
headers: [...headers],
|
||||
scope: self.registration.scope
|
||||
}, [port2])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
evt.respondWith(
|
||||
clients.matchAll({ type: 'window', includeUncontrolled: true })
|
||||
.then(getConsumer)
|
||||
.then(([data, mc]) => {
|
||||
const body = data.body === 'stream' ? new ReadableStream({
|
||||
pull(controller) {
|
||||
return new Promise(rs => {
|
||||
mc.port1.onmessage = evt => {
|
||||
evt.data
|
||||
? controller.enqueue(evt.data) // evt.data is Uint8Array
|
||||
: controller.close() // evt.data is null, means the stream ended
|
||||
rs()
|
||||
}
|
||||
mc.port1.postMessage(true) // send a pull request
|
||||
})
|
||||
},
|
||||
cancel() {
|
||||
// This event is never executed
|
||||
mc.port1.postMessage(false) // send a cancel request
|
||||
}
|
||||
}) : data.body
|
||||
|
||||
return new Response(body, data)
|
||||
})
|
||||
.catch(console.error)
|
||||
)
|
||||
})
|
||||
|
|
@ -48,15 +48,15 @@ WEBTORRENT_ANNOUNCE = announceList
|
|||
var nowPlaying,
|
||||
maxTorrents = 1,
|
||||
subStream
|
||||
function addTorrent(magnet) {
|
||||
async function addTorrent(magnet) {
|
||||
if (client.torrents.length >= maxTorrents) {
|
||||
client.remove(client.torrents[0].infoHash)
|
||||
}
|
||||
halfmoon.hideModal("tsearch")
|
||||
document.location.href = "#player"
|
||||
video.src = ""
|
||||
await sw
|
||||
client.add(magnet, async function (torrent) {
|
||||
video.src = ""
|
||||
await sw
|
||||
function onProgress() {
|
||||
peers.textContent = torrent.numPeers
|
||||
downSpeed.textContent = prettyBytes(torrent.downloadSpeed) + '/s'
|
||||
|
|
|
|||
0
app/offline.html
Normal file
0
app/offline.html
Normal file
104
app/sw.js
Normal file
104
app/sw.js
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
'use strict';
|
||||
|
||||
const CACHE_NAME = 'static-cache-v1';
|
||||
|
||||
const FILES_TO_CACHE = [
|
||||
'offline.html',
|
||||
'app.html',
|
||||
'js/animeHandler.js',
|
||||
'js/bundle.js',
|
||||
'js/playerHandler.js',
|
||||
'js/subtitleHandler.js',
|
||||
'js/torrentHandler.js',
|
||||
'js/util.js',
|
||||
'css/misc.css',
|
||||
'css/player.css',
|
||||
'logo.png'
|
||||
];
|
||||
|
||||
self.addEventListener('install', (evt) => {
|
||||
evt.waitUntil(
|
||||
caches.open(CACHE_NAME).then((cache) => {
|
||||
return cache.addAll(FILES_TO_CACHE);
|
||||
})
|
||||
);
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (evt) => {
|
||||
evt.waitUntil(
|
||||
caches.keys().then((keyList) => {
|
||||
return Promise.all(keyList.map((key) => {
|
||||
if (key !== CACHE_NAME) {
|
||||
return caches.delete(key);
|
||||
}
|
||||
}));
|
||||
})
|
||||
);
|
||||
self.clients.claim();
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', evt => {
|
||||
const { request } = evt
|
||||
const { url, method, headers } = request
|
||||
if (!url.includes(self.registration.scope + 'webtorrent/')) return null
|
||||
|
||||
function getConsumer(clients) {
|
||||
return new Promise(rs => {
|
||||
// Use race condition for whoever controls the response stream
|
||||
for (const client of clients) {
|
||||
const mc = new MessageChannel()
|
||||
const { port1, port2 } = mc
|
||||
port1.onmessage = evt => {
|
||||
rs([evt.data, mc])
|
||||
}
|
||||
client.postMessage({
|
||||
url,
|
||||
method,
|
||||
headers: [...headers],
|
||||
scope: self.registration.scope
|
||||
}, [port2])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
evt.respondWith(
|
||||
clients.matchAll({ type: 'window', includeUncontrolled: true })
|
||||
.then(getConsumer)
|
||||
.then(([data, mc]) => {
|
||||
const body = data.body === 'stream' ? new ReadableStream({
|
||||
pull(controller) {
|
||||
return new Promise(rs => {
|
||||
mc.port1.onmessage = evt => {
|
||||
evt.data
|
||||
? controller.enqueue(evt.data) // evt.data is Uint8Array
|
||||
: controller.close() // evt.data is null, means the stream ended
|
||||
rs()
|
||||
}
|
||||
mc.port1.postMessage(true) // send a pull request
|
||||
})
|
||||
},
|
||||
cancel() {
|
||||
// This event is never executed
|
||||
mc.port1.postMessage(false) // send a cancel request
|
||||
}
|
||||
}) : data.body
|
||||
|
||||
return new Response(body, data)
|
||||
})
|
||||
.catch(console.error)
|
||||
)
|
||||
})
|
||||
|
||||
// self.addEventListener('fetch', (evt) => {
|
||||
// if (evt.request.mode !== 'navigate') {
|
||||
// return;
|
||||
// }
|
||||
// evt.respondWith(
|
||||
// fetch(evt.request)
|
||||
// .catch(async () => {
|
||||
// const cache = await caches.open(CACHE_NAME);
|
||||
// return cache.match('offline.html');
|
||||
// })
|
||||
// );
|
||||
// });
|
||||
56
index.html
56
index.html
|
|
@ -1,34 +1,36 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<html lang="en" class="auto-scaling-disabled">
|
||||
<head>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="Miru">
|
||||
<meta name="description" content="Way too high quality anime for streaming, ad free in a simple solution.">
|
||||
<meta name="theme-color" content="#25282c" />
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="Miru">
|
||||
<meta name="description" content="Anime torrent streaming, ad free in a simple solution.">
|
||||
<meta name="theme-color" content="#111417" />
|
||||
|
||||
<link rel="icon" href="logo.png">
|
||||
<link rel="apple-touch-icon" href="logo.png">
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="apple-touch-icon" href="logo.png">
|
||||
<script>
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register('/sw.js')
|
||||
.then((reg) => {
|
||||
console.log('Service worker registered.', reg);
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<link rel="icon" href="logo.png">
|
||||
<title>Miru - Torrent streaming made simple!</title>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/halfmoon@1.1.0/css/halfmoon-variables.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
test
|
||||
<body class="with-custom-webkit-scrollbars with-custom-css-scrollbars">
|
||||
<div class="page-wrapper">
|
||||
<div class="content-wrapper">
|
||||
test
|
||||
<!--
|
||||
Add your page's main content here
|
||||
Examples:
|
||||
1. https://www.gethalfmoon.com/docs/content-and-cards/#building-a-page
|
||||
2. https://www.gethalfmoon.com/docs/grid-system/#building-a-dashboard
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/halfmoon@1.1.0/js/halfmoon.min.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "Miru",
|
||||
"name": "Miru - Torrent streaming made simple!",
|
||||
"short_name": "Miru",
|
||||
"start_url": "/app/app.html",
|
||||
"display": "standalone",
|
||||
|
|
@ -8,15 +8,20 @@
|
|||
],
|
||||
"lang": "en-US",
|
||||
"orientation": "landscape",
|
||||
"background_color": "#25282c",
|
||||
"theme_color": "#25282c",
|
||||
"background_color": "#111417",
|
||||
"theme_color": "#111417",
|
||||
"scope": "/app/",
|
||||
"description": "Way too high quality anime for streaming, ad free in a simple solution.",
|
||||
"description": "Anime torrent streaming, ad free in a simple solution.",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/logo.png",
|
||||
"sizes": "768x768",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
],
|
||||
"intent_filters": {
|
||||
"scope_url_scheme": "https",
|
||||
"scope_url_host": "miru.moe",
|
||||
"scope_url_path": "/app/"
|
||||
}
|
||||
}
|
||||
54
sw.js
54
sw.js
|
|
@ -1,53 +1 @@
|
|||
'use strict';
|
||||
|
||||
const CACHE_NAME = 'static-cache-v1';
|
||||
|
||||
const FILES_TO_CACHE = [
|
||||
'/offline.html',
|
||||
];
|
||||
|
||||
self.addEventListener('install', (evt) => {
|
||||
console.log('[ServiceWorker] Install');
|
||||
// CODELAB: Precache static resources here.
|
||||
evt.waitUntil(
|
||||
caches.open(CACHE_NAME).then((cache) => {
|
||||
console.log('[ServiceWorker] Pre-caching offline page');
|
||||
return cache.addAll(FILES_TO_CACHE);
|
||||
})
|
||||
);
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (evt) => {
|
||||
console.log('[ServiceWorker] Activate');
|
||||
// CODELAB: Remove previous cached data from disk.
|
||||
evt.waitUntil(
|
||||
caches.keys().then((keyList) => {
|
||||
return Promise.all(keyList.map((key) => {
|
||||
if (key !== CACHE_NAME) {
|
||||
console.log('[ServiceWorker] Removing old cache', key);
|
||||
return caches.delete(key);
|
||||
}
|
||||
}));
|
||||
})
|
||||
);
|
||||
self.clients.claim();
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (evt) => {
|
||||
console.log('[ServiceWorker] Fetch', evt.request.url);
|
||||
// CODELAB: Add fetch event handler here.
|
||||
if (evt.request.mode !== 'navigate') {
|
||||
// Not a page navigation, bail.
|
||||
return;
|
||||
}
|
||||
evt.respondWith(
|
||||
fetch(evt.request)
|
||||
.catch(() => {
|
||||
return caches.open(CACHE_NAME)
|
||||
.then((cache) => {
|
||||
return cache.match('offline.html');
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
self.addEventListener('fetch',(event)=>{});
|
||||
Loading…
Reference in a new issue