mirror of
https://github.com/TheBinaryNinja/tvapp2.git
synced 2026-06-12 20:05:42 -04:00
initial push from external dev branches
This commit is contained in:
116
server/dist/sources/adapters/dulo.js
vendored
Normal file
116
server/dist/sources/adapters/dulo.js
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
// dulo.tv source adapter (Phase 1). Ported from ../d-combine/sources/dulo/adapter.mjs.
|
||||
//
|
||||
// dulo.tv exposes a JSON catalog API and each channel's `source_url` IS a token-free HLS master
|
||||
// playlist. The memfs hosts gate playback behind an Origin allowlist, so the proxy injects
|
||||
// `Origin: https://dulo.tv` on every hop. No server-side resolve is needed.
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { snapshotFile } from '../paths.js';
|
||||
const SNAPSHOT = snapshotFile('dulo');
|
||||
const DULO_ORIGIN = 'https://dulo.tv';
|
||||
const DULO_API = process.env.DULO_API || 'https://dulo.tv/api/live-tv/channels';
|
||||
function isHttpUrl(url) {
|
||||
if (typeof url !== 'string')
|
||||
return false;
|
||||
try {
|
||||
const u = new URL(url);
|
||||
return u.protocol === 'https:' || u.protocol === 'http:';
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function toIso(ts) {
|
||||
if (!ts || typeof ts !== 'string')
|
||||
return null;
|
||||
const d = new Date(ts);
|
||||
return Number.isNaN(d.getTime()) ? null : d.toISOString();
|
||||
}
|
||||
const duloAdapter = {
|
||||
id: 'dulo',
|
||||
label: 'dulo',
|
||||
// Prefer the live catalog API; fall back to the captured snapshot when offline / region-blocked.
|
||||
async listChannels() {
|
||||
try {
|
||||
const res = await fetch(DULO_API, { headers: { Origin: DULO_ORIGIN } });
|
||||
if (!res.ok)
|
||||
throw new Error(`HTTP ${res.status}`);
|
||||
const body = (await res.json());
|
||||
const raw = body.channels || [];
|
||||
if (!raw.length)
|
||||
throw new Error('empty channel list');
|
||||
return { raw, meta: { endpoint: DULO_API, live: true, fetchedAt: new Date().toISOString() } };
|
||||
}
|
||||
catch (err) {
|
||||
const snap = JSON.parse(readFileSync(SNAPSHOT, 'utf8'));
|
||||
return {
|
||||
raw: snap.channels || [],
|
||||
meta: {
|
||||
endpoint: DULO_API,
|
||||
live: false,
|
||||
fallback: 'dulo.snapshot.json',
|
||||
reason: err.message,
|
||||
fetchedAt: new Date().toISOString(),
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
normalize(raw, { ingestedAt }) {
|
||||
const sourceChannelId = String(raw.id);
|
||||
const category = raw.category || null;
|
||||
return {
|
||||
_id: `dulo:${sourceChannelId}`,
|
||||
source: 'dulo',
|
||||
sourceChannelId,
|
||||
name: raw.name,
|
||||
category, // dulo has real semantic categories
|
||||
groupKey: category || 'uncategorized',
|
||||
groupLabel: category || 'uncategorized',
|
||||
logoUrl: raw.logo_url || null,
|
||||
streamEntryUrl: raw.source_url, // token-free master .m3u8 (handed straight to the proxy)
|
||||
isPlayable: isHttpUrl(raw.source_url),
|
||||
sourceCreatedAt: toIso(raw.created_at),
|
||||
sourceUpdatedAt: toIso(raw.updated_at),
|
||||
ingestedAt,
|
||||
};
|
||||
},
|
||||
grouping: { by: 'groupKey', groupOrder: 'alpha', channelOrder: 'name' },
|
||||
isEntryUrl() {
|
||||
return false; // dulo source_url is already the master — nothing to resolve
|
||||
},
|
||||
async resolveStream(entryUrl) {
|
||||
return { masterUrl: entryUrl }; // identity no-op
|
||||
},
|
||||
proxy: {
|
||||
upstreamHeaders() {
|
||||
return { Origin: DULO_ORIGIN }; // the memfs Origin allowlist gate
|
||||
},
|
||||
isAllowedUpstream(url) {
|
||||
try {
|
||||
const u = new URL(url);
|
||||
return (u.protocol === 'https:' || u.protocol === 'http:') && u.hostname.endsWith('.dulo.tv');
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onPlaylistChildHost: null, // static allowlist — nothing to learn at runtime
|
||||
relabelSegmentContentType(_url, contentType) {
|
||||
return contentType || 'application/octet-stream'; // plain TS — pass the upstream type through
|
||||
},
|
||||
classifyArtifact(url) {
|
||||
try {
|
||||
const p = new URL(url).pathname.toLowerCase();
|
||||
if (p.endsWith('.ts'))
|
||||
return 'segment';
|
||||
if (p.endsWith('.m3u8'))
|
||||
return p.includes('_output_') ? 'variant' : 'master';
|
||||
return 'other';
|
||||
}
|
||||
catch {
|
||||
return 'other';
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
export default duloAdapter;
|
||||
//# sourceMappingURL=dulo.js.map
|
||||
1
server/dist/sources/adapters/dulo.js.map
vendored
Normal file
1
server/dist/sources/adapters/dulo.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"dulo.js","sourceRoot":"","sources":["../../../src/sources/adapters/dulo.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,EAAE;AACF,gGAAgG;AAChG,2FAA2F;AAC3F,4EAA4E;AAE5E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;AACtC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,sCAAsC,CAAC;AAEhF,SAAS,SAAS,CAAC,GAAY;IAC7B,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,KAAK,CAAC,EAAW;IACxB,IAAI,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC/C,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC;IACvB,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;AAC5D,CAAC;AAED,MAAM,WAAW,GAAkB;IACjC,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,MAAM;IAEb,iGAAiG;IACjG,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC;YACxE,IAAI,CAAC,GAAG,CAAC,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YACnD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAyB,CAAC;YACxD,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;YAChC,IAAI,CAAC,GAAG,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;YACvD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,EAAE,CAAC;QAChG,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAyB,CAAC;YAChF,OAAO;gBACL,GAAG,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;gBACxB,IAAI,EAAE;oBACJ,QAAQ,EAAE,QAAQ;oBAClB,IAAI,EAAE,KAAK;oBACX,QAAQ,EAAE,oBAAoB;oBAC9B,MAAM,EAAG,GAAa,CAAC,OAAO;oBAC9B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC;aACF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,SAAS,CAAC,GAAQ,EAAE,EAAE,UAAU,EAAE;QAChC,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC;QACtC,OAAO;YACL,GAAG,EAAE,QAAQ,eAAe,EAAE;YAC9B,MAAM,EAAE,MAAM;YACd,eAAe;YACf,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,QAAQ,EAAE,oCAAoC;YAC9C,QAAQ,EAAE,QAAQ,IAAI,eAAe;YACrC,UAAU,EAAE,QAAQ,IAAI,eAAe;YACvC,OAAO,EAAE,GAAG,CAAC,QAAQ,IAAI,IAAI;YAC7B,cAAc,EAAE,GAAG,CAAC,UAAU,EAAE,yDAAyD;YACzF,UAAU,EAAE,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC;YACrC,eAAe,EAAE,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC;YACtC,eAAe,EAAE,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC;YACtC,UAAU;SACX,CAAC;IACJ,CAAC;IAED,QAAQ,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE;IAEvE,UAAU;QACR,OAAO,KAAK,CAAC,CAAC,6DAA6D;IAC7E,CAAC;IACD,KAAK,CAAC,aAAa,CAAC,QAAgB;QAClC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,iBAAiB;IACnD,CAAC;IAED,KAAK,EAAE;QACL,eAAe;YACb,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,kCAAkC;QACpE,CAAC;QACD,iBAAiB,CAAC,GAAW;YAC3B,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;gBACvB,OAAO,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;YAChG,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QACD,mBAAmB,EAAE,IAAI,EAAE,iDAAiD;QAC5E,yBAAyB,CAAC,IAAY,EAAE,WAAmB;YACzD,OAAO,WAAW,IAAI,0BAA0B,CAAC,CAAC,4CAA4C;QAChG,CAAC;QACD,gBAAgB,CAAC,GAAW;YAC1B,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;gBAC9C,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;oBAAE,OAAO,SAAS,CAAC;gBACxC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;oBAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;gBAC9E,OAAO,OAAO,CAAC;YACjB,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,OAAO,CAAC;YACjB,CAAC;QACH,CAAC;KACF;CACF,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
||||
Reference in New Issue
Block a user