diff --git a/index.js b/index.js index 2f935dd..066beb1 100644 --- a/index.js +++ b/index.js @@ -18,7 +18,7 @@ const EventEmitter = require('events'); // Configuration const PORT = process.env.PORT || 9520; const API_BASE = 'http://183.6.121.121:9558/api'; -const CACHE_DIR = process.env.CACHE_DIR ? path.resolve(process.env.CACHE_DIR) : path.join(__dirname, '.cache'); +const CACHE_DIR = path.join(__dirname, '.cache'); // Ensure cache directory exists if (!fs.existsSync(CACHE_DIR)) { @@ -177,12 +177,21 @@ async function generateThumbAndCache(reply, apiData, contentPath) { if (contentType.includes('video/')) { console.log('Generating video thumb:', srcPath); - const thumbTemp = path.join(dir, base.replace('.data', `.thumb.webp.tmp`)); + const thumbFrameTemp = path.join(dir, base.replace('.data', `.thumb.frame.png.tmp`)); const { spawn } = require('child_process'); - const args = ['-ss', '1', '-i', srcPath, '-frames:v', '1', '-vf', `scale=${width}:-2`, '-y', thumbTemp]; - await new Promise((resolve, reject) => { const p = spawn('ffmpeg', args, { stdio: 'ignore' }); p.on('error', reject); p.on('close', c => c === 0 ? resolve() : reject(new Error(`ffmpeg exit ${c}`))); }); + const args = ['-hide_banner', '-loglevel', 'error', '-nostdin', '-ss', '1', '-i', srcPath, '-frames:v', '1', '-vf', `scale=${width}:-2`, '-f', 'image2', '-vcodec', 'png', '-y', thumbFrameTemp]; + await new Promise((resolve, reject) => { + let err = ''; + const p = spawn('ffmpeg', args, { stdio: ['ignore', 'ignore', 'pipe'] }); + if (p.stderr) p.stderr.on('data', d => { err += d.toString(); }); + p.on('error', reject); + p.on('close', c => c === 0 ? resolve() : reject(new Error(`ffmpeg exit ${c}${err ? ': ' + err.trim() : ''}`))); + }); + const thumbTemp = path.join(dir, base.replace('.data', `.thumb.tmp`)); + await sharp(thumbFrameTemp).webp({ quality: 80 }).toFile(thumbTemp); try { fs.renameSync(thumbTemp, thumbFinal); } catch (e) { if (fs.existsSync(thumbFinal)) { try { fs.unlinkSync(thumbFinal); } catch (_) { } fs.renameSync(thumbTemp, thumbFinal); } else { throw e; } } - await fs.promises.writeFile(metaThumbPath, JSON.stringify({ api: apiData, headers: apiData.data.headers || {}, srcSize: stat.size, inputFormat: 'video' })); + await fs.promises.writeFile(metaThumbPath, JSON.stringify({ api: apiData, headers: apiData.data.headers || {}, srcSize: stat.size, inputFormat: 'webp' })); + try { if (fs.existsSync(thumbFrameTemp)) fs.unlinkSync(thumbFrameTemp); } catch (_) { } const tstat = fs.statSync(thumbFinal); reply.headers({ 'Content-Type': 'image/webp', 'Content-Length': tstat.size, 'Accept-Ranges': 'bytes', 'Access-Control-Allow-Origin': '*' }); return fs.createReadStream(thumbFinal); diff --git a/new.js b/new.js index e414ea7..2ba9cef 100644 --- a/new.js +++ b/new.js @@ -7,7 +7,7 @@ const crypto = require('crypto'); const EventEmitter = require('events'); // Configuration -const PORT = 9520; +const PORT = process.env.PORT || 9520; const API_BASE = 'http://127.0.0.1:9558/api'; const CACHE_DIR = process.env.CACHE_DIR ? path.resolve(process.env.CACHE_DIR) : path.join(__dirname, '.cache');