UNPKG

novel-opds-now

Version:

按需生成 epub,此模組不使用排程任務來生成 epub

237 lines 10.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.removeTempOutputDir = void 0; const tslib_1 = require("tslib"); const express_1 = require("express"); const bluebird_1 = (0, tslib_1.__importDefault)(require("bluebird")); const const_1 = require("novel-downloader/src/all/const"); const path_1 = require("path"); const fs_extra_1 = require("fs-extra"); const stream_1 = require("stream"); const util_1 = require("novel-downloader/src/all/util"); const logger_1 = (0, tslib_1.__importDefault)(require("debug-color2/logger")); const store_1 = require("../lib/store"); const content_disposition_1 = (0, tslib_1.__importDefault)(require("@lazy-http/content-disposition")); const showClient_1 = require("./util/showClient"); const ipfs_1 = require("../lib/store/ipfs"); const mimeFromBuffer_1 = require("../lib/util/mimeFromBuffer"); const doPackEpubFromSource_1 = require("../lib/doPackEpubFromSource"); const getNovelData_1 = require("../lib/site/cached-data/getNovelData"); const siteNeverExpired_1 = require("../lib/site/siteNeverExpired"); const demonovel_1 = require("./router/file/demonovel"); const epubProcessCacheJson_1 = require("../lib/epub/epubProcessCacheJson"); const use_1 = require("../lib/ipfs/use"); function fileHandler() { const router = (0, express_1.Router)(); router.use('/demo(novel)?', (0, demonovel_1.demoNovelFileHandler)()); router.use('/:siteID/:novelID', (req, res) => { let query = { ...req.params, ...req.query, }; delete query.siteID; delete query.id; logger_1.default.debug(req.method, req.baseUrl, req.url, req.params, query); (0, showClient_1.showClient)(req, res); let siteID = String(req.params.siteID || '') .trim() .replace(/\.xml$|[\/\\]+/ig, ''); let novel_id = String(req.params.novelID || '') .trim(); if (siteID.toLowerCase() === 'dmzj') { siteID = const_1.EnumNovelSiteList.NovelSiteDmzjApi; } let IDKEY = (0, util_1.siteID2IDKEY)(siteID); if (siteID === 'masiro') { IDKEY = 'masiro'; } return bluebird_1.default .resolve(IDKEY) .tap(IDKEY => { if (!IDKEY) { return Promise.reject(new Error(`${siteID} 模組不存在`)); } if (!novel_id) { return Promise.reject(new Error(`沒有指定需要下載的 id: '${novel_id}'`)); } }) .then(async () => { logger_1.default.info(`檢查是否存在緩存...`, siteID, novel_id); return (0, ipfs_1.getIPFSEpubFile)(IDKEY, [ req.params.novelID, novel_id, ], { query, }) .tap(gunData => { if (gunData === null || gunData === void 0 ? void 0 : gunData.exists) { let msg = ''; if (!(0, siteNeverExpired_1.siteNeverExpired)(siteID) && (query.debug || query.force)) { let mod = ` FORCE 模式`; if (query.debug) { mod = ` DEBUG 模式`; } msg = `,但${mod}已啟動,將試圖先從原始網站抓取更新`; } else if (!gunData.isGun) { msg = `,但已超過緩存時間,將試圖先從原始網站抓取更新`; } logger_1.default.yellow.info(`於緩存發現檔案${msg}...`, new Date(gunData.timestamp), siteID, novel_id); } else { logger_1.default.yellow.info(`沒有發現緩存,或緩存已損毀...`, siteID, novel_id); } }); }) .then(async (gunData) => { return Promise.resolve() .then(async () => { if ((gunData === null || gunData === void 0 ? void 0 : gunData.isGun) || (0, siteNeverExpired_1.siteNeverExpired)(siteID)) { return gunData; } let cp = await (0, doPackEpubFromSource_1.doPackEpubFromSource)(siteID, novel_id); if (cp.error) { return Promise.reject(cp.error); } let _data = await (0, epubProcessCacheJson_1.getEpubProcessCacheJson)(IDKEY, novel_id); if (!gunData && !_data) { gunData = await (0, store_1.getGunEpubFile2)([ IDKEY, ], [ req.params.novelID, novel_id, ], { query, }); if (gunData) { return gunData; } } if (!_data) { return Promise.reject(new Error(`建立檔案時失敗,${siteID} ${novel_id} 可能不存在或解析失敗...`)); } else if (_data.status === 504) { let e = new Error(`抓取 ${siteID} ${novel_id} 來源時失敗,伺服器可能忙碌或拒絕回應,請之後再重試...`); e.StatusCode = 504; return Promise.reject(e); } (0, epubProcessCacheJson_1.deleteEpubProcessCacheJson)(IDKEY, novel_id, _data); return _data; }) .catch(e => { if (gunData && gunData.exists) { logger_1.default.warn(`檔案建立失敗,使用P2P緩存代替`, siteID, novel_id); gunData.isGun = true; return gunData; } return Promise.reject(e); }); }) .then(async (data) => { var _a; const novelData = await (0, getNovelData_1.getNovelData)(siteID, novel_id); logger_1.default.success(`成功取得檔案...`, siteID, novel_id, novelData === null || novelData === void 0 ? void 0 : novelData.title); let fileContents; let isFromBuffer; if (data.base64) { let buf = Buffer.from(data.base64); if (buf.length) { fileContents = buf; isFromBuffer = true; } } if (!fileContents) { fileContents = await (0, fs_extra_1.readFile)(data.epub); } removeTempOutputDir(query, data); let filename = data.filename || IDKEY + '_' + (0, path_1.basename)(data.epub); if (!data.isGun || true) { logger_1.default.debug(`將檔案儲存到P2P緩存`, siteID, novel_id, novelData === null || novelData === void 0 ? void 0 : novelData.title); let gunData = { timestamp: isFromBuffer && data.timestamp ? data.timestamp : Date.now(), exists: true, filename, base64: isFromBuffer ? data.base64 : fileContents, }; (0, ipfs_1.putIPFSEpubFile)([ IDKEY, ], [ novel_id, req.params.novelID, data.novel_id, data.novel_id2, novel_id, ], gunData, {}); } if ((_a = res.connection) === null || _a === void 0 ? void 0 : _a.destroyed) { logger_1.default.info(`客戶端 ( ${req.clientIp} ) 已斷線,停止傳送檔案`, siteID, novel_id, novelData === null || novelData === void 0 ? void 0 : novelData.title); res.end(); } else { let readStream = new stream_1.PassThrough(); readStream.end(fileContents); let { mime, ext } = await (0, mimeFromBuffer_1.mimeFromBuffer)(fileContents); let http_filename = filename; if (query.filename) { http_filename = String(query.filename); } let attachment = (0, content_disposition_1.default)(http_filename); try { res.set('Content-disposition', attachment); } catch (e) { } res.set('Content-Type', mime); let cid; if (data === null || data === void 0 ? void 0 : data.href) { cid = new URL(data.href).pathname; } else { cid = await (0, use_1.getIPFSFromCache)().then(ipfs => ipfs.files.stat(`/novel-opds-now/${IDKEY}/${novel_id}/${filename}`)).then(r => '/ipfs/' + r.cid.toString()).catch(e => null); } if (cid === null || cid === void 0 ? void 0 : cid.length) { res.set('X-Ipfs-Path', cid); } logger_1.default.info(`將檔案傳送至客戶端 ( ${req.clientIp} )...`, filename, (filename !== http_filename) ? `=> ${http_filename}` : '', novelData === null || novelData === void 0 ? void 0 : novelData.title); readStream.pipe(res); } }) .catch(e => { let { message } = e; if (e.code === 'ENOENT') { message = `id 不存在 或 伺服器離線`; } let data = { error: message, params: req.params, timestamp: Date.now(), }; res.status(404).json(data); logger_1.default.warn(data, siteID, novel_id); logger_1.default.debug(`以下錯誤訊息為除錯用,並非每個都會對程式造成影響 =>`, e, siteID, novel_id); }); }); return router; } function removeTempOutputDir(query, data) { return bluebird_1.default.resolve().delay(30 * 1000) .then(() => { if (query.debug) { logger_1.default.debug(`忽略刪除下載暫存 ${data.outputDir}`); } else if (typeof data.removeCallback === 'function') { return data.removeCallback(); } else if (data.outputDir) { return (0, fs_extra_1.remove)(data.outputDir); } }) .catch(e => { logger_1.default.warn(`removeTempOutputDir`, e); }); } exports.removeTempOutputDir = removeTempOutputDir; exports.default = fileHandler; //# sourceMappingURL=file.js.map