Skip to content

Commit 27b82c9

Browse files
committed
feat: queued state has been added, pre add queue state
1 parent f34c98b commit 27b82c9

File tree

7 files changed

+77
-20
lines changed

7 files changed

+77
-20
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ytdlp-gui",
3-
"version": "0.9.8",
3+
"version": "0.9.9",
44
"description": "venipa-electron-template",
55
"main": "./out/main/index.js",
66
"author": "Venipa <[email protected]>",

src/main/stores/queue-database.helpers.ts

+24-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import {
66
InferInsertModel,
77
InferSelectModel,
88
isNotNull,
9-
like
9+
like,
10+
not
1011
} from 'drizzle-orm'
1112
import { omit } from 'lodash'
1213
import { db } from './queue-database'
@@ -30,11 +31,29 @@ function findDownloadByUrl(url: string, state?: string | string[]) {
3031
)
3132
.all()
3233
}
33-
function findDownloadByExactUrl(url: string) {
34+
function findDownloadByExactUrl(url: string, dbFileId?: SelectDownload['id']) {
3435
return db
3536
.select()
3637
.from(downloads)
37-
.where(and(eq(downloads.url, url), isNotNull(downloads.meta)))
38+
.where(
39+
and(
40+
eq(downloads.url, url),
41+
isNotNull(downloads.meta),
42+
...((dbFileId !== undefined && [not(eq(downloads.id, dbFileId))]) || [])
43+
)
44+
)
45+
.orderBy(desc(downloads.created))
46+
.get()
47+
}
48+
function findDownloadById(dbFileId: SelectDownload['id']) {
49+
return db
50+
.select()
51+
.from(downloads)
52+
.where(
53+
and(
54+
eq(downloads.id, dbFileId)
55+
)
56+
)
3857
.orderBy(desc(downloads.created))
3958
.get()
4059
}
@@ -56,6 +75,7 @@ export const queries = {
5675
updateDownload,
5776
deleteDownload,
5877
findDownloadByUrl,
59-
findDownloadByExactUrl
78+
findDownloadByExactUrl,
79+
findDownloadById
6080
}
6181
}

src/main/trpc/ytdlp.api.ts

