patreon-dl 1.6.1 → 1.7.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.
Files changed (77) hide show
  1. package/README.md +11 -0
  2. package/dist/cli/CLIOptions.d.ts.map +1 -1
  3. package/dist/cli/CLIOptions.js +1 -0
  4. package/dist/cli/CLIOptions.js.map +1 -1
  5. package/dist/cli/CommandLineParser.d.ts.map +1 -1
  6. package/dist/cli/CommandLineParser.js +13 -2
  7. package/dist/cli/CommandLineParser.js.map +1 -1
  8. package/dist/cli/ConfigFileParser.d.ts.map +1 -1
  9. package/dist/cli/ConfigFileParser.js +2 -0
  10. package/dist/cli/ConfigFileParser.js.map +1 -1
  11. package/dist/cli/helper/YouTubeConfigurator.js +2 -2
  12. package/dist/cli/helper/YouTubeConfigurator.js.map +1 -1
  13. package/dist/downloaders/Downloader.d.ts +2 -1
  14. package/dist/downloaders/Downloader.d.ts.map +1 -1
  15. package/dist/downloaders/Downloader.js +10 -12
  16. package/dist/downloaders/Downloader.js.map +1 -1
  17. package/dist/downloaders/DownloaderOptions.d.ts +2 -1
  18. package/dist/downloaders/DownloaderOptions.d.ts.map +1 -1
  19. package/dist/downloaders/DownloaderOptions.js +4 -2
  20. package/dist/downloaders/DownloaderOptions.js.map +1 -1
  21. package/dist/downloaders/PostDownloader.d.ts.map +1 -1
  22. package/dist/downloaders/PostDownloader.js +72 -167
  23. package/dist/downloaders/PostDownloader.js.map +1 -1
  24. package/dist/downloaders/PostsFetcher.d.ts +59 -0
  25. package/dist/downloaders/PostsFetcher.d.ts.map +1 -0
  26. package/dist/downloaders/PostsFetcher.js +348 -0
  27. package/dist/downloaders/PostsFetcher.js.map +1 -0
  28. package/dist/downloaders/ProductDownloader.d.ts.map +1 -1
  29. package/dist/downloaders/ProductDownloader.js +6 -7
  30. package/dist/downloaders/ProductDownloader.js.map +1 -1
  31. package/dist/downloaders/cache/StatusCache.d.ts +2 -2
  32. package/dist/downloaders/cache/StatusCache.d.ts.map +1 -1
  33. package/dist/downloaders/cache/StatusCache.js +11 -7
  34. package/dist/downloaders/cache/StatusCache.js.map +1 -1
  35. package/dist/downloaders/task/DownloadTask.d.ts +6 -1
  36. package/dist/downloaders/task/DownloadTask.d.ts.map +1 -1
  37. package/dist/downloaders/task/DownloadTask.js +19 -7
  38. package/dist/downloaders/task/DownloadTask.js.map +1 -1
  39. package/dist/downloaders/task/DownloadTaskFactory.d.ts +2 -4
  40. package/dist/downloaders/task/DownloadTaskFactory.d.ts.map +1 -1
  41. package/dist/downloaders/task/DownloadTaskFactory.js +15 -8
  42. package/dist/downloaders/task/DownloadTaskFactory.js.map +1 -1
  43. package/dist/downloaders/task/ExternalDownloaderTask.d.ts +2 -1
  44. package/dist/downloaders/task/ExternalDownloaderTask.d.ts.map +1 -1
  45. package/dist/downloaders/task/ExternalDownloaderTask.js +10 -3
  46. package/dist/downloaders/task/ExternalDownloaderTask.js.map +1 -1
  47. package/dist/downloaders/task/FFmpegDownloadTaskBase.d.ts.map +1 -1
  48. package/dist/downloaders/task/FFmpegDownloadTaskBase.js +15 -7
  49. package/dist/downloaders/task/FFmpegDownloadTaskBase.js.map +1 -1
  50. package/dist/downloaders/task/FetcherDownloadTask.d.ts.map +1 -1
  51. package/dist/downloaders/task/FetcherDownloadTask.js +5 -6
  52. package/dist/downloaders/task/FetcherDownloadTask.js.map +1 -1
  53. package/dist/parsers/PostParser.d.ts +1 -0
  54. package/dist/parsers/PostParser.d.ts.map +1 -1
  55. package/dist/parsers/PostParser.js +15 -12
  56. package/dist/parsers/PostParser.js.map +1 -1
  57. package/dist/utils/FSHelper.d.ts +23 -7
  58. package/dist/utils/FSHelper.d.ts.map +1 -1
  59. package/dist/utils/FSHelper.js +99 -30
  60. package/dist/utils/FSHelper.js.map +1 -1
  61. package/dist/utils/Fetcher.d.ts +2 -1
  62. package/dist/utils/Fetcher.d.ts.map +1 -1
  63. package/dist/utils/Fetcher.js +29 -11
  64. package/dist/utils/Fetcher.js.map +1 -1
  65. package/dist/utils/Sleeper.d.ts +9 -0
  66. package/dist/utils/Sleeper.d.ts.map +1 -0
  67. package/dist/utils/Sleeper.js +68 -0
  68. package/dist/utils/Sleeper.js.map +1 -0
  69. package/dist/utils/URLHelper.d.ts +1 -1
  70. package/dist/utils/URLHelper.d.ts.map +1 -1
  71. package/dist/utils/URLHelper.js +9 -0
  72. package/dist/utils/URLHelper.js.map +1 -1
  73. package/dist/utils/logging/ConsoleLogger.d.ts +1 -0
  74. package/dist/utils/logging/ConsoleLogger.d.ts.map +1 -1
  75. package/dist/utils/logging/ConsoleLogger.js +21 -9
  76. package/dist/utils/logging/ConsoleLogger.js.map +1 -1
  77. package/package.json +1 -1
