From 27bf48eb05a7c2ca2500ed899cc6ea0ead3b6de5 Mon Sep 17 00:00:00 2001 From: DebaucheryLibrarian Date: Mon, 2 Feb 2026 02:44:51 +0100 Subject: [PATCH] Improved handling of failed video stream fetching. Added proper Little Caprice album URL retrieval. --- src/media.js | 31 +++++++++++++++--------- src/scrapers/littlecapricedreams.js | 37 ++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/src/media.js b/src/media.js index da3d799e..dab65db5 100755 --- a/src/media.js +++ b/src/media.js @@ -672,22 +672,31 @@ async function fetchHttpSource(source, tempFileTarget, hashStream) { streamQueue.define('fetchStreamSource', async ({ source, tempFileTarget, hashStream }) => { const meta = { mimetype: 'video/mp4' }; - const video = ffmpeg(source.stream) + const command = ffmpeg(source.stream) .format('mp4') .outputOptions(['-movflags frag_keyframe+empty_moov']) - .on('start', (cmd) => logger.verbose(`Fetching stream from ${source.stream} with "${cmd}"`)) - .on('error', (error) => { - logger.error(`Failed to fetch stream from ${source.stream}: ${error.message}`); + .on('start', (cmd) => logger.verbose(`Fetching stream from ${source.stream} with "${cmd}"`)); - hashStream.end(); - tempFileTarget.end(); - }) - .pipe(); + const video = command.pipe(); - // await pipeline(video, hashStream, tempFileTarget); - await stream.promises.pipeline(video, hashStream, tempFileTarget); + await Promise.all([ + stream.promises.pipeline(video, hashStream, tempFileTarget), + new Promise((resolve, reject) => { + command.on('error', (error) => { + logger.error(`Failed to fetch stream from ${source.stream}: ${error.message}`); - logger.verbose(`Finished fetching stream from ${source.stream}`); + hashStream.end(); + tempFileTarget.end(); + + reject(error); + }); + + command.on('end', () => { + logger.verbose(`Finished fetching stream from ${source.stream}`); + resolve(); + }); + }), + ]); return meta; }, { diff --git a/src/scrapers/littlecapricedreams.js b/src/scrapers/littlecapricedreams.js index 4e11bc6e..e18db30c 100755 --- a/src/scrapers/littlecapricedreams.js +++ b/src/scrapers/littlecapricedreams.js @@ -82,14 +82,37 @@ async function fetchLatest(channel) { return res.status; } -async function attachPhotos(url, release) { - if (url) { - const res = await unprint.get(url); +async function fetchAlbumUrl(sceneUrl) { + // Upjax-Action query is redundant, but imitates original request + const res = await unprint.get(`${sceneUrl}?endpoint_request_timestamp=${Math.floor(Date.now() / 1000)}&Upjax-Action=lcd.project.actions`, { + headers: { + Referer: sceneUrl, + 'Upjax-Action': 'lcd.project.actions', + 'Upjax-Method': 'GET', + }, + }); + + if (res.ok) { + const albumUrl = res.data.js?.match(/"(https.*?)"/)?.[1]; + + if (albumUrl) { + return albumUrl; + } + } + + return null; +} + +async function attachPhotos(sceneUrl, release) { + const albumUrl = await fetchAlbumUrl(sceneUrl); + + if (albumUrl) { + const res = await unprint.get(albumUrl); if (res.ok) { release.photos = res.context.query.imgs('.gallery img').map((imgUrl) => ({ // eslint-disable-line no-param-reassign src: imgUrl, - referer: url, + referer: sceneUrl, })); release.photoCount = res.context.query.number('.image-amount'); // eslint-disable-line no-param-reassign @@ -126,7 +149,7 @@ async function scrapeScene({ query }, { url, include }) { }; if (include.photos) { - await attachPhotos(url.replace(/(\/)?$/, '-2$1'), release); + await attachPhotos(url, release); } const trailerFrame = query.url('.video iframe', { attribute: 'src' }); @@ -134,14 +157,12 @@ async function scrapeScene({ query }, { url, include }) { if (trailerId) { release.trailer = { - stream: `https://trailer.littlecaprice-dreams.com/${trailerId}/1920x1080/video.m3u8`, + stream: `https://trailer.littlecaprice-dreams.com/${trailerId}/playlist.m3u8`, quality: 1080, referer: url, }; } - console.log(release.trailer); - const channelSlug = slugify(query.content('.project-tags a[href*="collection/"]'), ''); release.channel = channelMap[channelSlug] || channelSlug;