fix playback: vendor hls.js locally, surface stream/API errors visibly
- jsdelivr CDN was a silent single point of failure (Hls undefined -> unhandled rejection -> black screen with no feedback) - play() now catches API errors; hls fatal + video media errors render 'Stream error: ...' under the player - server now binds 0.0.0.0 (LAN access); was 127.0.0.1 only
This commit is contained in:
1 parent
e4dde86d85
commit
6c752ae5bc
3 files changed
+22
-2
No files matched your search
+19
-1
@@ -24,6 +24,12 @@ function fail(err) {
|
|||||||
main.append(el("p", "error", "Error: " + err.message));
|
main.append(el("p", "error", "Error: " + err.message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showStreamError(msg) {
|
||||||
|
const p = el("p", "error", "Stream error: " + msg);
|
||||||
|
const player = document.getElementById("player");
|
||||||
|
if (player) player.append(p); else fail(new Error(msg));
|
||||||
|
}
|
||||||
|
|
||||||
// ---------- history ----------
|
// ---------- history ----------
|
||||||
const HKEY = "aniweb.history";
|
const HKEY = "aniweb.history";
|
||||||
const hist = () => JSON.parse(localStorage.getItem(HKEY) || "[]");
|
const hist = () => JSON.parse(localStorage.getItem(HKEY) || "[]");
|
||||||
@@ -139,14 +145,26 @@ function videoEl() {
|
|||||||
function stopHls() { if (hls) { hls.destroy(); hls = null; } }
|
function stopHls() { if (hls) { hls.destroy(); hls = null; } }
|
||||||
|
|
||||||
async function play(ep_id, ep_no) {
|
async function play(ep_id, ep_no) {
|
||||||
|
try {
|
||||||
const s = await api(`/api/episode/${ep_id}/stream?lang=${lang}`);
|
const s = await api(`/api/episode/${ep_id}/stream?lang=${lang}`);
|
||||||
stopHls();
|
stopHls();
|
||||||
const v = videoEl();
|
const v = videoEl();
|
||||||
document.getElementById("player").replaceChildren(v);
|
document.getElementById("player").replaceChildren(v);
|
||||||
if (!Hls.isSupported()) throw new Error("HLS not supported in this browser");
|
if (!window.Hls || !Hls.isSupported()) throw new Error("HLS not supported in this browser");
|
||||||
hls = new Hls();
|
hls = new Hls();
|
||||||
|
hls.on(Hls.Events.ERROR, (_, data) => {
|
||||||
|
if (data.fatal) {
|
||||||
|
showStreamError(`${data.type}: ${data.details}` +
|
||||||
|
(data.response ? ` (HTTP ${data.response.code})` : ""));
|
||||||
|
stopHls();
|
||||||
|
}
|
||||||
|
});
|
||||||
hls.loadSource("/stream/" + s.token);
|
hls.loadSource("/stream/" + s.token);
|
||||||
hls.attachMedia(v);
|
hls.attachMedia(v);
|
||||||
|
v.onerror = () => showStreamError("media error: " + (v.error?.message || v.error?.code));
|
||||||
|
} catch (e) {
|
||||||
|
showStreamError(e.message);
|
||||||
|
}
|
||||||
pushHistory({title: detail.name, slug_id: detail.slug_id, season_id: seasonId,
|
pushHistory({title: detail.name, slug_id: detail.slug_id, season_id: seasonId,
|
||||||
ep_id, lang, ep: ep_no});
|
ep_id, lang, ep: ep_no});
|
||||||
document.title = `${detail.name} E${ep_no} — ani-web`;
|
document.title = `${detail.name} E${ep_no} — ani-web`;
|
||||||
|
|||||||
Vendored
+2
@@ -0,0 +1,2 @@
|
|||||||
|
!function t(e){var r,i;r=this,i=function(){"use strict";function r(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.push.apply(r,i)}return r}function i(t){for(var e=1;e<arguments.length;e++){var i=null!=arguments[e]?arguments[e]:{};e%2?r(Object(i),!0).forEach((function(e){var r,a,s;r=t,a=e,s=i[e],(a=n(a))in r?Object.defineProperty(r,a,{value:s,enumerable:!0,configurable:!0,writable:!0}):r[a]=s})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(i)):r(Object(i)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(i,e))}))}return t}function n(t){var e=function(t,e){if("object"!=typeof t||!t)return t;var r=t[Symbol.toPrimitive];if(void 0!==r){var i=r.call(t,e||"default");if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===e?String:Number)(t)}(t,"string");return"symbol"==typeof e?e:String(e)}function a(t,e){for(var r=0;r<e.length;r++){var i=e[r];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,n(i.key),i)}}function s(t,e,r){return e&&a(t.prototype,e),r&&a(t,r),Object.defineProperty(t,"prototype",{writable:!1}),t}function o(){return o=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var i in r)Object.prototype.hasOwnProperty.call(r,i)&&(t[i]=r[i])}return t},o.apply(this,arguments)}function l(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,h(t,e)}function u(t){return u=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)},u(t)}function h(t,e){return h=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t},h(t,e)}function d(t,e,r){return d=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}()?Reflect.construct.bind():function(t,e,r){var i=[null];i.push.apply(i,e);var n=new(Function.bind.apply(t,i));return r&&h(n,r.prototype),n},d.apply(null,arguments)}function c(t){var e="function"==typeof Map?new Map:void 0;return c=function(t){if(null===t||!function(t){try{return-1!==Function.toString.call(t).indexOf("[native code]")}catch(e){return"function"==typeof t}}(t))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,r)}function r(){return d(t,arguments,u(this).constructor)}return r.prototype=Object.create(t.prototype,{constructor:{value:r,enumerable:!1,writable:!0,configurable:!0}}),h(r,t)},c(t)}function f(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,i=new Array(e);r<e;r++)i[r]=t[r];return i}function g(t,e){var r="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(r)return(r=r.call(t)).next.bind(r);if(Array.isArray(t)||(r=function(t,e){if(t){if("string"==typeof t)return f(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);return"Object"===r&&t.constructor&&(r=t.constructor.name),"Map"===r||"Set"===r?Array.from(t):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?f(t,e):void 0}}(t))||e&&t&&"number"==typeof t.length){r&&(t=r);var i=0;return function(){return i>=t.length?{done:!0}:{done:!1,value:t[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function v(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var m={exports:{}};!function(t,e){var r,i,n,a,s;r=/^(?=((?:[a-zA-Z0-9+\-.]+:)?))\1(?=((?:\/\/[^\/?#]*)?))\2(?=((?:(?:[^?#\/]*\/)*[^;?#\/]*)?))\3((?:;[^?#]*)?)(\?[^#]*)?(#[^]*)?$/,i=/^(?=([^\/?#]*))\1([^]*)$/,n=/(?:\/|^)\.(?=\/)/g,a=/(?:\/|^)\.\.\/(?!\.\.\/)[^\/]*(?=\/)/g,s={buildAbsoluteURL:function(t,e,r){if(r=r||{},t=t.trim(),!(e=e.trim())){if(!r.alwaysNormalize)return t;var n=s.parseURL(t);if(!n)throw new Error("Error trying to parse base URL.");return n.path=s.normalizePath(n.path),s.buildURLFromParts(n)}var a=s.parseURL(e);if(!a)throw new Error("Error trying to parse relative URL.");if(a.scheme)return r.alwaysNormalize?(a.path=s.normalizePath(a.path),s.buildURLFromParts(a)):e;var o=s.parseURL(t);if(!o)throw new Error("Error trying to parse base URL.");if(!o.netLoc&&o.path&&"/"!==o.path[0]){var l=i.exec(o.path);o.netLoc=l[1],o.path=l[2]}o.netLoc&&!o.path&&(o.path="/");var u={scheme:o.scheme,netLoc:a.netLoc,path:null,params:a.params,query:a.query,fragment:a.fragment};if(!a.netLoc&&(u.netLoc=o.netLoc,"/"!==a.path[0]))if(a.path){var h=o.path,d=h.substring(0,h.lastIndexOf("/")+1)+a.path;u.path=s.normalizePath(d)}else u.path=o.path,a.paramsLine truncated
|
||||||
|
//# sourceMappingURL=hls.min.js.map
|
||||||
+1
-1
@@ -14,7 +14,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</header>
|
</header>
|
||||||
<main id="main"><p class="muted">Search for an anime to get started.</p></main>
|
<main id="main"><p class="muted">Search for an anime to get started.</p></main>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/hls.min.js"></script>
|
<script src="hls.min.js"></script>
|
||||||
<script src="app.js"></script>
|
<script src="app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in new issue
Block a user