@@ -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, { DownloaderBootstrapData, DownloaderType } from './Bootstrap.js';\nimport { DownloaderInit, DownloaderOptions, FileExistsAction, getDownloaderInit } from './DownloaderOptions.js';\nimport { DownloaderEvent, DownloaderEventPayloadOf } from './DownloaderEvent.js';\nimport Logger, { LogLevel, commonLog } from '../utils/logging/Logger.js';\nimport { Campaign } from '../entities/Campaign.js';\nimport FSHelper, { WriteTextFileResult } from '../utils/FSHelper.js';\nimport DownloadTaskBatch from './task/DownloadTaskBatch.js';\nimport { IDownloadTask } from './task/DownloadTask.js';\nimport DownloadTaskFactory from './task/DownloadTaskFactory.js';\nimport FilenameFormatHelper from '../utils/FilenameFormatHelper.js';\nimport { Downloadable } from '../entities/Downloadable.js';\nimport { generateCampaignSummary } from './templates/CampaignInfo.js';\nimport path from 'path';\nimport URLHelper from '../utils/URLHelper.js';\nimport { AbortError } from 'node-fetch';\nimport ffmpeg from 'fluent-ffmpeg';\nimport InnertubeLoader from '../utils/InnertubeLoader.js';\nimport FFmpegDownloadTaskBase from './task/FFmpegDownloadTaskBase.js';\nimport { UserIdOrVanityParam } from '../entities/User.js';\nimport ExternalDownloaderTask from './task/ExternalDownloaderTask.js';\n\nexport type DownloaderConfig<T extends DownloaderType> =\n DownloaderInit &\n Omit<DownloaderBootstrapData<T>, 'type'>;\n\nexport interface DownloaderStartParams {\n signal?: AbortSignal;\n}\n\ninterface CreateDownloadTaskParams {\n target: Downloadable[];\n targetName: string;\n destDir: string;\n fileExistsAction: FileExistsAction;\n}\n\nexport default abstract class Downloader<T extends DownloaderType> extends EventEmitter {\n\n abstract name: string;\n\n protected fetcher: Fetcher;\n protected config: DownloaderConfig<T>;\n protected logger?: Logger | null;\n\n #hasEmittedEndEventOnAbort: boolean;\n\n constructor(bootstrap: DownloaderBootstrapData<T>, options?: DownloaderOptions) {\n super();\n this.#validateOptions(options);\n\n this.config = {\n ...bootstrap,\n ...getDownloaderInit(options)\n };\n\n this.fetcher = new Fetcher(options?.cookie, options?.logger);\n this.logger = options?.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.loadCredentials(this.config.pathToYouTubeCredentials);\n }\n\n this.#hasEmittedEndEventOnAbort = false;\n }\n\n protected createDownloadTaskBatch(name: string, ...createTasks: Array<CreateDownloadTaskParams | null>): DownloadTaskBatch {\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 });\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} downloading through FFmpeg (${__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 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, ...createTasks);\n }\n\n protected addToDownloadTaskBatch(batch: DownloadTaskBatch, ...createTasks: Array<CreateDownloadTaskParams | null>) {\n let failedCreateTaskCount = 0;\n for (const task of createTasks) {\n if (!task) {\n continue;\n }\n const { target, targetName, destDir } = 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 createdCount = 0;\n for (const tt of target) {\n try {\n const tasks = DownloadTaskFactory.createFromDownloadable({\n item: tt,\n destDir,\n fetcher: this.fetcher,\n embedDownloaders: this.config.embedDownloaders,\n destFilenameFormat: this.config.filenameFormat.media,\n fileExistsAction: task.fileExistsAction,\n maxRetries: this.config.request.maxRetries,\n downloadAllVariants: this.config.include.allMediaVariants,\n logger: this.logger\n });\n batch.addTasks(tasks);\n createdCount += tasks.length;\n }\n catch (error) {\n this.log('error', `Failed to create download task for item #${tt.id} in ${targetName}:`, error);\n failedCreateTaskCount++;\n }\n }\n if (createdCount > 0) {\n FSHelper.createDir(destDir);\n }\n }\n if (failedCreateTaskCount > 0) {\n this.log('warn', `${failedCreateTaskCount} items could not be processed for downloading`);\n }\n return batch;\n }\n\n abstract start(params: DownloaderStartParams): Promise<void>;\n\n static async getInstance(url: string, options?: DownloaderOptions) {\n const bootstrap = Bootstrap.getDownloaderBootstrapDataByURL(url);\n if (!bootstrap) {\n throw Error('Could not determine downloader type from URL');\n }\n switch (bootstrap.type) {\n case 'product':\n const ProductDownloader = (await import('./ProductDownloader.js')).default;\n return new ProductDownloader(bootstrap, options);\n case 'post':\n const PostDownloader = (await import('./PostDownloader.js')).default;\n return new PostDownloader(bootstrap, options);\n }\n }\n\n static async getCampaign(\n creator: string | UserIdOrVanityParam,\n signal?: AbortSignal,\n logger?: Logger | null\n ) {\n // Backwards compatibility - if 'creator' is string type, then it is vanity\n const url = URLHelper.constructUserPostsURL(typeof creator === 'object' ? creator : { vanity: creator });\n const downloader = await this.getInstance(url, { logger });\n const PostDownloader = (await import('./PostDownloader.js')).default;\n if (downloader instanceof PostDownloader) {\n return downloader.__getCampaign(signal);\n }\n throw Error('Type mismatch: PostDownloader expected');\n }\n\n #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 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 saveCampaignInfo(campaign: Campaign | null, signal?: AbortSignal) {\n\n return new Promise<void>(async (resolve) => {\n if (!this.config.include.campaignInfo) {\n resolve();\n return;\n }\n\n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n\n let batch: DownloadTaskBatch | null = null;\n const abortHandler = async () => {\n if (batch) {\n await batch.abort();\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 resolve();\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 = FSHelper.getCampaignDirs(campaign, this.config);\n this.log('debug', 'Campaign directories: ', campaignDirs);\n FSHelper.createDir(campaignDirs.root);\n 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 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, resolve)) {\n return;\n }\n\n const campaignRawFile = path.resolve(campaignDirs.info, 'campaign-api.json');\n const saveCampaignRawResult = await 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 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 = this.createDownloadTaskBatch(\n `Campaign #${campaign.id} (${campaign.name})`,\n {\n target: campaignMedia,\n targetName: `campaign #${campaign.id} -> images`,\n destDir: campaignDirs.info,\n fileExistsAction: this.config.fileExistsAction.info\n }\n );\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, resolve)) {\n return;\n }\n\n // Done\n this.log('info', 'Done saving campaign info');\n this.emit('targetEnd', { target: campaign, isSkipped: false });\n\n resolve();\n });\n\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, resolve: () => void) {\n if (signal && signal.aborted) {\n if (!this.#hasEmittedEndEventOnAbort) {\n this.emit('end', { aborted: true, message: 'Download aborted' });\n this.#hasEmittedEndEventOnAbort = true;\n }\n resolve();\n return true;\n }\n return false;\n }\n\n protected logWriteTextFileResult<T>(result: WriteTextFileResult, target: T & {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 });\n }\n catch (error) {\n if (error instanceof AbortError) {\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 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, { DownloaderBootstrapData, DownloaderType } from './Bootstrap.js';\nimport { DownloaderInit, DownloaderOptions, FileExistsAction, getDownloaderInit } from './DownloaderOptions.js';\nimport { DownloaderEvent, DownloaderEventPayloadOf } from './DownloaderEvent.js';\nimport Logger, { LogLevel, commonLog } from '../utils/logging/Logger.js';\nimport { Campaign } from '../entities/Campaign.js';\nimport FSHelper, { WriteTextFileResult } from '../utils/FSHelper.js';\nimport DownloadTaskBatch from './task/DownloadTaskBatch.js';\nimport { IDownloadTask } from './task/DownloadTask.js';\nimport DownloadTaskFactory from './task/DownloadTaskFactory.js';\nimport FilenameFormatHelper from '../utils/FilenameFormatHelper.js';\nimport { Downloadable } from '../entities/Downloadable.js';\nimport { generateCampaignSummary } from './templates/CampaignInfo.js';\nimport path from 'path';\nimport URLHelper from '../utils/URLHelper.js';\nimport { AbortError } from 'node-fetch';\nimport ffmpeg from 'fluent-ffmpeg';\nimport InnertubeLoader from '../utils/InnertubeLoader.js';\nimport FFmpegDownloadTaskBase from './task/FFmpegDownloadTaskBase.js';\nimport { UserIdOrVanityParam } from '../entities/User.js';\nimport ExternalDownloaderTask from './task/ExternalDownloaderTask.js';\n\nexport type DownloaderConfig<T extends DownloaderType> =\n DownloaderInit &\n Omit<DownloaderBootstrapData<T>, 'type'>;\n\nexport interface DownloaderStartParams {\n signal?: AbortSignal;\n}\n\ninterface CreateDownloadTaskParams {\n target: Downloadable[];\n targetName: string;\n destDir: string;\n fileExistsAction: FileExistsAction;\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\n #hasEmittedEndEventOnAbort: boolean;\n\n constructor(bootstrap: DownloaderBootstrapData<T>, options?: DownloaderOptions) {\n super();\n this.#validateOptions(options);\n\n this.config = {\n ...bootstrap,\n ...getDownloaderInit(options)\n };\n\n this.fetcher = new Fetcher(this.config, options?.cookie, options?.logger);\n this.fsHelper = new FSHelper(this.config, this.logger);\n this.logger = options?.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.loadCredentials(this.config.pathToYouTubeCredentials);\n }\n\n this.#hasEmittedEndEventOnAbort = false;\n }\n\n protected createDownloadTaskBatch(name: string, ...createTasks: Array<CreateDownloadTaskParams | null>): DownloadTaskBatch {\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 });\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} downloading through FFmpeg (${__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 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, ...createTasks);\n }\n\n protected addToDownloadTaskBatch(batch: DownloadTaskBatch, ...createTasks: Array<CreateDownloadTaskParams | null>) {\n let failedCreateTaskCount = 0;\n for (const task of createTasks) {\n if (!task) {\n continue;\n }\n const { target, targetName, destDir } = 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 createdCount = 0;\n for (const tt of target) {\n try {\n const tasks = DownloadTaskFactory.createFromDownloadable({\n config: this.config,\n item: tt,\n destDir,\n fetcher: this.fetcher,\n fileExistsAction: task.fileExistsAction,\n logger: this.logger\n });\n batch.addTasks(tasks);\n createdCount += tasks.length;\n }\n catch (error) {\n this.log('error', `Failed to create download task for item #${tt.id} in ${targetName}:`, error);\n failedCreateTaskCount++;\n }\n }\n if (createdCount > 0) {\n this.fsHelper.createDir(destDir);\n }\n }\n if (failedCreateTaskCount > 0) {\n this.log('warn', `${failedCreateTaskCount} items could not be processed for downloading`);\n }\n return batch;\n }\n\n abstract start(params: DownloaderStartParams): Promise<void>;\n\n static async getInstance(url: string, options?: DownloaderOptions) {\n const bootstrap = Bootstrap.getDownloaderBootstrapDataByURL(url);\n if (!bootstrap) {\n throw Error('Could not determine downloader type from URL');\n }\n switch (bootstrap.type) {\n case 'product':\n const ProductDownloader = (await import('./ProductDownloader.js')).default;\n return new ProductDownloader(bootstrap, options);\n case 'post':\n const PostDownloader = (await import('./PostDownloader.js')).default;\n return new PostDownloader(bootstrap, options);\n }\n }\n\n static async getCampaign(\n creator: string | UserIdOrVanityParam,\n signal?: AbortSignal,\n logger?: Logger | null\n ) {\n // Backwards compatibility - if 'creator' is string type, then it is vanity\n const url = URLHelper.constructUserPostsURL(typeof creator === 'object' ? creator : { vanity: creator });\n const downloader = await this.getInstance(url, { logger });\n const PostDownloader = (await import('./PostDownloader.js')).default;\n if (downloader instanceof PostDownloader) {\n return downloader.__getCampaign(signal);\n }\n throw Error('Type mismatch: PostDownloader expected');\n }\n\n #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 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 saveCampaignInfo(campaign: Campaign | null, signal?: AbortSignal) {\n\n return new Promise<void>(async (resolve) => {\n if (!this.config.include.campaignInfo) {\n resolve();\n return;\n }\n\n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n\n let batch: DownloadTaskBatch | null = null;\n const abortHandler = async () => {\n if (batch) {\n await batch.abort();\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 resolve();\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, resolve)) {\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 = this.createDownloadTaskBatch(\n `Campaign #${campaign.id} (${campaign.name})`,\n {\n target: campaignMedia,\n targetName: `campaign #${campaign.id} -> images`,\n destDir: campaignDirs.info,\n fileExistsAction: this.config.fileExistsAction.info\n }\n );\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, resolve)) {\n return;\n }\n\n // Done\n this.log('info', 'Done saving campaign info');\n this.emit('targetEnd', { target: campaign, isSkipped: false });\n\n resolve();\n });\n\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, resolve: () => void) {\n if (signal && signal.aborted) {\n if (!this.#hasEmittedEndEventOnAbort) {\n this.emit('end', { aborted: true, message: 'Download aborted' });\n this.#hasEmittedEndEventOnAbort = true;\n }\n resolve();\n return true;\n }\n return false;\n }\n\n protected logWriteTextFileResult<T>(result: WriteTextFileResult, target: T & {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 });\n }\n catch (error) {\n if (error instanceof AbortError) {\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 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"]}
@@ -41,8 +41,9 @@ export interface DownloaderOptions {
41
41
  };
42
42
  embedDownloaders?: EmbedDownloader[];
43
43
  logger?: Logger | null;
44
+ dryRun?: boolean;
44
45
  }
