{"version":3,"sources":["node_modules/file-saver/dist/FileSaver.min.js","src/app/_providers/saver.provider.ts","src/app/shared/_models/download.ts","src/app/shared/_services/download.service.ts"],"sourcesContent":["(function (a, b) {\n if (\"function\" == typeof define && define.amd) define([], b);else if (\"undefined\" != typeof exports) b();else {\n b(), a.FileSaver = {\n exports: {}\n }.exports;\n }\n})(this, function () {\n \"use strict\";\n\n function b(a, b) {\n return \"undefined\" == typeof b ? b = {\n autoBom: !1\n } : \"object\" != typeof b && (console.warn(\"Deprecated: Expected third argument to be a object\"), b = {\n autoBom: !b\n }), b.autoBom && /^\\s*(?:text\\/\\S*|application\\/xml|\\S*\\/\\S*\\+xml)\\s*;.*charset\\s*=\\s*utf-8/i.test(a.type) ? new Blob([\"\\uFEFF\", a], {\n type: a.type\n }) : a;\n }\n function c(a, b, c) {\n var d = new XMLHttpRequest();\n d.open(\"GET\", a), d.responseType = \"blob\", d.onload = function () {\n g(d.response, b, c);\n }, d.onerror = function () {\n console.error(\"could not download file\");\n }, d.send();\n }\n function d(a) {\n var b = new XMLHttpRequest();\n b.open(\"HEAD\", a, !1);\n try {\n b.send();\n } catch (a) {}\n return 200 <= b.status && 299 >= b.status;\n }\n function e(a) {\n try {\n a.dispatchEvent(new MouseEvent(\"click\"));\n } catch (c) {\n var b = document.createEvent(\"MouseEvents\");\n b.initMouseEvent(\"click\", !0, !0, window, 0, 0, 0, 80, 20, !1, !1, !1, !1, 0, null), a.dispatchEvent(b);\n }\n }\n var f = \"object\" == typeof window && window.window === window ? window : \"object\" == typeof self && self.self === self ? self : \"object\" == typeof global && global.global === global ? global : void 0,\n a = f.navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent),\n g = f.saveAs || (\"object\" != typeof window || window !== f ? function () {} : \"download\" in HTMLAnchorElement.prototype && !a ? function (b, g, h) {\n var i = f.URL || f.webkitURL,\n j = document.createElement(\"a\");\n g = g || b.name || \"download\", j.download = g, j.rel = \"noopener\", \"string\" == typeof b ? (j.href = b, j.origin === location.origin ? e(j) : d(j.href) ? c(b, g, h) : e(j, j.target = \"_blank\")) : (j.href = i.createObjectURL(b), setTimeout(function () {\n i.revokeObjectURL(j.href);\n }, 4E4), setTimeout(function () {\n e(j);\n }, 0));\n } : \"msSaveOrOpenBlob\" in navigator ? function (f, g, h) {\n if (g = g || f.name || \"download\", \"string\" != typeof f) navigator.msSaveOrOpenBlob(b(f, h), g);else if (d(f)) c(f, g, h);else {\n var i = document.createElement(\"a\");\n i.href = f, i.target = \"_blank\", setTimeout(function () {\n e(i);\n });\n }\n } : function (b, d, e, g) {\n if (g = g || open(\"\", \"_blank\"), g && (g.document.title = g.document.body.innerText = \"downloading...\"), \"string\" == typeof b) return c(b, d, e);\n var h = \"application/octet-stream\" === b.type,\n i = /constructor/i.test(f.HTMLElement) || f.safari,\n j = /CriOS\\/[\\d]+/.test(navigator.userAgent);\n if ((j || h && i || a) && \"undefined\" != typeof FileReader) {\n var k = new FileReader();\n k.onloadend = function () {\n var a = k.result;\n a = j ? a : a.replace(/^data:[^;]*;/, \"data:attachment/file;\"), g ? g.location.href = a : location = a, g = null;\n }, k.readAsDataURL(b);\n } else {\n var l = f.URL || f.webkitURL,\n m = l.createObjectURL(b);\n g ? g.location = m : location.href = m, g = null, setTimeout(function () {\n l.revokeObjectURL(m);\n }, 4E4);\n }\n });\n f.saveAs = g.saveAs = g, \"undefined\" != typeof module && (module.exports = g);\n});\n\n","import {InjectionToken} from '@angular/core'\nimport { saveAs } from 'file-saver';\n\nexport type Saver = (blob: Blob, filename?: string) => void\n\nexport const SAVER = new InjectionToken('saver')\n\nexport function getSaver(): Saver {\n return saveAs;\n}\n","import { HttpEvent, HttpEventType, HttpHeaders, HttpProgressEvent, HttpResponse } from \"@angular/common/http\";\n import { Observable } from \"rxjs\";\n import { scan } from \"rxjs/operators\";\n \n function isHttpResponse(event: HttpEvent): event is HttpResponse {\n return event.type === HttpEventType.Response;\n }\n \n function isHttpProgressEvent(\n event: HttpEvent\n ): event is HttpProgressEvent {\n return (\n event.type === HttpEventType.DownloadProgress ||\n event.type === HttpEventType.UploadProgress\n );\n }\n\n/**\n * Encapsulates an inprogress download of a Blob with progress reporting activated\n */ \nexport interface Download {\n content: Blob | null;\n progress: number;\n state: \"PENDING\" | \"IN_PROGRESS\" | \"DONE\";\n filename?: string;\n loaded?: number;\n total?: number\n}\n \nexport function download(saver?: (b: Blob, filename: string) => void): (source: Observable>) => Observable {\n return (source: Observable>) =>\n source.pipe(\n scan((previous: Download, event: HttpEvent): Download => {\n if (isHttpProgressEvent(event)) {\n return {\n progress: event.total\n ? Math.round((100 * event.loaded) / event.total)\n : previous.progress,\n state: 'IN_PROGRESS',\n content: null,\n loaded: event.loaded,\n total: event.total\n }\n }\n if (isHttpResponse(event)) {\n if (saver && event.body) {\n saver(event.body, getFilename(event.headers, ''))\n }\n return {\n progress: 100,\n state: 'DONE',\n content: event.body,\n filename: getFilename(event.headers, ''),\n }\n }\n return previous;\n },\n {state: 'PENDING', progress: 0, content: null}\n )\n )\n }\n\n\nfunction getFilename(headers: HttpHeaders, defaultName: string) {\n const tokens = (headers.get('content-disposition') || '').split(';');\n let filename = tokens[1].replace('filename=', '').replace(/\"/ig, '').trim(); \n if (filename.startsWith('download_') || filename.startsWith('kavita_download_')) {\n const ext = filename.substring(filename.lastIndexOf('.'), filename.length);\n if (defaultName !== '') {\n return defaultName + ext;\n }\n return filename.replace('kavita_', '').replace('download_', '');\n //return defaultName + ext;\n }\n return filename;\n }","import { HttpClient } from '@angular/common/http';\nimport {DestroyRef, inject, Inject, Injectable} from '@angular/core';\nimport { Series } from 'src/app/_models/series';\nimport { environment } from 'src/environments/environment';\nimport { ConfirmService } from '../confirm.service';\nimport { Chapter } from 'src/app/_models/chapter';\nimport { Volume } from 'src/app/_models/volume';\nimport {\n asyncScheduler,\n BehaviorSubject,\n Observable,\n tap,\n finalize,\n of,\n filter,\n} from 'rxjs';\nimport { download, Download } from '../_models/download';\nimport { PageBookmark } from 'src/app/_models/readers/page-bookmark';\nimport {switchMap, take, takeWhile, throttleTime} from 'rxjs/operators';\nimport { AccountService } from 'src/app/_services/account.service';\nimport { BytesPipe } from 'src/app/_pipes/bytes.pipe';\nimport {translate} from \"@jsverse/transloco\";\nimport {takeUntilDestroyed} from \"@angular/core/rxjs-interop\";\nimport {SAVER, Saver} from \"../../_providers/saver.provider\";\nimport {UtilityService} from \"./utility.service\";\nimport {UserCollection} from \"../../_models/collection-tag\";\nimport {RecentlyAddedItem} from \"../../_models/recently-added-item\";\nimport {NextExpectedChapter} from \"../../_models/series-detail/next-expected-chapter\";\nimport {BrowsePerson} from \"../../_models/person/browse-person\";\n\nexport const DEBOUNCE_TIME = 100;\n\nconst bytesPipe = new BytesPipe();\n\nexport interface DownloadEvent {\n /**\n * Type of entity being downloaded\n */\n entityType: DownloadEntityType;\n /**\n * What to show user. For example, for Series, we might show series name.\n */\n subTitle: string;\n /**\n * Progress of the download itself\n */\n progress: number;\n /**\n * Entity id. For entities without id like logs or bookmarks, uses 0 instead\n */\n id: number;\n}\n\n/**\n * Valid entity types for downloading\n */\nexport type DownloadEntityType = 'volume' | 'chapter' | 'series' | 'bookmark' | 'logs';\n/**\n * Valid entities for downloading. Undefined exclusively for logs.\n */\nexport type DownloadEntity = Series | Volume | Chapter | PageBookmark[] | undefined;\n\nexport type QueueableDownloadType = Chapter | Volume;\n\n@Injectable({\n providedIn: 'root'\n})\nexport class DownloadService {\n\n private baseUrl = environment.apiUrl;\n /**\n * Size in bytes in which to inform the user for confirmation before download starts. Defaults to 100 MB.\n */\n public SIZE_WARNING = 104_857_600;\n /**\n * Sie in bytes in which to inform the user that anything above may fail on iOS due to device limits. (200MB)\n */\n private IOS_SIZE_WARNING = 209_715_200;\n\n private downloadsSource: BehaviorSubject = new BehaviorSubject([]);\n /**\n * Active Downloads\n */\n public activeDownloads$ = this.downloadsSource.asObservable();\n\n private downloadQueue: BehaviorSubject = new BehaviorSubject([]);\n /**\n * Queued Downloads\n */\n public queuedDownloads$ = this.downloadQueue.asObservable();\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly confirmService = inject(ConfirmService);\n private readonly accountService = inject(AccountService);\n private readonly httpClient = inject(HttpClient);\n private readonly utilityService = inject(UtilityService);\n\n constructor(@Inject(SAVER) private save: Saver) {\n this.downloadQueue.subscribe((queue) => {\n if (queue.length > 0) {\n const entity = queue.shift();\n console.log('Download Queue shifting entity: ', entity);\n if (entity === undefined) return;\n this.processDownload(entity);\n }\n });\n }\n\n\n /**\n * Returns the entity subtitle (for the event widget) for a given entity\n * @param downloadEntityType\n * @param downloadEntity\n * @returns\n */\n downloadSubtitle(downloadEntityType: DownloadEntityType | undefined, downloadEntity: DownloadEntity | undefined) {\n switch (downloadEntityType) {\n case 'series':\n return (downloadEntity as Series).name;\n case 'volume':\n return (downloadEntity as Volume).minNumber + '';\n case 'chapter':\n return (downloadEntity as Chapter).minNumber + '';\n case 'bookmark':\n return '';\n case 'logs':\n return '';\n }\n return '';\n }\n\n /**\n * Downloads the entity to the user's system. This handles everything around downloads. This will prompt the user based on size checks and UserPreferences.PromptForDownload.\n * This will perform the download at a global level, if you need a handle to the download in question, use downloadService.activeDownloads$ and perform a filter on it.\n * @param entityType\n * @param entity\n * @param callback Optional callback. Returns the download or undefined (if the download is complete).\n */\n download(entityType: DownloadEntityType, entity: DownloadEntity, callback?: (d: Download | undefined) => void) {\n let sizeCheckCall: Observable;\n let downloadCall: Observable;\n switch (entityType) {\n case 'series':\n sizeCheckCall = this.downloadSeriesSize((entity as Series).id);\n downloadCall = this.downloadSeries(entity as Series);\n break;\n case 'volume':\n sizeCheckCall = this.downloadVolumeSize((entity as Volume).id);\n downloadCall = this.downloadVolume(entity as Volume);\n //this.enqueueDownload(entity as Volume);\n break;\n case 'chapter':\n sizeCheckCall = this.downloadChapterSize((entity as Chapter).id);\n downloadCall = this.downloadChapter(entity as Chapter);\n //this.enqueueDownload(entity as Chapter);\n break;\n case 'bookmark':\n sizeCheckCall = of(0);\n downloadCall = this.downloadBookmarks(entity as PageBookmark[]);\n break;\n case 'logs':\n sizeCheckCall = of(0);\n downloadCall = this.downloadLogs();\n break;\n default:\n return;\n }\n\n\n this.accountService.currentUser$.pipe(take(1), switchMap(user => {\n if (user && user.preferences.promptForDownloadSize) {\n return sizeCheckCall;\n }\n return of(0);\n }), switchMap(async (size) => {\n return await this.confirmSize(size, entityType);\n })\n ).pipe(filter(wantsToDownload => {\n return wantsToDownload;\n }),\n filter(_ => downloadCall !== undefined),\n switchMap(() => {\n return (downloadCall || of(undefined)).pipe(\n tap((d) => {\n if (callback) callback(d);\n }),\n takeWhile((val: Download) => {\n return val.state != 'DONE';\n }),\n finalize(() => {\n if (callback) callback(undefined);\n }))\n }), takeUntilDestroyed(this.destroyRef)\n ).subscribe(() => {});\n }\n\n private downloadSeriesSize(seriesId: number) {\n return this.httpClient.get(this.baseUrl + 'download/series-size?seriesId=' + seriesId);\n }\n\n private downloadVolumeSize(volumeId: number) {\n return this.httpClient.get(this.baseUrl + 'download/volume-size?volumeId=' + volumeId);\n }\n\n private downloadChapterSize(chapterId: number) {\n return this.httpClient.get(this.baseUrl + 'download/chapter-size?chapterId=' + chapterId);\n }\n\n private downloadLogs() {\n const downloadType = 'logs';\n const subtitle = this.downloadSubtitle(downloadType, undefined);\n return this.httpClient.get(this.baseUrl + 'server/logs',\n {observe: 'events', responseType: 'blob', reportProgress: true}\n ).pipe(\n throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),\n download((blob, filename) => {\n this.save(blob, decodeURIComponent(filename));\n }),\n tap((d) => this.updateDownloadState(d, downloadType, subtitle, 0)),\n finalize(() => this.finalizeDownloadState(downloadType, subtitle))\n );\n }\n\n\n private getIdKey(entity: Chapter | Volume) {\n if (this.utilityService.isVolume(entity)) return 'volumeId';\n if (this.utilityService.isChapter(entity)) return 'chapterId';\n if (this.utilityService.isSeries(entity)) return 'seriesId';\n return 'id';\n }\n\n private getDownloadEntityType(entity: Chapter | Volume): DownloadEntityType {\n if (this.utilityService.isVolume(entity)) return 'volume';\n if (this.utilityService.isChapter(entity)) return 'chapter';\n if (this.utilityService.isSeries(entity)) return 'series';\n return 'logs'; // This is a hack but it will never occur\n }\n\n private downloadEntity(entity: Chapter | Volume): Observable {\n const downloadEntityType = this.getDownloadEntityType(entity);\n const subtitle = this.downloadSubtitle(downloadEntityType, entity);\n const idKey = this.getIdKey(entity);\n const url = `${this.baseUrl}download/${downloadEntityType}?${idKey}=${entity.id}`;\n\n return this.httpClient.get(url, { observe: 'events', responseType: 'blob', reportProgress: true }).pipe(\n throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),\n download((blob, filename) => {\n this.save(blob, decodeURIComponent(filename));\n }),\n tap((d) => this.updateDownloadState(d, downloadEntityType, subtitle, entity.id)),\n finalize(() => this.finalizeDownloadState(downloadEntityType, subtitle))\n );\n }\n\n private downloadSeries(series: Series) {\n\n // TODO: Call backend for all the volumes and loose leaf chapters then enqueque them all\n\n const downloadType = 'series';\n const subtitle = this.downloadSubtitle(downloadType, series);\n return this.httpClient.get(this.baseUrl + 'download/series?seriesId=' + series.id,\n {observe: 'events', responseType: 'blob', reportProgress: true}\n ).pipe(\n throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),\n download((blob, filename) => {\n this.save(blob, decodeURIComponent(filename));\n }),\n tap((d) => this.updateDownloadState(d, downloadType, subtitle, series.id)),\n finalize(() => this.finalizeDownloadState(downloadType, subtitle))\n );\n }\n\n private finalizeDownloadState(entityType: DownloadEntityType, entitySubtitle: string) {\n let values = this.downloadsSource.getValue();\n values = values.filter(v => !(v.entityType === entityType && v.subTitle === entitySubtitle));\n this.downloadsSource.next(values);\n }\n\n private updateDownloadState(d: Download, entityType: DownloadEntityType, entitySubtitle: string, id: number) {\n let values = this.downloadsSource.getValue();\n if (d.state === 'PENDING') {\n const index = values.findIndex(v => v.entityType === entityType && v.subTitle === entitySubtitle);\n if (index >= 0) return; // Don't let us duplicate add\n values.push({entityType: entityType, subTitle: entitySubtitle, progress: 0, id});\n } else if (d.state === 'IN_PROGRESS') {\n const index = values.findIndex(v => v.entityType === entityType && v.subTitle === entitySubtitle);\n if (index >= 0) {\n values[index].progress = d.progress;\n }\n } else if (d.state === 'DONE') {\n values = values.filter(v => !(v.entityType === entityType && v.subTitle === entitySubtitle));\n }\n this.downloadsSource.next(values);\n\n }\n\n private downloadChapter(chapter: Chapter) {\n return this.downloadEntity(chapter);\n }\n\n private downloadVolume(volume: Volume) {\n return this.downloadEntity(volume);\n }\n\n private async confirmSize(size: number, entityType: DownloadEntityType) {\n const showIosWarning = size > this.IOS_SIZE_WARNING && /iPad|iPhone|iPod/.test(navigator.userAgent);\n return (size < this.SIZE_WARNING ||\n await this.confirmService.confirm(translate('toasts.confirm-download-size',\n {entityType: translate('entity-type.' + entityType), size: bytesPipe.transform(size)})\n + (!showIosWarning ? '' : '

' + translate('toasts.confirm-download-size-ios'))));\n }\n\n private downloadBookmarks(bookmarks: PageBookmark[]) {\n const downloadType = 'bookmark';\n const subtitle = this.downloadSubtitle(downloadType, bookmarks);\n\n return this.httpClient.post(this.baseUrl + 'download/bookmarks', {bookmarks},\n {observe: 'events', responseType: 'blob', reportProgress: true}\n ).pipe(\n throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),\n download((blob, filename) => {\n this.save(blob, decodeURIComponent(filename));\n }),\n tap((d) => this.updateDownloadState(d, downloadType, subtitle, 0)),\n finalize(() => this.finalizeDownloadState(downloadType, subtitle))\n );\n }\n\n\n\n private processDownload(entity: QueueableDownloadType): void {\n const downloadObservable = this.downloadEntity(entity);\n console.log('Process Download called for entity: ', entity);\n\n // When we consume one, we need to take it off the queue\n\n downloadObservable.subscribe((downloadEvent) => {\n // Download completed, process the next item in the queue\n if (downloadEvent.state === 'DONE') {\n this.processNextDownload();\n }\n });\n }\n\n private processNextDownload(): void {\n const currentQueue = this.downloadQueue.value;\n if (currentQueue.length > 0) {\n const nextEntity = currentQueue[0];\n this.processDownload(nextEntity);\n }\n }\n\n private enqueueDownload(entity: QueueableDownloadType): void {\n const currentQueue = this.downloadQueue.value;\n const newQueue = [...currentQueue, entity];\n this.downloadQueue.next(newQueue);\n\n // If the queue was empty, start processing the download\n if (currentQueue.length === 0) {\n this.processNextDownload();\n }\n }\n\n mapToEntityType(events: DownloadEvent[], entity: Series | Volume | Chapter | UserCollection | PageBookmark | RecentlyAddedItem | NextExpectedChapter | BrowsePerson) {\n if(this.utilityService.isSeries(entity)) {\n return events.find(e => e.entityType === 'series' && e.id == entity.id\n && e.subTitle === this.downloadSubtitle('series', (entity as Series))) || null;\n }\n\n if(this.utilityService.isVolume(entity)) {\n return events.find(e => e.entityType === 'volume' && e.id == entity.id\n && e.subTitle === this.downloadSubtitle('volume', (entity as Volume))) || null;\n }\n\n if(this.utilityService.isChapter(entity)) {\n return events.find(e => e.entityType === 'chapter' && e.id == entity.id\n && e.subTitle === this.downloadSubtitle('chapter', (entity as Chapter))) || null;\n }\n\n // Is PageBookmark[]\n if(entity.hasOwnProperty('length')) {\n return events.find(e => e.entityType === 'bookmark'\n && e.subTitle === this.downloadSubtitle('bookmark', [(entity as PageBookmark)])) || null;\n }\n\n return null;\n }\n}\n"],"mappings":"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","names":["require_FileSaver_min","__commonJSMin","exports","module","a","b","c","d","g","f","h","i","j","e","k","l","m","import_file_saver","SAVER","InjectionToken","getSaver","saveAs","isHttpResponse","event","type","HttpEventType","Response","isHttpProgressEvent","DownloadProgress","UploadProgress","download","saver","source","pipe","scan","previous","progress","total","Math","round","loaded","state","content","body","getFilename","headers","filename","defaultName","get","split","replace","trim","startsWith","ext","substring","lastIndexOf","length","DEBOUNCE_TIME","bytesPipe","BytesPipe","DownloadService","constructor","save","baseUrl","environment","apiUrl","SIZE_WARNING","IOS_SIZE_WARNING","downloadsSource","BehaviorSubject","activeDownloads$","asObservable","downloadQueue","queuedDownloads$","destroyRef","inject","DestroyRef","confirmService","ConfirmService","accountService","AccountService","httpClient","HttpClient","utilityService","UtilityService","subscribe","queue","length","entity","shift","console","log","undefined","processDownload","downloadSubtitle","downloadEntityType","downloadEntity","name","minNumber","download","entityType","callback","sizeCheckCall","downloadCall","downloadSeriesSize","id","downloadSeries","downloadVolumeSize","downloadVolume","downloadChapterSize","downloadChapter","of","downloadBookmarks","downloadLogs","currentUser$","pipe","take","switchMap","user","preferences","promptForDownloadSize","size","__async","confirmSize","filter","wantsToDownload","_","tap","d","takeWhile","val","state","finalize","takeUntilDestroyed","seriesId","get","volumeId","chapterId","downloadType","subtitle","observe","responseType","reportProgress","throttleTime","asyncScheduler","leading","trailing","blob","filename","decodeURIComponent","updateDownloadState","finalizeDownloadState","getIdKey","isVolume","isChapter","isSeries","getDownloadEntityType","idKey","url","series","entitySubtitle","values","getValue","v","subTitle","next","findIndex","push","progress","index","chapter","volume","showIosWarning","test","navigator","userAgent","confirm","translate","transform","bookmarks","post","downloadObservable","downloadEvent","processNextDownload","currentQueue","value","nextEntity","enqueueDownload","newQueue","mapToEntityType","events","find","e","hasOwnProperty","ɵɵinject","SAVER","factory","ɵfac","providedIn"],"x_google_ignoreList":[0]}