patreon-dl 3.6.0 → 3.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.
- package/NOTICE +23 -0
- package/README.md +16 -5
- package/bin/EmbedlyDownloader.js +1 -1
- package/bin/patreon-dl-vimeo.js +7 -4
- package/dist/browse/api/CampaignAPIMixin.d.ts +1 -1
- package/dist/browse/api/ContentAPIMixin.d.ts +4 -1
- package/dist/browse/api/ContentAPIMixin.js +44 -11
- package/dist/browse/api/ContentAPIMixin.js.map +1 -1
- package/dist/browse/api/FilterAPIMixin.d.ts +1 -1
- package/dist/browse/api/SettingsAPIMixin.d.ts +1 -0
- package/dist/browse/api/SettingsAPIMixin.js +4 -2
- package/dist/browse/api/SettingsAPIMixin.js.map +1 -1
- package/dist/browse/api/index.d.ts +12 -6
- package/dist/browse/db/CampaignDBMixin.d.ts +3 -3
- package/dist/browse/db/ContentDBMixin.d.ts +14 -14
- package/dist/browse/db/ContentDBMixin.js +12 -5
- package/dist/browse/db/ContentDBMixin.js.map +1 -1
- package/dist/browse/db/index.d.ts +17 -17
- package/dist/browse/server/handler/SettingsAPIRequestHandler.js +2 -1
- package/dist/browse/server/handler/SettingsAPIRequestHandler.js.map +1 -1
- package/dist/browse/types/Settings.d.ts +3 -0
- package/dist/browse/types/Settings.js.map +1 -1
- package/dist/browse/web/assets/index-CW4CUoWl.css +1 -0
- package/dist/browse/web/assets/{index-Dw_64hkR.js → index-CziUWlSw.js} +31 -31
- package/dist/browse/web/index.html +2 -2
- package/dist/cli/CLIOptions.js +10 -1
- package/dist/cli/CLIOptions.js.map +1 -1
- package/dist/cli/CommandLineParser.d.ts +1 -0
- package/dist/cli/CommandLineParser.js +11 -3
- package/dist/cli/CommandLineParser.js.map +1 -1
- package/dist/downloaders/Bootstrap.d.ts +6 -0
- package/dist/downloaders/Bootstrap.js +26 -0
- package/dist/downloaders/Bootstrap.js.map +1 -1
- package/dist/downloaders/Downloader.d.ts +5 -4
- package/dist/downloaders/Downloader.js +3 -1
- package/dist/downloaders/Downloader.js.map +1 -1
- package/dist/downloaders/InitialData.js +1 -0
- package/dist/downloaders/InitialData.js.map +1 -1
- package/dist/downloaders/PostDownloader.js +16 -0
- package/dist/downloaders/PostDownloader.js.map +1 -1
- package/dist/downloaders/PostsFetcher.js +29 -12
- package/dist/downloaders/PostsFetcher.js.map +1 -1
- package/dist/downloaders/ProductDownloader.js +8 -0
- package/dist/downloaders/ProductDownloader.js.map +1 -1
- package/dist/downloaders/ProductsFetcher.js +32 -15
- package/dist/downloaders/ProductsFetcher.js.map +1 -1
- package/dist/downloaders/task/DownloadTaskFactory.d.ts +4 -0
- package/dist/downloaders/task/DownloadTaskFactory.js +3 -2
- package/dist/downloaders/task/DownloadTaskFactory.js.map +1 -1
- package/dist/downloaders/task/YouTubeDownloadTask.js +7 -2
- package/dist/downloaders/task/YouTubeDownloadTask.js.map +1 -1
- package/dist/entities/Post.d.ts +1 -1
- package/dist/entities/Post.js.map +1 -1
- package/dist/entities/Product.d.ts +1 -1
- package/dist/entities/Product.js.map +1 -1
- package/dist/parsers/PostParser.d.ts +1 -1
- package/dist/parsers/PostParser.js +69 -13
- package/dist/parsers/PostParser.js.map +1 -1
- package/dist/parsers/ProductParser.d.ts +1 -1
- package/dist/parsers/ProductParser.js +5 -6
- package/dist/parsers/ProductParser.js.map +1 -1
- package/dist/utils/FilenameFormatHelper.d.ts +2 -2
- package/dist/utils/FilenameFormatHelper.js +45 -2
- package/dist/utils/FilenameFormatHelper.js.map +1 -1
- package/dist/utils/MediaFilenameResolver.d.ts +4 -1
- package/dist/utils/MediaFilenameResolver.js +6 -4
- package/dist/utils/MediaFilenameResolver.js.map +1 -1
- package/dist/utils/URLHelper.js +8 -8
- 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/yt/InnertubeLoader.d.ts +19 -1
- package/dist/utils/yt/InnertubeLoader.js +55 -15
- package/dist/utils/yt/InnertubeLoader.js.map +1 -1
- package/package.json +2 -1
- package/dist/browse/web/assets/index-DjOKbT1U.css +0 -1
|
@@ -49,6 +49,9 @@ _ProductDownloader_startPromise = new WeakMap(), _ProductDownloader_instances =
|
|
|
49
49
|
if (productFetch.type === 'byShop') {
|
|
50
50
|
this.log('info', `Targeting products by '${productFetch.vanity}'`);
|
|
51
51
|
}
|
|
52
|
+
else if (productFetch.type === 'byFile') {
|
|
53
|
+
this.log('info', `Target product given by API data in "${productFetch.filePath}"`);
|
|
54
|
+
}
|
|
52
55
|
else {
|
|
53
56
|
this.log('info', `Targeting product #${productFetch.productId}`);
|
|
54
57
|
}
|
|
@@ -183,6 +186,9 @@ _ProductDownloader_startPromise = new WeakMap(), _ProductDownloader_instances =
|
|
|
183
186
|
if (productFetch.type === 'byShop') {
|
|
184
187
|
this.log('info', `Done downloading products by '${productFetch.vanity}'`);
|
|
185
188
|
}
|
|
189
|
+
else if (productFetch.type === 'byFile') {
|
|
190
|
+
this.log('info', `Done downloading product given in "${productFetch.filePath}"`);
|
|
191
|
+
}
|
|
186
192
|
else {
|
|
187
193
|
this.log('info', `Done downloading product #${productFetch.productId}`);
|
|
188
194
|
}
|
|
@@ -272,6 +278,7 @@ _ProductDownloader_startPromise = new WeakMap(), _ProductDownloader_instances =
|
|
|
272
278
|
const batchResult = await this.createDownloadTaskBatch(`Product #${product.id} (${product.name})`, signal, previewMedia.length > 0 ? {
|
|
273
279
|
target: previewMedia,
|
|
274
280
|
targetName: `product #${product.id} -> preview media`,
|
|
281
|
+
src: product,
|
|
275
282
|
dirs: {
|
|
276
283
|
campaign: campaignDir,
|
|
277
284
|
main: productDirs.previewMedia,
|
|
@@ -281,6 +288,7 @@ _ProductDownloader_startPromise = new WeakMap(), _ProductDownloader_instances =
|
|
|
281
288
|
} : null, contentMedia.length > 0 ? {
|
|
282
289
|
target: contentMedia,
|
|
283
290
|
targetName: `product #${product.id} -> content media`,
|
|
291
|
+
src: product,
|
|
284
292
|
dirs: {
|
|
285
293
|
campaign: campaignDir,
|
|
286
294
|
main: productDirs.contentMedia,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductDownloader.js","sourceRoot":"","sources":["../../src/downloaders/ProductDownloader.ts"],"names":[],"mappings":"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","sourcesContent":["import ProductParser from '../parsers/ProductParser.js';\nimport URLHelper from '../utils/URLHelper.js';\nimport Downloader, { type DownloaderConfig, type DownloaderStartParams } from './Downloader.js';\nimport StatusCache from './cache/StatusCache.js';\nimport { generateProductSummary } from './templates/ProductInfo.js';\nimport path from 'path';\nimport { TargetSkipReason } from './DownloaderEvent.js';\nimport { ProductType, type Product } from '../entities/Product.js';\nimport { type Downloadable } from '../entities/Downloadable.js';\nimport Bootstrap from './Bootstrap.js';\nimport ProductsFetcher from './ProductsFetcher.js';\nimport { type ProductDirectories } from '../utils/FSHelper.js';\nimport { type DBInstance } from '../browse/db/index.js';\n\nexport default class ProductDownloader extends Downloader<Product> {\n\n static version = '1.0.1';\n\n name = 'ProductDownloader';\n\n #startPromise: Promise<void> | null = null;\n\n doStart(params?: DownloaderStartParams): Promise<void> {\n\n if (this.#startPromise) {\n throw Error('Downloader already running');\n }\n\n this.#startPromise = this.#doStart(params)\n .finally(() => {\n this.#startPromise = null;\n });\n\n return this.#startPromise;\n }\n\n async #doStart(params?: DownloaderStartParams): Promise<void> {\n try {\n const { signal } = params || {};\n const productFetch = this.config.productFetch;\n const db = await this.db();\n\n if (this.checkAbortSignal(signal)) {\n return;\n }\n\n if (productFetch.type === 'byShop') {\n this.log('info', `Targeting products by '${productFetch.vanity}'`);\n }\n else {\n this.log('info', `Targeting product #${productFetch.productId}`);\n }\n\n // Step 1: get products (if by shop) or target product\n const productsFetcher = new ProductsFetcher({\n config: this.config,\n fetcher: this.fetcher,\n logger: this.logger,\n signal\n });\n productsFetcher.on('statusChange', ({current}) => {\n if (current.status === 'running') {\n this.emit('fetchBegin', { targetType: productsFetcher.getTargetType() });\n }\n });\n productsFetcher.begin();\n\n // Step 2: download products in each fetched list\n let downloaded = 0;\n let skippedUnviewable = 0;\n let skippedRedundant = 0;\n let skippedPublishDateOutOfRange = 0;\n let campaignSaved = false;\n let stopConditionMet = false;\n const productsParser = new ProductParser(this.logger);\n while (productsFetcher.hasNext()) {\n const { list, aborted, error } = await productsFetcher.next();\n if (!list || aborted) {\n break;\n }\n if (!list && error) {\n this.emit('end', { aborted: false, error, message: 'ProductsFetcher error' });\n return;\n }\n if (!campaignSaved && list.items[0]?.campaign) {\n await this.saveCampaignInfo(list.items[0].campaign, signal);\n campaignSaved = true;\n if (this.checkAbortSignal(signal)) {\n return;\n }\n }\n\n for (const _product of list.items) {\n\n if (stopConditionMet) {\n break;\n }\n\n let product = _product;\n\n if (this.#isFetchingMultipleProducts(productFetch)) {\n // Refresh to ensure media links have not expired\n this.log('debug', `Refresh product #${_product.id}`);\n const productURL = URLHelper.constructProductAPIURL(product.id);\n const { json } = await this.commonFetchAPI(productURL, signal);\n let refreshed: Product | null = null;\n if (json) {\n refreshed = productsParser.parseProductsAPIResponse(json, productURL).items[0] || null;\n if (!refreshed) {\n this.log('warn', `Refreshed product #${_product.id} but got empty value - going to use existing data`);\n }\n else if (refreshed.id !== _product.id) {\n this.log('warn', `Refreshed product #${_product.id} but ID mismatch - going to use existing data`);\n refreshed = null;\n }\n else {\n // Refreshed data does not have productType - reinstate it\n refreshed.productType = _product.productType;\n }\n }\n else if (this.checkAbortSignal(signal)) {\n return;\n }\n else {\n this.log('warn', `Failed to refresh product #${_product.id} - going to use existing data`);\n }\n if (refreshed) {\n this.log('debug', `Use refreshed product data #${refreshed.id}`);\n product = refreshed;\n }\n }\n\n this.emit('targetBegin', { target: product });\n\n // Step 4.1: product directories\n const productDirs = this.fsHelper.getProductDirs(product);\n this.log('debug', 'Product directories:', productDirs);\n\n // Step 4.2: Check with status cache\n const statusCache = StatusCache.getInstance(this.config, productDirs.statusCache, this.logger);\n if (!product.productType || product.productType === ProductType.DigitalCommerce) {\n const statusCacheValidation = statusCache.validate(product, productDirs.root, this.config)\n if (!statusCacheValidation.invalidated) {\n this.log('info', `Skipped downloading product #${product.id}: already downloaded`);\n this.emit('targetEnd', {\n target: product,\n isSkipped: true,\n skipReason: TargetSkipReason.AlreadyDownloaded,\n skipMessage: 'Target already downloaded'\n });\n skippedRedundant++;\n if (this.config.stopOn === 'previouslyDownloaded') {\n stopConditionMet = true;\n }\n continue;\n }\n }\n \n switch ((await this.#doDownload(\n product,\n productDirs,\n statusCache,\n db,\n signal\n )).status) {\n case 'aborted':\n return;\n case 'downloaded':\n downloaded++;\n break;\n case 'skippedPublishDateOutOfRange':\n skippedPublishDateOutOfRange++;\n if (this.config.stopOn === 'postPublishDateOutOfRange' ||\n this.config.stopOn === 'publishDateOutOfRange'\n ) {\n stopConditionMet = true;\n }\n break;\n case 'skippedUnviewable':\n skippedUnviewable++;\n break;\n }\n\n if (this.checkAbortSignal(signal)) {\n return;\n }\n }\n\n if (stopConditionMet) {\n break;\n }\n }\n\n if (this.checkAbortSignal(signal)) {\n return;\n }\n\n if (stopConditionMet && this.#isFetchingMultipleProducts(productFetch)) {\n this.log('info', `Stop downloader: stop condition \"${this.config.stopOn}\" met`)\n }\n\n // Done\n if (productFetch.type === 'byShop') {\n this.log('info', `Done downloading products by '${productFetch.vanity}'`);\n }\n else {\n this.log('info', `Done downloading product #${productFetch.productId}`);\n }\n let endMessage = 'Done';\n if (this.#isFetchingMultipleProducts(productFetch)) {\n const skippedStrParts: string[] = [];\n if (skippedUnviewable) {\n skippedStrParts.push(`${skippedUnviewable} unviewable`);\n }\n if (skippedRedundant) {\n skippedStrParts.push(`${skippedRedundant} redundant`);\n }\n if (skippedPublishDateOutOfRange) {\n skippedStrParts.push(`${skippedPublishDateOutOfRange} with publish date out of range`);\n }\n const skippedStr = skippedStrParts.length > 0 ? ` (skipped: ${skippedStrParts.join(', ')})` : '';\n endMessage = `Total ${downloaded} / ${productsFetcher.getTotal()} products processed${skippedStr}`;\n this.log('info', endMessage);\n }\n this.emit('end', { aborted: false, message: endMessage });\n }\n finally {\n await this.closeDB();\n if (this.logger) {\n await this.logger.end();\n }\n }\n }\n\n async #doDownload(\n product: Product,\n productDirs: ProductDirectories,\n statusCache: StatusCache,\n db: DBInstance,\n signal?: AbortSignal\n ): Promise<{status: 'skippedUnviewable' | 'skippedPublishDateOutOfRange' | 'aborted' | 'downloaded' }> {\n // Step 1: Check whether we should download product\n // -- 1.1 Accessibility\n if (!product.isAccessible) {\n if (this.config.include.lockedContent) {\n this.log('warn', `Product #${product.id} is not accessible by current user`);\n }\n else {\n this.log('warn', `Skipped downloading product #${product.id}: not accessible by current user`);\n this.emit('targetEnd', {\n target: product,\n isSkipped: true,\n skipReason: TargetSkipReason.Inaccessible,\n skipMessage: 'Target is not accessible by current user'\n });\n return {\n status: 'skippedUnviewable'\n };\n }\n }\n // -- 1.4 Config option 'include.productsPublished'\n if (this.isPublishDateOutOfRange(product)) {\n return {\n status: 'skippedPublishDateOutOfRange'\n };\n }\n\n this.fsHelper.createDir(productDirs.root);\n\n // Step 2: save product info\n if (this.config.include.contentInfo) {\n this.log('info', 'Save product info');\n this.emit('phaseBegin', { target: product, phase: 'saveInfo' });\n this.fsHelper.createDir(productDirs.info);\n const summary = generateProductSummary(product);\n const summaryFile = path.resolve(productDirs.info, 'info.txt');\n const saveSummaryResult = await this.fsHelper.writeTextFile(summaryFile, summary, this.config.fileExistsAction.info);\n this.logWriteTextFileResult(saveSummaryResult, product, 'product summary');\n\n const productRawFile = path.resolve(productDirs.info, 'product-api.json');\n const saveProductRawResult = await this.fsHelper.writeTextFile(\n productRawFile, product.raw, this.config.fileExistsAction.infoAPI);\n this.logWriteTextFileResult(saveProductRawResult, product, 'product API data');\n this.emit('phaseEnd', { target: product, phase: 'saveInfo' });\n }\n\n // Step 3: Download product media items\n const incPreview = this.config.include.previewMedia;\n const incContent = this.config.include.contentMedia;\n this.log('info', 'Download:', {\n ['preview items']: incPreview === true ? 'yes' : incPreview === false ? 'no' : JSON.stringify(incPreview),\n ['content items']: incContent === true ? 'yes' : incContent === false ? 'no' : JSON.stringify(incContent)\n });\n\n const __inc = (inc: boolean | Array<any>, target: Downloadable) => {\n if (typeof inc === 'boolean') {\n return inc;\n }\n return (inc.includes(target.type as any));\n };\n\n const previewMedia = product.previewMedia.filter((tt) => __inc(incPreview, tt));\n const contentMedia = product.contentMedia.filter((tt) => __inc(incContent, tt));\n const campaignDir = product.campaign ? this.fsHelper.getCampaignDirs(product.campaign).root : null;\n\n if (this.config.include.previewMedia || this.config.include.contentMedia) {\n this.emit('phaseBegin', { target: product, phase: 'saveMedia' });\n const batchResult = await this.createDownloadTaskBatch(\n `Product #${product.id} (${product.name})`,\n signal,\n\n previewMedia.length > 0 ? {\n target: previewMedia,\n targetName: `product #${product.id} -> preview media`,\n dirs: {\n campaign: campaignDir,\n main: productDirs.previewMedia,\n thumbnails: productDirs.thumbnails\n },\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n contentMedia.length > 0 ? {\n target: contentMedia,\n targetName: `product #${product.id} -> content media`,\n dirs: {\n campaign: campaignDir,\n main: productDirs.contentMedia,\n thumbnails: productDirs.thumbnails\n },\n fileExistsAction: this.config.fileExistsAction.content,\n ignoreCreateTaskErrors: !product.isAccessible\n } : null\n );\n\n const { batch } = batchResult;\n\n const abortHandler = () => {\n void (async () => {\n this.log('info', 'Abort signal received');\n if (batch) {\n await batch.abort();\n }\n })();\n };\n if (signal) {\n signal.addEventListener('abort', abortHandler, { once: true });\n }\n \n try {\n if (this.checkAbortSignal(signal)) {\n return {\n status: 'aborted'\n };\n }\n \n batch.prestart();\n this.log('info', `Download batch created (#${batch.id}): ${batch.getTasks('pending').length} downloads pending`);\n this.emit('phaseBegin', { target: product, phase: 'batchDownload', batch });\n\n await batch.start();\n\n // Step 4: Update status cache\n statusCache.updateOnDownload(product, productDirs.root, batch.getTasks('error').length > 0 || batchResult.errorCount > 0, this.config);\n\n await batch.destroy();\n }\n finally {\n if (signal) {\n signal.removeEventListener('abort', abortHandler);\n }\n }\n\n this.emit('phaseEnd', { target: product, phase: 'batchDownload' });\n this.emit('phaseEnd', { target: product, phase: 'saveMedia' });\n }\n\n if (this.checkAbortSignal(signal)) {\n return {\n status: 'aborted'\n };\n }\n\n // Step 5: Save to DB\n let skipDB = false;\n let saveReferencedEntityId: (id: string) => void;\n const dbProduct = db.getContent(product.id, 'product');\n if (!product.isAccessible) {\n // Skip if existing db record (if any) refers to accessible product\n skipDB = dbProduct !== null && dbProduct.isAccessible;\n }\n if (!skipDB) {\n db.saveContent(product);\n saveReferencedEntityId = (id) => {\n product.referencedEntityId = id;\n db.saveContent(product);\n };\n }\n else {\n this.log('info', `Skip overwrite existing accessible product #${product.id} in DB with current unviewable version`);\n saveReferencedEntityId = (id) => {\n // Ensure referencedEntityId is updated\n dbProduct!.referencedEntityId = id;\n db.saveContent(dbProduct!);\n };\n }\n\n // Step 6: check product type and download referenced product / collection\n await this.#processProductType(product, saveReferencedEntityId, signal);\n\n // Done\n this.log('info', `Done downloading product #${product.id}`);\n this.emit('targetEnd', { target: product, isSkipped: false });\n\n return {\n status: 'downloaded'\n }\n }\n\n // Carry out further action based on product type\n async #processProductType(\n product: Product,\n saveReferencedEntityId: (id: string) => void,\n signal?: AbortSignal\n ) {\n if (product.productType === undefined || product.productType === ProductType.DigitalCommerce) {\n this.log('debug', `Product type \"${product.productType}\": no further action required`);\n return;\n }\n if (product.productType === ProductType.Post || product.productType === ProductType.Collection) {\n const bootstrap = Bootstrap.getDownloaderBootstrapDataByURL(product.url);\n if (bootstrap?.type === 'post') {\n this.log('info', `Download ${product.productType} referenced by product: ${product.url}`);\n const PostDownloader = (await import('./PostDownloader.js')).default;\n const downloader = new PostDownloader(\n {\n ...this.config,\n ...bootstrap\n },\n this.db,\n this.logger,\n {\n skipSaveCampaign: true,\n keepLoggerOpen: true,\n keepDBOpen: true\n }\n );\n try {\n await downloader.start({ signal });\n this.log('info', `Done downloading ${product.productType} referenced by product`);\n }\n catch (error) {\n if (signal?.aborted) {\n throw error;\n }\n this.log('error', `Error downloading ${product.productType} referenced by product (url: ${product.url})`, error);\n }\n let referencedEntityId: string | undefined = undefined;\n let bootstrapMismatch = false;\n if (bootstrap.postFetch.type === 'single') {\n bootstrapMismatch = product.productType !== ProductType.Post;\n referencedEntityId = bootstrap.postFetch.postId;\n }\n if (bootstrap.postFetch.type === 'byCollection') {\n bootstrapMismatch = product.productType !== ProductType.Collection;\n referencedEntityId = bootstrap.postFetch.collectionId;\n }\n if (bootstrapMismatch) {\n this.log('warn', `Product type \"${product.productType}\" does not match URL \"${product.url}\" (${bootstrap.postFetch.type})`);\n }\n else if (referencedEntityId) {\n saveReferencedEntityId(referencedEntityId);\n }\n }\n else {\n this.log('error', `Product type is \"${product.productType}\" but could not create downloader from URL \"${product.url}\"`);\n }\n return;\n }\n this.log('debug', `Unknown product type \"${product.productType}\": no further action can be taken`);\n return;\n }\n\n #isFetchingMultipleProducts(productFetch: DownloaderConfig<Product>['productFetch']): productFetch is DownloaderConfig<Product>['productFetch'] & { type: 'byShop' } {\n return productFetch.type === 'byShop';\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ProductDownloader.js","sourceRoot":"","sources":["../../src/downloaders/ProductDownloader.ts"],"names":[],"mappings":"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","sourcesContent":["import ProductParser from '../parsers/ProductParser.js';\nimport URLHelper from '../utils/URLHelper.js';\nimport Downloader, { type DownloaderConfig, type DownloaderStartParams } from './Downloader.js';\nimport StatusCache from './cache/StatusCache.js';\nimport { generateProductSummary } from './templates/ProductInfo.js';\nimport path from 'path';\nimport { TargetSkipReason } from './DownloaderEvent.js';\nimport { ProductType, type Product } from '../entities/Product.js';\nimport { type Downloadable } from '../entities/Downloadable.js';\nimport Bootstrap from './Bootstrap.js';\nimport ProductsFetcher from './ProductsFetcher.js';\nimport { type ProductDirectories } from '../utils/FSHelper.js';\nimport { type DBInstance } from '../browse/db/index.js';\n\nexport default class ProductDownloader extends Downloader<Product> {\n\n static version = '1.0.1';\n\n name = 'ProductDownloader';\n\n #startPromise: Promise<void> | null = null;\n\n doStart(params?: DownloaderStartParams): Promise<void> {\n\n if (this.#startPromise) {\n throw Error('Downloader already running');\n }\n\n this.#startPromise = this.#doStart(params)\n .finally(() => {\n this.#startPromise = null;\n });\n\n return this.#startPromise;\n }\n\n async #doStart(params?: DownloaderStartParams): Promise<void> {\n try {\n const { signal } = params || {};\n const productFetch = this.config.productFetch;\n const db = await this.db();\n\n if (this.checkAbortSignal(signal)) {\n return;\n }\n\n if (productFetch.type === 'byShop') {\n this.log('info', `Targeting products by '${productFetch.vanity}'`);\n }\n else if (productFetch.type === 'byFile') {\n this.log('info', `Target product given by API data in \"${productFetch.filePath}\"`);\n }\n else {\n this.log('info', `Targeting product #${productFetch.productId}`);\n }\n\n // Step 1: get products (if by shop) or target product\n const productsFetcher = new ProductsFetcher({\n config: this.config,\n fetcher: this.fetcher,\n logger: this.logger,\n signal\n });\n productsFetcher.on('statusChange', ({current}) => {\n if (current.status === 'running') {\n this.emit('fetchBegin', { targetType: productsFetcher.getTargetType() });\n }\n });\n productsFetcher.begin();\n\n // Step 2: download products in each fetched list\n let downloaded = 0;\n let skippedUnviewable = 0;\n let skippedRedundant = 0;\n let skippedPublishDateOutOfRange = 0;\n let campaignSaved = false;\n let stopConditionMet = false;\n const productsParser = new ProductParser(this.logger);\n while (productsFetcher.hasNext()) {\n const { list, aborted, error } = await productsFetcher.next();\n if (!list || aborted) {\n break;\n }\n if (!list && error) {\n this.emit('end', { aborted: false, error, message: 'ProductsFetcher error' });\n return;\n }\n if (!campaignSaved && list.items[0]?.campaign) {\n await this.saveCampaignInfo(list.items[0].campaign, signal);\n campaignSaved = true;\n if (this.checkAbortSignal(signal)) {\n return;\n }\n }\n\n for (const _product of list.items) {\n\n if (stopConditionMet) {\n break;\n }\n\n let product = _product;\n\n if (this.#isFetchingMultipleProducts(productFetch)) {\n // Refresh to ensure media links have not expired\n this.log('debug', `Refresh product #${_product.id}`);\n const productURL = URLHelper.constructProductAPIURL(product.id);\n const { json } = await this.commonFetchAPI(productURL, signal);\n let refreshed: Product | null = null;\n if (json) {\n refreshed = productsParser.parseProductsAPIResponse(json, productURL).items[0] || null;\n if (!refreshed) {\n this.log('warn', `Refreshed product #${_product.id} but got empty value - going to use existing data`);\n }\n else if (refreshed.id !== _product.id) {\n this.log('warn', `Refreshed product #${_product.id} but ID mismatch - going to use existing data`);\n refreshed = null;\n }\n else {\n // Refreshed data does not have productType - reinstate it\n refreshed.productType = _product.productType;\n }\n }\n else if (this.checkAbortSignal(signal)) {\n return;\n }\n else {\n this.log('warn', `Failed to refresh product #${_product.id} - going to use existing data`);\n }\n if (refreshed) {\n this.log('debug', `Use refreshed product data #${refreshed.id}`);\n product = refreshed;\n }\n }\n\n this.emit('targetBegin', { target: product });\n\n // Step 4.1: product directories\n const productDirs = this.fsHelper.getProductDirs(product);\n this.log('debug', 'Product directories:', productDirs);\n\n // Step 4.2: Check with status cache\n const statusCache = StatusCache.getInstance(this.config, productDirs.statusCache, this.logger);\n if (!product.productType || product.productType === ProductType.DigitalCommerce) {\n const statusCacheValidation = statusCache.validate(product, productDirs.root, this.config)\n if (!statusCacheValidation.invalidated) {\n this.log('info', `Skipped downloading product #${product.id}: already downloaded`);\n this.emit('targetEnd', {\n target: product,\n isSkipped: true,\n skipReason: TargetSkipReason.AlreadyDownloaded,\n skipMessage: 'Target already downloaded'\n });\n skippedRedundant++;\n if (this.config.stopOn === 'previouslyDownloaded') {\n stopConditionMet = true;\n }\n continue;\n }\n }\n \n switch ((await this.#doDownload(\n product,\n productDirs,\n statusCache,\n db,\n signal\n )).status) {\n case 'aborted':\n return;\n case 'downloaded':\n downloaded++;\n break;\n case 'skippedPublishDateOutOfRange':\n skippedPublishDateOutOfRange++;\n if (this.config.stopOn === 'postPublishDateOutOfRange' ||\n this.config.stopOn === 'publishDateOutOfRange'\n ) {\n stopConditionMet = true;\n }\n break;\n case 'skippedUnviewable':\n skippedUnviewable++;\n break;\n }\n\n if (this.checkAbortSignal(signal)) {\n return;\n }\n }\n\n if (stopConditionMet) {\n break;\n }\n }\n\n if (this.checkAbortSignal(signal)) {\n return;\n }\n\n if (stopConditionMet && this.#isFetchingMultipleProducts(productFetch)) {\n this.log('info', `Stop downloader: stop condition \"${this.config.stopOn}\" met`)\n }\n\n // Done\n if (productFetch.type === 'byShop') {\n this.log('info', `Done downloading products by '${productFetch.vanity}'`);\n }\n else if (productFetch.type === 'byFile') {\n this.log('info', `Done downloading product given in \"${productFetch.filePath}\"`);\n }\n else {\n this.log('info', `Done downloading product #${productFetch.productId}`);\n }\n let endMessage = 'Done';\n if (this.#isFetchingMultipleProducts(productFetch)) {\n const skippedStrParts: string[] = [];\n if (skippedUnviewable) {\n skippedStrParts.push(`${skippedUnviewable} unviewable`);\n }\n if (skippedRedundant) {\n skippedStrParts.push(`${skippedRedundant} redundant`);\n }\n if (skippedPublishDateOutOfRange) {\n skippedStrParts.push(`${skippedPublishDateOutOfRange} with publish date out of range`);\n }\n const skippedStr = skippedStrParts.length > 0 ? ` (skipped: ${skippedStrParts.join(', ')})` : '';\n endMessage = `Total ${downloaded} / ${productsFetcher.getTotal()} products processed${skippedStr}`;\n this.log('info', endMessage);\n }\n this.emit('end', { aborted: false, message: endMessage });\n }\n finally {\n await this.closeDB();\n if (this.logger) {\n await this.logger.end();\n }\n }\n }\n\n async #doDownload(\n product: Product,\n productDirs: ProductDirectories,\n statusCache: StatusCache,\n db: DBInstance,\n signal?: AbortSignal\n ): Promise<{status: 'skippedUnviewable' | 'skippedPublishDateOutOfRange' | 'aborted' | 'downloaded' }> {\n // Step 1: Check whether we should download product\n // -- 1.1 Accessibility\n if (!product.isAccessible) {\n if (this.config.include.lockedContent) {\n this.log('warn', `Product #${product.id} is not accessible by current user`);\n }\n else {\n this.log('warn', `Skipped downloading product #${product.id}: not accessible by current user`);\n this.emit('targetEnd', {\n target: product,\n isSkipped: true,\n skipReason: TargetSkipReason.Inaccessible,\n skipMessage: 'Target is not accessible by current user'\n });\n return {\n status: 'skippedUnviewable'\n };\n }\n }\n // -- 1.4 Config option 'include.productsPublished'\n if (this.isPublishDateOutOfRange(product)) {\n return {\n status: 'skippedPublishDateOutOfRange'\n };\n }\n\n this.fsHelper.createDir(productDirs.root);\n\n // Step 2: save product info\n if (this.config.include.contentInfo) {\n this.log('info', 'Save product info');\n this.emit('phaseBegin', { target: product, phase: 'saveInfo' });\n this.fsHelper.createDir(productDirs.info);\n const summary = generateProductSummary(product);\n const summaryFile = path.resolve(productDirs.info, 'info.txt');\n const saveSummaryResult = await this.fsHelper.writeTextFile(summaryFile, summary, this.config.fileExistsAction.info);\n this.logWriteTextFileResult(saveSummaryResult, product, 'product summary');\n\n const productRawFile = path.resolve(productDirs.info, 'product-api.json');\n const saveProductRawResult = await this.fsHelper.writeTextFile(\n productRawFile, product.raw, this.config.fileExistsAction.infoAPI);\n this.logWriteTextFileResult(saveProductRawResult, product, 'product API data');\n this.emit('phaseEnd', { target: product, phase: 'saveInfo' });\n }\n\n // Step 3: Download product media items\n const incPreview = this.config.include.previewMedia;\n const incContent = this.config.include.contentMedia;\n this.log('info', 'Download:', {\n ['preview items']: incPreview === true ? 'yes' : incPreview === false ? 'no' : JSON.stringify(incPreview),\n ['content items']: incContent === true ? 'yes' : incContent === false ? 'no' : JSON.stringify(incContent)\n });\n\n const __inc = (inc: boolean | Array<any>, target: Downloadable) => {\n if (typeof inc === 'boolean') {\n return inc;\n }\n return (inc.includes(target.type as any));\n };\n\n const previewMedia = product.previewMedia.filter((tt) => __inc(incPreview, tt));\n const contentMedia = product.contentMedia.filter((tt) => __inc(incContent, tt));\n const campaignDir = product.campaign ? this.fsHelper.getCampaignDirs(product.campaign).root : null;\n\n if (this.config.include.previewMedia || this.config.include.contentMedia) {\n this.emit('phaseBegin', { target: product, phase: 'saveMedia' });\n const batchResult = await this.createDownloadTaskBatch(\n `Product #${product.id} (${product.name})`,\n signal,\n\n previewMedia.length > 0 ? {\n target: previewMedia,\n targetName: `product #${product.id} -> preview media`,\n src: product,\n dirs: {\n campaign: campaignDir,\n main: productDirs.previewMedia,\n thumbnails: productDirs.thumbnails\n },\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n contentMedia.length > 0 ? {\n target: contentMedia,\n targetName: `product #${product.id} -> content media`,\n src: product,\n dirs: {\n campaign: campaignDir,\n main: productDirs.contentMedia,\n thumbnails: productDirs.thumbnails\n },\n fileExistsAction: this.config.fileExistsAction.content,\n ignoreCreateTaskErrors: !product.isAccessible\n } : null\n );\n\n const { batch } = batchResult;\n\n const abortHandler = () => {\n void (async () => {\n this.log('info', 'Abort signal received');\n if (batch) {\n await batch.abort();\n }\n })();\n };\n if (signal) {\n signal.addEventListener('abort', abortHandler, { once: true });\n }\n \n try {\n if (this.checkAbortSignal(signal)) {\n return {\n status: 'aborted'\n };\n }\n \n batch.prestart();\n this.log('info', `Download batch created (#${batch.id}): ${batch.getTasks('pending').length} downloads pending`);\n this.emit('phaseBegin', { target: product, phase: 'batchDownload', batch });\n\n await batch.start();\n\n // Step 4: Update status cache\n statusCache.updateOnDownload(product, productDirs.root, batch.getTasks('error').length > 0 || batchResult.errorCount > 0, this.config);\n\n await batch.destroy();\n }\n finally {\n if (signal) {\n signal.removeEventListener('abort', abortHandler);\n }\n }\n\n this.emit('phaseEnd', { target: product, phase: 'batchDownload' });\n this.emit('phaseEnd', { target: product, phase: 'saveMedia' });\n }\n\n if (this.checkAbortSignal(signal)) {\n return {\n status: 'aborted'\n };\n }\n\n // Step 5: Save to DB\n let skipDB = false;\n let saveReferencedEntityId: (id: string) => void;\n const dbProduct = db.getContent(product.id, 'product');\n if (!product.isAccessible) {\n // Skip if existing db record (if any) refers to accessible product\n skipDB = dbProduct !== null && dbProduct.isAccessible;\n }\n if (!skipDB) {\n db.saveContent(product);\n saveReferencedEntityId = (id) => {\n product.referencedEntityId = id;\n db.saveContent(product);\n };\n }\n else {\n this.log('info', `Skip overwrite existing accessible product #${product.id} in DB with current unviewable version`);\n saveReferencedEntityId = (id) => {\n // Ensure referencedEntityId is updated\n dbProduct!.referencedEntityId = id;\n db.saveContent(dbProduct!);\n };\n }\n\n // Step 6: check product type and download referenced product / collection\n await this.#processProductType(product, saveReferencedEntityId, signal);\n\n // Done\n this.log('info', `Done downloading product #${product.id}`);\n this.emit('targetEnd', { target: product, isSkipped: false });\n\n return {\n status: 'downloaded'\n }\n }\n\n // Carry out further action based on product type\n async #processProductType(\n product: Product,\n saveReferencedEntityId: (id: string) => void,\n signal?: AbortSignal\n ) {\n if (product.productType === undefined || product.productType === ProductType.DigitalCommerce) {\n this.log('debug', `Product type \"${product.productType}\": no further action required`);\n return;\n }\n if (product.productType === ProductType.Post || product.productType === ProductType.Collection) {\n const bootstrap = Bootstrap.getDownloaderBootstrapDataByURL(product.url);\n if (bootstrap?.type === 'post') {\n this.log('info', `Download ${product.productType} referenced by product: ${product.url}`);\n const PostDownloader = (await import('./PostDownloader.js')).default;\n const downloader = new PostDownloader(\n {\n ...this.config,\n ...bootstrap\n },\n this.db,\n this.logger,\n {\n skipSaveCampaign: true,\n keepLoggerOpen: true,\n keepDBOpen: true\n }\n );\n try {\n await downloader.start({ signal });\n this.log('info', `Done downloading ${product.productType} referenced by product`);\n }\n catch (error) {\n if (signal?.aborted) {\n throw error;\n }\n this.log('error', `Error downloading ${product.productType} referenced by product (url: ${product.url})`, error);\n }\n let referencedEntityId: string | undefined = undefined;\n let bootstrapMismatch = false;\n if (bootstrap.postFetch.type === 'single') {\n bootstrapMismatch = product.productType !== ProductType.Post;\n referencedEntityId = bootstrap.postFetch.postId;\n }\n if (bootstrap.postFetch.type === 'byCollection') {\n bootstrapMismatch = product.productType !== ProductType.Collection;\n referencedEntityId = bootstrap.postFetch.collectionId;\n }\n if (bootstrapMismatch) {\n this.log('warn', `Product type \"${product.productType}\" does not match URL \"${product.url}\" (${bootstrap.postFetch.type})`);\n }\n else if (referencedEntityId) {\n saveReferencedEntityId(referencedEntityId);\n }\n }\n else {\n this.log('error', `Product type is \"${product.productType}\" but could not create downloader from URL \"${product.url}\"`);\n }\n return;\n }\n this.log('debug', `Unknown product type \"${product.productType}\": no further action can be taken`);\n return;\n }\n\n #isFetchingMultipleProducts(productFetch: DownloaderConfig<Product>['productFetch']): productFetch is DownloaderConfig<Product>['productFetch'] & { type: 'byShop' } {\n return productFetch.type === 'byShop';\n }\n}\n"]}
|
|
@@ -11,12 +11,14 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
11
11
|
};
|
|
12
12
|
var _ProductsFetcher_instances, _ProductsFetcher_pointers, _ProductsFetcher_fetched, _ProductsFetcher_total, _ProductsFetcher_nextPromises, _ProductsFetcher_sleeper, _ProductsFetcher_noSleep, _ProductsFetcher_setStatus, _ProductsFetcher_isRunning, _ProductsFetcher_doBegin, _ProductsFetcher_handleError, _ProductsFetcher_isFetchingMultipleProducts, _ProductsFetcher_getInitialContext, _ProductsFetcher_fetchAPI;
|
|
13
13
|
import EventEmitter from 'events';
|
|
14
|
+
import fse from 'fs-extra';
|
|
14
15
|
import { commonLog } from '../utils/logging/Logger.js';
|
|
15
16
|
import Downloader from './Downloader.js';
|
|
16
17
|
import URLHelper from '../utils/URLHelper.js';
|
|
17
18
|
import ProductParser from '../parsers/ProductParser.js';
|
|
18
19
|
import Sleeper from '../utils/Sleeper.js';
|
|
19
20
|
import { InitialData } from './InitialData.js';
|
|
21
|
+
import path from 'path';
|
|
20
22
|
const SLEEPER_INTERVAL = 900000; // 15 mins
|
|
21
23
|
class ProductsFetcher extends EventEmitter {
|
|
22
24
|
constructor(params) {
|
|
@@ -187,37 +189,42 @@ _ProductsFetcher_pointers = new WeakMap(), _ProductsFetcher_fetched = new WeakMa
|
|
|
187
189
|
__classPrivateFieldGet(this, _ProductsFetcher_instances, "m", _ProductsFetcher_setStatus).call(this, { status: 'running' });
|
|
188
190
|
__classPrivateFieldGet(this, _ProductsFetcher_pointers, "f").fetching = 0;
|
|
189
191
|
const productFetch = this.config.productFetch;
|
|
190
|
-
let
|
|
191
|
-
let campaign;
|
|
192
|
-
let obtainCampaignFromProduct;
|
|
192
|
+
let ctx;
|
|
193
193
|
try {
|
|
194
|
-
|
|
195
|
-
productsAPIURL = ctx.productsAPIURL;
|
|
196
|
-
obtainCampaignFromProduct = ctx.campaign.obtainFromProduct;
|
|
197
|
-
campaign = ctx.campaign.data;
|
|
194
|
+
ctx = await __classPrivateFieldGet(this, _ProductsFetcher_instances, "m", _ProductsFetcher_getInitialContext).call(this);
|
|
198
195
|
}
|
|
199
196
|
catch (error) {
|
|
200
197
|
__classPrivateFieldGet(this, _ProductsFetcher_instances, "m", _ProductsFetcher_handleError).call(this, error);
|
|
201
198
|
return;
|
|
202
199
|
}
|
|
200
|
+
const obtainCampaignFromProduct = ctx.campaign.obtainFromProduct;
|
|
201
|
+
const campaign = ctx.campaign.data;
|
|
203
202
|
if (__classPrivateFieldGet(this, _ProductsFetcher_instances, "m", _ProductsFetcher_isFetchingMultipleProducts).call(this, productFetch)) {
|
|
204
203
|
this.log('info', 'Fetch products');
|
|
205
|
-
this.log('debug', `Request initial products from API URL "${
|
|
204
|
+
this.log('debug', `Request initial products from API URL "${ctx.src}"`);
|
|
205
|
+
}
|
|
206
|
+
else if (productFetch.type === 'byFile') {
|
|
207
|
+
this.log('info', `Read product data from "${ctx.src}"`);
|
|
206
208
|
}
|
|
207
209
|
else {
|
|
208
210
|
this.log('info', 'Fetch target product');
|
|
209
|
-
this.log('debug', `Request product #${productFetch.productId} from API URL "${
|
|
211
|
+
this.log('debug', `Request product #${productFetch.productId} from API URL "${ctx.src}`);
|
|
210
212
|
}
|
|
211
213
|
let json;
|
|
212
214
|
try {
|
|
213
|
-
|
|
215
|
+
if (ctx.srcType === 'url') {
|
|
216
|
+
json = await __classPrivateFieldGet(this, _ProductsFetcher_instances, "m", _ProductsFetcher_fetchAPI).call(this, ctx.src);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
json = fse.readJsonSync(ctx.src);
|
|
220
|
+
}
|
|
214
221
|
}
|
|
215
222
|
catch (error) {
|
|
216
223
|
__classPrivateFieldGet(this, _ProductsFetcher_instances, "m", _ProductsFetcher_handleError).call(this, error);
|
|
217
224
|
return;
|
|
218
225
|
}
|
|
219
226
|
const productsParser = new ProductParser(this.logger);
|
|
220
|
-
const list = productsParser.parseProductsAPIResponse(json,
|
|
227
|
+
const list = productsParser.parseProductsAPIResponse(json, ctx.src, obtainCampaignFromProduct ? undefined : campaign);
|
|
221
228
|
__classPrivateFieldSet(this, _ProductsFetcher_fetched, [list], "f");
|
|
222
229
|
__classPrivateFieldGet(this, _ProductsFetcher_pointers, "f").lastFetched = __classPrivateFieldGet(this, _ProductsFetcher_pointers, "f").fetching;
|
|
223
230
|
__classPrivateFieldGet(this, _ProductsFetcher_pointers, "f").fetching = null;
|
|
@@ -297,7 +304,6 @@ _ProductsFetcher_pointers = new WeakMap(), _ProductsFetcher_fetched = new WeakMa
|
|
|
297
304
|
return productFetch.type === 'byShop';
|
|
298
305
|
}, _ProductsFetcher_getInitialContext = async function _ProductsFetcher_getInitialContext() {
|
|
299
306
|
const productFetch = this.config.productFetch;
|
|
300
|
-
let apiURL;
|
|
301
307
|
switch (productFetch.type) {
|
|
302
308
|
case 'byShop': {
|
|
303
309
|
// Shop API does not return full campaign info (missing creator and rewards),
|
|
@@ -306,17 +312,28 @@ _ProductsFetcher_pointers = new WeakMap(), _ProductsFetcher_fetched = new WeakMa
|
|
|
306
312
|
const { campaignId } = await this.getInitialData(initialDataPageURL);
|
|
307
313
|
const campaign = await Downloader.getCampaign({ campaignId }, this.signal, this.config);
|
|
308
314
|
return {
|
|
309
|
-
|
|
315
|
+
src: URLHelper.constructShopAPIURL({ campaignId }),
|
|
316
|
+
srcType: 'url',
|
|
310
317
|
campaign: {
|
|
311
318
|
obtainFromProduct: false,
|
|
312
319
|
data: campaign
|
|
313
320
|
}
|
|
314
321
|
};
|
|
315
322
|
}
|
|
323
|
+
case 'byFile': {
|
|
324
|
+
return {
|
|
325
|
+
src: path.resolve(productFetch.filePath),
|
|
326
|
+
srcType: 'file',
|
|
327
|
+
campaign: {
|
|
328
|
+
obtainFromProduct: true,
|
|
329
|
+
data: null
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
}
|
|
316
333
|
case 'single': {
|
|
317
|
-
apiURL = URLHelper.constructProductAPIURL(productFetch.productId);
|
|
318
334
|
return {
|
|
319
|
-
|
|
335
|
+
src: URLHelper.constructProductAPIURL(productFetch.productId),
|
|
336
|
+
srcType: 'url',
|
|
320
337
|
campaign: {
|
|
321
338
|
obtainFromProduct: true,
|
|
322
339
|
data: null
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductsFetcher.js","sourceRoot":"","sources":["../../src/downloaders/ProductsFetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import EventEmitter from 'events';\nimport { type Campaign, type Product } from '../entities/index.js';\nimport { type Logger } from '../utils/logging/index.js';\nimport { type LogLevel, commonLog } from '../utils/logging/Logger.js';\nimport Downloader, { type DownloaderConfig } from './Downloader.js';\nimport URLHelper from '../utils/URLHelper.js';\nimport type Fetcher from '../utils/Fetcher.js';\nimport ProductParser from '../parsers/ProductParser.js';\nimport { type ProductList } from '../entities/Product.js';\nimport Sleeper from '../utils/Sleeper.js';\nimport { InitialData } from './InitialData.js';\n\nexport type ProductsFetcherStatus = {\n status: 'ready' | 'running' | 'completed' | 'aborted';\n error?: undefined;\n} | {\n status: 'error';\n error: any;\n};\n\nexport type ProductsFetcherEvent = 'fetched' | 'statusChange';\nexport type ProductsFetcherEventPayload<T extends ProductsFetcherEvent> =\n T extends 'fetched' ? {\n list: ProductList;\n index: number;\n } :\n T extends 'statusChange' ? {\n current: ProductsFetcherStatus;\n old: ProductsFetcherStatus;\n } :\n never;\n\nexport interface ProductsFetcherResult {\n list: ProductList | null;\n error?: any;\n aborted: boolean;\n}\n\nconst SLEEPER_INTERVAL = 900000; // 15 mins\n\nexport default class ProductsFetcher extends EventEmitter {\n\n name = 'ProductsFetcher';\n\n protected status: ProductsFetcherStatus;\n protected config: DownloaderConfig<Product>;\n protected fetcher: Fetcher;\n protected signal?: AbortSignal;\n protected logger?: Logger | null;\n\n #pointers: {\n fetching: number | null;\n lastFetched: number | null;\n returning: number | null;\n lastReturned: number | null; // Last returned in next()\n };\n #fetched: ProductList[];\n #total: number | null;\n #nextPromises: Array<Promise<ProductsFetcherResult> | undefined>;\n #sleeper: Sleeper | null;\n #noSleep: boolean;\n\n constructor(params: {\n config: DownloaderConfig<Product>,\n fetcher: Fetcher,\n logger?: Logger | null,\n signal?: AbortSignal\n }) {\n super();\n const { config, fetcher, logger, signal } = params;\n this.config = config;\n this.fetcher = fetcher;\n this.logger = logger;\n this.signal = signal;\n this.#fetched = [];\n this.status = { status: 'ready' };\n this.#pointers = {\n fetching: null,\n lastFetched: null,\n returning: null,\n lastReturned: null\n };\n this.#nextPromises = [];\n this.#sleeper = null;\n this.#noSleep = false;\n }\n\n isFetchingMultiple() {\n return this.#isFetchingMultipleProducts(this.config.productFetch);\n }\n\n getTargetType() {\n return this.#isFetchingMultipleProducts(this.config.productFetch) ? 'products' : 'product';\n }\n\n protected log(level: LogLevel, ...msg: any[]) {\n commonLog(this.logger, level, this.name, ...msg);\n }\n\n #setStatus(status: ProductsFetcherStatus) {\n const oldStatus = this.status;\n this.status = status;\n this.emit('statusChange', { current: status, old: oldStatus });\n }\n\n #isRunning() {\n return this.status.status === 'running';\n }\n\n begin() {\n void this.#doBegin();\n }\n\n async #doBegin() {\n if (this.status.status !== 'ready') {\n throw Error('ProductsFetcher already running or has ended');\n }\n\n this.#setStatus({ status: 'running' });\n\n this.#pointers.fetching = 0;\n const productFetch = this.config.productFetch;\n let productsAPIURL: string;\n let campaign: Campaign | null;\n let obtainCampaignFromProduct: boolean;\n try {\n const ctx = await this.#getInitialContext();\n productsAPIURL = ctx.productsAPIURL;\n obtainCampaignFromProduct = ctx.campaign.obtainFromProduct;\n campaign = ctx.campaign.data;\n }\n catch (error) {\n this.#handleError(error);\n return;\n }\n if (this.#isFetchingMultipleProducts(productFetch)) {\n this.log('info', 'Fetch products');\n this.log('debug', `Request initial products from API URL \"${productsAPIURL}\"`);\n }\n else {\n this.log('info', 'Fetch target product');\n this.log('debug', `Request product #${productFetch.productId} from API URL \"${productsAPIURL}`);\n }\n\n let json;\n try {\n json = await this.#fetchAPI(productsAPIURL);\n }\n catch (error) {\n this.#handleError(error);\n return;\n }\n\n const productsParser = new ProductParser(this.logger);\n const list = productsParser.parseProductsAPIResponse(\n json,\n productsAPIURL,\n obtainCampaignFromProduct ? undefined : campaign\n );\n this.#fetched = [ list ];\n this.#pointers.lastFetched = this.#pointers.fetching;\n this.#pointers.fetching = null;\n this.emit('fetched', { list, index: 0 });\n\n const total = this.#total = this.#fetched[0].total;\n if (this.#isFetchingMultipleProducts(productFetch)) {\n let totalFetched = this.#fetched[0].items.length;\n this.log('info', `Fetched products: ${totalFetched} / ${total}`);\n let nextURL = this.#fetched[0].nextURL;\n while (nextURL) {\n let json;\n try {\n this.#pointers.fetching = this.#pointers.lastFetched !== null ? this.#pointers.lastFetched + 1 : 1;\n const sleep = !this.#pointers.returning || this.#pointers.returning < this.#pointers.fetching;\n if (sleep && !this.#sleeper) {\n this.log('debug', `Has more products - will fetch in ${SLEEPER_INTERVAL / 1000} seconds`);\n this.#sleeper = Sleeper.getInstance(SLEEPER_INTERVAL, this.signal);\n await this.#sleeper.start();\n }\n this.log('debug', `Request more products from API URL \"${nextURL}\"`);\n json = await this.#fetchAPI(nextURL);\n }\n catch (error) {\n this.#handleError(error);\n json = null;\n }\n finally {\n if (this.#sleeper) {\n this.#sleeper.destroy();\n this.#sleeper = null;\n }\n }\n if (!json) {\n nextURL = null;\n }\n else {\n const list = productsParser.parseProductsAPIResponse(json, nextURL);\n this.#fetched.push(list);\n const fetched = list.items.length;\n totalFetched += fetched;\n this.log('info', `Fetched products: ${totalFetched} / ${total}`);\n nextURL = list.nextURL;\n this.#pointers.lastFetched = this.#pointers.fetching;\n this.#pointers.fetching = null;\n this.emit('fetched', { list, index: this.#fetched.length - 1 });\n }\n }\n if (!this.checkAbortSignal()) {\n if (total && totalFetched < total) {\n this.log('warn', `Done, but some products were not fetched. Total expected: ${total}; currently fetched: ${totalFetched}`);\n }\n else {\n this.log('info', `Done. ${totalFetched} products fetched`);\n }\n\n if (this.#isRunning()) {\n this.#setStatus({ status: 'completed' });\n }\n }\n }\n // Set 'completed' if not fetching multiple products\n else if (!this.checkAbortSignal() && this.#isRunning()) {\n this.#setStatus({ status: 'completed' });\n }\n }\n\n #handleError(error: any) {\n const statusName = this.status.status;\n if (statusName === 'aborted' || statusName === 'completed') {\n return;\n }\n if (this.signal?.aborted) {\n this.log('warn', 'Abort');\n this.#setStatus({ status: 'aborted' });\n return;\n }\n this.log('error', error);\n this.#setStatus({ status: 'error', error });\n }\n\n #isFetchingMultipleProducts(productFetch: DownloaderConfig<Product>['productFetch']): productFetch is DownloaderConfig<Product>['productFetch'] & { type: 'byShop' } {\n return productFetch.type === 'byShop';\n }\n\n async #getInitialContext() {\n const productFetch = this.config.productFetch;\n let apiURL: string;\n switch (productFetch.type) {\n case 'byShop': {\n // Shop API does not return full campaign info (missing creator and rewards),\n // so we fetch separately.\n const initialDataPageURL = URLHelper.constructCampaignPageURL({ vanity: productFetch.vanity });\n const { campaignId } = await this.getInitialData(initialDataPageURL);\n const campaign = await Downloader.getCampaign({ campaignId }, this.signal, this.config);\n return {\n productsAPIURL: URLHelper.constructShopAPIURL({ campaignId }),\n campaign: {\n obtainFromProduct: false as const,\n data: campaign\n }\n };\n }\n case 'single': {\n apiURL = URLHelper.constructProductAPIURL(productFetch.productId);\n return {\n productsAPIURL: apiURL,\n campaign: {\n obtainFromProduct: true as const,\n data: null\n }\n };\n }\n }\n }\n\n getInitialData(url: string) {\n const id = new InitialData(this.config, this.fetcher, this.logger);\n return id.get(url, this.signal);\n }\n\n async #fetchAPI(url: string) {\n return (await this.fetcher.get({ url, type: 'json', maxRetries: this.config.request.maxRetries, signal: this.signal })).json;\n }\n\n protected checkAbortSignal() {\n return this.signal && this.signal.aborted;\n }\n\n hasNext() {\n const lastReturned = this.#pointers.lastReturned !== null ? this.#pointers.lastReturned : -1;\n return this.#isRunning() || (this.#fetched.length > 0 && lastReturned < this.#fetched.length - 1);\n }\n\n async next(): Promise<ProductsFetcherResult> {\n this.#pointers.returning = this.#pointers.lastReturned !== null ? this.#pointers.lastReturned + 1 : 0;\n const ptr = this.#pointers.returning;\n this.log('debug', `next() requested (${ptr})`);\n const __parseStatus = (status: ProductsFetcherStatus) => {\n let list: ProductList | null | undefined;\n let aborted = false;\n let error: any;\n switch (status.status) {\n case 'aborted':\n list = null;\n aborted = true;\n break;\n case 'error':\n if (this.#fetched[ptr]) {\n list = this.#fetched[ptr];\n }\n else {\n list = null;\n error = status.error;\n }\n break;\n case 'completed':\n list = this.#fetched[ptr] || null;\n break;\n default:\n list = this.#fetched[ptr] || undefined;\n }\n return { list, aborted, error };\n };\n if (this.#isRunning() && !this.#fetched[ptr]) {\n let result = this.#nextPromises[ptr];\n if (!result) {\n let resolved = false;\n result = new Promise<ProductsFetcherResult>((resolve) => {\n const fetchedListener = () => {\n if (resolved) {\n this.off('fetched', fetchedListener);\n return;\n }\n if (this.#fetched[ptr]) {\n this.off('fetched', fetchedListener);\n resolved = true;\n resolve({\n list: this.#fetched[ptr],\n aborted: false\n });\n }\n };\n const statusListener = (args: { current: ProductsFetcherStatus }) => {\n if (resolved) {\n this.off('statusChange', statusListener);\n return;\n }\n const { list, aborted, error } = __parseStatus(args.current);\n if (list !== undefined) {\n this.off('statusChange', statusListener);\n resolved = true;\n resolve({ list, aborted, error });\n }\n };\n this.on('fetched', fetchedListener);\n this.on('statusChange', statusListener);\n if (!this.#noSleep) {\n this.#noSleep = true;\n }\n if (this.#sleeper) {\n this.log('debug', 'Wake up early from sleep');\n this.#sleeper.wake();\n }\n })\n .finally(() => {\n this.#nextPromises[ptr] = undefined;\n this.#noSleep = false;\n this.#pointers.lastReturned = this.#pointers.returning;\n this.#pointers.returning = null;\n if (resolved) {\n this.log('debug', `next() handled (${ptr})`);\n }\n else {\n this.log('debug', `next() handled (${ptr}) - no resolve`);\n }\n });\n this.#nextPromises[ptr] = result;\n }\n return result;\n }\n this.#pointers.lastReturned = this.#pointers.returning;\n this.#pointers.returning = null;\n this.log('debug', `next() handled (${ptr})`);\n return __parseStatus(this.status);\n }\n\n getTotal() {\n return this.#total;\n }\n\n emit<T extends ProductsFetcherEvent>(eventName: T, args: ProductsFetcherEventPayload<T>): boolean;\n emit(eventName: string | symbol, ...args: any[]): boolean {\n return super.emit(eventName, ...args);\n }\n\n on<T extends ProductsFetcherEvent>(eventName: T, listener: (args: ProductsFetcherEventPayload<T>) => void): this;\n on(eventName: string | symbol, listener: (...args: any[]) => void): this {\n return super.on(eventName, listener);\n }\n\n off<T extends ProductsFetcherEvent>(eventName: T, listener: (args: ProductsFetcherEventPayload<T>) => void): this;\n off(eventName: string | symbol, listener: (...args: any[]) => void): this {\n return super.off(eventName, listener);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ProductsFetcher.js","sourceRoot":"","sources":["../../src/downloaders/ProductsFetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import EventEmitter from 'events';\nimport fse from 'fs-extra';\nimport { type Product } from '../entities/index.js';\nimport { type Logger } from '../utils/logging/index.js';\nimport { type LogLevel, commonLog } from '../utils/logging/Logger.js';\nimport Downloader, { type DownloaderConfig } from './Downloader.js';\nimport URLHelper from '../utils/URLHelper.js';\nimport type Fetcher from '../utils/Fetcher.js';\nimport ProductParser from '../parsers/ProductParser.js';\nimport { type ProductList } from '../entities/Product.js';\nimport Sleeper from '../utils/Sleeper.js';\nimport { InitialData } from './InitialData.js';\nimport path from 'path';\n\nexport type ProductsFetcherStatus = {\n status: 'ready' | 'running' | 'completed' | 'aborted';\n error?: undefined;\n} | {\n status: 'error';\n error: any;\n};\n\nexport type ProductsFetcherEvent = 'fetched' | 'statusChange';\nexport type ProductsFetcherEventPayload<T extends ProductsFetcherEvent> =\n T extends 'fetched' ? {\n list: ProductList;\n index: number;\n } :\n T extends 'statusChange' ? {\n current: ProductsFetcherStatus;\n old: ProductsFetcherStatus;\n } :\n never;\n\nexport interface ProductsFetcherResult {\n list: ProductList | null;\n error?: any;\n aborted: boolean;\n}\n\nconst SLEEPER_INTERVAL = 900000; // 15 mins\n\nexport default class ProductsFetcher extends EventEmitter {\n\n name = 'ProductsFetcher';\n\n protected status: ProductsFetcherStatus;\n protected config: DownloaderConfig<Product>;\n protected fetcher: Fetcher;\n protected signal?: AbortSignal;\n protected logger?: Logger | null;\n\n #pointers: {\n fetching: number | null;\n lastFetched: number | null;\n returning: number | null;\n lastReturned: number | null; // Last returned in next()\n };\n #fetched: ProductList[];\n #total: number | null;\n #nextPromises: Array<Promise<ProductsFetcherResult> | undefined>;\n #sleeper: Sleeper | null;\n #noSleep: boolean;\n\n constructor(params: {\n config: DownloaderConfig<Product>,\n fetcher: Fetcher,\n logger?: Logger | null,\n signal?: AbortSignal\n }) {\n super();\n const { config, fetcher, logger, signal } = params;\n this.config = config;\n this.fetcher = fetcher;\n this.logger = logger;\n this.signal = signal;\n this.#fetched = [];\n this.status = { status: 'ready' };\n this.#pointers = {\n fetching: null,\n lastFetched: null,\n returning: null,\n lastReturned: null\n };\n this.#nextPromises = [];\n this.#sleeper = null;\n this.#noSleep = false;\n }\n\n isFetchingMultiple() {\n return this.#isFetchingMultipleProducts(this.config.productFetch);\n }\n\n getTargetType() {\n return this.#isFetchingMultipleProducts(this.config.productFetch) ? 'products' : 'product';\n }\n\n protected log(level: LogLevel, ...msg: any[]) {\n commonLog(this.logger, level, this.name, ...msg);\n }\n\n #setStatus(status: ProductsFetcherStatus) {\n const oldStatus = this.status;\n this.status = status;\n this.emit('statusChange', { current: status, old: oldStatus });\n }\n\n #isRunning() {\n return this.status.status === 'running';\n }\n\n begin() {\n void this.#doBegin();\n }\n\n async #doBegin() {\n if (this.status.status !== 'ready') {\n throw Error('ProductsFetcher already running or has ended');\n }\n\n this.#setStatus({ status: 'running' });\n\n this.#pointers.fetching = 0;\n const productFetch = this.config.productFetch;\n let ctx;\n try {\n ctx = await this.#getInitialContext();\n }\n catch (error) {\n this.#handleError(error);\n return;\n }\n const obtainCampaignFromProduct = ctx.campaign.obtainFromProduct;\n const campaign = ctx.campaign.data;\n if (this.#isFetchingMultipleProducts(productFetch)) {\n this.log('info', 'Fetch products');\n this.log('debug', `Request initial products from API URL \"${ctx.src}\"`);\n }\n else if (productFetch.type === 'byFile') {\n this.log('info', `Read product data from \"${ctx.src}\"`);\n }\n else {\n this.log('info', 'Fetch target product');\n this.log('debug', `Request product #${productFetch.productId} from API URL \"${ctx.src}`);\n }\n\n let json;\n try {\n if (ctx.srcType === 'url') {\n json = await this.#fetchAPI(ctx.src);\n }\n else {\n json = fse.readJsonSync(ctx.src);\n }\n }\n catch (error) {\n this.#handleError(error);\n return;\n }\n\n const productsParser = new ProductParser(this.logger);\n const list = productsParser.parseProductsAPIResponse(\n json,\n ctx.src,\n obtainCampaignFromProduct ? undefined : campaign\n );\n this.#fetched = [ list ];\n this.#pointers.lastFetched = this.#pointers.fetching;\n this.#pointers.fetching = null;\n this.emit('fetched', { list, index: 0 });\n\n const total = this.#total = this.#fetched[0].total;\n if (this.#isFetchingMultipleProducts(productFetch)) {\n let totalFetched = this.#fetched[0].items.length;\n this.log('info', `Fetched products: ${totalFetched} / ${total}`);\n let nextURL = this.#fetched[0].nextURL;\n while (nextURL) {\n let json;\n try {\n this.#pointers.fetching = this.#pointers.lastFetched !== null ? this.#pointers.lastFetched + 1 : 1;\n const sleep = !this.#pointers.returning || this.#pointers.returning < this.#pointers.fetching;\n if (sleep && !this.#sleeper) {\n this.log('debug', `Has more products - will fetch in ${SLEEPER_INTERVAL / 1000} seconds`);\n this.#sleeper = Sleeper.getInstance(SLEEPER_INTERVAL, this.signal);\n await this.#sleeper.start();\n }\n this.log('debug', `Request more products from API URL \"${nextURL}\"`);\n json = await this.#fetchAPI(nextURL);\n }\n catch (error) {\n this.#handleError(error);\n json = null;\n }\n finally {\n if (this.#sleeper) {\n this.#sleeper.destroy();\n this.#sleeper = null;\n }\n }\n if (!json) {\n nextURL = null;\n }\n else {\n const list = productsParser.parseProductsAPIResponse(json, nextURL);\n this.#fetched.push(list);\n const fetched = list.items.length;\n totalFetched += fetched;\n this.log('info', `Fetched products: ${totalFetched} / ${total}`);\n nextURL = list.nextURL;\n this.#pointers.lastFetched = this.#pointers.fetching;\n this.#pointers.fetching = null;\n this.emit('fetched', { list, index: this.#fetched.length - 1 });\n }\n }\n if (!this.checkAbortSignal()) {\n if (total && totalFetched < total) {\n this.log('warn', `Done, but some products were not fetched. Total expected: ${total}; currently fetched: ${totalFetched}`);\n }\n else {\n this.log('info', `Done. ${totalFetched} products fetched`);\n }\n\n if (this.#isRunning()) {\n this.#setStatus({ status: 'completed' });\n }\n }\n }\n // Set 'completed' if not fetching multiple products\n else if (!this.checkAbortSignal() && this.#isRunning()) {\n this.#setStatus({ status: 'completed' });\n }\n }\n\n #handleError(error: any) {\n const statusName = this.status.status;\n if (statusName === 'aborted' || statusName === 'completed') {\n return;\n }\n if (this.signal?.aborted) {\n this.log('warn', 'Abort');\n this.#setStatus({ status: 'aborted' });\n return;\n }\n this.log('error', error);\n this.#setStatus({ status: 'error', error });\n }\n\n #isFetchingMultipleProducts(productFetch: DownloaderConfig<Product>['productFetch']): productFetch is DownloaderConfig<Product>['productFetch'] & { type: 'byShop' } {\n return productFetch.type === 'byShop';\n }\n\n async #getInitialContext() {\n const productFetch = this.config.productFetch;\n switch (productFetch.type) {\n case 'byShop': {\n // Shop API does not return full campaign info (missing creator and rewards),\n // so we fetch separately.\n const initialDataPageURL = URLHelper.constructCampaignPageURL({ vanity: productFetch.vanity });\n const { campaignId } = await this.getInitialData(initialDataPageURL);\n const campaign = await Downloader.getCampaign({ campaignId }, this.signal, this.config);\n return {\n src: URLHelper.constructShopAPIURL({ campaignId }),\n srcType: 'url' as const,\n campaign: {\n obtainFromProduct: false as const,\n data: campaign\n }\n };\n }\n case 'byFile': {\n return {\n src: path.resolve(productFetch.filePath),\n srcType: 'file' as const,\n campaign: {\n obtainFromProduct: true as const,\n data: null\n }\n };\n }\n case 'single': {\n return {\n src: URLHelper.constructProductAPIURL(productFetch.productId),\n srcType: 'url' as const,\n campaign: {\n obtainFromProduct: true as const,\n data: null\n }\n };\n }\n }\n }\n\n getInitialData(url: string) {\n const id = new InitialData(this.config, this.fetcher, this.logger);\n return id.get(url, this.signal);\n }\n\n async #fetchAPI(url: string) {\n return (await this.fetcher.get({ url, type: 'json', maxRetries: this.config.request.maxRetries, signal: this.signal })).json;\n }\n\n protected checkAbortSignal() {\n return this.signal && this.signal.aborted;\n }\n\n hasNext() {\n const lastReturned = this.#pointers.lastReturned !== null ? this.#pointers.lastReturned : -1;\n return this.#isRunning() || (this.#fetched.length > 0 && lastReturned < this.#fetched.length - 1);\n }\n\n async next(): Promise<ProductsFetcherResult> {\n this.#pointers.returning = this.#pointers.lastReturned !== null ? this.#pointers.lastReturned + 1 : 0;\n const ptr = this.#pointers.returning;\n this.log('debug', `next() requested (${ptr})`);\n const __parseStatus = (status: ProductsFetcherStatus) => {\n let list: ProductList | null | undefined;\n let aborted = false;\n let error: any;\n switch (status.status) {\n case 'aborted':\n list = null;\n aborted = true;\n break;\n case 'error':\n if (this.#fetched[ptr]) {\n list = this.#fetched[ptr];\n }\n else {\n list = null;\n error = status.error;\n }\n break;\n case 'completed':\n list = this.#fetched[ptr] || null;\n break;\n default:\n list = this.#fetched[ptr] || undefined;\n }\n return { list, aborted, error };\n };\n if (this.#isRunning() && !this.#fetched[ptr]) {\n let result = this.#nextPromises[ptr];\n if (!result) {\n let resolved = false;\n result = new Promise<ProductsFetcherResult>((resolve) => {\n const fetchedListener = () => {\n if (resolved) {\n this.off('fetched', fetchedListener);\n return;\n }\n if (this.#fetched[ptr]) {\n this.off('fetched', fetchedListener);\n resolved = true;\n resolve({\n list: this.#fetched[ptr],\n aborted: false\n });\n }\n };\n const statusListener = (args: { current: ProductsFetcherStatus }) => {\n if (resolved) {\n this.off('statusChange', statusListener);\n return;\n }\n const { list, aborted, error } = __parseStatus(args.current);\n if (list !== undefined) {\n this.off('statusChange', statusListener);\n resolved = true;\n resolve({ list, aborted, error });\n }\n };\n this.on('fetched', fetchedListener);\n this.on('statusChange', statusListener);\n if (!this.#noSleep) {\n this.#noSleep = true;\n }\n if (this.#sleeper) {\n this.log('debug', 'Wake up early from sleep');\n this.#sleeper.wake();\n }\n })\n .finally(() => {\n this.#nextPromises[ptr] = undefined;\n this.#noSleep = false;\n this.#pointers.lastReturned = this.#pointers.returning;\n this.#pointers.returning = null;\n if (resolved) {\n this.log('debug', `next() handled (${ptr})`);\n }\n else {\n this.log('debug', `next() handled (${ptr}) - no resolve`);\n }\n });\n this.#nextPromises[ptr] = result;\n }\n return result;\n }\n this.#pointers.lastReturned = this.#pointers.returning;\n this.#pointers.returning = null;\n this.log('debug', `next() handled (${ptr})`);\n return __parseStatus(this.status);\n }\n\n getTotal() {\n return this.#total;\n }\n\n emit<T extends ProductsFetcherEvent>(eventName: T, args: ProductsFetcherEventPayload<T>): boolean;\n emit(eventName: string | symbol, ...args: any[]): boolean {\n return super.emit(eventName, ...args);\n }\n\n on<T extends ProductsFetcherEvent>(eventName: T, listener: (args: ProductsFetcherEventPayload<T>) => void): this;\n on(eventName: string | symbol, listener: (...args: any[]) => void): this {\n return super.on(eventName, listener);\n }\n\n off<T extends ProductsFetcherEvent>(eventName: T, listener: (args: ProductsFetcherEventPayload<T>) => void): this;\n off(eventName: string | symbol, listener: (...args: any[]) => void): this {\n return super.off(eventName, listener);\n }\n}\n"]}
|
|
@@ -6,6 +6,9 @@ import { type EmbedDownloader, type FileExistsAction } from '../DownloaderOption
|
|
|
6
6
|
import type Logger from '../../utils/logging/Logger.js';
|
|
7
7
|
import { type DownloaderConfig } from '../Downloader.js';
|
|
8
8
|
import type Bottleneck from 'bottleneck';
|
|
9
|
+
import { type Collection, type Post } from '../../entities/Post.js';
|
|
10
|
+
import { type Product } from '../../entities/Product.js';
|
|
11
|
+
import { type Campaign } from '../../entities/Campaign.js';
|
|
9
12
|
export default class DownloadTaskFactory {
|
|
10
13
|
#private;
|
|
11
14
|
static createFromDownloadable(params: {
|
|
@@ -16,6 +19,7 @@ export default class DownloadTaskFactory {
|
|
|
16
19
|
thumbnails: string | null;
|
|
17
20
|
};
|
|
18
21
|
item: Downloadable;
|
|
22
|
+
src: Post | Product | Campaign | Collection;
|
|
19
23
|
isAttachment?: boolean;
|
|
20
24
|
fetcher: Fetcher;
|
|
21
25
|
fileExistsAction: FileExistsAction;
|
|
@@ -55,7 +55,7 @@ const COLLECTION_THUMBNAIL_URL_PRIORITY = [
|
|
|
55
55
|
const NULL_VARIANT = '/*NULL*/';
|
|
56
56
|
class DownloadTaskFactory {
|
|
57
57
|
static async createFromDownloadable(params) {
|
|
58
|
-
const { config, dirs, item, isAttachment = false, fetcher, fileExistsAction, callbacks, limiter, signal, logger } = params;
|
|
58
|
+
const { config, dirs, item, src, isAttachment = false, fetcher, fileExistsAction, callbacks, limiter, signal, logger } = params;
|
|
59
59
|
const embedDownloaders = config.embedDownloaders;
|
|
60
60
|
const destFilenameFormat = config.filenameFormat.media;
|
|
61
61
|
const downloadAllVariants = config.include.allMediaVariants;
|
|
@@ -88,7 +88,7 @@ class DownloadTaskFactory {
|
|
|
88
88
|
const srcURLs = __classPrivateFieldGet(this, _a, "m", _DownloadTaskFactory_getSrcURLs).call(this, item, downloadAllVariants);
|
|
89
89
|
const urlToTasks = [];
|
|
90
90
|
for (const [variant, url] of Object.entries(srcURLs)) {
|
|
91
|
-
const destFilenameResolver = new MediaFilenameResolver(item, url, destFilenameFormat, variant !== NULL_VARIANT ? variant : null, downloadAllVariants);
|
|
91
|
+
const destFilenameResolver = new MediaFilenameResolver(item, url, src, destFilenameFormat, variant !== NULL_VARIANT ? variant : null, downloadAllVariants);
|
|
92
92
|
if (signal?.aborted) {
|
|
93
93
|
return tasks;
|
|
94
94
|
}
|
|
@@ -162,6 +162,7 @@ class DownloadTaskFactory {
|
|
|
162
162
|
config: __config,
|
|
163
163
|
dirs,
|
|
164
164
|
item: videoThumbnailMediaItem,
|
|
165
|
+
src,
|
|
165
166
|
fetcher,
|
|
166
167
|
fileExistsAction,
|
|
167
168
|
callbacks,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DownloadTaskFactory.js","sourceRoot":"","sources":["../../../src/downloaders/task/DownloadTaskFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'path';\nimport { type DummyMediaItem } from '../../entities/MediaItem.js';\nimport type Fetcher from '../../utils/Fetcher.js';\nimport MediaFilenameResolver from '../../utils/MediaFilenameResolver.js';\nimport {type DownloadTaskCallbacks} from './DownloadTask.js';\nimport DownloadTask from './DownloadTask.js';\nimport FetcherDownloadTask from './FetcherDownloadTask.js';\nimport { type Downloadable, isDownloadableWithThumbnail, isEmbed, isYouTubeEmbed } from '../../entities/Downloadable.js';\nimport { type EmbedDownloader, type FileExistsAction } from '../DownloaderOptions.js';\nimport type Logger from '../../utils/logging/Logger.js';\nimport YouTubeDownloadTask from './YouTubeDownloadTask.js';\nimport ExternalDownloaderTask from './ExternalDownloaderTask.js';\nimport { type DownloaderConfig } from '../Downloader.js';\nimport type Bottleneck from 'bottleneck';\nimport ThumbnailFilenameResolver from '../../utils/ThmbnailFilenameResolver.js';\n\nconst DEFAULT_IMAGE_URL_PRIORITY = [\n 'original',\n 'default',\n 'download',\n 'defaultSmall',\n 'thumbnailLarge',\n 'thumbnail',\n 'thumbnailSmall'\n];\n\nconst CAMPAIGN_COVER_PHOTO_URL_PRIORITY = [\n 'xlarge',\n 'large',\n 'medium',\n 'small',\n 'xsmall'\n];\n\nconst POST_COVER_IMAGE_URL_PRIORITY = [\n 'large',\n 'default',\n 'thumb',\n 'thumbSquareLarge',\n 'thumbSquare'\n];\n\nconst POST_THUMBNAIL_URL_PRIORITY = [\n 'large2',\n 'default',\n 'large',\n 'square'\n];\n\nconst COLLECTION_THUMBNAIL_URL_PRIORITY = [\n 'original',\n 'defaultLarge',\n 'default',\n 'url',\n 'defaultSmall',\n 'defaultBlurred',\n 'thumbnailLarge',\n 'thumbnail',\n 'thumbnailSmall'\n];\n\nconst NULL_VARIANT = '/*NULL*/';\n\nexport default class DownloadTaskFactory {\n\n static #getSrcURLs(item: Downloadable, allVariants: boolean) {\n if (item.type === 'image') {\n let urls: Record<string, string | null> = {};\n let priority: string[] = [];\n switch (item.imageType) {\n case 'single':\n return {\n [NULL_VARIANT]: item.imageURL\n };\n case 'default':\n urls = {\n ...item.imageURLs,\n download: item.downloadURL\n };\n priority = DEFAULT_IMAGE_URL_PRIORITY;\n break;\n case 'campaignCoverPhoto':\n urls = item.imageURLs;\n priority = CAMPAIGN_COVER_PHOTO_URL_PRIORITY;\n break;\n case 'postCoverImage':\n urls = item.imageURLs;\n priority = POST_COVER_IMAGE_URL_PRIORITY;\n break;\n case 'postThumbnail':\n urls = item.imageURLs;\n priority = POST_THUMBNAIL_URL_PRIORITY;\n break;\n case 'collectionThumbnail':\n urls = item.imageURLs;\n priority = COLLECTION_THUMBNAIL_URL_PRIORITY;\n }\n if (allVariants) {\n return urls;\n }\n return this.#pickVariant(urls, priority);\n }\n else if (item.type === 'video') {\n let videoVariantName = 'display';\n if (item.size.width && item.size.height) {\n videoVariantName = `${item.size.width}x${item.size.height}`;\n }\n const urls = {\n download: item.downloadURL,\n [videoVariantName]: item.displayURL\n };\n if (allVariants) {\n return urls;\n }\n const priority = [ 'download', videoVariantName ];\n return this.#pickVariant(urls, priority);\n }\n else if (item.type === 'audio') {\n return {\n [NULL_VARIANT]: item.url\n };\n }\n else if (item.type === 'file') {\n return {\n [NULL_VARIANT]: item.downloadURL\n };\n }\n else if (item.type === 'dummy') {\n return item.srcURLs;\n }\n else if (item.type === 'attachment') {\n return {\n [NULL_VARIANT]: item.downloadURL\n };\n }\n\n return {};\n }\n\n static async createFromDownloadable(params: {\n config: DownloaderConfig<any>,\n dirs: {\n campaign: string | null;\n main: string;\n thumbnails: string | null;\n },\n item: Downloadable,\n isAttachment?: boolean,\n fetcher: Fetcher,\n fileExistsAction: FileExistsAction,\n callbacks?: DownloadTaskCallbacks | null,\n limiter: Bottleneck,\n signal?: AbortSignal,\n logger?: Logger | null;\n }) {\n\n const {\n config,\n dirs,\n item,\n isAttachment = false,\n fetcher,\n fileExistsAction,\n callbacks,\n limiter,\n signal,\n logger\n } = params;\n const embedDownloaders = config.embedDownloaders;\n const destFilenameFormat = config.filenameFormat.media;\n const downloadAllVariants = config.include.allMediaVariants;\n const tasks: DownloadTask[] = [];\n\n if (isEmbed(item)) {\n // Check if external downloader configured for embed item\n const embedDownloader = this.findEmbedDownloader(embedDownloaders, item.provider);\n if (embedDownloader) {\n const task = ExternalDownloaderTask.fromEmbedDownloader(config, embedDownloader, item, dirs.main, callbacks || null, logger);\n if (task) {\n tasks.push(task);\n }\n }\n // Use our own implementation if no external downloader configured for YT embeds\n else if (isYouTubeEmbed(item) && item.url) {\n tasks.push(await DownloadTask.create(YouTubeDownloadTask, {\n downloadType: 'main',\n config,\n src: item.url,\n destDir: dirs.main,\n fileExistsAction,\n srcEntity: item,\n fetcher,\n callbacks: callbacks || null,\n logger\n },\n limiter,\n signal));\n }\n }\n else {\n const srcURLs = this.#getSrcURLs(item, downloadAllVariants);\n const urlToTasks: DownloadTask[] = [];\n for (const [ variant, url ] of Object.entries(srcURLs)) {\n const destFilenameResolver = \n new MediaFilenameResolver(item, url, destFilenameFormat,\n variant !== NULL_VARIANT ? variant : null, downloadAllVariants);\n\n if (signal?.aborted) {\n return tasks;\n }\n\n if (url) {\n urlToTasks.push(await DownloadTask.create(FetcherDownloadTask, {\n downloadType: 'variant',\n config,\n fetcher,\n src: url,\n destDir: dirs.main,\n destFilenameResolver,\n fileExistsAction,\n isAttachment,\n srcEntity: item,\n callbacks: callbacks || null,\n logger\n },\n limiter,\n signal));\n }\n }\n if (urlToTasks.length > 0) {\n urlToTasks[0].downloadType = 'main';\n }\n tasks.push(...urlToTasks);\n }\n\n if (config.include.mediaThumbnails && dirs.thumbnails && isDownloadableWithThumbnail(item)) {\n const thumbnailURL = item.thumbnailURL;\n // Thumbnails in `dirs.thumbnails` are for browse function, so\n // no need to follow config's FileExistsAction.\n const fse: FileExistsAction = 'overwrite';\n // Same with FilenameResolver\n const fnr = new ThumbnailFilenameResolver(item);\n tasks.push(await DownloadTask.create(FetcherDownloadTask, {\n downloadType: 'thumbnail',\n config,\n fetcher,\n src: thumbnailURL,\n destDir: dirs.thumbnails,\n destFilenameResolver: fnr,\n fileExistsAction: fse,\n srcEntity: item,\n callbacks: callbacks || null,\n logger\n },\n limiter,\n signal));\n }\n \n // Create a DownloadTask backed by a DummyMediaItem for video thumbnail.\n // Note this is saved in the same dir as the video itself, unlike thumbnails for browse function,\n // so need to follow config's FileExistsAction and filename format.\n if (item.type === 'video' && item.thumbnailURL) {\n let filename: string | null = null;\n if (item.filename) {\n // Video file extension not applicable to thumbnail, so strip it.\n filename = path.parse(item.filename).name;\n }\n const videoThumbnailMediaItem: DummyMediaItem = {\n type: 'dummy',\n id: item.id,\n filename,\n mimeType: null,\n srcURLs: {\n thumbnail: item.thumbnailURL\n }\n };\n const __config = {\n ...config,\n include: {\n ...config.include,\n allMediaVariants: true // Ensure variant name ('thumbnail') appears in dest filename\n }\n };\n tasks.push(\n ...await this.createFromDownloadable({\n config: __config,\n dirs,\n item: videoThumbnailMediaItem,\n fetcher,\n fileExistsAction,\n callbacks,\n limiter,\n signal,\n logger\n })\n );\n }\n\n if (tasks.length === 0) {\n throw Error('No src URL found');\n }\n\n return tasks;\n }\n\n static #pickVariant(urls: Record<string, any>, priority: string[]) {\n for (const variant of priority) {\n if (urls[variant]) {\n return {\n [variant]: urls[variant]\n };\n }\n }\n return {};\n }\n\n static findEmbedDownloader(edl: EmbedDownloader[], provider?: string | null) {\n return edl.find((dl) => dl.provider.toLowerCase() === provider?.trim().toLowerCase());\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"DownloadTaskFactory.js","sourceRoot":"","sources":["../../../src/downloaders/task/DownloadTaskFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'path';\nimport { type DummyMediaItem } from '../../entities/MediaItem.js';\nimport type Fetcher from '../../utils/Fetcher.js';\nimport MediaFilenameResolver from '../../utils/MediaFilenameResolver.js';\nimport {type DownloadTaskCallbacks} from './DownloadTask.js';\nimport DownloadTask from './DownloadTask.js';\nimport FetcherDownloadTask from './FetcherDownloadTask.js';\nimport { type Downloadable, isDownloadableWithThumbnail, isEmbed, isYouTubeEmbed } from '../../entities/Downloadable.js';\nimport { type EmbedDownloader, type FileExistsAction } from '../DownloaderOptions.js';\nimport type Logger from '../../utils/logging/Logger.js';\nimport YouTubeDownloadTask from './YouTubeDownloadTask.js';\nimport ExternalDownloaderTask from './ExternalDownloaderTask.js';\nimport { type DownloaderConfig } from '../Downloader.js';\nimport type Bottleneck from 'bottleneck';\nimport ThumbnailFilenameResolver from '../../utils/ThmbnailFilenameResolver.js';\nimport { type Collection, type Post } from '../../entities/Post.js';\nimport { type Product } from '../../entities/Product.js';\nimport { type Campaign } from '../../entities/Campaign.js';\n\nconst DEFAULT_IMAGE_URL_PRIORITY = [\n 'original',\n 'default',\n 'download',\n 'defaultSmall',\n 'thumbnailLarge',\n 'thumbnail',\n 'thumbnailSmall'\n];\n\nconst CAMPAIGN_COVER_PHOTO_URL_PRIORITY = [\n 'xlarge',\n 'large',\n 'medium',\n 'small',\n 'xsmall'\n];\n\nconst POST_COVER_IMAGE_URL_PRIORITY = [\n 'large',\n 'default',\n 'thumb',\n 'thumbSquareLarge',\n 'thumbSquare'\n];\n\nconst POST_THUMBNAIL_URL_PRIORITY = [\n 'large2',\n 'default',\n 'large',\n 'square'\n];\n\nconst COLLECTION_THUMBNAIL_URL_PRIORITY = [\n 'original',\n 'defaultLarge',\n 'default',\n 'url',\n 'defaultSmall',\n 'defaultBlurred',\n 'thumbnailLarge',\n 'thumbnail',\n 'thumbnailSmall'\n];\n\nconst NULL_VARIANT = '/*NULL*/';\n\nexport default class DownloadTaskFactory {\n\n static #getSrcURLs(item: Downloadable, allVariants: boolean) {\n if (item.type === 'image') {\n let urls: Record<string, string | null> = {};\n let priority: string[] = [];\n switch (item.imageType) {\n case 'single':\n return {\n [NULL_VARIANT]: item.imageURL\n };\n case 'default':\n urls = {\n ...item.imageURLs,\n download: item.downloadURL\n };\n priority = DEFAULT_IMAGE_URL_PRIORITY;\n break;\n case 'campaignCoverPhoto':\n urls = item.imageURLs;\n priority = CAMPAIGN_COVER_PHOTO_URL_PRIORITY;\n break;\n case 'postCoverImage':\n urls = item.imageURLs;\n priority = POST_COVER_IMAGE_URL_PRIORITY;\n break;\n case 'postThumbnail':\n urls = item.imageURLs;\n priority = POST_THUMBNAIL_URL_PRIORITY;\n break;\n case 'collectionThumbnail':\n urls = item.imageURLs;\n priority = COLLECTION_THUMBNAIL_URL_PRIORITY;\n }\n if (allVariants) {\n return urls;\n }\n return this.#pickVariant(urls, priority);\n }\n else if (item.type === 'video') {\n let videoVariantName = 'display';\n if (item.size.width && item.size.height) {\n videoVariantName = `${item.size.width}x${item.size.height}`;\n }\n const urls = {\n download: item.downloadURL,\n [videoVariantName]: item.displayURL\n };\n if (allVariants) {\n return urls;\n }\n const priority = [ 'download', videoVariantName ];\n return this.#pickVariant(urls, priority);\n }\n else if (item.type === 'audio') {\n return {\n [NULL_VARIANT]: item.url\n };\n }\n else if (item.type === 'file') {\n return {\n [NULL_VARIANT]: item.downloadURL\n };\n }\n else if (item.type === 'dummy') {\n return item.srcURLs;\n }\n else if (item.type === 'attachment') {\n return {\n [NULL_VARIANT]: item.downloadURL\n };\n }\n\n return {};\n }\n\n static async createFromDownloadable(params: {\n config: DownloaderConfig<any>,\n dirs: {\n campaign: string | null;\n main: string;\n thumbnails: string | null;\n },\n item: Downloadable,\n src: Post | Product | Campaign | Collection,\n isAttachment?: boolean,\n fetcher: Fetcher,\n fileExistsAction: FileExistsAction,\n callbacks?: DownloadTaskCallbacks | null,\n limiter: Bottleneck,\n signal?: AbortSignal,\n logger?: Logger | null;\n }) {\n\n const {\n config,\n dirs,\n item,\n src,\n isAttachment = false,\n fetcher,\n fileExistsAction,\n callbacks,\n limiter,\n signal,\n logger\n } = params;\n const embedDownloaders = config.embedDownloaders;\n const destFilenameFormat = config.filenameFormat.media;\n const downloadAllVariants = config.include.allMediaVariants;\n const tasks: DownloadTask[] = [];\n\n if (isEmbed(item)) {\n // Check if external downloader configured for embed item\n const embedDownloader = this.findEmbedDownloader(embedDownloaders, item.provider);\n if (embedDownloader) {\n const task = ExternalDownloaderTask.fromEmbedDownloader(config, embedDownloader, item, dirs.main, callbacks || null, logger);\n if (task) {\n tasks.push(task);\n }\n }\n // Use our own implementation if no external downloader configured for YT embeds\n else if (isYouTubeEmbed(item) && item.url) {\n tasks.push(await DownloadTask.create(YouTubeDownloadTask, {\n downloadType: 'main',\n config,\n src: item.url,\n destDir: dirs.main,\n fileExistsAction,\n srcEntity: item,\n fetcher,\n callbacks: callbacks || null,\n logger\n },\n limiter,\n signal));\n }\n }\n else {\n const srcURLs = this.#getSrcURLs(item, downloadAllVariants);\n const urlToTasks: DownloadTask[] = [];\n for (const [ variant, url ] of Object.entries(srcURLs)) {\n const destFilenameResolver = \n new MediaFilenameResolver(item, url, src, destFilenameFormat,\n variant !== NULL_VARIANT ? variant : null, downloadAllVariants);\n\n if (signal?.aborted) {\n return tasks;\n }\n\n if (url) {\n urlToTasks.push(await DownloadTask.create(FetcherDownloadTask, {\n downloadType: 'variant',\n config,\n fetcher,\n src: url,\n destDir: dirs.main,\n destFilenameResolver,\n fileExistsAction,\n isAttachment,\n srcEntity: item,\n callbacks: callbacks || null,\n logger\n },\n limiter,\n signal));\n }\n }\n if (urlToTasks.length > 0) {\n urlToTasks[0].downloadType = 'main';\n }\n tasks.push(...urlToTasks);\n }\n\n if (config.include.mediaThumbnails && dirs.thumbnails && isDownloadableWithThumbnail(item)) {\n const thumbnailURL = item.thumbnailURL;\n // Thumbnails in `dirs.thumbnails` are for browse function, so\n // no need to follow config's FileExistsAction.\n const fse: FileExistsAction = 'overwrite';\n // Same with FilenameResolver\n const fnr = new ThumbnailFilenameResolver(item);\n tasks.push(await DownloadTask.create(FetcherDownloadTask, {\n downloadType: 'thumbnail',\n config,\n fetcher,\n src: thumbnailURL,\n destDir: dirs.thumbnails,\n destFilenameResolver: fnr,\n fileExistsAction: fse,\n srcEntity: item,\n callbacks: callbacks || null,\n logger\n },\n limiter,\n signal));\n }\n \n // Create a DownloadTask backed by a DummyMediaItem for video thumbnail.\n // Note this is saved in the same dir as the video itself, unlike thumbnails for browse function,\n // so need to follow config's FileExistsAction and filename format.\n if (item.type === 'video' && item.thumbnailURL) {\n let filename: string | null = null;\n if (item.filename) {\n // Video file extension not applicable to thumbnail, so strip it.\n filename = path.parse(item.filename).name;\n }\n const videoThumbnailMediaItem: DummyMediaItem = {\n type: 'dummy',\n id: item.id,\n filename,\n mimeType: null,\n srcURLs: {\n thumbnail: item.thumbnailURL\n }\n };\n const __config = {\n ...config,\n include: {\n ...config.include,\n allMediaVariants: true // Ensure variant name ('thumbnail') appears in dest filename\n }\n };\n tasks.push(\n ...await this.createFromDownloadable({\n config: __config,\n dirs,\n item: videoThumbnailMediaItem,\n src,\n fetcher,\n fileExistsAction,\n callbacks,\n limiter,\n signal,\n logger\n })\n );\n }\n\n if (tasks.length === 0) {\n throw Error('No src URL found');\n }\n\n return tasks;\n }\n\n static #pickVariant(urls: Record<string, any>, priority: string[]) {\n for (const variant of priority) {\n if (urls[variant]) {\n return {\n [variant]: urls[variant]\n };\n }\n }\n return {};\n }\n\n static findEmbedDownloader(edl: EmbedDownloader[], provider?: string | null) {\n return edl.find((dl) => dl.provider.toLowerCase() === provider?.trim().toLowerCase());\n }\n}\n"]}
|
|
@@ -225,8 +225,11 @@ class YouTubeDownloadTask extends FFmpegDownloadTaskBase {
|
|
|
225
225
|
this.log('debug', `Choose best-quality stream for YouTube video #${video.basic_info.id}`);
|
|
226
226
|
const stream = await __classPrivateFieldGet(this, _YouTubeDownloadTask_instances, "m", _YouTubeDownloadTask_pickStream).call(this, video);
|
|
227
227
|
if (!stream) {
|
|
228
|
-
const errMsg = `Stream not found for YouTube video #${video.basic_info.id}`;
|
|
228
|
+
const errMsg = `Stream not found for YouTube video #${video.basic_info.id || videoId}`;
|
|
229
229
|
this.log('error', errMsg);
|
|
230
|
+
if (video.playability_status) {
|
|
231
|
+
this.log('error', `The playability status of the video is: ${video.playability_status.status} - ${video.playability_status.reason}`);
|
|
232
|
+
}
|
|
230
233
|
throw Error(errMsg);
|
|
231
234
|
}
|
|
232
235
|
// Test streams - YT sometimes imposes a delay before the streams become accessible
|
|
@@ -318,7 +321,9 @@ _a = YouTubeDownloadTask, _YouTubeDownloadTask_destDir = new WeakMap(), _YouTube
|
|
|
318
321
|
return (await InnertubeLoader.getInstance(this.config)).getVideoInfo(videoId);
|
|
319
322
|
}, _YouTubeDownloadTask_resolveURL = async function _YouTubeDownloadTask_resolveURL(url) {
|
|
320
323
|
if (!__classPrivateFieldGet(_a, _a, "f", _YouTubeDownloadTask_innertubeForResolveURL)) {
|
|
321
|
-
__classPrivateFieldSet(_a, _a, await InnertubeLib.Innertube.create(
|
|
324
|
+
__classPrivateFieldSet(_a, _a, await InnertubeLib.Innertube.create({
|
|
325
|
+
player_id: '9f4cc5e4'
|
|
326
|
+
}), "f", _YouTubeDownloadTask_innertubeForResolveURL);
|
|
322
327
|
}
|
|
323
328
|
const innertube = __classPrivateFieldGet(_a, _a, "f", _YouTubeDownloadTask_innertubeForResolveURL);
|
|
324
329
|
const endpoint = await innertube.resolveURL(url);
|