45
- export type DownloaderInit = DeepRequired<Pick<DownloaderOptions, 'outDir' | 'useStatusCache' | 'pathToFFmpeg' | 'pathToYouTubeCredentials' | 'dirNameFormat' | 'filenameFormat' | 'include' | 'request' | 'fileExistsAction' | 'embedDownloaders'>>;
46
+ export type DownloaderInit = DeepRequired<Pick<DownloaderOptions, 'outDir' | 'useStatusCache' | 'pathToFFmpeg' | 'pathToYouTubeCredentials' | 'dirNameFormat' | 'filenameFormat' | 'include' | 'request' | 'fileExistsAction' | 'embedDownloaders' | 'dryRun'>>;
46
47
  export declare function getDownloaderInit(options?: DownloaderOptions): DownloaderInit;
47
48
  export declare function getDefaultDownloaderOutDir(): string;
48
49
  //# sourceMappingURL=DownloaderOptions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DownloaderOptions.d.ts","sourceRoot":"","sources":["../../src/downloaders/DownloaderOptions.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,4BAA4B,CAAC;AAChD,OAAO,EAAE,YAAY,EAAe,MAAM,kBAAkB,CAAC;AAE7D,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,mBAAmB,CAAC;AAEzF,MAAM,WAAW,wBAAwB;IACvC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,KAAK,CAAC,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,YAAY,CAAC,GAAG,KAAK,GAAG,MAAM,CAAC;IACxF,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;IACpC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC,CAAC;IAC5D,YAAY,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,YAAY,GAAG,MAAM,CAAC,CAAC;IACpF,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,cAAc,CAAC,EAAE;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAA;IACD,OAAO,CAAC,EAAE,wBAAwB,CAAC;IACnC,OAAO,CAAC,EAAE;QACR,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,gBAAgB,CAAC,EAAE;QACjB,OAAO,CAAC,EAAE,gBAAgB,CAAC;QAC3B,IAAI,CAAC,EAAE,gBAAgB,CAAC;QACxB,OAAO,CAAC,EAAE,gBAAgB,CAAC;KAC5B,CAAC;IACF,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,MAAM,cAAc,GAAG,YAAY,CAAC,IAAI,CAAC,iBAAiB,EAC9D,QAAQ,GACR,gBAAgB,GAChB,cAAc,GACd,0BAA0B,GAC1B,eAAe,GACf,gBAAgB,GAChB,SAAS,GACT,SAAS,GACT,kBAAkB,GAClB,kBAAkB,CAAC,CAAC,CAAC;AAqCvB,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,cAAc,CAoC7E;AAED,wBAAgB,0BAA0B,WAEzC"}
