@serifpersia/dango 3.6.7 → 3.6.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/client/dist/assets/{AnimeCard-C3P9zWi9.js → AnimeCard-DKDJK8Mp.js} +1 -1
- package/client/dist/assets/{AnimeInfo-Et6687Tl.js → AnimeInfo-CTcvfjva.js} +1 -1
- package/client/dist/assets/{AnimeInfoPage-DX4eNnlH.js → AnimeInfoPage-B_UiacIN.js} +2 -2
- package/client/dist/assets/{Asmr-CCdEWrFi.js → Asmr-DMSN2vxl.js} +2 -2
- package/client/dist/assets/{AsmrResetProgressModal-DgEWBJOw.js → AsmrResetProgressModal-CRwfOatX.js} +1 -1
- package/client/dist/assets/{AvSyncCalibrator-CQ2fjf2E.js → AvSyncCalibrator-CRJsi-vz.js} +1 -1
- package/client/dist/assets/{Home-DUkUTTTy.js → Home-pwmK9_Eh.js} +1 -1
- package/client/dist/assets/{Insights-QCh4xW12.js → Insights-m7kFzg2A.js} +1 -1
- package/client/dist/assets/{LibraryListPage-BoTxRqHz.js → LibraryListPage-C1wpPvu6.js} +1 -1
- package/client/dist/assets/ListeningList-OzfEI1Ga.js +1 -0
- package/client/dist/assets/{Manga-HydR-L7o.js → Manga-ChRCExhK.js} +1 -1
- package/client/dist/assets/{MangaInfoPage-CBakEI9a.js → MangaInfoPage-DSHJPo2A.js} +1 -1
- package/client/dist/assets/{MangaReadPage-DwAR3iPy.js → MangaReadPage-CzOVY1wA.js} +1 -1
- package/client/dist/assets/{MangaResetProgressModal-DGzl8vsO.js → MangaResetProgressModal-CJfzdUBb.js} +1 -1
- package/client/dist/assets/{Mature-Pi0TxKuF.js → Mature-CifQMfhs.js} +1 -1
- package/client/dist/assets/{MediaCard--cuFxOCS.js → MediaCard-CM10yB9V.js} +1 -1
- package/client/dist/assets/{OptionListMenu-B3D39dGS.js → OptionListMenu-6Kovbsqw.js} +1 -1
- package/client/dist/assets/{Player-CsH4x_I_.js → Player-CK0hT-u4.js} +2 -2
- package/client/dist/assets/{PlayerSettings-DGxBsi3F.js → PlayerSettings-Bb66uqT9.js} +1 -1
- package/client/dist/assets/{QueueOptionsButton-Djq4Cpex.js → QueueOptionsButton-C_nTj8_q.js} +1 -1
- package/client/dist/assets/{QueueRail-DOrYgNVX.js → QueueRail-DUK7URAE.js} +1 -1
- package/client/dist/assets/{ReadingList-DwYoBrNk.js → ReadingList-Ck9LJThU.js} +1 -1
- package/client/dist/assets/{ResetProgressModal-CMF86mX6.js → ResetProgressModal-BUphIv0k.js} +1 -1
- package/client/dist/assets/{Search-DFkhuk-x.js → Search-zJyP15h6.js} +1 -1
- package/client/dist/assets/{Settings-DBB2r0VQ.js → Settings-BYdoSEUh.js} +1 -1
- package/client/dist/assets/{SkeletonGrid-DJelJgAv.js → SkeletonGrid-CqgbOhjX.js} +1 -1
- package/client/dist/assets/{Trackers-DGYXFhYZ.js → Trackers-BVjyv6CM.js} +1 -1
- package/client/dist/assets/{Tv-C5MDGD2Z.js → Tv-L13ylswR.js} +1 -1
- package/client/dist/assets/{TvInfo-DrKuK13u.js → TvInfo-Cvcm5U2D.js} +1 -1
- package/client/dist/assets/{TvPopup-DtHilRDT.js → TvPopup-DhxfKvYm.js} +1 -1
- package/client/dist/assets/{TvSearch-CzNxdu_w.js → TvSearch-P8bFE6_X.js} +1 -1
- package/client/dist/assets/{TvWatchlist-D7p4br6S.js → TvWatchlist-D5gVPjtb.js} +1 -1
- package/client/dist/assets/{Watchlist-DrOzswl2.js → Watchlist-Cjq8l3rU.js} +1 -1
- package/client/dist/assets/{hls-BGCX7mJy.js → hls-BkzuANAg.js} +1 -1
- package/client/dist/assets/{index-CnfZwsds.js → index-CLVgzKLk.js} +19 -19
- package/client/dist/assets/{useAnimeInfoData-DYXWBPF-.js → useAnimeInfoData-DZJZu-so.js} +1 -1
- package/client/dist/assets/{useAsmr-BbhQ59bk.js → useAsmr-CvrMGHuo.js} +1 -1
- package/client/dist/assets/useAsmrPopup-Bimy8Ouw.js +1 -0
- package/client/dist/assets/{useMangaLibrary-DuesWQaE.js → useMangaLibrary--MiN11uR.js} +1 -1
- package/client/dist/assets/{useMangaPopup-D57OVGUr.js → useMangaPopup-CR5XhKKS.js} +1 -1
- package/client/dist/assets/{useProviders-mpQb_dix.js → useProviders-DqdT4fA5.js} +1 -1
- package/client/dist/assets/{useTv-DGflCsSI.js → useTv-BL0HMDyP.js} +1 -1
- package/client/dist/assets/{useTvLibrary-BqeSmyc4.js → useTvLibrary-D4U4iqN8.js} +1 -1
- package/client/dist/index.html +1 -1
- package/package.json +3 -5
- package/server/dist/config.js +1 -174
- package/server/dist/server.js +1068 -289
- package/server/dist/shipped-defaults.js +1 -6
- package/server/package.json +4 -5
- package/client/dist/assets/Asmr.module-CdWlioTY.js +0 -1
- package/client/dist/assets/ListeningList-DguKjI_t.js +0 -1
- package/client/dist/assets/Music-BGH_0voi.css +0 -1
- package/client/dist/assets/Music-CQpyXTLH.js +0 -1
- package/client/dist/assets/Radio-CCHNFN7R.css +0 -1
- package/client/dist/assets/Radio-DF6g6odd.js +0 -1
- package/client/dist/assets/Radio.module-DGSZLpKM.js +0 -1
- package/client/dist/assets/useAsmrPopup-SymV1J-b.js +0 -1
- package/server/dist/app-auth.js +0 -157
- package/server/dist/app-hono.js +0 -598
- package/server/dist/db/drizzle.js +0 -16
- package/server/dist/db/schema-anime.js +0 -61
- package/server/dist/db/schema-asmr.js +0 -13
- package/server/dist/db/schema-manga.js +0 -31
- package/server/dist/db/schema-tv.js +0 -18
- package/server/dist/db.js +0 -217
- package/server/dist/discord-gateway.js +0 -385
- package/server/dist/discord-rpc.js +0 -413
- package/server/dist/github-sync.js +0 -508
- package/server/dist/google.js +0 -741
- package/server/dist/hono/asmr.js +0 -10
- package/server/dist/hono/auth.js +0 -49
- package/server/dist/hono/music.js +0 -209
- package/server/dist/hono/proxy.js +0 -827
- package/server/dist/hono/tv.js +0 -200
- package/server/dist/hono/watchlist.js +0 -341
- package/server/dist/lib/anilist.js +0 -1583
- package/server/dist/lib/anischedule.js +0 -191
- package/server/dist/lib/insights.js +0 -185
- package/server/dist/lib/ipc.js +0 -23
- package/server/dist/lib/kitsu.js +0 -517
- package/server/dist/lib/mal-import.js +0 -291
- package/server/dist/lib/mal.js +0 -957
- package/server/dist/lib/migration.js +0 -310
- package/server/dist/lib/offline-db.js +0 -395
- package/server/dist/lib/potoken.js +0 -135
- package/server/dist/lib/recommendations.service.js +0 -216
- package/server/dist/lib/temp-ids.js +0 -3
- package/server/dist/lib/tmdb.js +0 -72
- package/server/dist/lib/tracker/anilist-tracker.js +0 -308
- package/server/dist/lib/tracker/manga-sync.service.js +0 -773
- package/server/dist/lib/tracker/sync-state.js +0 -21
- package/server/dist/lib/tracker/sync.service.js +0 -476
- package/server/dist/lib/translate.js +0 -79
- package/server/dist/lib/ump.js +0 -106
- package/server/dist/lib/ytmusic.js +0 -162
- package/server/dist/logger.js +0 -16
- package/server/dist/providers/manga/manga.types.js +0 -1
- package/server/dist/providers/provider.interface.js +0 -1
- package/server/dist/providers/remote-loader.js +0 -614
- package/server/dist/providers/remote-types.js +0 -159
- package/server/dist/providers/title-matching.js +0 -226
- package/server/dist/providers/tv.types.js +0 -1
- package/server/dist/rclone.js +0 -120
- package/server/dist/repositories/asmr.repository.js +0 -77
- package/server/dist/repositories/insights.repository.js +0 -106
- package/server/dist/repositories/library.repository.js +0 -94
- package/server/dist/repositories/mal-cache.repository.js +0 -52
- package/server/dist/repositories/manga.repository.js +0 -95
- package/server/dist/repositories/notifications.repository.js +0 -60
- package/server/dist/repositories/queue.repository.js +0 -72
- package/server/dist/repositories/settings.repository.js +0 -30
- package/server/dist/repositories/shows-meta.repository.js +0 -58
- package/server/dist/repositories/temp-show-ids.repository.js +0 -63
- package/server/dist/repositories/tv.repository.js +0 -93
- package/server/dist/repositories/watched-episodes.repository.js +0 -82
- package/server/dist/repositories/watchlist.repository.js +0 -60
- package/server/dist/scripts/backfill-episode-duration.js +0 -42
- package/server/dist/sync-payload.js +0 -91
- package/server/dist/sync.js +0 -657
- package/server/dist/trpc/context.js +0 -7
- package/server/dist/trpc/errors.js +0 -15
- package/server/dist/trpc/index.js +0 -18
- package/server/dist/trpc/router.js +0 -49
- package/server/dist/trpc/routers/asmr-library.js +0 -112
- package/server/dist/trpc/routers/asmr-progress.js +0 -121
- package/server/dist/trpc/routers/asmr.js +0 -87
- package/server/dist/trpc/routers/auth.js +0 -194
- package/server/dist/trpc/routers/continue-watching.js +0 -81
- package/server/dist/trpc/routers/data.js +0 -1026
- package/server/dist/trpc/routers/discord.js +0 -285
- package/server/dist/trpc/routers/discovery.js +0 -11
- package/server/dist/trpc/routers/insights.js +0 -14
- package/server/dist/trpc/routers/manga-library.js +0 -263
- package/server/dist/trpc/routers/manga-progress.js +0 -169
- package/server/dist/trpc/routers/manga.js +0 -201
- package/server/dist/trpc/routers/music.js +0 -655
- package/server/dist/trpc/routers/notifications.js +0 -80
- package/server/dist/trpc/routers/progress.js +0 -109
- package/server/dist/trpc/routers/queue.js +0 -93
- package/server/dist/trpc/routers/radio.js +0 -145
- package/server/dist/trpc/routers/settings.js +0 -96
- package/server/dist/trpc/routers/tracker.js +0 -213
- package/server/dist/trpc/routers/tv-library.js +0 -135
- package/server/dist/trpc/routers/tv-progress.js +0 -159
- package/server/dist/trpc/routers/tv.js +0 -551
- package/server/dist/trpc/routers/watchlist.js +0 -550
- package/server/dist/trpc/validation.js +0 -258
- package/server/dist/utils/cache.utils.js +0 -25
- package/server/dist/utils/cookie.utils.js +0 -13
- package/server/dist/utils/db-utils.js +0 -17
- package/server/dist/utils/env.utils.js +0 -77
- package/server/dist/utils/http.utils.js +0 -82
- package/server/dist/utils/request-context.js +0 -2
- package/server/dist/utils/security.utils.js +0 -76
- /package/client/dist/assets/{Asmr-D1KuQwQy.css → useAsmrPopup-D1KuQwQy.css} +0 -0
package/server/dist/hono/asmr.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export function isJasmrApi(mod) {
|
|
2
|
-
if (!mod || typeof mod !== 'object')
|
|
3
|
-
return false;
|
|
4
|
-
const m = mod;
|
|
5
|
-
return (typeof m.browse === 'function' &&
|
|
6
|
-
typeof m.getEpisodes === 'function' &&
|
|
7
|
-
typeof m.getStreamUrls === 'function' &&
|
|
8
|
-
typeof m.getImages === 'function' &&
|
|
9
|
-
typeof m.getChapters === 'function');
|
|
10
|
-
}
|
package/server/dist/hono/auth.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import logger from '../logger.js';
|
|
2
|
-
import { googleDriveService } from '../google.js';
|
|
3
|
-
import { updateEnvFile } from '../utils/env.utils.js';
|
|
4
|
-
export function registerAuth(app, getDbs, runSync) {
|
|
5
|
-
app.get('/api/auth/google/callback', async (c) => {
|
|
6
|
-
const code = c.req.query('code');
|
|
7
|
-
if (!code) {
|
|
8
|
-
return c.text('No code provided', 400);
|
|
9
|
-
}
|
|
10
|
-
await googleDriveService.handleCallback(code);
|
|
11
|
-
const user = await googleDriveService.getUserProfile();
|
|
12
|
-
await updateEnvFile({ SYNC_PROVIDER: 'google' });
|
|
13
|
-
logger.info('User logged in. Syncing database (please wait)...');
|
|
14
|
-
const dbs = getDbs();
|
|
15
|
-
try {
|
|
16
|
-
await runSync(dbs.db, dbs.mangaDb, 'google');
|
|
17
|
-
}
|
|
18
|
-
catch (err) {
|
|
19
|
-
logger.error({ err }, 'Post-login sync failed');
|
|
20
|
-
}
|
|
21
|
-
const responseHtml = `
|
|
22
|
-
<html>
|
|
23
|
-
<head><meta name="viewport" content="width=device-width, initial-scale=1" /></head>
|
|
24
|
-
<body>
|
|
25
|
-
<h1>Authentication Successful</h1>
|
|
26
|
-
<p>Database synced. Returning to dango...</p>
|
|
27
|
-
<p><a href="/?google_auth=success">Tap here if you are not redirected</a></p>
|
|
28
|
-
<script>
|
|
29
|
-
(function () {
|
|
30
|
-
var payload = { type: 'GOOGLE_AUTH_SUCCESS', user: ${JSON.stringify(user)} };
|
|
31
|
-
try {
|
|
32
|
-
if (window.opener && !window.opener.closed) {
|
|
33
|
-
window.opener.postMessage(payload, window.location.origin);
|
|
34
|
-
setTimeout(function () { window.close(); }, 300);
|
|
35
|
-
setTimeout(function () { window.location.href = '/?google_auth=success'; }, 1500);
|
|
36
|
-
} else {
|
|
37
|
-
window.location.href = '/?google_auth=success';
|
|
38
|
-
}
|
|
39
|
-
} catch (e) {
|
|
40
|
-
window.location.href = '/?google_auth=success';
|
|
41
|
-
}
|
|
42
|
-
})();
|
|
43
|
-
</script>
|
|
44
|
-
</body>
|
|
45
|
-
</html>
|
|
46
|
-
`;
|
|
47
|
-
return c.html(responseHtml);
|
|
48
|
-
});
|
|
49
|
-
}
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import logger from '../logger.js';
|
|
2
|
-
import { parseUmpResponse } from '../lib/ump.js';
|
|
3
|
-
import { mintPoToken, resetPoTokens } from '../lib/potoken.js';
|
|
4
|
-
import { getInnertube, getAuthedInnertube, getMusicCookie, refreshAuthedInnertube, } from '../lib/ytmusic.js';
|
|
5
|
-
const UPSTREAM_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:156.0) Gecko/20100101 Firefox/156.0';
|
|
6
|
-
const audioCache = new Map();
|
|
7
|
-
const AUDIO_CACHE_MS = 5 * 60 * 1000;
|
|
8
|
-
const FIRST_CHUNK = 16384;
|
|
9
|
-
const AUDIO_CHUNK = 262144;
|
|
10
|
-
const UMP_CVER = '1.20260920.16.00';
|
|
11
|
-
const audioTotalCache = new Map();
|
|
12
|
-
const umpSessions = new Map();
|
|
13
|
-
function randomCpn() {
|
|
14
|
-
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
15
|
-
let out = '';
|
|
16
|
-
for (let i = 0; i < 16; i++)
|
|
17
|
-
out += chars[Math.floor(Math.random() * chars.length)];
|
|
18
|
-
return out;
|
|
19
|
-
}
|
|
20
|
-
function getUmpSession(videoId) {
|
|
21
|
-
let session = umpSessions.get(videoId);
|
|
22
|
-
if (!session) {
|
|
23
|
-
session = { cpn: randomCpn(), rn: 0, carry: null };
|
|
24
|
-
umpSessions.set(videoId, session);
|
|
25
|
-
}
|
|
26
|
-
return session;
|
|
27
|
-
}
|
|
28
|
-
function boundWindow(clientRange, videoId) {
|
|
29
|
-
const total = audioTotalCache.get(videoId);
|
|
30
|
-
const clamp = (start, end) => {
|
|
31
|
-
if (total !== undefined)
|
|
32
|
-
end = Math.min(end, total - 1);
|
|
33
|
-
return [start, Math.max(end, start)];
|
|
34
|
-
};
|
|
35
|
-
const m = /^bytes=(\d+)-(\d*)$/.exec((clientRange ?? '').trim());
|
|
36
|
-
if (m && m[2] !== '') {
|
|
37
|
-
const s = Number(m[1]);
|
|
38
|
-
const e = Number(m[2]);
|
|
39
|
-
if (e - s + 1 <= AUDIO_CHUNK)
|
|
40
|
-
return [s, e];
|
|
41
|
-
return clamp(s, s + AUDIO_CHUNK - 1);
|
|
42
|
-
}
|
|
43
|
-
const start = m ? Number(m[1]) : 0;
|
|
44
|
-
return clamp(start, start + (start === 0 ? FIRST_CHUNK : AUDIO_CHUNK) - 1);
|
|
45
|
-
}
|
|
46
|
-
async function decipherWith(yt, videoId) {
|
|
47
|
-
const info = await yt.music.getInfo(videoId);
|
|
48
|
-
const streaming = info.streaming_data;
|
|
49
|
-
const formats = streaming?.adaptive_formats ?? [];
|
|
50
|
-
const sorted = [...formats]
|
|
51
|
-
.filter((f) => f.has_audio && !f.has_video)
|
|
52
|
-
.sort((a, b) => (b.bitrate ?? 0) - (a.bitrate ?? 0));
|
|
53
|
-
const player = yt.session.player;
|
|
54
|
-
for (const fmt of sorted) {
|
|
55
|
-
try {
|
|
56
|
-
const url = await fmt.decipher(player);
|
|
57
|
-
if (url && url.startsWith('http')) {
|
|
58
|
-
const entry = { url, mimeType: fmt.mime_type, fetchedAt: Date.now() };
|
|
59
|
-
audioCache.set(videoId, entry);
|
|
60
|
-
return entry;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
// ignore
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
throw new Error('No stream available');
|
|
68
|
-
}
|
|
69
|
-
async function decipherAudio(videoId) {
|
|
70
|
-
const cached = audioCache.get(videoId);
|
|
71
|
-
if (cached && Date.now() - cached.fetchedAt < AUDIO_CACHE_MS)
|
|
72
|
-
return cached;
|
|
73
|
-
const authed = await getAuthedInnertube().catch(() => null);
|
|
74
|
-
if (authed) {
|
|
75
|
-
try {
|
|
76
|
-
return await decipherWith(authed, videoId);
|
|
77
|
-
}
|
|
78
|
-
catch (err) {
|
|
79
|
-
logger.warn({ err }, '[music] authed stream lookup failed, retrying with a fresh saved-cookie session');
|
|
80
|
-
const fresh = await refreshAuthedInnertube();
|
|
81
|
-
if (fresh) {
|
|
82
|
-
try {
|
|
83
|
-
return await decipherWith(fresh, videoId);
|
|
84
|
-
}
|
|
85
|
-
catch (retryErr) {
|
|
86
|
-
logger.warn({ err: retryErr }, '[music] refreshed stream lookup failed, falling back to public session');
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return decipherWith(await getInnertube(), videoId);
|
|
92
|
-
}
|
|
93
|
-
export function registerMusic(app) {
|
|
94
|
-
app.get('/api/music/stream', async (c) => {
|
|
95
|
-
const videoId = String(c.req.query('videoId') || c.req.query('id') || '').trim();
|
|
96
|
-
if (!videoId)
|
|
97
|
-
return c.json({ error: 'videoId is required' }, 400);
|
|
98
|
-
try {
|
|
99
|
-
const entry = await decipherAudio(videoId);
|
|
100
|
-
return c.json({ url: entry.url, mimeType: entry.mimeType });
|
|
101
|
-
}
|
|
102
|
-
catch (err) {
|
|
103
|
-
logger.error({ err }, '[music] stream failed');
|
|
104
|
-
return c.json({ error: 'Stream lookup failed' }, 502);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
app.get('/api/music/audio', async (c) => {
|
|
108
|
-
const videoId = String(c.req.query('videoId') || c.req.query('id') || '').trim();
|
|
109
|
-
if (!videoId)
|
|
110
|
-
return c.json({ error: 'videoId is required' }, 400);
|
|
111
|
-
const signal = c.req.raw.signal.aborted
|
|
112
|
-
? c.req.raw.signal
|
|
113
|
-
: AbortSignal.any([c.req.raw.signal, AbortSignal.timeout(30000)]);
|
|
114
|
-
try {
|
|
115
|
-
for (let attempt = 0; attempt < 3; attempt++) {
|
|
116
|
-
if (attempt === 1)
|
|
117
|
-
umpSessions.delete(videoId);
|
|
118
|
-
if (attempt === 2) {
|
|
119
|
-
audioCache.delete(videoId);
|
|
120
|
-
umpSessions.delete(videoId);
|
|
121
|
-
resetPoTokens(videoId);
|
|
122
|
-
}
|
|
123
|
-
let entry;
|
|
124
|
-
try {
|
|
125
|
-
entry = await decipherAudio(videoId);
|
|
126
|
-
}
|
|
127
|
-
catch {
|
|
128
|
-
return c.json({ error: 'No stream available' }, 502);
|
|
129
|
-
}
|
|
130
|
-
const clen = /[?&]clen=(\d+)/.exec(entry.url)?.[1];
|
|
131
|
-
if (clen && !audioTotalCache.has(videoId))
|
|
132
|
-
audioTotalCache.set(videoId, Number(clen));
|
|
133
|
-
const [rangeStart, rangeEnd] = boundWindow(c.req.header('range') ?? null, videoId);
|
|
134
|
-
const session = getUmpSession(videoId);
|
|
135
|
-
let pot = '';
|
|
136
|
-
try {
|
|
137
|
-
pot = await mintPoToken(videoId);
|
|
138
|
-
}
|
|
139
|
-
catch (err) {
|
|
140
|
-
logger.warn({ err }, '[music] PoToken mint failed, trying without attestation');
|
|
141
|
-
}
|
|
142
|
-
const upstreamUrl = `${entry.url}&cpn=${session.cpn}&cver=${UMP_CVER}` +
|
|
143
|
-
`&range=${rangeStart}-${rangeEnd}&rn=${session.rn}&rbuf=0` +
|
|
144
|
-
(pot ? `&pot=${encodeURIComponent(pot)}` : '') +
|
|
145
|
-
`&ump=1&srfvp=1`;
|
|
146
|
-
session.rn += 1;
|
|
147
|
-
let raw;
|
|
148
|
-
try {
|
|
149
|
-
const cookie = getMusicCookie();
|
|
150
|
-
const upstream = await fetch(upstreamUrl, {
|
|
151
|
-
method: 'POST',
|
|
152
|
-
headers: {
|
|
153
|
-
'User-Agent': UPSTREAM_UA,
|
|
154
|
-
Referer: 'https://music.youtube.com/',
|
|
155
|
-
Origin: 'https://music.youtube.com/',
|
|
156
|
-
...(cookie ? { Cookie: cookie } : {}),
|
|
157
|
-
},
|
|
158
|
-
body: 'x\x00',
|
|
159
|
-
signal,
|
|
160
|
-
});
|
|
161
|
-
if (upstream.status !== 200) {
|
|
162
|
-
try {
|
|
163
|
-
await upstream.body?.cancel();
|
|
164
|
-
}
|
|
165
|
-
catch {
|
|
166
|
-
// ignore
|
|
167
|
-
}
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
raw = Buffer.from(await upstream.arrayBuffer());
|
|
171
|
-
}
|
|
172
|
-
catch (err) {
|
|
173
|
-
if (c.req.raw.signal.aborted)
|
|
174
|
-
return new Response(null, { status: 499 });
|
|
175
|
-
logger.error({ err }, '[music] audio upstream failed');
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
const parsed = parseUmpResponse(raw, session.carry);
|
|
179
|
-
session.carry = parsed.carry;
|
|
180
|
-
if (parsed.status === 3) {
|
|
181
|
-
logger.warn({ videoId }, '[music] stream protection blocked, refreshing token');
|
|
182
|
-
resetPoTokens(videoId);
|
|
183
|
-
umpSessions.delete(videoId);
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
if (parsed.media.length === 0)
|
|
187
|
-
continue;
|
|
188
|
-
const total = audioTotalCache.get(videoId);
|
|
189
|
-
const headers = new Headers();
|
|
190
|
-
headers.set('Content-Type', entry.mimeType || 'audio/webm');
|
|
191
|
-
headers.set('Content-Length', String(parsed.media.length));
|
|
192
|
-
if (total) {
|
|
193
|
-
headers.set('Content-Range', `bytes ${rangeStart}-${rangeStart + parsed.media.length - 1}/${total}`);
|
|
194
|
-
}
|
|
195
|
-
headers.set('Accept-Ranges', 'bytes');
|
|
196
|
-
headers.set('Access-Control-Allow-Origin', '*');
|
|
197
|
-
return new Response(parsed.media, { status: 206, headers });
|
|
198
|
-
}
|
|
199
|
-
logger.warn({ videoId }, '[music] audio upstream gave no media after retries');
|
|
200
|
-
return c.json({ error: 'Upstream error' }, 502);
|
|
201
|
-
}
|
|
202
|
-
catch (err) {
|
|
203
|
-
if (c.req.raw.signal.aborted)
|
|
204
|
-
return new Response(null, { status: 499 });
|
|
205
|
-
logger.error({ err }, '[music] audio failed');
|
|
206
|
-
return c.json({ error: 'Stream lookup failed' }, 502);
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
}
|