From 9a959f932600fb39b075b1c6c4c8d7bac3d184f9 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 3 Dec 2019 22:32:07 +0200 Subject: add "completed" panel --- .vscode/launch.json | 2 +- app/main.py | 24 +++++------ app/ytdl.py | 49 +++++++++++++++------- ui/src/app/app.component.html | 74 ++++++++++++++++++++------------- ui/src/app/app.component.sass | 34 ++++++++++++--- ui/src/app/app.component.ts | 72 +++++++++++++++++++++----------- ui/src/app/app.module.ts | 5 ++- ui/src/app/downloads.service.ts | 62 +++++++++++++++++---------- ui/src/app/master-checkbox.component.ts | 53 +++++++++++++++++++++++ 9 files changed, 266 insertions(+), 109 deletions(-) create mode 100644 ui/src/app/master-checkbox.component.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 3d4107f..4b2e858 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Python: Youtube-dealer", + "name": "Python: MeTube", "type": "python", "request": "launch", "program": "${workspaceFolder}/app/main.py", diff --git a/app/main.py b/app/main.py index 9d5fb2e..4c48aeb 100644 --- a/app/main.py +++ b/app/main.py @@ -43,8 +43,14 @@ class Notifier(DownloadQueueNotifier): async def updated(self, dl): await sio.emit('updated', serializer.encode(dl)) - async def deleted(self, id): - await sio.emit('deleted', serializer.encode(id)) + async def completed(self, dl): + await sio.emit('completed', serializer.encode(dl)) + + async def canceled(self, id): + await sio.emit('canceled', serializer.encode(id)) + + async def cleared(self, id): + await sio.emit('cleared', serializer.encode(id)) dqueue = DownloadQueue(config, Notifier()) @@ -61,21 +67,15 @@ async def add(request): async def delete(request): post = await request.json() ids = post.get('ids') - if not ids: + where = post.get('where') + if not ids or where not in ['queue', 'done']: raise web.HTTPBadRequest() - status = await dqueue.delete(ids) + status = await (dqueue.cancel(ids) if where == 'queue' else dqueue.clear(ids)) return web.Response(text=serializer.encode(status)) -@routes.get('/queue') -def queue(request): - ret = dqueue.get() - return web.Response(text=serializer.encode(ret)) - @sio.event async def connect(sid, environ): - ret = dqueue.get() - #ret = [["XeNTV0kyHaU", {"id": "XeNTV0kyHaU", "title": "2020 Mercedes ACTROS \u2013 Digital Side Mirrors, Electronic Stability, Auto Braking, Side Guard Safety", "url": "XeNTV0kyHaU", "status": None, "percentage": 0}], ["76wlIusQe9U", {"id": "76wlIusQe9U", "title": "Toyota HIACE 2020 \u2013 Toyota Wagon / Toyota HIACE 2019 and 2020", "url": "76wlIusQe9U", "status": None, "percentage": 0}], ["n_d5LPwflMM", {"id": "n_d5LPwflMM", "title": "2020 Toyota GRANVIA \u2013 Toyota 8 Seater LUXURY VAN / ALL-NEW Toyota GRANVIA 2020", "url": "n_d5LPwflMM", "status": None, "percentage": 0}], ["Dv4ZFhCpF1M", {"id": "Dv4ZFhCpF1M", "title": "Toyota SIENNA 2019 vs Honda ODYSSEY 2019", "url": "Dv4ZFhCpF1M", "status": None, "percentage": 0}], ["GjHJFb3Mgqw", {"id": "GjHJFb3Mgqw", "title": "How It's Made (Buses) \u2013 How Buses are made? SETRA BUS Production", "url": "GjHJFb3Mgqw", "status": None, "percentage": 0}]] - await sio.emit('queue', serializer.encode(ret), to=sid) + await sio.emit('all', serializer.encode(dqueue.get()), to=sid) @routes.get('/') def index(request): diff --git a/app/ytdl.py b/app/ytdl.py index d1512ef..9fe4840 100644 --- a/app/ytdl.py +++ b/app/ytdl.py @@ -78,7 +78,13 @@ class DownloadQueueNotifier: async def updated(self, dl): raise NotImplementedError - async def deleted(self, id): + async def completed(self, dl): + raise NotImplementedError + + async def canceled(self, id): + raise NotImplementedError + + async def cleared(self, id): raise NotImplementedError class DownloadQueue: @@ -86,6 +92,7 @@ class DownloadQueue: self.config = config self.notifier = notifier self.queue = OrderedDict() + self.done = OrderedDict() self.event = asyncio.Event() asyncio.ensure_future(self.__download()) @@ -116,20 +123,28 @@ class DownloadQueue: self.event.set() return {'status': 'ok'} - async def delete(self, ids): + async def cancel(self, ids): for id in ids: if id not in self.queue: + log.warn(f'requested cancel for non-existent download {id}') + continue + self.queue[id].cancel() + del self.queue[id] + await self.notifier.canceled(id) + return {'status': 'ok'} + + async def clear(self, ids): + for id in ids: + if id not in self.done: log.warn(f'requested delete for non-existent download {id}') continue - if self.queue[id].info.status is not None: - self.queue[id].cancel() - else: - del self.queue[id] - await self.notifier.deleted(id) + del self.done[id] + await self.notifier.cleared(id) return {'status': 'ok'} def get(self): - return list((k, v.info) for k, v in self.queue.items()) + return(list((k, v.info) for k, v in self.queue.items()), + list((k, v.info) for k, v in self.done.items())) async def __download(self): while True: @@ -144,11 +159,15 @@ class DownloadQueue: async def updated_cb(): await self.notifier.updated(entry.info) asyncio.ensure_future(entry.update_status(updated_cb)) await start_aw - if entry.info.status != 'finished' and entry.tmpfilename and os.path.isfile(entry.tmpfilename): - try: - os.remove(entry.tmpfilename) - except: - pass + if entry.info.status != 'finished': + if entry.tmpfilename and os.path.isfile(entry.tmpfilename): + try: + os.remove(entry.tmpfilename) + except: + pass + entry.info.status = 'error' entry.close() - del self.queue[id] - await self.notifier.deleted(id) + if id in self.queue: + del self.queue[id] + self.done[id] = entry + await self.notifier.completed(entry.info) diff --git a/ui/src/app/app.component.html b/ui/src/app/app.component.html index 3796b72..b05aee7 100644 --- a/ui/src/app/app.component.html +++ b/ui/src/app/app.component.html @@ -1,10 +1,9 @@