1
+ {"version":3,"file":"DownloaderOptions.d.ts","sourceRoot":"","sources":["../../src/downloaders/DownloaderOptions.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,4BAA4B,CAAC;AAChD,OAAO,EAAE,YAAY,EAAe,MAAM,kBAAkB,CAAC;AAE7D,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,mBAAmB,CAAC;AAEzF,MAAM,WAAW,wBAAwB;IACvC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,KAAK,CAAC,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,YAAY,CAAC,GAAG,KAAK,GAAG,MAAM,CAAC;IACxF,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;IACpC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC,CAAC;IAC5D,YAAY,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,YAAY,GAAG,MAAM,CAAC,CAAC;IACpF,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,cAAc,CAAC,EAAE;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAA;IACD,OAAO,CAAC,EAAE,wBAAwB,CAAC;IACnC,OAAO,CAAC,EAAE;QACR,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,gBAAgB,CAAC,EAAE;QACjB,OAAO,CAAC,EAAE,gBAAgB,CAAC;QAC3B,IAAI,CAAC,EAAE,gBAAgB,CAAC;QACxB,OAAO,CAAC,EAAE,gBAAgB,CAAC;KAC5B,CAAC;IACF,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,cAAc,GAAG,YAAY,CAAC,IAAI,CAAC,iBAAiB,EAC9D,QAAQ,GACR,gBAAgB,GAChB,cAAc,GACd,0BAA0B,GAC1B,eAAe,GACf,gBAAgB,GAChB,SAAS,GACT,SAAS,GACT,kBAAkB,GAClB,kBAAkB,GAClB,QAAQ,CAAC,CAAC,CAAC;AAsCb,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,cAAc,CAqC7E;AAED,wBAAgB,0BAA0B,WAEzC"}
@@ -32,7 +32,8 @@ const DEFAULT_DOWNLOADER_INIT = {
32
32
  info: 'saveAsCopyIfNewer',
33
33
  infoAPI: 'overwrite'
34
34
  },
35
- embedDownloaders: []
35
+ embedDownloaders: [],
36
+ dryRun: false
36
37
  };
37
38
  export function getDownloaderInit(options) {
38
39
  const defaults = DEFAULT_DOWNLOADER_INIT;
@@ -68,7 +69,8 @@ export function getDownloaderInit(options) {
68
69
  info: options?.fileExistsAction?.info || defaults.fileExistsAction.info,
69
70
  infoAPI: options?.fileExistsAction?.infoAPI || defaults.fileExistsAction.infoAPI
70
71
  },
71
- embedDownloaders: pickDefined(options?.embedDownloaders, defaults.embedDownloaders)
72
+ embedDownloaders: pickDefined(options?.embedDownloaders, defaults.embedDownloaders),
73
+ dryRun: pickDefined(options?.dryRun, defaults.dryRun)
72
74
  };
73
75
  }