+40-10
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ export const ytdlpRouter = router({
3232
url: z.string().url().array()
3333
})
3434
)
35-
.mutation(async ({ input: { url }, ctx }) => {
35+
.mutation(async ({ input: { url: urls }, ctx }) => {
36+
const dbEntries = await addToDatabase(urls)
3637
const files = await queuePromiseStack(
37-
url.map((u) => () => queueYtdlMetaCheck(u).catch(() => null)),
38+
dbEntries.map((u) => () => queueYtdlMetaCheck(u).catch(() => null)),
3839
MAX_PARALLEL_DOWNLOADS
3940
).then((files) => files.filter((s) => !!s))
4041
const asyncResult = ytdlpDownloadQueue.addAll(
@@ -231,14 +232,42 @@ const deleteDownloadItem = (dbFile: SelectDownload) =>
231232
})
232233
}
233234
})
235+
const addToDatabase = async (urls: string[]) => {
236+
const [items] = await db.batch(
237+
urls
238+
.map((url) => {
239+
if (typeof url !== 'string' || !/^https/gi.test(url)) return null
240+
return queries.downloads.createDownload({
241+
filepath: '',
242+
filesize: 0,
243+
meta: {} as any,
244+
metaId: '',
245+
source: new URL(url).hostname,
246+
title: url,
247+
url,
248+
state: 'queued',
249+
type: null,
250+
error: null,
251+
retryCount: 0
252+
})
253+
})
254+
.filter(Boolean) as any
255+
)
256+
ytdlpEvents.emit('list', items)
257+
log.debug('addToDatabase', { items })
258+
return items as SelectDownload[]
259+
}
234260
const queueYtdlMetaCheck = async (
235-
url: string
261+
createdDbFile: SelectDownload
236262
): Promise<{ dbFile: SelectDownload; videoInfo: VideoInfo }> => {
237-
if (typeof url !== 'string' || !/^https/gi.test(url)) throw new Error('Invalid url format')
263+
const { url } = createdDbFile
264+
log.debug('meta', `added url`, url, createdDbFile)
265+
if (!createdDbFile.url) throw new Error('Invalid url format')
238266
ytdlpEvents.emit('status', { action: 'getVideoInfo', state: 'progressing' })
239-
log.debug('meta', `added url ${url}`)
240-
const existingDbFile = await queries.downloads.findDownloadByExactUrl(url)
241-
let [dbFile] = await queries.downloads.createDownload({
267+
let dbFile = await queries.downloads.findDownloadById(createdDbFile.id)
268+
if (!dbFile) throw new Error('Entry has been not found or has been removed')
269+
const existingDbFile = await queries.downloads.findDownloadByExactUrl(url, dbFile.id)
270+
Object.assign(dbFile, {
242271
metaId: existingDbFile?.metaId ?? '',
243272
meta: existingDbFile?.meta ?? ({} as any),
244273
filepath: existingDbFile?.filepath ?? '',
@@ -247,10 +276,10 @@ const queueYtdlMetaCheck = async (
247276
state: 'fetching_meta',
248277
title: existingDbFile?.title ?? url,
249278
type: null,
250-
url,
251279
error: null,
252280
retryCount: 0
253281
})
282+
await queries.downloads.updateDownload(dbFile.id, dbFile)
254283
ytdlpEvents.emit('list', [dbFile])
255284
if (!dbFile.meta?.filename) {
256285
const { value: videoInfo, error: videoInfoError } = await ytdl.getVideoInfo(url)
@@ -372,8 +401,9 @@ const queueYtdlDownload = async (dbFile: SelectDownload, videoInfo: VideoInfo) =
372401
pushLogToClient(`[${dbFile.id}=${dbFile.metaId}] finished download: ${dbFile.title}`, 'success')
373402
return await updateEntry()
374403
}
375-
function handleYtAddEvent(url: string) {
376-
queueYtdlMetaCheck(url).then(({ dbFile, videoInfo }) => {
404+
async function handleYtAddEvent(url: string) {
405+
const [newDbFile] = await addToDatabase([url])
406+
await queueYtdlMetaCheck(newDbFile).then(({ dbFile, videoInfo }) => {
377407
const asyncResult = ytdlpDownloadQueue.add(() => queueYtdlDownload(dbFile, videoInfo))
378408
if (ytdlpDownloadQueue.isPaused) ytdlpDownloadQueue.start()
379409
return asyncResult

src/main/trpc/ytdlp.core.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const checkBrokenLinks = async () => {
1414
const itemCount = await db
1515
.update(downloads)
1616
.set({ state: 'cancelled' })
17-
.where(inArray(downloads.state, ['downloading', 'fetching_meta']))
17+
.where(inArray(downloads.state, ['downloading', 'fetching_meta', 'queued']))
1818
logger.info(`Updated state of ${itemCount.rowsAffected} to cancelled`)
1919
}
2020

src/renderer/src/pages/components/add-link.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import SelectDownloadBox from './select-download-path'
1414
const httpsRegex = /^https?/i
1515
export default function AddLink({ showDownloadPath }: { showDownloadPath?: boolean }) {
1616
const { settings, setSetting } = useApp()
17-
const { mutateAsync: queueDownloadFromUrl, isLoading } = trpc.ytdl.downloadMedia.useMutation({
17+
const { mutateAsync: queueDownloadFromUrl } = trpc.ytdl.downloadMedia.useMutation({
1818
onError(error, variables, context) {
1919
toast.error(error.data!.code, { description: error.message })
2020
}
@@ -63,7 +63,6 @@ export default function AddLink({ showDownloadPath }: { showDownloadPath?: boole
6363
<div className="flex-auto"></div>
6464
<QTooltip content="Enable/Disable clipboard monitoring">
6565
<Button
66-
disabled={isLoading}
6766
variant={'ghost'}
6867
onClick={() =>
6968
setSetting('features.clipboardMonitor', !settings.features.clipboardMonitor)

src/renderer/src/pages/components/link-list.tsx

+9-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
LucideFileX,
1616
LucideFolderOpen,
1717
LucideGlobe,
18+
LucideListPlus,
1819
LucideRedo2,
1920
LucideSquare,
2021
LucideX
@@ -43,6 +44,7 @@ export function LinkListItem(props: YTDLItem & { key: any }) {
4344
const cancelled = useMemo(() => state === 'cancelled', [state, status])
4445
const downloading = useMemo(() => state === 'downloading', [state, status])
4546
const processingMeta = useMemo(() => state === 'fetching_meta', [state, status])
47+
const queued = useMemo(() => state === 'queued', [state, status])
4648
const faviconUrl = useMemo(
4749
() =>
4850
source && `https://icons.duckduckgo.com/ip3/${source.replace(TrimSubdomainRegex, '')}.ico`,
@@ -65,6 +67,12 @@ export function LinkListItem(props: YTDLItem & { key: any }) {
6567
<div className="size-5 p-1 flex flex-col items-center justify-center bg-green-500 text-white rounded-full">
6668
<LucideCheck className="stroke-[4px]" />
6769
</div>
70+
) : queued ? (
71+
<QTooltip className="cursor-default" content={'Queued'} side="right">
72+
<div className="flex flex-col items-center justify-center size-10 relative">
73+
<LucideListPlus className="size-5 text-secondary-foreground" />
74+
</div>
75+
</QTooltip>
6876
) : downloading && status ? (
6977
<QTooltip className="cursor-default" content={'Download Progress'} side="right">
7078
<div className="flex flex-col items-center justify-center size-10 relative">
@@ -177,7 +185,7 @@ export function LinkListItem(props: YTDLItem & { key: any }) {
177185
<LucideFileX className="stroke-current" />
178186
</ButtonLoading>
179187
)}
180-
{(error || cancelled) && (
188+
{(error || cancelled || queued) && (
181189
<ButtonLoading
182190
variant={'ghost'}
183191
size={'sm'}

src/renderer/src/pages/components/status-bar.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export default function StatusBar() {
6666
</>
6767
) : updateProgress && !updateDone ? (
6868
<>
69-
<Appear>Downloading... {(updateProgress.percent as number).toFixed(2).padStart(5, ' ')}%</Appear>
69+
<Appear>Downloading... {(updateProgress.percent as number).toFixed(2).padStart(6, ' ')}%</Appear>
7070
<div className="h-10 w-px bg-muted"></div>
7171
</>
7272
) : updateAvailable && !updateDone ? (

0 commit comments

Comments
 (0)