Files
VidBee/src/main/lib/download-queue.ts

146 lines
3.7 KiB
TypeScript

import { EventEmitter } from 'node:events'
import type { DownloadItem, DownloadOptions } from '../../shared/types'
interface QueueItem {
id: string
options: DownloadOptions
item: DownloadItem
}
export class DownloadQueue extends EventEmitter {
private queue: QueueItem[] = []
private activeDownloads: Map<string, QueueItem> = new Map()
private completedDownloads: Map<string, QueueItem> = new Map()
private maxConcurrent: number
constructor(maxConcurrent: number = 5) {
super()
this.maxConcurrent = maxConcurrent
}
setMaxConcurrent(max: number): void {
this.maxConcurrent = max
this.processQueue()
}
add(id: string, options: DownloadOptions, item: DownloadItem): void {
this.queue.push({ id, options, item })
this.emit('queue-updated', this.getQueueStatus())
this.processQueue()
}
remove(id: string): boolean {
// Remove from queue
const queueIndex = this.queue.findIndex((item) => item.id === id)
if (queueIndex !== -1) {
this.queue.splice(queueIndex, 1)
this.emit('queue-updated', this.getQueueStatus())
return true
}
// Remove from active downloads
if (this.activeDownloads.has(id)) {
this.activeDownloads.delete(id)
this.emit('queue-updated', this.getQueueStatus())
this.processQueue()
return true
}
return false
}
downloadCompleted(id: string): void {
const activeDownload = this.activeDownloads.get(id)
if (activeDownload) {
this.completedDownloads.set(id, activeDownload)
this.activeDownloads.delete(id)
}
this.emit('queue-updated', this.getQueueStatus())
this.processQueue()
}
private processQueue(): void {
while (this.activeDownloads.size < this.maxConcurrent && this.queue.length > 0) {
const item = this.queue.shift()
if (item) {
this.activeDownloads.set(item.id, item)
this.emit('start-download', item)
}
}
this.emit('queue-updated', this.getQueueStatus())
}
getQueueStatus(): {
queued: number
active: number
activeIds: string[]
} {
return {
queued: this.queue.length,
active: this.activeDownloads.size,
activeIds: Array.from(this.activeDownloads.keys())
}
}
isDownloading(id: string): boolean {
return this.activeDownloads.has(id)
}
getCompletedDownload(id: string): QueueItem | undefined {
return this.completedDownloads.get(id)
}
getItemDetails(id: string): { options: DownloadOptions; item: DownloadItem } | undefined {
const inActive = this.activeDownloads.get(id)
if (inActive) {
return {
options: inActive.options,
item: { ...inActive.item }
}
}
const inQueue = this.queue.find((entry) => entry.id === id)
if (inQueue) {
return {
options: inQueue.options,
item: { ...inQueue.item }
}
}
const completed = this.completedDownloads.get(id)
if (completed) {
return {
options: completed.options,
item: { ...completed.item }
}
}
return undefined
}
updateItemInfo(id: string, updates: Partial<DownloadItem>): void {
// Update in queue
const queueItem = this.queue.find((item) => item.id === id)
if (queueItem) {
Object.assign(queueItem.item, updates)
}
// Update in active downloads
const activeItem = this.activeDownloads.get(id)
if (activeItem) {
Object.assign(activeItem.item, updates)
}
// Update in completed downloads
const completedItem = this.completedDownloads.get(id)
if (completedItem) {
Object.assign(completedItem.item, updates)
}
}
clear(): void {
this.queue = []
this.emit('queue-updated', this.getQueueStatus())
}
}