74
76
  export function getDefaultDownloaderOutDir() {
@@ -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 Logger from '../utils/logging/Logger.js';\nimport { DeepRequired, pickDefined } from '../utils/Misc.js';\n\nexport type FileExistsAction = 'overwrite' | 'skip' | 'saveAsCopy' | 'saveAsCopyIfNewer';\n\nexport interface DownloaderIncludeOptions {\n lockedContent?: boolean;\n postsWithMediaType?: Array<'image' | 'video' | 'audio' | 'attachment'> | 'any' | 'none';\n postsInTier?: Array<string> | 'any';\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}\n\nexport interface EmbedDownloader {\n provider: string;\n exec: string;\n}\n\nexport interface DownloaderOptions {\n cookie?: string;\n useStatusCache?: boolean;\n pathToFFmpeg?: string | null;\n pathToYouTubeCredentials?: 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 };\n fileExistsAction?: {\n content?: FileExistsAction;\n info?: FileExistsAction;\n infoAPI?: FileExistsAction;\n };\n embedDownloaders?: EmbedDownloader[];\n logger?: Logger | null;\n}\n\nexport type DownloaderInit = DeepRequired<Pick<DownloaderOptions,\n 'outDir' |\n 'useStatusCache' |\n 'pathToFFmpeg' |\n 'pathToYouTubeCredentials' |\n 'dirNameFormat' |\n 'filenameFormat' |\n 'include' |\n 'request' |\n 'fileExistsAction' |\n 'embedDownloaders'>>;\n\nconst DEFAULT_DOWNLOADER_INIT: DeepRequired<DownloaderInit> = {\n outDir: process.cwd(),\n useStatusCache: true,\n pathToFFmpeg: null,\n pathToYouTubeCredentials: 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 campaignInfo: true,\n contentInfo: true,\n previewMedia: true,\n contentMedia: true,\n allMediaVariants: false\n },\n request: {\n maxRetries: 3,\n maxConcurrent: 10,\n minTime: 333\n },\n fileExistsAction: {\n content: 'skip',\n info: 'saveAsCopyIfNewer',\n infoAPI: 'overwrite'\n },\n embedDownloaders: []\n};\n\nexport function getDownloaderInit(options?: DownloaderOptions): DownloaderInit {\n const defaults = DEFAULT_DOWNLOADER_INIT;\n return {\n outDir: options?.outDir ? path.resolve(options.outDir) : defaults.outDir,\n useStatusCache: pickDefined(options?.useStatusCache, defaults.useStatusCache),\n pathToFFmpeg: pickDefined(options?.pathToFFmpeg, defaults.pathToFFmpeg),\n pathToYouTubeCredentials: pickDefined(options?.pathToYouTubeCredentials, defaults.pathToYouTubeCredentials),\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 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 },\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 },\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 };\n}\n\nexport function getDefaultDownloaderOutDir() {\n return DEFAULT_DOWNLOADER_INIT.outDir;\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 Logger from '../utils/logging/Logger.js';\nimport { DeepRequired, pickDefined } from '../utils/Misc.js';\n\nexport type FileExistsAction = 'overwrite' | 'skip' | 'saveAsCopy' | 'saveAsCopyIfNewer';\n\nexport interface DownloaderIncludeOptions {\n lockedContent?: boolean;\n postsWithMediaType?: Array<'image' | 'video' | 'audio' | 'attachment'> | 'any' | 'none';\n postsInTier?: Array<string> | 'any';\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}\n\nexport interface EmbedDownloader {\n provider: string;\n exec: string;\n}\n\nexport interface DownloaderOptions {\n cookie?: string;\n useStatusCache?: boolean;\n pathToFFmpeg?: string | null;\n pathToYouTubeCredentials?: 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 };\n fileExistsAction?: {\n content?: FileExistsAction;\n info?: FileExistsAction;\n infoAPI?: FileExistsAction;\n };\n embedDownloaders?: EmbedDownloader[];\n logger?: Logger | null;\n dryRun?: boolean;\n}\n\nexport type DownloaderInit = DeepRequired<Pick<DownloaderOptions,\n 'outDir' |\n 'useStatusCache' |\n 'pathToFFmpeg' |\n 'pathToYouTubeCredentials' |\n 'dirNameFormat' |\n 'filenameFormat' |\n 'include' |\n 'request' |\n 'fileExistsAction' |\n 'embedDownloaders' |\n 'dryRun'>>;\n\nconst DEFAULT_DOWNLOADER_INIT: DeepRequired<DownloaderInit> = {\n outDir: process.cwd(),\n useStatusCache: true,\n pathToFFmpeg: null,\n pathToYouTubeCredentials: 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 campaignInfo: true,\n contentInfo: true,\n previewMedia: true,\n contentMedia: true,\n allMediaVariants: false\n },\n request: {\n maxRetries: 3,\n maxConcurrent: 10,\n minTime: 333\n },\n fileExistsAction: {\n content: 'skip',\n info: 'saveAsCopyIfNewer',\n infoAPI: 'overwrite'\n },\n embedDownloaders: [],\n dryRun: false\n};\n\nexport function getDownloaderInit(options?: DownloaderOptions): DownloaderInit {\n const defaults = DEFAULT_DOWNLOADER_INIT;\n return {\n outDir: options?.outDir ? path.resolve(options.outDir) : defaults.outDir,\n useStatusCache: pickDefined(options?.useStatusCache, defaults.useStatusCache),\n pathToFFmpeg: pickDefined(options?.pathToFFmpeg, defaults.pathToFFmpeg),\n pathToYouTubeCredentials: pickDefined(options?.pathToYouTubeCredentials, defaults.pathToYouTubeCredentials),\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 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 },\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 },\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 dryRun: pickDefined(options?.dryRun, defaults.dryRun)\n };\n}\n\nexport function getDefaultDownloaderOutDir() {\n return DEFAULT_DOWNLOADER_INIT.outDir;\n}"]}
@@ -1 +1 @@
1
- {"version":3,"file":"PostDownloader.d.ts","sourceRoot":"","sources":["../../src/downloaders/PostDownloader.ts"],"names":[],"mappings":"AAGA,OAAO,UAAU,EAAE,EAAoB,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAKtF,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAQ3C,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,UAAU,CAAC,IAAI,CAAC;;IAE1D,MAAM,CAAC,OAAO,SAAW;IAEzB,IAAI,SAAoB;IAIxB,KAAK,CAAC,MAAM,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqf9C,aAAa,CAAC,MAAM,CAAC,EAAE,WAAW;CAkIzC"}
1
+ {"version":3,"file":"PostDownloader.d.ts","sourceRoot":"","sources":["../../src/downloaders/PostDownloader.ts"],"names":[],"mappings":"AAEA,OAAO,UAAU,EAAE,EAAoB,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGtF,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAS3C,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,UAAU,CAAC,IAAI,CAAC;;IAE1D,MAAM,CAAC,OAAO,SAAW;IAEzB,IAAI,SAAoB;IAIxB,KAAK,CAAC,MAAM,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqZ9C,aAAa,CAAC,MAAM,CAAC,EAAE,WAAW;CAyHzC"}
@@ -9,13 +9,10 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
10
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
11
  };
