Add auto start option for metube

This commit is contained in:
Qiao Wang 2023-12-09 12:35:31 +08:00
parent ca68c9d0fd
commit d12fc37a50
9 changed files with 457 additions and 397 deletions

View file

@ -117,9 +117,10 @@ async def add(request):
format = post.get('format')
folder = post.get('folder')
custom_name_prefix = post.get('custom_name_prefix')
auto_start = post.get('auto_start')
if custom_name_prefix is None:
custom_name_prefix = ''
status = await dqueue.add(url, quality, format, folder, custom_name_prefix)
status = await dqueue.add(url, quality, format, folder, custom_name_prefix, auto_start)
return web.Response(text=serializer.encode(status))
@routes.post(config.URL_PREFIX + 'delete')
@ -132,6 +133,13 @@ async def delete(request):
status = await (dqueue.cancel(ids) if where == 'queue' else dqueue.clear(ids))
return web.Response(text=serializer.encode(status))
@routes.post(config.URL_PREFIX + 'start')
async def start(request):
post = await request.json()
ids = post.get('ids')
status = await dqueue.start_pending(ids)
return web.Response(text=serializer.encode(status))
@routes.get(config.URL_PREFIX + 'history')
async def history(request):
history = { 'done': [], 'queue': []}
@ -227,4 +235,4 @@ app.on_response_prepare.append(on_prepare)
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
log.info(f"Listening on {config.HOST}:{config.PORT}")
web.run_app(app, host=config.HOST, port=config.PORT, reuse_port=True)
web.run_app(app, host=config.HOST, port=8081, reuse_port=False)

View file

@ -36,7 +36,8 @@ class DownloadInfo:
self.format = format
self.folder = folder
self.custom_name_prefix = custom_name_prefix
self.status = self.msg = self.percent = self.speed = self.eta = None
self.msg = self.percent = self.speed = self.eta = None
self.status = "pending"
self.timestamp = time.time_ns()
class Download:
@ -57,6 +58,7 @@ class Download:
self.loop = None
self.notifier = None
def _download(self):
try:
def put_status(st):
@ -193,13 +195,13 @@ class PersistentQueue:
def empty(self):
return not bool(self.dict)
class DownloadQueue:
def __init__(self, config, notifier):
self.config = config
self.notifier = notifier
self.queue = PersistentQueue(self.config.STATE_DIR + '/queue')
self.done = PersistentQueue(self.config.STATE_DIR + '/completed')
self.pending = PersistentQueue(self.config.STATE_DIR + '/pending')
self.done.load()
async def __import_queue(self):
@ -242,7 +244,7 @@ class DownloadQueue:
dldirectory = base_directory
return dldirectory, None
async def __add_entry(self, entry, quality, format, folder, custom_name_prefix, already):
async def __add_entry(self, entry, quality, format, folder, custom_name_prefix, auto_start, already):
if not entry:
return {'status': 'error', 'msg': "Invalid/empty data was given."}
@ -258,7 +260,7 @@ class DownloadQueue:
for property in ("id", "title", "uploader", "uploader_id"):
if property in entry:
etr[f"playlist_{property}"] = entry[property]
results.append(await self.__add_entry(etr, quality, format, folder, custom_name_prefix, already))
results.append(await self.__add_entry(etr, quality, format, folder, custom_name_prefix, auto_start, already))
if any(res['status'] == 'error' for res in results):
return {'status': 'error', 'msg': ', '.join(res['msg'] for res in results if res['status'] == 'error' and 'msg' in res)}
return {'status': 'ok'}
@ -273,15 +275,18 @@ class DownloadQueue:
for property, value in entry.items():
if property.startswith("playlist"):
output = output.replace(f"%({property})s", str(value))
self.queue.put(Download(dldirectory, self.config.TEMP_DIR, output, output_chapter, quality, format, self.config.YTDL_OPTIONS, dl))
self.event.set()
if auto_start is True:
self.queue.put(Download(dldirectory, self.config.TEMP_DIR, output, output_chapter, quality, format, self.config.YTDL_OPTIONS, dl))
self.event.set()
else:
self.pending.put(Download(dldirectory, self.config.TEMP_DIR, output, output_chapter, quality, format, self.config.YTDL_OPTIONS, dl))
await self.notifier.added(dl)
return {'status': 'ok'}
elif etype.startswith('url'):
return await self.add(entry['url'], quality, format, folder, custom_name_prefix, already)
return await self.add(entry['url'], quality, format, folder, custom_name_prefix, auto_start, already)
return {'status': 'error', 'msg': f'Unsupported resource "{etype}"'}
async def add(self, url, quality, format, folder, custom_name_prefix, already=None):
async def add(self, url, quality, format, folder, custom_name_prefix, auto_start=True, already=None):
log.info(f'adding {url}: {quality=} {format=} {already=} {folder=} {custom_name_prefix=}')
already = set() if already is None else already
if url in already:
@ -293,7 +298,18 @@ class DownloadQueue:
entry = await asyncio.get_running_loop().run_in_executor(None, self.__extract_info, url)
except yt_dlp.utils.YoutubeDLError as exc:
return {'status': 'error', 'msg': str(exc)}
return await self.__add_entry(entry, quality, format, folder, custom_name_prefix, already)
return await self.__add_entry(entry, quality, format, folder, custom_name_prefix, auto_start, already)
async def start_pending(self, ids):
for id in ids:
if not self.pending.exists(id):
log.warn(f'requested start for non-existent download {id}')
continue
dl = self.pending.get(id)
self.queue.put(dl)
self.pending.delete(id)
self.event.set()
return {'status': 'ok'}
async def cancel(self, ids):
for id in ids:
@ -324,7 +340,7 @@ class DownloadQueue:
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.pending.items()),
list((k, v.info) for k, v in self.done.items()))
async def __download(self):