patreon-dl 3.7.0 → 3.8.0
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 +29 -1
- package/dist/browse/api/CampaignAPIMixin.d.ts +1 -1
- package/dist/browse/api/ContentAPIMixin.d.ts +3 -3
- package/dist/browse/api/FilterAPIMixin.d.ts +1 -1
- package/dist/browse/api/index.d.ts +10 -10
- package/dist/browse/db/CampaignDBMixin.d.ts +3 -3
- package/dist/browse/db/ContentDBMixin.d.ts +13 -13
- package/dist/browse/db/index.d.ts +16 -16
- package/dist/browse/web/assets/index-CQnQD2xz.css +1 -0
- package/dist/browse/web/assets/index-CtZbx-Du.js +218 -0
- package/dist/browse/web/index.html +2 -2
- package/dist/cli/CLIOptions.js +2 -0
- package/dist/cli/CLIOptions.js.map +1 -1
- package/dist/cli/CommandLineParser.d.ts +4 -0
- package/dist/cli/CommandLineParser.js +65 -32
- package/dist/cli/CommandLineParser.js.map +1 -1
- package/dist/cli/ConfigFileParser.js +2 -0
- package/dist/cli/ConfigFileParser.js.map +1 -1
- package/dist/cli/helper/PostList.d.ts +6 -0
- package/dist/cli/helper/PostList.js +106 -0
- package/dist/cli/helper/PostList.js.map +1 -0
- package/dist/cli/index.js +73 -53
- package/dist/cli/index.js.map +1 -1
- package/dist/downloaders/Bootstrap.d.ts +5 -0
- package/dist/downloaders/Bootstrap.js +10 -0
- package/dist/downloaders/Bootstrap.js.map +1 -1
- package/dist/downloaders/Downloader.d.ts +4 -4
- package/dist/downloaders/Downloader.js +5 -58
- package/dist/downloaders/Downloader.js.map +1 -1
- package/dist/downloaders/DownloaderOptions.d.ts +1 -0
- package/dist/downloaders/DownloaderOptions.js +2 -0
- package/dist/downloaders/DownloaderOptions.js.map +1 -1
- package/dist/downloaders/IncludeCriteriaHelper.d.ts +25 -0
- package/dist/downloaders/IncludeCriteriaHelper.js +160 -0
- package/dist/downloaders/IncludeCriteriaHelper.js.map +1 -0
- package/dist/downloaders/InitialData.js +20 -6
- package/dist/downloaders/InitialData.js.map +1 -1
- package/dist/downloaders/PostDownloader.js +62 -98
- package/dist/downloaders/PostDownloader.js.map +1 -1
- package/dist/downloaders/PostsFetcher.js +4 -2
- package/dist/downloaders/PostsFetcher.js.map +1 -1
- package/dist/downloaders/ProductDownloader.js +31 -21
- package/dist/downloaders/ProductDownloader.js.map +1 -1
- package/dist/downloaders/task/M3U8DownloadTask.d.ts +1 -0
- package/dist/downloaders/task/M3U8DownloadTask.js +137 -39
- package/dist/downloaders/task/M3U8DownloadTask.js.map +1 -1
- package/dist/downloaders/task/YouTubeDownloadTask.js +1 -3
- package/dist/downloaders/task/YouTubeDownloadTask.js.map +1 -1
- package/dist/parsers/PageParser.js +8 -3
- package/dist/parsers/PageParser.js.map +1 -1
- package/dist/utils/Fetcher.d.ts +4 -1
- package/dist/utils/Fetcher.js +6 -1
- package/dist/utils/Fetcher.js.map +1 -1
- package/dist/utils/URLHelper.d.ts +4 -0
- package/dist/utils/URLHelper.js +17 -0
- package/dist/utils/URLHelper.js.map +1 -1
- package/dist/utils/YouTubeCredentialsCapturer.js +1 -1
- package/dist/utils/YouTubeCredentialsCapturer.js.map +1 -1
- package/dist/utils/logging/ConsoleLogger.js +5 -0
- package/dist/utils/logging/ConsoleLogger.js.map +1 -1
- package/dist/utils/yt/InnertubeLoader.d.ts +4 -6
- package/dist/utils/yt/InnertubeLoader.js +14 -14
- package/dist/utils/yt/InnertubeLoader.js.map +1 -1
- package/dist/utils/yt/PoToken.js +53 -27
- package/dist/utils/yt/PoToken.js.map +1 -1
- package/package.json +12 -8
- package/dist/browse/web/assets/index-CW4CUoWl.css +0 -1
- package/dist/browse/web/assets/index-CziUWlSw.js +0 -218
|
@@ -16,7 +16,6 @@ import deepFreeze from 'deep-freeze';
|
|
|
16
16
|
import Fetcher from '../utils/Fetcher.js';
|
|
17
17
|
import Bootstrap from './Bootstrap.js';
|
|
18
18
|
import { getDownloaderInit } from './DownloaderOptions.js';
|
|
19
|
-
import { TargetSkipReason } from './DownloaderEvent.js';
|
|
20
19
|
import Logger from '../utils/logging/Logger.js';
|
|
21
20
|
import { commonLog } from '../utils/logging/Logger.js';
|
|
22
21
|
import FSHelper from '../utils/FSHelper.js';
|
|
@@ -364,8 +363,8 @@ class Downloader extends EventEmitter {
|
|
|
364
363
|
log(level, ...msg) {
|
|
365
364
|
commonLog(this.logger, level, this.name, ...msg);
|
|
366
365
|
}
|
|
367
|
-
getConfig() {
|
|
368
|
-
return deepFreeze(this.config);
|
|
366
|
+
getConfig(ro = true) {
|
|
367
|
+
return ro ? deepFreeze(this.config) : this.config;
|
|
369
368
|
}
|
|
370
369
|
checkAbortSignal(signal) {
|
|
371
370
|
if (signal && signal.aborted) {
|
|
@@ -416,67 +415,15 @@ class Downloader extends EventEmitter {
|
|
|
416
415
|
this.log('debug', `Fetch user data from API URL "${url}"`);
|
|
417
416
|
return this.commonFetchAPI(url, signal);
|
|
418
417
|
}
|
|
419
|
-
isPublishDateOutOfRange(entity, emit = true) {
|
|
420
|
-
const publishedAfter = entity.type === 'post' ? this.config.include.postsPublished.after : this.config.include.productsPublished.after;
|
|
421
|
-
const publishedBefore = entity.type === 'post' ? this.config.include.postsPublished.before : this.config.include.productsPublished.before;
|
|
422
|
-
if (publishedAfter || publishedBefore) {
|
|
423
|
-
const targetPublishedAt = entity.publishedAt;
|
|
424
|
-
let parsedPublishedAt = null;
|
|
425
|
-
if (!targetPublishedAt) {
|
|
426
|
-
this.log('warn', `config.include.productsPublished: ignored - ${entity.type} #${entity.id} missing publish date`);
|
|
427
|
-
}
|
|
428
|
-
else {
|
|
429
|
-
try {
|
|
430
|
-
parsedPublishedAt = new Date(targetPublishedAt);
|
|
431
|
-
}
|
|
432
|
-
catch (error) {
|
|
433
|
-
this.log('error', `Failed to parse publish date of ${entity.type} #${entity.id} ("${targetPublishedAt}"): `, error);
|
|
434
|
-
this.log('warn', `config.include.productsPublished: ignored - publish date of ${entity.type} #${entity.id} could not be parsed`);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
let skip = false;
|
|
438
|
-
if (parsedPublishedAt) {
|
|
439
|
-
const isAfter = publishedAfter ? parsedPublishedAt.getTime() >= publishedAfter.valueOf().getTime() : true;
|
|
440
|
-
const isBefore = publishedBefore ? parsedPublishedAt.getTime() < publishedBefore.valueOf().getTime() : true;
|
|
441
|
-
skip = !isAfter || !isBefore;
|
|
442
|
-
let eq = null;
|
|
443
|
-
if (publishedAfter && publishedBefore) {
|
|
444
|
-
eq = `${publishedAfter.toString()} <= *${targetPublishedAt}* < ${publishedBefore.toString()}`;
|
|
445
|
-
}
|
|
446
|
-
else if (publishedAfter) {
|
|
447
|
-
eq = `${publishedAfter.toString()} <= *${targetPublishedAt}*`;
|
|
448
|
-
}
|
|
449
|
-
else if (publishedBefore) {
|
|
450
|
-
eq = `*${targetPublishedAt}* < ${publishedBefore.toString()}`;
|
|
451
|
-
}
|
|
452
|
-
if (eq) {
|
|
453
|
-
if (skip) {
|
|
454
|
-
this.log('warn', `Skipped downloading ${entity.type} #${entity.id}: publish date out of range`);
|
|
455
|
-
this.log('debug', `Publish date test failed for ${entity.type} #${entity.id}: ${eq}`);
|
|
456
|
-
}
|
|
457
|
-
else {
|
|
458
|
-
this.log('debug', `Publish date test OK for ${entity.type} #${entity.id}: ${eq}`);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
if (skip && emit) {
|
|
462
|
-
this.emit('targetEnd', {
|
|
463
|
-
target: entity,
|
|
464
|
-
isSkipped: true,
|
|
465
|
-
skipReason: TargetSkipReason.PublishDateOutOfRange,
|
|
466
|
-
skipMessage: 'Publish date out of range'
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
return skip;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
return false;
|
|
473
|
-
}
|
|
474
418
|
async closeDB() {
|
|
475
419
|
if (__classPrivateFieldGet(this, _Downloader_dbPromise, "f")) {
|
|
476
420
|
(await __classPrivateFieldGet(this, _Downloader_dbPromise, "f")).close();
|
|
477
421
|
__classPrivateFieldSet(this, _Downloader_dbPromise, null, "f");
|
|
478
422
|
}
|
|
479
423
|
}
|
|
424
|
+
getFetcher() {
|
|
425
|
+
return this.fetcher;
|
|
426
|
+
}
|
|
480
427
|
on(event, listener) {
|
|
481
428
|
return super.on(event, listener);
|
|
482
429
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Downloader.js","sourceRoot":"","sources":["../../src/downloaders/Downloader.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport { EventEmitter } from 'events';\nimport deepFreeze from 'deep-freeze';\nimport Fetcher from '../utils/Fetcher.js';\nimport Bootstrap, { type PostDownloaderBootstrapData, type ProductDownloaderBootstrapData, type DownloaderBootstrapData, type DownloaderType } from './Bootstrap.js';\nimport { type DownloaderInit, type DownloaderOptions, type FileExistsAction, getDownloaderInit } from './DownloaderOptions.js';\nimport { TargetSkipReason, type DownloaderEvent, type DownloaderEventPayloadOf } from './DownloaderEvent.js';\nimport {type LogLevel} from '../utils/logging/Logger.js';\nimport Logger from '../utils/logging/Logger.js';\nimport { commonLog } from '../utils/logging/Logger.js';\nimport { type Campaign } from '../entities/Campaign.js';\nimport FSHelper, { type WriteTextFileResult } from '../utils/FSHelper.js';\nimport DownloadTaskBatch from './task/DownloadTaskBatch.js';\nimport { type IDownloadTask } from './task/DownloadTask.js';\nimport DownloadTaskFactory from './task/DownloadTaskFactory.js';\nimport FilenameFormatHelper from '../utils/FilenameFormatHelper.js';\nimport { type Downloadable } from '../entities/Downloadable.js';\nimport { generateCampaignSummary } from './templates/CampaignInfo.js';\nimport path from 'path';\nimport URLHelper from '../utils/URLHelper.js';\nimport ffmpeg from 'fluent-ffmpeg';\nimport InnertubeLoader from '../utils/yt/InnertubeLoader.js';\nimport FFmpegDownloadTaskBase from './task/FFmpegDownloadTaskBase.js';\nimport ExternalDownloaderTask from './task/ExternalDownloaderTask.js';\nimport DB, { type DBInstance } from '../browse/db/index.js';\nimport PostParser from '../parsers/PostParser.js';\nimport { isDenoInstalled } from '../utils/Misc.js';\nimport { type Product } from '../entities/Product.js';\nimport { type Collection, type Post } from '../entities/Post.js';\n\nexport type DownloaderConfig<T extends DownloaderType> =\n DownloaderInit &\n DownloaderBootstrapData<T>;\n\nexport interface DownloaderStartParams {\n signal?: AbortSignal;\n}\n\nexport type GetCampaignParams = \n string |\n { userId: string; vanity?: never, campaignId?: never; } |\n { userId?: never; vanity: string, campaignId?: never; } |\n { vanity?: never; userId?: never; campaignId: string; };\n\ninterface CreateDownloadTaskParams<T extends DownloaderType> {\n target: Downloadable[];\n targetName: string;\n src: T | Campaign | Collection,\n dirs: {\n campaign: string | null;\n main: string;\n thumbnails: string | null;\n };\n fileExistsAction: FileExistsAction;\n isAttachment?: boolean;\n ignoreCreateTaskErrors?: boolean;\n}\n\nexport default abstract class Downloader<T extends DownloaderType> extends EventEmitter {\n\n abstract name: string;\n\n protected fetcher: Fetcher;\n protected fsHelper: FSHelper;\n protected config: DownloaderConfig<T>;\n protected logger?: Logger | null;\n protected db: () => Promise<DBInstance>;\n #dbPromise: Promise<DBInstance> | null;\n\n #hasEmittedEndEventOnAbort: boolean;\n\n constructor(config: DownloaderConfig<T>, db: () => Promise<DBInstance>, logger?: Logger | null) {\n super();\n\n this.config = config;\n this.fetcher = new Fetcher(this.config, logger);\n this.fsHelper = new FSHelper(this.config, logger);\n this.#dbPromise = null;\n this.db = async () => {\n if (!this.#dbPromise) {\n this.#dbPromise = db();\n }\n return this.#dbPromise;\n }\n this.logger = logger;\n\n if (this.config.pathToFFmpeg) {\n ffmpeg.setFfmpegPath(this.config.pathToFFmpeg);\n }\n\n InnertubeLoader.setLogger(this.logger);\n if (this.config.pathToYouTubeCredentials) {\n InnertubeLoader.setCredentialsFile(this.config.pathToYouTubeCredentials);\n }\n\n this.#hasEmittedEndEventOnAbort = false;\n }\n\n protected createDownloadTaskBatch(\n name: string,\n signal?: AbortSignal,\n ...createTasks: Array<CreateDownloadTaskParams<T> | null>\n ): Promise<{ batch: DownloadTaskBatch; errorCount: number; }> {\n\n const __getDownloadIdString = (task: IDownloadTask, batch: DownloadTaskBatch) => {\n let result = `#${batch.id}.${task.id}`;\n if (task.retryCount > 0) {\n result += `-r${task.retryCount}`;\n }\n return result;\n };\n\n const batch = new DownloadTaskBatch({\n name,\n fetcher: this.fetcher,\n limiter: this.config.request,\n logger: this.logger\n });\n\n batch.on('taskStart', ({task}) => {\n const retryOrBeginStr = task.retryCount > 0 ? 'retry' : 'begin';\n const isExternal = task instanceof ExternalDownloaderTask;\n const destStr = isExternal ? ' -> Unknown destination (external process)' : task.resolvedDestFilename ? ` -> ${task.resolvedDestFilename}` : '';\n this.log('info', `Download ${retryOrBeginStr} (${__getDownloadIdString(task, batch)}): [type: ${task.srcEntity.type}; ID: #${task.srcEntity.id}]${destStr}`);\n if (task instanceof FFmpegDownloadTaskBase) {\n const retryOrBeginStr = task.retryCount > 0 ? 'Retry' : 'Begin';\n this.log('info', `${retryOrBeginStr} FFmpeg task (${__getDownloadIdString(task, batch)}): ${task.commandLine}`);\n }\n });\n\n batch.on('taskComplete', ({task}) => {\n const isExternal = task instanceof ExternalDownloaderTask;\n const destStr = isExternal ? ': Unknown destination (external process)' : task.resolvedDestPath ? `: \"${task.resolvedDestPath}\"` : '';\n this.log('info', `Download complete (${__getDownloadIdString(task, batch)})${destStr}`);\n });\n\n batch.on('taskError', ({error, willRetry}) => {\n const { task, cause, message } = error;\n const retryStr = willRetry ? '- will retry' : '';\n this.log('error', `Download error (${__getDownloadIdString(task, batch)}):`, cause || message, `(${task.src})`, retryStr);\n });\n\n batch.on('taskAbort', ({task}) => {\n this.log('warn', `Download aborted (${__getDownloadIdString(task, batch)})`);\n });\n\n batch.on('taskSkip', ({task, reason}) => {\n this.log('warn', `Download skipped (${__getDownloadIdString(task, batch)}): ${reason.message}`);\n });\n\n batch.on('taskSpawn', ({origin, spawn}) => {\n this.log('info', `Download spawned: #${batch.id}.${origin.id} -> #${batch.id}.${spawn.id}`);\n });\n\n /**\n * Uncomment this block to log download progress\n\n batch.on('taskProgress', ({task, progress}) => {\n if (progress) {\n if (progress.length) {\n this.log('info', `Download progress (${__getDownloadIdString(task, batch)}): ${progress.lengthDownloaded} / ${progress.length} ${progress.lengthUnit}s / ${progress.percent}% (${progress.speed} kB/s)`,);\n }\n else {\n this.log('info', `Download progress (${__getDownloadIdString(task, batch)}): ${progress.lengthDownloaded} / ? ${progress.lengthUnit}s (${progress.speed} kB/s)`,);\n }\n }\n else {\n this.log('warn', `Download progress not available (${__getDownloadIdString(task, batch)})`);\n }\n });\n\n */\n\n batch.on('complete', () => {\n const total = batch.getTasks().length;\n const completed = batch.getTasks('completed').length;\n const error = batch.getTasks('error').length;\n const aborted = batch.getTasks('aborted').length;\n const skipped = batch.getTasks('skipped').length;\n const counts = [\n `${total} downloads`,\n `${completed} completed`,\n `${error} errors`,\n `${skipped} skipped`,\n `${aborted} aborted`\n ].join('; ');\n this.log('info', `Download batch complete (#${batch.id}): ${counts}`);\n });\n\n return this.addToDownloadTaskBatch(batch, signal, ...createTasks);\n }\n\n protected async addToDownloadTaskBatch(\n batch: DownloadTaskBatch,\n signal?: AbortSignal,\n ...createTasks: Array<CreateDownloadTaskParams<T> | null>\n ) {\n let failedCreateTaskCount = 0;\n for (const task of createTasks) {\n if (!task) {\n continue;\n }\n const { target, targetName, src, dirs } = task;\n this.log('info', `Create download tasks for ${targetName}`);\n if (task.target.length === 0) {\n this.log('warn', `No items in ${targetName}`);\n continue;\n }\n let ensureDirs: string[] = [];\n for (const tt of target) {\n try {\n const tasks = await DownloadTaskFactory.createFromDownloadable({\n config: this.config,\n dirs,\n item: tt,\n src,\n fetcher: this.fetcher,\n fileExistsAction: task.fileExistsAction,\n isAttachment: task.isAttachment,\n limiter: batch.limiter,\n signal,\n logger: this.logger\n });\n\n if (signal?.aborted) {\n return { batch, errorCount: failedCreateTaskCount };\n }\n\n // Filter out tasks that are DOA (errors that occurred in DownloadTask.create())\n for (const task of tasks) {\n if (task.doa) {\n this.log('error', `Failed to create download task for item #${tt.id} in ${targetName}:`, task.doa.msg, task.doa.cause);\n failedCreateTaskCount++;\n }\n }\n const createdTasks = tasks.filter((task) => !task.doa);\n batch.addTasks(createdTasks);\n ensureDirs = createdTasks.reduce<string[]>((result, task) => {\n const dir = task.resolvedDestPath ? path.dirname(task.resolvedDestPath) : null;\n if (dir && !result.includes(dir)) {\n result.push(dir);\n }\n return result;\n }, ensureDirs);\n }\n catch (error) {\n if (signal?.aborted) {\n this.log('warn', 'Operation aborted');\n return { batch, errorCount: failedCreateTaskCount };\n }\n if (!task.ignoreCreateTaskErrors) {\n this.log('error', `Failed to create download task(s) for item #${tt.id} in ${targetName}:`, error);\n failedCreateTaskCount++;\n }\n }\n }\n for (const dir of ensureDirs) {\n this.fsHelper.createDir(dir);\n }\n }\n if (failedCreateTaskCount > 0) {\n this.log('warn', `${failedCreateTaskCount} items could not be processed for downloading`);\n }\n return { batch, errorCount: failedCreateTaskCount };\n }\n\n async start(params: DownloaderStartParams) {\n try {\n await this.doStart(params);\n }\n finally {\n InnertubeLoader.reset();\n }\n }\n\n abstract doStart(params: DownloaderStartParams): Promise<void>;\n\n static async getInstance(\n target: string | ProductDownloaderBootstrapData | PostDownloaderBootstrapData,\n options?: DownloaderOptions\n ) {\n const bootstrap = typeof target === 'string' ? Bootstrap.getDownloaderBootstrapDataByURL(target) : target;\n if (!bootstrap) {\n throw Error('Could not determine downloader type from URL');\n }\n this.#validateOptions(options);\n\n const config = {\n ...bootstrap,\n ...getDownloaderInit(options)\n };\n const logger = options?.logger;\n const fsHelper = new FSHelper(config, logger);\n const db = () => DB.getInstance(fsHelper.getDBFilePath(), config.dryRun, logger);\n \n switch (config.type) {\n case 'product': {\n const ProductDownloader = (await import('./ProductDownloader.js')).default;\n return new ProductDownloader(config, db, logger);\n }\n case 'post': {\n const PostDownloader = (await import('./PostDownloader.js')).default;\n return new PostDownloader(config, db, logger);\n }\n }\n }\n\n static async getCampaign(\n params: GetCampaignParams,\n signal?: AbortSignal,\n options?: Logger | null | Pick<DownloaderOptions, 'cookie' | 'request' | 'logger'>\n ) {\n // Backwards compatibility - if 'params' is string type, then it is vanity\n let url: string;\n if (typeof params === 'string') {\n url = URLHelper.constructUserPostsURL({ vanity: params });\n }\n else if (params.userId || params.vanity) {\n url = URLHelper.constructUserPostsURL(params);\n }\n else {\n // Sole purpose of passing 'dummy' vanity is to create the PostDownloader instance\n url = URLHelper.constructUserPostsURL({ vanity: 'dummy' });\n }\n const downloader = await this.getInstance(\n url,\n options instanceof Logger ? { logger: options } : (options || undefined)\n );\n const PostDownloader = (await import('./PostDownloader.js')).default;\n if (downloader instanceof PostDownloader) {\n if (typeof params === 'object' && params.campaignId) {\n const { json } = await downloader.fetchCampaign(params.campaignId, signal);\n const parser = new PostParser(options instanceof Logger ? options : options?.logger);\n return parser.parseCampaignAPIResponse(json);\n }\n return downloader.__getCampaign(signal);\n }\n throw Error('Type mismatch: PostDownloader expected');\n }\n\n static #validateOptions(options?: DownloaderOptions) {\n if (!options) {\n return true;\n }\n\n // Check FFmpeg path exists\n if (options.pathToFFmpeg) {\n if (!fs.existsSync(options.pathToFFmpeg)) {\n throw Error(`Path to FFmpeg executable \"${options.pathToFFmpeg}\" does not exist`);\n }\n else if (!fs.lstatSync(options.pathToFFmpeg).isFile()) {\n throw Error(`Path to FFmpeg executable \"${options.pathToFFmpeg}\" does not point to a file`);\n }\n }\n\n // Check Deno path exists and startable\n if (options.pathToDeno) {\n if (!fs.existsSync(options.pathToDeno)) {\n throw Error(`Path to Deno executable \"${options.pathToDeno}\" does not exist`);\n }\n else if (!fs.lstatSync(options.pathToDeno).isFile()) {\n throw Error(`Path to Deno executable \"${options.pathToDeno}\" does not point to a file`);\n }\n const di = isDenoInstalled(options.pathToDeno);\n if (!di.installed) {\n throw Error(`Could not start Deno executable \"${options.pathToDeno}\"`, { cause: di.error });\n }\n }\n\n // Check outDir is a directory\n if (options.outDir) {\n if (fs.existsSync(options.outDir) && !fs.lstatSync(options.outDir).isDirectory()) {\n throw Error(`\"${options.outDir}\" is not a directory`);\n }\n }\n\n // Check formats are valid\n const campaignDirNameFormat = options.dirNameFormat?.campaign;\n if (campaignDirNameFormat) {\n const validate = FilenameFormatHelper.validateCampaignDirNameFormat(campaignDirNameFormat);\n if (!validate.validateOK) {\n throw Error(`Campaign directory name format '${campaignDirNameFormat}' is invalid (matched against ${validate.regex})`);\n }\n }\n const contentDirNameFormat = options.dirNameFormat?.content;\n if (contentDirNameFormat) {\n const validate = FilenameFormatHelper.validateContentDirNameFormat(contentDirNameFormat);\n if (!validate.validateOK) {\n throw Error(`Content directory name format '${contentDirNameFormat}' is invalid (matched against ${validate.regex})`);\n }\n }\n const mediaFilenameFormat = options.filenameFormat?.media;\n if (mediaFilenameFormat) {\n const validate = FilenameFormatHelper.validateMediaFilenameFormat(mediaFilenameFormat);\n if (!validate.validateOK) {\n throw Error(`Media filename format '${mediaFilenameFormat}' is invalid (matched against ${validate.regex})`);\n }\n }\n\n return true;\n }\n\n protected async saveCampaignInfo(campaign: Campaign | null, signal?: AbortSignal) {\n const db = await this.db();\n if (!this.config.include.campaignInfo) {\n if (campaign) {\n db.saveCampaign(campaign, new Date());\n }\n return;\n }\n\n if (this.checkAbortSignal(signal)) {\n return;\n }\n\n let batch: DownloadTaskBatch | null = null;\n const abortHandler = () => {\n void (async () => {\n if (batch) {\n await batch.abort();\n }\n })();\n };\n if (signal) {\n signal.addEventListener('abort', abortHandler, { once: true });\n }\n\n if (!campaign) {\n this.log('warn', 'Skipped saving campaign info: target unavailable');\n return;\n }\n\n this.log('info', `Save campaign info #${campaign.id}`);\n this.emit('targetBegin', { target: campaign });\n this.emit('phaseBegin', { target: campaign, phase: 'saveInfo' });\n\n // Step 1: create campaign directories\n const campaignDirs = this.fsHelper.getCampaignDirs(campaign);\n this.log('debug', 'Campaign directories: ', campaignDirs);\n this.fsHelper.createDir(campaignDirs.root);\n this.fsHelper.createDir(campaignDirs.info);\n\n // Step 2: save summary and raw json\n const summary = generateCampaignSummary(campaign);\n const summaryFile = path.resolve(campaignDirs.info, 'info.txt');\n const saveSummaryResult = await this.fsHelper.writeTextFile(summaryFile, summary, this.config.fileExistsAction.info);\n this.logWriteTextFileResult(saveSummaryResult, campaign, 'campaign summary');\n\n // Campaign / creator raw data might not be complete. Fetch directly from API.\n // Strictly speaking, we should check for 'error' in results, but since it's not going to be fatal we'll just skip it.\n const { json: fetchedCampaignAPIData } = await this.fetchCampaign(campaign.id, signal);\n const { json: fetchedCreatorAPIData } = campaign.creator ? await this.fetchUser(campaign.creator.id, signal) : { json: null };\n\n if (this.checkAbortSignal(signal)) {\n return;\n }\n\n const campaignRawFile = path.resolve(campaignDirs.info, 'campaign-api.json');\n const saveCampaignRawResult = await this.fsHelper.writeTextFile(\n campaignRawFile, fetchedCampaignAPIData || campaign.raw, this.config.fileExistsAction.infoAPI);\n this.logWriteTextFileResult(saveCampaignRawResult, campaign, 'campaign API data');\n\n if (campaign.creator) {\n const creatorRawFile = path.resolve(campaignDirs.info, 'creator-api.json');\n const saveCreatorRawResult = await this.fsHelper.writeTextFile(\n creatorRawFile, fetchedCreatorAPIData || campaign.creator.raw, this.config.fileExistsAction.infoAPI);\n this.logWriteTextFileResult(saveCreatorRawResult, campaign.creator, 'creator API data');\n }\n\n this.emit('phaseEnd', { target: campaign, phase: 'saveInfo' });\n\n // Step 3: download campaign media items\n this.emit('phaseBegin', { target: campaign, phase: 'saveMedia' });\n const campaignMedia: Downloadable[] = [\n campaign.avatarImage,\n campaign.coverPhoto\n ];\n if (campaign.creator) {\n campaignMedia.push(\n campaign.creator.image,\n campaign.creator.thumbnail\n );\n }\n for (const reward of campaign.rewards) {\n if (reward.image) {\n campaignMedia.push(reward.image);\n }\n }\n batch = (await this.createDownloadTaskBatch(\n `Campaign #${campaign.id} (${campaign.name})`,\n signal,\n {\n target: campaignMedia,\n targetName: `campaign #${campaign.id} -> images`,\n src: campaign,\n dirs: {\n campaign: campaignDirs.root,\n main: campaignDirs.info,\n thumbnails: null\n },\n fileExistsAction: this.config.fileExistsAction.info\n }\n )).batch;\n if (this.checkAbortSignal(signal)) {\n return;\n }\n batch.prestart();\n this.emit('phaseBegin', { target: campaign, phase: 'batchDownload', batch });\n await batch.start();\n await batch.destroy();\n this.emit('phaseEnd', { target: campaign, phase: 'batchDownload' });\n this.emit('phaseEnd', { target: campaign, phase: 'saveMedia' });\n\n if (signal) {\n signal.removeEventListener('abort', abortHandler);\n }\n if (this.checkAbortSignal(signal)) {\n return;\n }\n\n // Step 4: save to DB\n db.saveCampaign(campaign, new Date());\n\n // Done\n this.log('info', 'Done saving campaign info');\n this.emit('targetEnd', { target: campaign, isSkipped: false });\n }\n\n protected log(level: LogLevel, ...msg: any[]) {\n commonLog(this.logger, level, this.name, ...msg);\n }\n\n getConfig() {\n return deepFreeze(this.config);\n }\n\n protected checkAbortSignal(signal: AbortSignal | undefined) {\n if (signal && signal.aborted) {\n if (!this.#hasEmittedEndEventOnAbort) {\n this.emit('end', { aborted: true, message: 'Download aborted' });\n this.#hasEmittedEndEventOnAbort = true;\n }\n return true;\n }\n return false;\n }\n\n protected logWriteTextFileResult(result: WriteTextFileResult, target: {id: string}, targetName: string) {\n switch (result.status) {\n case 'completed':\n this.log('info', `Saved ${targetName} to \"${result.filePath}\"`);\n break;\n case 'skipped':\n this.log('warn', `Skipped saving ${targetName} #${target.id}: ${result.message}`);\n break;\n case 'error':\n this.log('error', `Error saving ${targetName} #${target.id} to \"${result.filePath}\":`, result.error);\n }\n }\n\n protected async commonFetchAPI(url: string, signal?: AbortSignal) {\n let json, requestAPIError: any;\n try {\n json = (await this.fetcher.get({ url, type: 'json', maxRetries: this.config.request.maxRetries, signal })).json;\n }\n catch (error) {\n if (signal?.aborted) {\n this.log('warn', 'API request aborted');\n }\n else {\n this.log('error', `Error requesting API URL \"${url}\": `, error);\n requestAPIError = error;\n }\n json = null;\n }\n return { json, error: requestAPIError };\n }\n\n protected fetchCampaign(campaignId: string, signal?: AbortSignal) {\n const url = URLHelper.constructCampaignAPIURL(campaignId);\n this.log('debug', `Fetch campaign data from API URL \"${url}\"`);\n return this.commonFetchAPI(url, signal);\n }\n\n protected fetchUser(userId: string, signal?: AbortSignal) {\n const url = URLHelper.constructUserAPIURL(userId);\n this.log('debug', `Fetch user data from API URL \"${url}\"`);\n return this.commonFetchAPI(url, signal);\n }\n\n protected isPublishDateOutOfRange(entity: Post | Product, emit = true) {\n const publishedAfter = entity.type === 'post' ? this.config.include.postsPublished.after : this.config.include.productsPublished.after;\n const publishedBefore = entity.type === 'post' ? this.config.include.postsPublished.before : this.config.include.productsPublished.before;\n if (publishedAfter || publishedBefore) {\n const targetPublishedAt = entity.publishedAt;\n let parsedPublishedAt: Date | null = null;\n if (!targetPublishedAt) {\n this.log('warn', `config.include.productsPublished: ignored - ${entity.type} #${entity.id} missing publish date`);\n }\n else {\n try {\n parsedPublishedAt = new Date(targetPublishedAt);\n }\n catch (error: any) {\n this.log('error', `Failed to parse publish date of ${entity.type} #${entity.id} (\"${targetPublishedAt}\"): `, error);\n this.log('warn', `config.include.productsPublished: ignored - publish date of ${entity.type} #${entity.id} could not be parsed`);\n }\n }\n let skip = false;\n if (parsedPublishedAt) {\n const isAfter = publishedAfter ? parsedPublishedAt.getTime() >= publishedAfter.valueOf().getTime() : true;\n const isBefore = publishedBefore ? parsedPublishedAt.getTime() < publishedBefore.valueOf().getTime() : true;\n skip = !isAfter || !isBefore;\n let eq: string | null = null;\n if (publishedAfter && publishedBefore) {\n eq = `${publishedAfter.toString()} <= *${targetPublishedAt}* < ${publishedBefore.toString()}`;\n }\n else if (publishedAfter) {\n eq = `${publishedAfter.toString()} <= *${targetPublishedAt}*`;\n }\n else if (publishedBefore) {\n eq = `*${targetPublishedAt}* < ${publishedBefore.toString()}`;\n }\n if (eq) {\n if (skip) {\n this.log('warn', `Skipped downloading ${entity.type} #${entity.id}: publish date out of range`);\n this.log('debug', `Publish date test failed for ${entity.type} #${entity.id}: ${eq}`);\n }\n else {\n this.log('debug', `Publish date test OK for ${entity.type} #${entity.id}: ${eq}`);\n }\n }\n if (skip && emit) {\n this.emit('targetEnd', {\n target: entity,\n isSkipped: true,\n skipReason: TargetSkipReason.PublishDateOutOfRange,\n skipMessage: 'Publish date out of range'\n });\n }\n return skip;\n }\n }\n return false;\n }\n\n protected async closeDB() {\n if (this.#dbPromise) {\n (await this.#dbPromise).close();\n this.#dbPromise = null;\n }\n }\n\n on<T extends DownloaderEvent>(event: T, listener: (args: DownloaderEventPayloadOf<T>) => void): this;\n on(event: string | symbol, listener: (...args: any[]) => void): this {\n return super.on(event, listener);\n }\n\n once<T extends DownloaderEvent>(event: T, listener: (args: DownloaderEventPayloadOf<T>) => void): this;\n once(event: string | symbol, listener: (...args: any[]) => void): this {\n return super.once(event, listener);\n }\n\n off<T extends DownloaderEvent>(event: T, listener: (args: DownloaderEventPayloadOf<T>) => void): this;\n off(event: string | symbol, listener: (...args: any[]) => void): this {\n return super.off(event, listener);\n }\n\n emit<T extends DownloaderEvent>(event: T, args: DownloaderEventPayloadOf<T>): boolean;\n emit(event: string | symbol, ...args: any[]): boolean {\n return super.emit(event, ...args);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Downloader.js","sourceRoot":"","sources":["../../src/downloaders/Downloader.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport { EventEmitter } from 'events';\nimport deepFreeze from 'deep-freeze';\nimport Fetcher from '../utils/Fetcher.js';\nimport Bootstrap, { type PostDownloaderBootstrapData, type ProductDownloaderBootstrapData, type DownloaderBootstrapData, type DownloaderType } from './Bootstrap.js';\nimport { type DownloaderInit, type DownloaderOptions, type FileExistsAction, getDownloaderInit } from './DownloaderOptions.js';\nimport { type DownloaderEvent, type DownloaderEventPayloadOf } from './DownloaderEvent.js';\nimport {type LogLevel} from '../utils/logging/Logger.js';\nimport Logger from '../utils/logging/Logger.js';\nimport { commonLog } from '../utils/logging/Logger.js';\nimport { type Campaign } from '../entities/Campaign.js';\nimport FSHelper, { type WriteTextFileResult } from '../utils/FSHelper.js';\nimport DownloadTaskBatch from './task/DownloadTaskBatch.js';\nimport { type IDownloadTask } from './task/DownloadTask.js';\nimport DownloadTaskFactory from './task/DownloadTaskFactory.js';\nimport FilenameFormatHelper from '../utils/FilenameFormatHelper.js';\nimport { type Downloadable } from '../entities/Downloadable.js';\nimport { generateCampaignSummary } from './templates/CampaignInfo.js';\nimport path from 'path';\nimport URLHelper from '../utils/URLHelper.js';\nimport ffmpeg from 'fluent-ffmpeg';\nimport InnertubeLoader from '../utils/yt/InnertubeLoader.js';\nimport FFmpegDownloadTaskBase from './task/FFmpegDownloadTaskBase.js';\nimport ExternalDownloaderTask from './task/ExternalDownloaderTask.js';\nimport DB, { type DBInstance } from '../browse/db/index.js';\nimport PostParser from '../parsers/PostParser.js';\nimport { isDenoInstalled } from '../utils/Misc.js';\nimport { type Collection } from '../entities/Post.js';\n\nexport type DownloaderConfig<T extends DownloaderType> =\n DownloaderInit &\n DownloaderBootstrapData<T>;\n\nexport interface DownloaderStartParams {\n signal?: AbortSignal;\n}\n\nexport type GetCampaignParams = \n string |\n { userId: string; vanity?: never, campaignId?: never; } |\n { userId?: never; vanity: string, campaignId?: never; } |\n { vanity?: never; userId?: never; campaignId: string; };\n\ninterface CreateDownloadTaskParams<T extends DownloaderType> {\n target: Downloadable[];\n targetName: string;\n src: T | Campaign | Collection,\n dirs: {\n campaign: string | null;\n main: string;\n thumbnails: string | null;\n };\n fileExistsAction: FileExistsAction;\n isAttachment?: boolean;\n ignoreCreateTaskErrors?: boolean;\n}\n\nexport default abstract class Downloader<T extends DownloaderType> extends EventEmitter {\n\n abstract name: string;\n\n protected fetcher: Fetcher;\n protected fsHelper: FSHelper;\n protected config: DownloaderConfig<T>;\n protected logger?: Logger | null;\n protected db: () => Promise<DBInstance>;\n #dbPromise: Promise<DBInstance> | null;\n\n #hasEmittedEndEventOnAbort: boolean;\n\n constructor(config: DownloaderConfig<T>, db: () => Promise<DBInstance>, logger?: Logger | null) {\n super();\n\n this.config = config;\n this.fetcher = new Fetcher(this.config, logger);\n this.fsHelper = new FSHelper(this.config, logger);\n this.#dbPromise = null;\n this.db = async () => {\n if (!this.#dbPromise) {\n this.#dbPromise = db();\n }\n return this.#dbPromise;\n }\n this.logger = logger;\n\n if (this.config.pathToFFmpeg) {\n ffmpeg.setFfmpegPath(this.config.pathToFFmpeg);\n }\n\n InnertubeLoader.setLogger(this.logger);\n if (this.config.pathToYouTubeCredentials) {\n InnertubeLoader.setCredentialsFile(this.config.pathToYouTubeCredentials);\n }\n\n this.#hasEmittedEndEventOnAbort = false;\n }\n\n protected createDownloadTaskBatch(\n name: string,\n signal?: AbortSignal,\n ...createTasks: Array<CreateDownloadTaskParams<T> | null>\n ): Promise<{ batch: DownloadTaskBatch; errorCount: number; }> {\n\n const __getDownloadIdString = (task: IDownloadTask, batch: DownloadTaskBatch) => {\n let result = `#${batch.id}.${task.id}`;\n if (task.retryCount > 0) {\n result += `-r${task.retryCount}`;\n }\n return result;\n };\n\n const batch = new DownloadTaskBatch({\n name,\n fetcher: this.fetcher,\n limiter: this.config.request,\n logger: this.logger\n });\n\n batch.on('taskStart', ({task}) => {\n const retryOrBeginStr = task.retryCount > 0 ? 'retry' : 'begin';\n const isExternal = task instanceof ExternalDownloaderTask;\n const destStr = isExternal ? ' -> Unknown destination (external process)' : task.resolvedDestFilename ? ` -> ${task.resolvedDestFilename}` : '';\n this.log('info', `Download ${retryOrBeginStr} (${__getDownloadIdString(task, batch)}): [type: ${task.srcEntity.type}; ID: #${task.srcEntity.id}]${destStr}`);\n if (task instanceof FFmpegDownloadTaskBase) {\n const retryOrBeginStr = task.retryCount > 0 ? 'Retry' : 'Begin';\n this.log('info', `${retryOrBeginStr} FFmpeg task (${__getDownloadIdString(task, batch)}): ${task.commandLine}`);\n }\n });\n\n batch.on('taskComplete', ({task}) => {\n const isExternal = task instanceof ExternalDownloaderTask;\n const destStr = isExternal ? ': Unknown destination (external process)' : task.resolvedDestPath ? `: \"${task.resolvedDestPath}\"` : '';\n this.log('info', `Download complete (${__getDownloadIdString(task, batch)})${destStr}`);\n });\n\n batch.on('taskError', ({error, willRetry}) => {\n const { task, cause, message } = error;\n const retryStr = willRetry ? '- will retry' : '';\n this.log('error', `Download error (${__getDownloadIdString(task, batch)}):`, cause || message, `(${task.src})`, retryStr);\n });\n\n batch.on('taskAbort', ({task}) => {\n this.log('warn', `Download aborted (${__getDownloadIdString(task, batch)})`);\n });\n\n batch.on('taskSkip', ({task, reason}) => {\n this.log('warn', `Download skipped (${__getDownloadIdString(task, batch)}): ${reason.message}`);\n });\n\n batch.on('taskSpawn', ({origin, spawn}) => {\n this.log('info', `Download spawned: #${batch.id}.${origin.id} -> #${batch.id}.${spawn.id}`);\n });\n\n /**\n * Uncomment this block to log download progress\n\n batch.on('taskProgress', ({task, progress}) => {\n if (progress) {\n if (progress.length) {\n this.log('info', `Download progress (${__getDownloadIdString(task, batch)}): ${progress.lengthDownloaded} / ${progress.length} ${progress.lengthUnit}s / ${progress.percent}% (${progress.speed} kB/s)`,);\n }\n else {\n this.log('info', `Download progress (${__getDownloadIdString(task, batch)}): ${progress.lengthDownloaded} / ? ${progress.lengthUnit}s (${progress.speed} kB/s)`,);\n }\n }\n else {\n this.log('warn', `Download progress not available (${__getDownloadIdString(task, batch)})`);\n }\n });\n\n */\n\n batch.on('complete', () => {\n const total = batch.getTasks().length;\n const completed = batch.getTasks('completed').length;\n const error = batch.getTasks('error').length;\n const aborted = batch.getTasks('aborted').length;\n const skipped = batch.getTasks('skipped').length;\n const counts = [\n `${total} downloads`,\n `${completed} completed`,\n `${error} errors`,\n `${skipped} skipped`,\n `${aborted} aborted`\n ].join('; ');\n this.log('info', `Download batch complete (#${batch.id}): ${counts}`);\n });\n\n return this.addToDownloadTaskBatch(batch, signal, ...createTasks);\n }\n\n protected async addToDownloadTaskBatch(\n batch: DownloadTaskBatch,\n signal?: AbortSignal,\n ...createTasks: Array<CreateDownloadTaskParams<T> | null>\n ) {\n let failedCreateTaskCount = 0;\n for (const task of createTasks) {\n if (!task) {\n continue;\n }\n const { target, targetName, src, dirs } = task;\n this.log('info', `Create download tasks for ${targetName}`);\n if (task.target.length === 0) {\n this.log('warn', `No items in ${targetName}`);\n continue;\n }\n let ensureDirs: string[] = [];\n for (const tt of target) {\n try {\n const tasks = await DownloadTaskFactory.createFromDownloadable({\n config: this.config,\n dirs,\n item: tt,\n src,\n fetcher: this.fetcher,\n fileExistsAction: task.fileExistsAction,\n isAttachment: task.isAttachment,\n limiter: batch.limiter,\n signal,\n logger: this.logger\n });\n\n if (signal?.aborted) {\n return { batch, errorCount: failedCreateTaskCount };\n }\n\n // Filter out tasks that are DOA (errors that occurred in DownloadTask.create())\n for (const task of tasks) {\n if (task.doa) {\n this.log('error', `Failed to create download task for item #${tt.id} in ${targetName}:`, task.doa.msg, task.doa.cause);\n failedCreateTaskCount++;\n }\n }\n const createdTasks = tasks.filter((task) => !task.doa);\n batch.addTasks(createdTasks);\n ensureDirs = createdTasks.reduce<string[]>((result, task) => {\n const dir = task.resolvedDestPath ? path.dirname(task.resolvedDestPath) : null;\n if (dir && !result.includes(dir)) {\n result.push(dir);\n }\n return result;\n }, ensureDirs);\n }\n catch (error) {\n if (signal?.aborted) {\n this.log('warn', 'Operation aborted');\n return { batch, errorCount: failedCreateTaskCount };\n }\n if (!task.ignoreCreateTaskErrors) {\n this.log('error', `Failed to create download task(s) for item #${tt.id} in ${targetName}:`, error);\n failedCreateTaskCount++;\n }\n }\n }\n for (const dir of ensureDirs) {\n this.fsHelper.createDir(dir);\n }\n }\n if (failedCreateTaskCount > 0) {\n this.log('warn', `${failedCreateTaskCount} items could not be processed for downloading`);\n }\n return { batch, errorCount: failedCreateTaskCount };\n }\n\n async start(params: DownloaderStartParams) {\n try {\n await this.doStart(params);\n }\n finally {\n InnertubeLoader.reset();\n }\n }\n\n abstract doStart(params: DownloaderStartParams): Promise<void>;\n\n static async getInstance(\n target: string | ProductDownloaderBootstrapData | PostDownloaderBootstrapData,\n options?: DownloaderOptions\n ) {\n const bootstrap = typeof target === 'string' ? Bootstrap.getDownloaderBootstrapDataByURL(target) : target;\n if (!bootstrap) {\n throw Error('Could not determine downloader type from URL');\n }\n this.#validateOptions(options);\n\n const config = {\n ...bootstrap,\n ...getDownloaderInit(options)\n };\n const logger = options?.logger;\n const fsHelper = new FSHelper(config, logger);\n const db = () => DB.getInstance(fsHelper.getDBFilePath(), config.dryRun, logger);\n \n switch (config.type) {\n case 'product': {\n const ProductDownloader = (await import('./ProductDownloader.js')).default;\n return new ProductDownloader(config, db, logger);\n }\n case 'post': {\n const PostDownloader = (await import('./PostDownloader.js')).default;\n return new PostDownloader(config, db, logger);\n }\n }\n }\n\n static async getCampaign(\n params: GetCampaignParams,\n signal?: AbortSignal,\n options?: Logger | null | Pick<DownloaderOptions, 'cookie' | 'request' | 'logger'>\n ) {\n // Backwards compatibility - if 'params' is string type, then it is vanity\n let url: string;\n if (typeof params === 'string') {\n url = URLHelper.constructUserPostsURL({ vanity: params });\n }\n else if (params.userId || params.vanity) {\n url = URLHelper.constructUserPostsURL(params);\n }\n else {\n // Sole purpose of passing 'dummy' vanity is to create the PostDownloader instance\n url = URLHelper.constructUserPostsURL({ vanity: 'dummy' });\n }\n const downloader = await this.getInstance(\n url,\n options instanceof Logger ? { logger: options } : (options || undefined)\n );\n const PostDownloader = (await import('./PostDownloader.js')).default;\n if (downloader instanceof PostDownloader) {\n if (typeof params === 'object' && params.campaignId) {\n const { json } = await downloader.fetchCampaign(params.campaignId, signal);\n const parser = new PostParser(options instanceof Logger ? options : options?.logger);\n return parser.parseCampaignAPIResponse(json);\n }\n return downloader.__getCampaign(signal);\n }\n throw Error('Type mismatch: PostDownloader expected');\n }\n\n static #validateOptions(options?: DownloaderOptions) {\n if (!options) {\n return true;\n }\n\n // Check FFmpeg path exists\n if (options.pathToFFmpeg) {\n if (!fs.existsSync(options.pathToFFmpeg)) {\n throw Error(`Path to FFmpeg executable \"${options.pathToFFmpeg}\" does not exist`);\n }\n else if (!fs.lstatSync(options.pathToFFmpeg).isFile()) {\n throw Error(`Path to FFmpeg executable \"${options.pathToFFmpeg}\" does not point to a file`);\n }\n }\n\n // Check Deno path exists and startable\n if (options.pathToDeno) {\n if (!fs.existsSync(options.pathToDeno)) {\n throw Error(`Path to Deno executable \"${options.pathToDeno}\" does not exist`);\n }\n else if (!fs.lstatSync(options.pathToDeno).isFile()) {\n throw Error(`Path to Deno executable \"${options.pathToDeno}\" does not point to a file`);\n }\n const di = isDenoInstalled(options.pathToDeno);\n if (!di.installed) {\n throw Error(`Could not start Deno executable \"${options.pathToDeno}\"`, { cause: di.error });\n }\n }\n\n // Check outDir is a directory\n if (options.outDir) {\n if (fs.existsSync(options.outDir) && !fs.lstatSync(options.outDir).isDirectory()) {\n throw Error(`\"${options.outDir}\" is not a directory`);\n }\n }\n\n // Check formats are valid\n const campaignDirNameFormat = options.dirNameFormat?.campaign;\n if (campaignDirNameFormat) {\n const validate = FilenameFormatHelper.validateCampaignDirNameFormat(campaignDirNameFormat);\n if (!validate.validateOK) {\n throw Error(`Campaign directory name format '${campaignDirNameFormat}' is invalid (matched against ${validate.regex})`);\n }\n }\n const contentDirNameFormat = options.dirNameFormat?.content;\n if (contentDirNameFormat) {\n const validate = FilenameFormatHelper.validateContentDirNameFormat(contentDirNameFormat);\n if (!validate.validateOK) {\n throw Error(`Content directory name format '${contentDirNameFormat}' is invalid (matched against ${validate.regex})`);\n }\n }\n const mediaFilenameFormat = options.filenameFormat?.media;\n if (mediaFilenameFormat) {\n const validate = FilenameFormatHelper.validateMediaFilenameFormat(mediaFilenameFormat);\n if (!validate.validateOK) {\n throw Error(`Media filename format '${mediaFilenameFormat}' is invalid (matched against ${validate.regex})`);\n }\n }\n\n return true;\n }\n\n protected async saveCampaignInfo(campaign: Campaign | null, signal?: AbortSignal) {\n const db = await this.db();\n if (!this.config.include.campaignInfo) {\n if (campaign) {\n db.saveCampaign(campaign, new Date());\n }\n return;\n }\n\n if (this.checkAbortSignal(signal)) {\n return;\n }\n\n let batch: DownloadTaskBatch | null = null;\n const abortHandler = () => {\n void (async () => {\n if (batch) {\n await batch.abort();\n }\n })();\n };\n if (signal) {\n signal.addEventListener('abort', abortHandler, { once: true });\n }\n\n if (!campaign) {\n this.log('warn', 'Skipped saving campaign info: target unavailable');\n return;\n }\n\n this.log('info', `Save campaign info #${campaign.id}`);\n this.emit('targetBegin', { target: campaign });\n this.emit('phaseBegin', { target: campaign, phase: 'saveInfo' });\n\n // Step 1: create campaign directories\n const campaignDirs = this.fsHelper.getCampaignDirs(campaign);\n this.log('debug', 'Campaign directories: ', campaignDirs);\n this.fsHelper.createDir(campaignDirs.root);\n this.fsHelper.createDir(campaignDirs.info);\n\n // Step 2: save summary and raw json\n const summary = generateCampaignSummary(campaign);\n const summaryFile = path.resolve(campaignDirs.info, 'info.txt');\n const saveSummaryResult = await this.fsHelper.writeTextFile(summaryFile, summary, this.config.fileExistsAction.info);\n this.logWriteTextFileResult(saveSummaryResult, campaign, 'campaign summary');\n\n // Campaign / creator raw data might not be complete. Fetch directly from API.\n // Strictly speaking, we should check for 'error' in results, but since it's not going to be fatal we'll just skip it.\n const { json: fetchedCampaignAPIData } = await this.fetchCampaign(campaign.id, signal);\n const { json: fetchedCreatorAPIData } = campaign.creator ? await this.fetchUser(campaign.creator.id, signal) : { json: null };\n\n if (this.checkAbortSignal(signal)) {\n return;\n }\n\n const campaignRawFile = path.resolve(campaignDirs.info, 'campaign-api.json');\n const saveCampaignRawResult = await this.fsHelper.writeTextFile(\n campaignRawFile, fetchedCampaignAPIData || campaign.raw, this.config.fileExistsAction.infoAPI);\n this.logWriteTextFileResult(saveCampaignRawResult, campaign, 'campaign API data');\n\n if (campaign.creator) {\n const creatorRawFile = path.resolve(campaignDirs.info, 'creator-api.json');\n const saveCreatorRawResult = await this.fsHelper.writeTextFile(\n creatorRawFile, fetchedCreatorAPIData || campaign.creator.raw, this.config.fileExistsAction.infoAPI);\n this.logWriteTextFileResult(saveCreatorRawResult, campaign.creator, 'creator API data');\n }\n\n this.emit('phaseEnd', { target: campaign, phase: 'saveInfo' });\n\n // Step 3: download campaign media items\n this.emit('phaseBegin', { target: campaign, phase: 'saveMedia' });\n const campaignMedia: Downloadable[] = [\n campaign.avatarImage,\n campaign.coverPhoto\n ];\n if (campaign.creator) {\n campaignMedia.push(\n campaign.creator.image,\n campaign.creator.thumbnail\n );\n }\n for (const reward of campaign.rewards) {\n if (reward.image) {\n campaignMedia.push(reward.image);\n }\n }\n batch = (await this.createDownloadTaskBatch(\n `Campaign #${campaign.id} (${campaign.name})`,\n signal,\n {\n target: campaignMedia,\n targetName: `campaign #${campaign.id} -> images`,\n src: campaign,\n dirs: {\n campaign: campaignDirs.root,\n main: campaignDirs.info,\n thumbnails: null\n },\n fileExistsAction: this.config.fileExistsAction.info\n }\n )).batch;\n if (this.checkAbortSignal(signal)) {\n return;\n }\n batch.prestart();\n this.emit('phaseBegin', { target: campaign, phase: 'batchDownload', batch });\n await batch.start();\n await batch.destroy();\n this.emit('phaseEnd', { target: campaign, phase: 'batchDownload' });\n this.emit('phaseEnd', { target: campaign, phase: 'saveMedia' });\n\n if (signal) {\n signal.removeEventListener('abort', abortHandler);\n }\n if (this.checkAbortSignal(signal)) {\n return;\n }\n\n // Step 4: save to DB\n db.saveCampaign(campaign, new Date());\n\n // Done\n this.log('info', 'Done saving campaign info');\n this.emit('targetEnd', { target: campaign, isSkipped: false });\n }\n\n protected log(level: LogLevel, ...msg: any[]) {\n commonLog(this.logger, level, this.name, ...msg);\n }\n\n getConfig(ro: false): DownloaderConfig<T>;\n getConfig(ro?: true): deepFreeze.DeepReadonly<DownloaderConfig<T>>;\n getConfig(ro = true) {\n return ro ? deepFreeze(this.config) : this.config;\n }\n\n protected checkAbortSignal(signal: AbortSignal | undefined) {\n if (signal && signal.aborted) {\n if (!this.#hasEmittedEndEventOnAbort) {\n this.emit('end', { aborted: true, message: 'Download aborted' });\n this.#hasEmittedEndEventOnAbort = true;\n }\n return true;\n }\n return false;\n }\n\n protected logWriteTextFileResult(result: WriteTextFileResult, target: {id: string}, targetName: string) {\n switch (result.status) {\n case 'completed':\n this.log('info', `Saved ${targetName} to \"${result.filePath}\"`);\n break;\n case 'skipped':\n this.log('warn', `Skipped saving ${targetName} #${target.id}: ${result.message}`);\n break;\n case 'error':\n this.log('error', `Error saving ${targetName} #${target.id} to \"${result.filePath}\":`, result.error);\n }\n }\n\n protected async commonFetchAPI(url: string, signal?: AbortSignal) {\n let json, requestAPIError: any;\n try {\n json = (await this.fetcher.get({ url, type: 'json', maxRetries: this.config.request.maxRetries, signal })).json;\n }\n catch (error) {\n if (signal?.aborted) {\n this.log('warn', 'API request aborted');\n }\n else {\n this.log('error', `Error requesting API URL \"${url}\": `, error);\n requestAPIError = error;\n }\n json = null;\n }\n return { json, error: requestAPIError };\n }\n\n protected fetchCampaign(campaignId: string, signal?: AbortSignal) {\n const url = URLHelper.constructCampaignAPIURL(campaignId);\n this.log('debug', `Fetch campaign data from API URL \"${url}\"`);\n return this.commonFetchAPI(url, signal);\n }\n\n protected fetchUser(userId: string, signal?: AbortSignal) {\n const url = URLHelper.constructUserAPIURL(userId);\n this.log('debug', `Fetch user data from API URL \"${url}\"`);\n return this.commonFetchAPI(url, signal);\n }\n\n protected async closeDB() {\n if (this.#dbPromise) {\n (await this.#dbPromise).close();\n this.#dbPromise = null;\n }\n }\n\n getFetcher() {\n return this.fetcher;\n }\n\n on<T extends DownloaderEvent>(event: T, listener: (args: DownloaderEventPayloadOf<T>) => void): this;\n on(event: string | symbol, listener: (...args: any[]) => void): this {\n return super.on(event, listener);\n }\n\n once<T extends DownloaderEvent>(event: T, listener: (args: DownloaderEventPayloadOf<T>) => void): this;\n once(event: string | symbol, listener: (...args: any[]) => void): this {\n return super.once(event, listener);\n }\n\n off<T extends DownloaderEvent>(event: T, listener: (args: DownloaderEventPayloadOf<T>) => void): this;\n off(event: string | symbol, listener: (...args: any[]) => void): this {\n return super.off(event, listener);\n }\n\n emit<T extends DownloaderEvent>(event: T, args: DownloaderEventPayloadOf<T>): boolean;\n emit(event: string | symbol, ...args: any[]): boolean {\n return super.emit(event, ...args);\n }\n}\n"]}
|
|
@@ -27,6 +27,7 @@ export interface DownloaderIncludeOptions {
|
|
|
27
27
|
contentInfo?: boolean;
|
|
28
28
|
previewMedia?: boolean | Array<'image' | 'video' | 'audio'>;
|
|
29
29
|
contentMedia?: boolean | Array<'image' | 'video' | 'audio' | 'attachment' | 'file'>;
|
|
30
|
+
protectedMedia?: boolean;
|
|
30
31
|
allMediaVariants?: boolean;
|
|
31
32
|
mediaThumbnails?: boolean;
|
|
32
33
|
mediaByFilename?: {
|
|
@@ -30,6 +30,7 @@ const DEFAULT_DOWNLOADER_INIT = {
|
|
|
30
30
|
campaignInfo: true,
|
|
31
31
|
contentInfo: true,
|
|
32
32
|
previewMedia: true,
|
|
33
|
+
protectedMedia: false,
|
|
33
34
|
contentMedia: true,
|
|
34
35
|
allMediaVariants: false,
|
|
35
36
|
mediaThumbnails: true,
|
|
@@ -101,6 +102,7 @@ export function getDownloaderInit(options) {
|
|
|
101
102
|
campaignInfo: pickDefined(options?.include?.campaignInfo, defaults.include.campaignInfo),
|
|
102
103
|
contentInfo: pickDefined(options?.include?.contentInfo, defaults.include.contentInfo),
|
|
103
104
|
previewMedia: pickDefined(options?.include?.previewMedia, defaults.include.previewMedia),
|
|
105
|
+
protectedMedia: pickDefined(options?.include?.protectedMedia, defaults.include.protectedMedia),
|
|
104
106
|
contentMedia: pickDefined(options?.include?.contentMedia, defaults.include.contentMedia),
|
|
105
107
|
allMediaVariants: pickDefined(options?.include?.allMediaVariants, defaults.include.allMediaVariants),
|
|
106
108
|
mediaThumbnails: pickDefined(options?.include?.mediaThumbnails, defaults.include.mediaThumbnails),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DownloaderOptions.js","sourceRoot":"","sources":["../../src/downloaders/DownloaderOptions.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'path';\nimport type Logger from '../utils/logging/Logger.js';\nimport { type DeepRequired, pickDefined } from '../utils/Misc.js';\nimport type DateTime from '../utils/DateTime.js';\n\nconst DEFAULT_USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0';\n\n\nexport type FileExistsAction = 'overwrite' | 'skip' | 'saveAsCopy' | 'saveAsCopyIfNewer';\nexport type StopOnCondition =\n 'never'\n | 'previouslyDownloaded'\n | 'publishDateOutOfRange'\n /**\n * @deprecated\n */\n | 'postPreviouslyDownloaded'\n /**\n * @deprecated\n */\n | 'postPublishDateOutOfRange';\n\nexport interface DownloaderIncludeOptions {\n lockedContent?: boolean;\n postsWithMediaType?: Array<'image' | 'video' | 'audio' | 'attachment' | 'podcast'> | 'any' | 'none';\n postsInTier?: Array<string> | 'any';\n postsPublished?: {\n after?: DateTime | null;\n before?: DateTime | null;\n }\n productsPublished?: {\n after?: DateTime | null;\n before?: DateTime | null;\n };\n campaignInfo?: boolean;\n contentInfo?: boolean;\n previewMedia?: boolean | Array<'image' | 'video' | 'audio'>;\n contentMedia?: boolean | Array<'image' | 'video' | 'audio' | 'attachment' | 'file'>;\n allMediaVariants?: boolean;\n mediaThumbnails?: boolean;\n mediaByFilename?: {\n images?: string | null;\n audio?: string | null;\n attachments?: string | null;\n };\n comments?: boolean;\n}\n\nexport interface ProxyOptions {\n url: string;\n rejectUnauthorizedTLS?: boolean;\n}\n\nexport interface EmbedDownloader {\n provider: string;\n exec: string;\n}\n\nexport interface DownloaderOptions {\n cookie?: string;\n useStatusCache?: boolean;\n stopOn?: StopOnCondition;\n pathToFFmpeg?: string | null;\n pathToYouTubeCredentials?: string | null;\n pathToDeno?: string | null;\n outDir?: string;\n dirNameFormat?: {\n campaign?: string;\n content?: string;\n };\n filenameFormat?: {\n media?: string;\n }\n include?: DownloaderIncludeOptions;\n request?: {\n maxRetries?: number;\n maxConcurrent?: number;\n minTime?: number;\n proxy?: ProxyOptions | null;\n userAgent?: string;\n };\n fileExistsAction?: {\n content?: FileExistsAction;\n info?: FileExistsAction;\n infoAPI?: FileExistsAction;\n };\n embedDownloaders?: EmbedDownloader[];\n maxVideoResolution?: number | null;\n logger?: Logger | null;\n dryRun?: boolean;\n}\n\nexport type DownloaderInit = DeepRequired<Pick<DownloaderOptions,\n 'outDir' |\n 'useStatusCache' |\n 'stopOn' |\n 'pathToFFmpeg' |\n 'pathToYouTubeCredentials' |\n 'pathToDeno' |\n 'dirNameFormat' |\n 'filenameFormat' |\n 'include' |\n 'request' |\n 'fileExistsAction' |\n 'embedDownloaders' |\n 'dryRun'>> & {\n cookie?: string;\n maxVideoResolution?: number | null;\n };\n\nconst DEFAULT_DOWNLOADER_INIT: DownloaderInit = {\n outDir: process.cwd(),\n useStatusCache: true,\n stopOn: 'never',\n pathToFFmpeg: null,\n pathToYouTubeCredentials: null,\n pathToDeno: null,\n dirNameFormat: {\n campaign: '{creator.vanity}[ - ]?{campaign.name}',\n content: '{content.id}[ - ]?{content.name}'\n },\n filenameFormat: {\n media: '{media.filename}'\n },\n include: {\n lockedContent: true,\n postsWithMediaType: 'any',\n postsInTier: 'any',\n postsPublished: {\n after: null,\n before: null\n },\n productsPublished: {\n after: null,\n before: null\n },\n campaignInfo: true,\n contentInfo: true,\n previewMedia: true,\n contentMedia: true,\n allMediaVariants: false,\n mediaThumbnails: true,\n mediaByFilename: {\n images: null,\n audio: null,\n attachments: null\n },\n comments: false\n },\n request: {\n maxRetries: 3,\n maxConcurrent: 10,\n minTime: 333,\n proxy: {\n url: '',\n rejectUnauthorizedTLS: true\n },\n userAgent: DEFAULT_USER_AGENT\n },\n fileExistsAction: {\n content: 'skip',\n info: 'saveAsCopyIfNewer',\n infoAPI: 'overwrite'\n },\n embedDownloaders: [],\n maxVideoResolution: null,\n dryRun: false\n};\n\nexport function getDownloaderInit(options?: DownloaderOptions): DownloaderInit {\n const defaults = DEFAULT_DOWNLOADER_INIT;\n\n let proxy: DownloaderInit['request']['proxy'] = null;\n if (options?.request?.proxy && defaults.request.proxy) {\n proxy = {\n url: options.request.proxy.url,\n rejectUnauthorizedTLS: pickDefined(options.request.proxy.rejectUnauthorizedTLS, defaults.request.proxy.rejectUnauthorizedTLS)\n };\n }\n if (!proxy?.url) {\n proxy = null;\n }\n\n return {\n cookie: options?.cookie,\n outDir: options?.outDir ? path.resolve(options.outDir) : defaults.outDir,\n useStatusCache: pickDefined(options?.useStatusCache, defaults.useStatusCache),\n stopOn: pickDefined(options?.stopOn, defaults.stopOn),\n pathToFFmpeg: pickDefined(options?.pathToFFmpeg, defaults.pathToFFmpeg),\n pathToYouTubeCredentials: pickDefined(options?.pathToYouTubeCredentials, defaults.pathToYouTubeCredentials),\n pathToDeno: pickDefined(options?.pathToDeno, defaults.pathToDeno),\n dirNameFormat: {\n campaign: options?.dirNameFormat?.campaign || defaults.dirNameFormat.campaign,\n content: options?.dirNameFormat?.content || defaults.dirNameFormat.content\n },\n filenameFormat: {\n media: options?.filenameFormat?.media || defaults.filenameFormat.media\n },\n include: {\n lockedContent: pickDefined(options?.include?.lockedContent, defaults.include.lockedContent),\n postsWithMediaType: pickDefined(options?.include?.postsWithMediaType, defaults.include.postsWithMediaType),\n postsInTier: pickDefined(options?.include?.postsInTier, defaults.include.postsInTier),\n postsPublished: {\n after: pickDefined(options?.include?.postsPublished?.after, defaults.include.postsPublished.after),\n before: pickDefined(options?.include?.postsPublished?.before, defaults.include.postsPublished.before)\n },\n productsPublished: {\n after: pickDefined(options?.include?.productsPublished?.after, defaults.include.productsPublished.after),\n before: pickDefined(options?.include?.productsPublished?.before, defaults.include.productsPublished.before)\n },\n campaignInfo: pickDefined(options?.include?.campaignInfo, defaults.include.campaignInfo),\n contentInfo: pickDefined(options?.include?.contentInfo, defaults.include.contentInfo),\n previewMedia: pickDefined(options?.include?.previewMedia, defaults.include.previewMedia),\n contentMedia: pickDefined(options?.include?.contentMedia, defaults.include.contentMedia),\n allMediaVariants: pickDefined(options?.include?.allMediaVariants, defaults.include.allMediaVariants),\n mediaThumbnails: pickDefined(options?.include?.mediaThumbnails, defaults.include.mediaThumbnails),\n mediaByFilename: {\n images: pickDefined(options?.include?.mediaByFilename?.images, defaults.include.mediaByFilename.images),\n audio: pickDefined(options?.include?.mediaByFilename?.audio, defaults.include.mediaByFilename.audio),\n attachments: pickDefined(options?.include?.mediaByFilename?.attachments, defaults.include.mediaByFilename.attachments)\n },\n comments: pickDefined(options?.include?.comments, defaults.include.comments)\n },\n request: {\n maxRetries: pickDefined(options?.request?.maxRetries, defaults.request.maxRetries),\n maxConcurrent: pickDefined(options?.request?.maxConcurrent, defaults.request.maxConcurrent),\n minTime: pickDefined(options?.request?.minTime, defaults.request.minTime),\n proxy,\n userAgent: pickDefined(options?.request?.userAgent, defaults.request.userAgent)\n },\n fileExistsAction: {\n content: options?.fileExistsAction?.content || defaults.fileExistsAction.content,\n info: options?.fileExistsAction?.info || defaults.fileExistsAction.info,\n infoAPI: options?.fileExistsAction?.infoAPI || defaults.fileExistsAction.infoAPI\n },\n embedDownloaders: pickDefined(options?.embedDownloaders, defaults.embedDownloaders),\n maxVideoResolution: pickDefined(options?.maxVideoResolution, defaults.maxVideoResolution),\n dryRun: pickDefined(options?.dryRun, defaults.dryRun)\n };\n}\n\nexport function getDefaultDownloaderOutDir() {\n return DEFAULT_DOWNLOADER_INIT.outDir;\n}\n\nexport function getDefaultDownloaderOptions(): DeepRequired<DownloaderOptions> {\n return {\n ...getDownloaderInit(),\n cookie: '',\n maxVideoResolution: null,\n logger: null\n };\n}"]}
|
|
1
|
+
{"version":3,"file":"DownloaderOptions.js","sourceRoot":"","sources":["../../src/downloaders/DownloaderOptions.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'path';\nimport type Logger from '../utils/logging/Logger.js';\nimport { type DeepRequired, pickDefined } from '../utils/Misc.js';\nimport type DateTime from '../utils/DateTime.js';\n\nconst DEFAULT_USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0';\n\n\nexport type FileExistsAction = 'overwrite' | 'skip' | 'saveAsCopy' | 'saveAsCopyIfNewer';\nexport type StopOnCondition =\n 'never'\n | 'previouslyDownloaded'\n | 'publishDateOutOfRange'\n /**\n * @deprecated\n */\n | 'postPreviouslyDownloaded'\n /**\n * @deprecated\n */\n | 'postPublishDateOutOfRange';\n\nexport interface DownloaderIncludeOptions {\n lockedContent?: boolean;\n postsWithMediaType?: Array<'image' | 'video' | 'audio' | 'attachment' | 'podcast'> | 'any' | 'none';\n postsInTier?: Array<string> | 'any';\n postsPublished?: {\n after?: DateTime | null;\n before?: DateTime | null;\n }\n productsPublished?: {\n after?: DateTime | null;\n before?: DateTime | null;\n };\n campaignInfo?: boolean;\n contentInfo?: boolean;\n previewMedia?: boolean | Array<'image' | 'video' | 'audio'>;\n contentMedia?: boolean | Array<'image' | 'video' | 'audio' | 'attachment' | 'file'>;\n protectedMedia?: boolean;\n allMediaVariants?: boolean;\n mediaThumbnails?: boolean;\n mediaByFilename?: {\n images?: string | null;\n audio?: string | null;\n attachments?: string | null;\n };\n comments?: boolean;\n}\n\nexport interface ProxyOptions {\n url: string;\n rejectUnauthorizedTLS?: boolean;\n}\n\nexport interface EmbedDownloader {\n provider: string;\n exec: string;\n}\n\nexport interface DownloaderOptions {\n cookie?: string;\n useStatusCache?: boolean;\n stopOn?: StopOnCondition;\n pathToFFmpeg?: string | null;\n pathToYouTubeCredentials?: string | null;\n pathToDeno?: string | null;\n outDir?: string;\n dirNameFormat?: {\n campaign?: string;\n content?: string;\n };\n filenameFormat?: {\n media?: string;\n }\n include?: DownloaderIncludeOptions;\n request?: {\n maxRetries?: number;\n maxConcurrent?: number;\n minTime?: number;\n proxy?: ProxyOptions | null;\n userAgent?: string;\n };\n fileExistsAction?: {\n content?: FileExistsAction;\n info?: FileExistsAction;\n infoAPI?: FileExistsAction;\n };\n embedDownloaders?: EmbedDownloader[];\n maxVideoResolution?: number | null;\n logger?: Logger | null;\n dryRun?: boolean;\n}\n\nexport type DownloaderInit = DeepRequired<Pick<DownloaderOptions,\n 'outDir' |\n 'useStatusCache' |\n 'stopOn' |\n 'pathToFFmpeg' |\n 'pathToYouTubeCredentials' |\n 'pathToDeno' |\n 'dirNameFormat' |\n 'filenameFormat' |\n 'include' |\n 'request' |\n 'fileExistsAction' |\n 'embedDownloaders' |\n 'dryRun'>> & {\n cookie?: string;\n maxVideoResolution?: number | null;\n };\n\nconst DEFAULT_DOWNLOADER_INIT: DownloaderInit = {\n outDir: process.cwd(),\n useStatusCache: true,\n stopOn: 'never',\n pathToFFmpeg: null,\n pathToYouTubeCredentials: null,\n pathToDeno: null,\n dirNameFormat: {\n campaign: '{creator.vanity}[ - ]?{campaign.name}',\n content: '{content.id}[ - ]?{content.name}'\n },\n filenameFormat: {\n media: '{media.filename}'\n },\n include: {\n lockedContent: true,\n postsWithMediaType: 'any',\n postsInTier: 'any',\n postsPublished: {\n after: null,\n before: null\n },\n productsPublished: {\n after: null,\n before: null\n },\n campaignInfo: true,\n contentInfo: true,\n previewMedia: true,\n protectedMedia: false,\n contentMedia: true,\n allMediaVariants: false,\n mediaThumbnails: true,\n mediaByFilename: {\n images: null,\n audio: null,\n attachments: null\n },\n comments: false\n },\n request: {\n maxRetries: 3,\n maxConcurrent: 10,\n minTime: 333,\n proxy: {\n url: '',\n rejectUnauthorizedTLS: true\n },\n userAgent: DEFAULT_USER_AGENT\n },\n fileExistsAction: {\n content: 'skip',\n info: 'saveAsCopyIfNewer',\n infoAPI: 'overwrite'\n },\n embedDownloaders: [],\n maxVideoResolution: null,\n dryRun: false\n};\n\nexport function getDownloaderInit(options?: DownloaderOptions): DownloaderInit {\n const defaults = DEFAULT_DOWNLOADER_INIT;\n\n let proxy: DownloaderInit['request']['proxy'] = null;\n if (options?.request?.proxy && defaults.request.proxy) {\n proxy = {\n url: options.request.proxy.url,\n rejectUnauthorizedTLS: pickDefined(options.request.proxy.rejectUnauthorizedTLS, defaults.request.proxy.rejectUnauthorizedTLS)\n };\n }\n if (!proxy?.url) {\n proxy = null;\n }\n\n return {\n cookie: options?.cookie,\n outDir: options?.outDir ? path.resolve(options.outDir) : defaults.outDir,\n useStatusCache: pickDefined(options?.useStatusCache, defaults.useStatusCache),\n stopOn: pickDefined(options?.stopOn, defaults.stopOn),\n pathToFFmpeg: pickDefined(options?.pathToFFmpeg, defaults.pathToFFmpeg),\n pathToYouTubeCredentials: pickDefined(options?.pathToYouTubeCredentials, defaults.pathToYouTubeCredentials),\n pathToDeno: pickDefined(options?.pathToDeno, defaults.pathToDeno),\n dirNameFormat: {\n campaign: options?.dirNameFormat?.campaign || defaults.dirNameFormat.campaign,\n content: options?.dirNameFormat?.content || defaults.dirNameFormat.content\n },\n filenameFormat: {\n media: options?.filenameFormat?.media || defaults.filenameFormat.media\n },\n include: {\n lockedContent: pickDefined(options?.include?.lockedContent, defaults.include.lockedContent),\n postsWithMediaType: pickDefined(options?.include?.postsWithMediaType, defaults.include.postsWithMediaType),\n postsInTier: pickDefined(options?.include?.postsInTier, defaults.include.postsInTier),\n postsPublished: {\n after: pickDefined(options?.include?.postsPublished?.after, defaults.include.postsPublished.after),\n before: pickDefined(options?.include?.postsPublished?.before, defaults.include.postsPublished.before)\n },\n productsPublished: {\n after: pickDefined(options?.include?.productsPublished?.after, defaults.include.productsPublished.after),\n before: pickDefined(options?.include?.productsPublished?.before, defaults.include.productsPublished.before)\n },\n campaignInfo: pickDefined(options?.include?.campaignInfo, defaults.include.campaignInfo),\n contentInfo: pickDefined(options?.include?.contentInfo, defaults.include.contentInfo),\n previewMedia: pickDefined(options?.include?.previewMedia, defaults.include.previewMedia),\n protectedMedia: pickDefined(options?.include?.protectedMedia, defaults.include.protectedMedia),\n contentMedia: pickDefined(options?.include?.contentMedia, defaults.include.contentMedia),\n allMediaVariants: pickDefined(options?.include?.allMediaVariants, defaults.include.allMediaVariants),\n mediaThumbnails: pickDefined(options?.include?.mediaThumbnails, defaults.include.mediaThumbnails),\n mediaByFilename: {\n images: pickDefined(options?.include?.mediaByFilename?.images, defaults.include.mediaByFilename.images),\n audio: pickDefined(options?.include?.mediaByFilename?.audio, defaults.include.mediaByFilename.audio),\n attachments: pickDefined(options?.include?.mediaByFilename?.attachments, defaults.include.mediaByFilename.attachments)\n },\n comments: pickDefined(options?.include?.comments, defaults.include.comments)\n },\n request: {\n maxRetries: pickDefined(options?.request?.maxRetries, defaults.request.maxRetries),\n maxConcurrent: pickDefined(options?.request?.maxConcurrent, defaults.request.maxConcurrent),\n minTime: pickDefined(options?.request?.minTime, defaults.request.minTime),\n proxy,\n userAgent: pickDefined(options?.request?.userAgent, defaults.request.userAgent)\n },\n fileExistsAction: {\n content: options?.fileExistsAction?.content || defaults.fileExistsAction.content,\n info: options?.fileExistsAction?.info || defaults.fileExistsAction.info,\n infoAPI: options?.fileExistsAction?.infoAPI || defaults.fileExistsAction.infoAPI\n },\n embedDownloaders: pickDefined(options?.embedDownloaders, defaults.embedDownloaders),\n maxVideoResolution: pickDefined(options?.maxVideoResolution, defaults.maxVideoResolution),\n dryRun: pickDefined(options?.dryRun, defaults.dryRun)\n };\n}\n\nexport function getDefaultDownloaderOutDir() {\n return DEFAULT_DOWNLOADER_INIT.outDir;\n}\n\nexport function getDefaultDownloaderOptions(): DeepRequired<DownloaderOptions> {\n return {\n ...getDownloaderInit(),\n cookie: '',\n maxVideoResolution: null,\n logger: null\n };\n}"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Post, Product } from "../entities/index.js";
|
|
2
|
+
import { type LogLevel } from "../utils/logging/Logger.js";
|
|
3
|
+
import type Logger from "../utils/logging/Logger.js";
|
|
4
|
+
import { type DownloaderConfig } from "./Downloader.js";
|
|
5
|
+
export type IncludeCriteriaCheckPostResult = {
|
|
6
|
+
ok: true;
|
|
7
|
+
} | {
|
|
8
|
+
ok: false;
|
|
9
|
+
reason: 'unviewable' | 'unmetMediaTypeCriteria' | 'notInTier' | 'publishDateOutOfRange';
|
|
10
|
+
};
|
|
11
|
+
export type IncludeCriteriaCheckProductResult = {
|
|
12
|
+
ok: true;
|
|
13
|
+
} | {
|
|
14
|
+
ok: false;
|
|
15
|
+
reason: 'unviewable' | 'publishDateOutOfRange';
|
|
16
|
+
};
|
|
17
|
+
export declare class IncludeCriteriaHelper {
|
|
18
|
+
name: 'IncludeCriteriaHelper';
|
|
19
|
+
protected logger?: Logger | null;
|
|
20
|
+
constructor(logger?: Logger | null);
|
|
21
|
+
checkPost(post: Post, config: DownloaderConfig<Post>): IncludeCriteriaCheckPostResult;
|
|
22
|
+
checkProduct(product: Product, config: DownloaderConfig<Product>): IncludeCriteriaCheckProductResult;
|
|
23
|
+
protected isPublishDateOutOfRange<T extends Post | Product>(entity: T, config: DownloaderConfig<T>): boolean;
|
|
24
|
+
protected log(level: LogLevel, ...msg: any[]): void;
|
|
25
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { isYouTubeEmbed } from "../entities/Downloadable.js";
|
|
2
|
+
import { commonLog } from "../utils/logging/Logger.js";
|
|
3
|
+
export class IncludeCriteriaHelper {
|
|
4
|
+
constructor(logger) {
|
|
5
|
+
this.logger = logger;
|
|
6
|
+
}
|
|
7
|
+
checkPost(post, config) {
|
|
8
|
+
// -- 1. Viewability
|
|
9
|
+
if (!post.isViewable && !config.include.lockedContent) {
|
|
10
|
+
return {
|
|
11
|
+
ok: false,
|
|
12
|
+
reason: 'unviewable'
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
// -- 2. Config option 'include.postsWithMediaType'
|
|
16
|
+
const postsWithMediaType = config.include.postsWithMediaType;
|
|
17
|
+
if (postsWithMediaType !== 'any') {
|
|
18
|
+
const hasAttachments = post.attachments.length > 0;
|
|
19
|
+
const hasAudio = !!post.audio || !!post.audioPreview;
|
|
20
|
+
const hasImages = post.images.length > 0;
|
|
21
|
+
const hasVideo = !!post.video || !!post.videoPreview || !!(post.embed && (post.embed.type === 'videoEmbed' || isYouTubeEmbed(post.embed)));
|
|
22
|
+
const isPodcast = post.postType === 'podcast';
|
|
23
|
+
let skip = false;
|
|
24
|
+
if (postsWithMediaType === 'none') {
|
|
25
|
+
skip = hasAttachments || hasAudio || hasImages || hasVideo;
|
|
26
|
+
}
|
|
27
|
+
else if (Array.isArray(postsWithMediaType)) {
|
|
28
|
+
skip = !((postsWithMediaType.includes('attachment') && hasAttachments) ||
|
|
29
|
+
(postsWithMediaType.includes('audio') && hasAudio) ||
|
|
30
|
+
(postsWithMediaType.includes('image') && hasImages) ||
|
|
31
|
+
(postsWithMediaType.includes('video') && hasVideo) ||
|
|
32
|
+
(postsWithMediaType.includes('podcast') && isPodcast && (hasAudio || hasVideo)));
|
|
33
|
+
}
|
|
34
|
+
if (skip) {
|
|
35
|
+
this.log('debug', 'Match criteria failed:', `config.include.postsWithMediaType: ${JSON.stringify(postsWithMediaType)} <-> post #${post.id}:`, {
|
|
36
|
+
hasAttachments,
|
|
37
|
+
hasAudio,
|
|
38
|
+
hasImages,
|
|
39
|
+
hasVideo
|
|
40
|
+
});
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
reason: 'unmetMediaTypeCriteria'
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// -- 3. Config option 'include.postsInTier'
|
|
48
|
+
const postsInTier = config.include.postsInTier;
|
|
49
|
+
const isAnyTier = postsInTier === 'any' || postsInTier.includes('any');
|
|
50
|
+
if (!isAnyTier) {
|
|
51
|
+
const applicableTierIds = postsInTier.filter((id) => post.campaign?.rewards.find((r) => r.id === id));
|
|
52
|
+
if (!post.campaign) {
|
|
53
|
+
this.log('warn', 'config.include.postsInTier: ignored - post missing campaign info');
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
this.log('debug', 'config.include.postsInTier: applicable tier IDs:', applicableTierIds);
|
|
57
|
+
}
|
|
58
|
+
let skip = false;
|
|
59
|
+
if (!post.campaign) {
|
|
60
|
+
skip = false;
|
|
61
|
+
}
|
|
62
|
+
else if (applicableTierIds.length === 0) {
|
|
63
|
+
skip = true;
|
|
64
|
+
}
|
|
65
|
+
else if (!post.tiers.find((tier) => tier.id === 'patrons')) {
|
|
66
|
+
skip = applicableTierIds.every((id) => !post.tiers.find((tier) => tier.id === id));
|
|
67
|
+
}
|
|
68
|
+
if (skip) {
|
|
69
|
+
this.log('debug', 'Match criteria failed:', `config.include.postsInTier: ${JSON.stringify(applicableTierIds)} <-> post #${post.id}:`, post.tiers);
|
|
70
|
+
return {
|
|
71
|
+
ok: false,
|
|
72
|
+
reason: 'notInTier'
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (post.campaign) {
|
|
76
|
+
this.log('debug', 'Match criteria OK:', `config.include.postsInTier: ${JSON.stringify(applicableTierIds)} <-> post #${post.id}:`, post.tiers);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// -- 4. Config option 'include.postsPublished'
|
|
80
|
+
if (this.isPublishDateOutOfRange(post, config)) {
|
|
81
|
+
return {
|
|
82
|
+
ok: false,
|
|
83
|
+
reason: 'publishDateOutOfRange'
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
ok: true
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
checkProduct(product, config) {
|
|
91
|
+
// -- 1. Viewability
|
|
92
|
+
if (!product.isAccessible && !config.include.lockedContent) {
|
|
93
|
+
return {
|
|
94
|
+
ok: false,
|
|
95
|
+
reason: 'unviewable'
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
// -- 2. Config option 'include.productsPublished'
|
|
99
|
+
if (this.isPublishDateOutOfRange(product, config)) {
|
|
100
|
+
return {
|
|
101
|
+
ok: false,
|
|
102
|
+
reason: 'publishDateOutOfRange'
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
ok: true
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
isPublishDateOutOfRange(entity, config) {
|
|
110
|
+
const publishedAfter = entity.type === 'post' ? config.include.postsPublished.after : config.include.productsPublished.after;
|
|
111
|
+
const publishedBefore = entity.type === 'post' ? config.include.postsPublished.before : config.include.productsPublished.before;
|
|
112
|
+
if (publishedAfter || publishedBefore) {
|
|
113
|
+
const targetPublishedAt = entity.publishedAt;
|
|
114
|
+
let parsedPublishedAt = null;
|
|
115
|
+
if (!targetPublishedAt) {
|
|
116
|
+
this.log('warn', `config.include.productsPublished: ignored - ${entity.type} #${entity.id} missing publish date`);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
try {
|
|
120
|
+
parsedPublishedAt = new Date(targetPublishedAt);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
this.log('error', `Failed to parse publish date of ${entity.type} #${entity.id} ("${targetPublishedAt}"): `, error);
|
|
124
|
+
this.log('warn', `config.include.productsPublished: ignored - publish date of ${entity.type} #${entity.id} could not be parsed`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
let skip = false;
|
|
128
|
+
if (parsedPublishedAt) {
|
|
129
|
+
const isAfter = publishedAfter ? parsedPublishedAt.getTime() >= publishedAfter.valueOf().getTime() : true;
|
|
130
|
+
const isBefore = publishedBefore ? parsedPublishedAt.getTime() < publishedBefore.valueOf().getTime() : true;
|
|
131
|
+
skip = !isAfter || !isBefore;
|
|
132
|
+
let eq = null;
|
|
133
|
+
if (publishedAfter && publishedBefore) {
|
|
134
|
+
eq = `${publishedAfter.toString()} <= *${targetPublishedAt}* < ${publishedBefore.toString()}`;
|
|
135
|
+
}
|
|
136
|
+
else if (publishedAfter) {
|
|
137
|
+
eq = `${publishedAfter.toString()} <= *${targetPublishedAt}*`;
|
|
138
|
+
}
|
|
139
|
+
else if (publishedBefore) {
|
|
140
|
+
eq = `*${targetPublishedAt}* < ${publishedBefore.toString()}`;
|
|
141
|
+
}
|
|
142
|
+
if (eq) {
|
|
143
|
+
if (skip) {
|
|
144
|
+
// this.log('warn', `Skipped downloading ${entity.type} #${entity.id}: publish date out of range`);
|
|
145
|
+
this.log('debug', `Publish date test failed for ${entity.type} #${entity.id}: ${eq}`);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
this.log('debug', `Publish date test OK for ${entity.type} #${entity.id}: ${eq}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return skip;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
log(level, ...msg) {
|
|
157
|
+
commonLog(this.logger, level, this.name, ...msg);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=IncludeCriteriaHelper.js.map
|