12
- var _PostDownloader_instances, _PostDownloader_startPromise, _PostDownloader_isFetchingMultiplePosts, _PostDownloader_getInitialPostsAPIUL, _PostDownloader_getInitialDataPageURL, _PostDownloader_getInitialData, _PostDownloader_requestPosts, _PostDownloader_createDownloadTaskBatchForPost;
12
+ var _PostDownloader_instances, _PostDownloader_startPromise, _PostDownloader_isFetchingMultiplePosts, _PostDownloader_createDownloadTaskBatchForPost;
13
13
  import { AbortError } from 'node-fetch';
14
- import FSHelper from '../utils/FSHelper.js';
15
- import URLHelper, { PostSortOrder } from '../utils/URLHelper.js';
14
+ import URLHelper from '../utils/URLHelper.js';
16
15
  import Downloader from './Downloader.js';
17
- import PageParser from '../parsers/PageParser.js';
18
- import ObjectHelper from '../utils/ObjectHelper.js';
19
16
  import PostParser from '../parsers/PostParser.js';
20
17
  import { isYouTubeEmbed } from '../entities/Downloadable.js';
21
18
  import StatusCache from './cache/StatusCache.js';
@@ -23,6 +20,7 @@ import { generatePostEmbedSummary, generatePostSummary } from './templates/PostI
23
20
  import path from 'path';
24
21
  import { TargetSkipReason } from './DownloaderEvent.js';
25
22
  import DownloadTaskFactory from './task/DownloadTaskFactory.js';
23
+ import PostsFetcher from './PostsFetcher.js';
26
24
  export default class PostDownloader extends Downloader {
27
25
  constructor() {
28
26
  super(...arguments);
@@ -68,42 +66,37 @@ export default class PostDownloader extends Downloader {
68
66
  this.log('info', `Filters: ${filterStr}`);
69
67
  }
70
68
  }
71
- // Step 1: Get initial posts (if by user) or target post
72
- let postsAPIURL;
73
- try {
74
- postsAPIURL = await __classPrivateFieldGet(this, _PostDownloader_instances, "m", _PostDownloader_getInitialPostsAPIUL).call(this, signal, resolve, resolve);
75
- }
76
- catch (error) {
77
- return;
78
- }
79
- if (__classPrivateFieldGet(this, _PostDownloader_instances, "m", _PostDownloader_isFetchingMultiplePosts).call(this, postFetch)) {
80
- this.log('info', 'Fetch posts');
81
- this.log('debug', `Request initial posts from API URL "${postsAPIURL}"`);
82
- this.emit('fetchBegin', { targetType: 'posts' });
83
- }
84
- else {
85
- this.log('info', 'Fetch target post');
86
- this.log('debug', `Request post #${postFetch.postId} from API URL "${postsAPIURL}`);
87
- this.emit('fetchBegin', { targetType: 'post' });
88
- }
89
- let json;
90
- try {
91
- json = await __classPrivateFieldGet(this, _PostDownloader_instances, "m", _PostDownloader_requestPosts).call(this, postsAPIURL, signal, resolve, resolve);
92
- }
93
- catch (error) {
94
- return;
95
- }
96
- // Step 2: parse, download and, if targeting posts by user, repeat for next batch
97
- const postsParser = new PostParser(this.logger);
98
- let total = null;
69
+ // Step 1: Get posts (if by user) or target post
70
+ const postsFetcher = new PostsFetcher({
71
+ config: this.config,
72
+ fetcher: this.fetcher,
73
+ logger: this.logger,
74
+ signal
75
+ });
76
+ postsFetcher.on('statusChange', ({ current }) => {
77
+ if (current.status === 'running') {
78
+ this.emit('fetchBegin', { targetType: postsFetcher.getTargetType() });
79
+ }
80
+ });
81
+ postsFetcher.begin();
82
+ // Step 2: download posts in each fetched collection
99
83
  let downloaded = 0;
100
84
  let skippedUnviewable = 0;
101
85
  let skippedRedundant = 0;
102
86
  let skippedUnmetMediaTypeCriteria = 0;
103
87
  let skippedNotInTier = 0;
104
88
  let campaignSaved = false;
105
- while (json) {
106
- const collection = postsParser.parsePostsAPIResponse(json, postsAPIURL);
89
+ const postsParser = new PostParser(this.logger);
90
+ while (postsFetcher.hasNext()) {
91
+ const { collection, aborted, error } = await postsFetcher.next();
92
+ if (!collection || aborted) {
93
+ break;
94
+ }
95
+ if (!collection && error) {
96
+ this.emit('end', { aborted: false, error, message: 'PostsFetcher error' });
97
+ resolve();
98
+ return;
99
+ }
107
100
  if (!campaignSaved && collection.posts[0]?.campaign) {
108
101
  await this.saveCampaignInfo(collection.posts[0].campaign, signal);
109
102
  campaignSaved = true;
@@ -111,17 +104,41 @@ export default class PostDownloader extends Downloader {
111
104
  return;
112
105
  }
113
106
  }
114
- total = collection.total;
115
- if (__classPrivateFieldGet(this, _PostDownloader_instances, "m", _PostDownloader_isFetchingMultiplePosts).call(this, postFetch)) {
116
- this.log('debug', `${collection.posts.length} posts fetched`);
117
- }
118
- for (const post of collection.posts) {
107
+ for (const _post of collection.posts) {
108
+ let post = _post;
109
+ if (__classPrivateFieldGet(this, _PostDownloader_instances, "m", _PostDownloader_isFetchingMultiplePosts).call(this, postFetch)) {
110
+ // Refresh to ensure media links have not expired
111
+ this.log('debug', `Refresh post #${_post.id}`);
112
+ const postURL = URLHelper.constructPostsAPIURL({ postId: _post.id });
113
+ const { json } = await this.commonFetchAPI(postURL, signal);
114
+ let refreshed = null;
115
+ if (json) {
116
+ refreshed = postsParser.parsePostsAPIResponse(json, postURL).posts[0] || null;
117
+ if (!refreshed) {
118
+ this.log('warn', `Refreshed post #${_post.id} but got empty value - going to use existing data`);
119
+ }
120
+ else if (refreshed.id !== _post.id) {
121
+ this.log('warn', `Refreshed post #${_post.id} but ID mismatch - going to use existing data`);
122
+ refreshed = null;
123
+ }
124
+ }
125
+ else if (this.checkAbortSignal(signal, resolve)) {
126
+ return;
127
+ }
128
+ else {
129
+ this.log('warn', `Failed to refresh post #${_post.id} - going to use existing data`);
130
+ }
131
+ if (refreshed) {
132
+ this.log('debug', `Use refreshed post data #${refreshed.id}`);
133
+ post = refreshed;
134
+ }
135
+ }
119
136
  this.emit('targetBegin', { target: post });
120
137
  // Step 4.1: post directories
121
- const postDirs = FSHelper.getPostDirs(post, this.config);
138
+ const postDirs = this.fsHelper.getPostDirs(post);
122
139
  this.log('debug', 'Post directories:', postDirs);
123
140
  // Step 4.2: Check with status cache
124
- const statusCache = StatusCache.getInstance(postDirs.statusCache, this.logger, this.config.useStatusCache);
141
+ const statusCache = StatusCache.getInstance(this.config, postDirs.statusCache, this.logger);
125
142
  if (statusCache.validate(post, postDirs.root, this.config)) {
126
143
  this.log('info', `Skipped downloading post #${post.id}: already downloaded and nothing has changed since last download`);
127
144
  this.emit('targetEnd', {
@@ -228,7 +245,7 @@ export default class PostDownloader extends Downloader {
228
245
  if (this.config.include.contentInfo) {
229
246
  this.log('info', `Save post info #${post.id}`);
230
247
  this.emit('phaseBegin', { target: post, phase: 'saveInfo' });
231
- FSHelper.createDir(postDirs.info);
248
+ this.fsHelper.createDir(postDirs.info);
232
249
  // Post raw data might not be complete or consistent with other posts in the collection.
233
250
  // Fetch directly from API.
234
251
  // Strictly speaking, we should check for 'error' in results, but since it's not going to be fatal we'll just skip it.
@@ -242,10 +259,10 @@ export default class PostDownloader extends Downloader {
242
259
  // Save summary and raw json
243
260
  const summary = generatePostSummary(post);
244
261
  const summaryFile = path.resolve(postDirs.info, 'info.txt');
245
- const saveSummaryResult = await FSHelper.writeTextFile(summaryFile, summary, this.config.fileExistsAction.info);
262
+ const saveSummaryResult = await this.fsHelper.writeTextFile(summaryFile, summary, this.config.fileExistsAction.info);
246
263
  this.logWriteTextFileResult(saveSummaryResult, post, 'post summary');
247
264
  const postRawFile = path.resolve(postDirs.info, 'post-api.json');
248
- const savePostRawResult = await FSHelper.writeTextFile(postRawFile, fetchedPostAPIData || post.raw, this.config.fileExistsAction.infoAPI);
265
+ const savePostRawResult = await this.fsHelper.writeTextFile(postRawFile, fetchedPostAPIData || post.raw, this.config.fileExistsAction.infoAPI);
249
266
  this.logWriteTextFileResult(savePostRawResult, post, 'post API data');
250
267
  this.emit('phaseEnd', { target: post, phase: 'saveInfo' });
251
268
  // (Downloading of info media items deferred to the next step)
@@ -256,7 +273,7 @@ export default class PostDownloader extends Downloader {
256
273
  // Step 4.5: save embed info
257
274
  if (post.embed && this.config.include.contentMedia) {
258
275
  this.log('info', `Save embed info of post #${post.id}`);
259
- FSHelper.createDir(postDirs.embed);
276
+ this.fsHelper.createDir(postDirs.embed);
260
277
  const embedSummary = generatePostEmbedSummary(post.embed);
261
278
  let embedFilename;
262
279
  switch (post.embed.type) {
@@ -270,7 +287,7 @@ export default class PostDownloader extends Downloader {
270
287
  embedFilename = 'embedded-unknown.txt';
271
288
  }
272
289
  const embedFile = path.resolve(postDirs.embed, embedFilename);
273
- const saveSummaryResult = await FSHelper.writeTextFile(embedFile, embedSummary, this.config.fileExistsAction.content);
290
+ const saveSummaryResult = await this.fsHelper.writeTextFile(embedFile, embedSummary, this.config.fileExistsAction.content);
274
291
  this.logWriteTextFileResult(saveSummaryResult, post, 'embed info');
275
292
  }
276
293
  // Step 4.6: create download tasks
@@ -313,26 +330,6 @@ export default class PostDownloader extends Downloader {
313
330
  return;
314
331
  }
315
332
  }
316
- if (__classPrivateFieldGet(this, _PostDownloader_instances, "m", _PostDownloader_isFetchingMultiplePosts).call(this, postFetch)) {
317
- if (collection.nextURL) {
318
- this.log('info', 'Fetch more posts');
319
- this.log('debug', `Request next batch of posts from API URL "${collection.nextURL}`);
320
- this.emit('fetchBegin', { targetType: 'posts' });
321
- try {
322
- json = await __classPrivateFieldGet(this, _PostDownloader_instances, "m", _PostDownloader_requestPosts).call(this, collection.nextURL, signal, resolve, resolve);
323
- }
324
- catch (error) {
325
- return;
326
- }
327
- }
328
- else {
329
- this.log('debug', 'No further posts to fetch');
330
- json = null;
331
- }
332
- }
333
- else {
334
- json = null;
335
- }
336
333
  }
337
334
  if (this.checkAbortSignal(signal, resolve)) {
338
335
  return;
@@ -369,7 +366,7 @@ export default class PostDownloader extends Downloader {
369
366
  skippedStrParts.push(`${skippedNotInTier} not in tier`);
370
367
  }
371
368
  const skippedStr = skippedStrParts.length > 0 ? ` (skipped: ${skippedStrParts.join(', ')})` : '';
372
- endMessage = `Total ${downloaded} / ${total} posts processed${skippedStr}`;
369
+ endMessage = `Total ${downloaded} / ${postsFetcher.getTotal()} posts processed${skippedStr}`;
373
370
  this.log('info', endMessage);
374
371
  }
375
372
  this.emit('end', { aborted: false, message: endMessage });
@@ -400,7 +397,13 @@ export default class PostDownloader extends Downloader {
400
397
  if (!url) {
401
398
  throw Error('Internal error: invalid config');
402
399
  }
403
- const { campaignId } = await __classPrivateFieldGet(this, _PostDownloader_instances, "m", _PostDownloader_getInitialData).call(this, url, signal);
400
+ const postsFetcher = new PostsFetcher({
401
+ config: this.config,
402
+ fetcher: this.fetcher,
403
+ logger: this.logger,
404
+ signal
405
+ });
406
+ const { campaignId } = await postsFetcher.getInitialData(url);
404
407
  const postsParser = new PostParser(this.logger);
405
408
  const res = await this.fetchCampaign(campaignId);
406
409
  if (signal?.aborted) {
@@ -414,104 +417,6 @@ export default class PostDownloader extends Downloader {
414
417
  }
415
418
  _PostDownloader_startPromise = new WeakMap(), _PostDownloader_instances = new WeakSet(), _PostDownloader_isFetchingMultiplePosts = function _PostDownloader_isFetchingMultiplePosts(postFetch) {
416
419
  return postFetch.type === 'byUser' || postFetch.type === 'byUserId' || postFetch.type === 'byCollection';
417
- }, _PostDownloader_getInitialPostsAPIUL = async function _PostDownloader_getInitialPostsAPIUL(signal, resolveOnAbort, resolveOnError) {
418
- const postFetch = this.config.postFetch;
419
- if (__classPrivateFieldGet(this, _PostDownloader_instances, "m", _PostDownloader_isFetchingMultiplePosts).call(this, postFetch)) {
420
- const pageURL = __classPrivateFieldGet(this, _PostDownloader_instances, "m", _PostDownloader_getInitialDataPageURL).call(this);
421
- const { campaignId, currentUserId } = await __classPrivateFieldGet(this, _PostDownloader_instances, "m", _PostDownloader_getInitialData).call(this, pageURL, signal, resolveOnAbort, resolveOnError);
422
- let sort;
423
- if (postFetch.type === 'byCollection') {
424
- sort = PostSortOrder.CollectionOrder;
425
- }
426
- return URLHelper.constructPostsAPIURL({
427
- campaignId,
428
- currentUserId: this.config.include.lockedContent ? undefined : currentUserId,
429
- filters: postFetch.filters,
430
- sort
431
- });
432
- }
433
- return URLHelper.constructPostsAPIURL({ postId: postFetch.postId });
434
- }, _PostDownloader_getInitialDataPageURL = function _PostDownloader_getInitialDataPageURL() {
435
- const postFetch = this.config.postFetch;
436
- switch (postFetch.type) {
437
- case 'byUser':
438
- return URLHelper.constructCampaignPageURL({ vanity: postFetch.vanity });
439
- case 'byUserId':
440
- return URLHelper.constructCampaignPageURL({ userId: postFetch.userId });
441
- case 'byCollection':
442
- return URLHelper.constructCollectionURL(postFetch.collectionId);
443
- default:
444
- throw Error(`postFetch type mismatch: expecting 'byUser', 'byUserId' or 'byCollection' but got '${postFetch.type}'`);
445
- }
446
- }, _PostDownloader_getInitialData = async function _PostDownloader_getInitialData(url, signal, resolveOnAbort, resolveOnError) {
447
- this.log('debug', `Fetch initial data from "${url}"`);
448
- let page, requestPageError;
449
- try {
450
- page = await this.fetcher.get({ url, type: 'html', maxRetries: this.config.request.maxRetries, signal });
451
- }
452
- catch (error) {
453
- if (error instanceof AbortError) {
454
- this.log('warn', 'Page request aborted');
455
- }
456
- else {
457
- requestPageError = error;
458
- }
459
- page = null;
460
- }
461
- if (!page) {
462
- if (resolveOnAbort && this.checkAbortSignal(signal, resolveOnAbort)) {
463
- throw Error();
464
- }
465
- this.log('error', `Error requesting page "${url}": `, requestPageError);
466
- this.emit('end', { aborted: false, error: requestPageError, message: 'Request error' });
467
- if (resolveOnError) {
468
- resolveOnError();
469
- }
470
- throw Error();
471
- }
472
- const pageParser = new PageParser(this.logger);
473
- let initialData, parseInitialDataError;
474
- try {
475
- initialData = pageParser.parseInitialData(page, url);
476
- }
477
- catch (error) {
478
- parseInitialDataError = error;
479
- initialData = null;
480
- }
481
- if (!initialData) {
482
- this.log('error', `Failed to obtain initial page data from "${url}":`, parseInitialDataError);
483
- this.emit('end', { aborted: false, error: parseInitialDataError, message: 'Parse error' });
484
- if (resolveOnError) {
485
- resolveOnError();
486
- }
487
- throw Error();
488
- }
489
- const campaignId = ObjectHelper.getProperty(initialData, 'bootstrap.campaign.data.id');
490
- const currentUserId = ObjectHelper.getProperty(initialData, 'bootstrap.currentUser.data.id');
491
- this.log('debug', `Initial data: campaign ID '${campaignId}'; current user ID '${currentUserId}'`);
492
- if (!campaignId) {
493
- const err = Error(`Campaign ID not found in initial data of "${url}"`);
494
- this.log('error', err);
495
- this.emit('end', { aborted: false, error: err, message: 'Data error (campaign ID not found)' });
496
- if (resolveOnError) {
497
- resolveOnError();
498
- }
499
- throw Error();
500
- }
501
- return { campaignId, currentUserId };
502
- }, _PostDownloader_requestPosts = async function _PostDownloader_requestPosts(url, signal, resolveOnAbort, resolveOnError) {
503
- const { json, error: requestAPIError } = await this.commonFetchAPI(url, signal);
504
- if (!json) {
505
- if (this.checkAbortSignal(signal, resolveOnAbort)) {
506
- throw Error();
507
- }
508
- this.log('error', 'Failed to fetch posts');
509
- this.log('warn', 'End with error');
510
- this.emit('end', { aborted: false, error: requestAPIError, message: 'API request error' });
511
- resolveOnError();
512
- throw Error();
513
- }
514
- return json;
515
420
  }, _PostDownloader_createDownloadTaskBatchForPost = function _PostDownloader_createDownloadTaskBatchForPost(post, postDirs) {
516
421
  const incPreview = this.config.include.previewMedia;
517
422
  const incContent = this.config.include.contentMedia;