diff --git a/app/routes/api/system.py b/app/routes/api/system.py index 84a510c1..123a631e 100644 --- a/app/routes/api/system.py +++ b/app/routes/api/system.py @@ -1,11 +1,13 @@ import asyncio import logging +import time from aiohttp import web from aiohttp.web import Request, Response from aiohttp.web_runner import GracefulExit from app.library.config import Config +from app.library.DownloadQueue import DownloadQueue from app.library.encoder import Encoder from app.library.Events import EventBus, Events from app.library.router import route @@ -13,10 +15,80 @@ from app.library.router import route LOG: logging.Logger = logging.getLogger(__name__) +@route("POST", "api/system/pause", "system.pause") +async def downloads_pause(queue: DownloadQueue, encoder: Encoder, notify: EventBus) -> Response: + """ + Pause non-active downloads. + + Args: + request (Request): The request object. + queue (DownloadQueue): The download queue instance. + encoder (Encoder): The encoder instance. + notify (EventBus): The event bus instance. + + Returns: + Response: The response object. + + """ + if queue.is_paused(): + return web.json_response( + {"message": "Non-active downloads are already paused."}, + status=web.HTTPNotAcceptable.status_code, + dumps=encoder.encode, + ) + + queue.pause() + + msg = "Non-active downloads have been paused." + await notify.emit( + Events.PAUSED, + data={"paused": True, "at": time.time()}, + title="Downloads Paused", + message=msg, + ) + + return web.json_response(data={"message": msg}, status=web.HTTPOk.status_code, dumps=encoder.encode) + + +@route("POST", "api/system/resume", "system.resume") +async def downloads_resume(queue: DownloadQueue, encoder: Encoder, notify: EventBus) -> Response: + """ + Resume non-active downloads. + + Args: + request (Request): The request object. + queue (DownloadQueue): The download queue instance. + encoder (Encoder): The encoder instance. + notify (EventBus): The event bus instance. + + Returns: + Response: The response object. + + """ + if not queue.is_paused(): + return web.json_response( + {"message": "Non-active downloads are not paused."}, + status=web.HTTPNotAcceptable.status_code, + dumps=encoder.encode, + ) + + queue.resume() + + msg = "Resumed all downloads." + await notify.emit( + Events.RESUMED, + data={"paused": False, "at": time.time()}, + title="Downloads Resumed", + message=msg, + ) + + return web.json_response(data={"message": msg}, status=web.HTTPOk.status_code, dumps=encoder.encode) + + @route("POST", "api/system/shutdown", "system.shutdown") async def shutdown_system(request: Request, config: Config, encoder: Encoder, notify: EventBus) -> Response: """ - Get the presets. + Initiate application shutdown. Args: request (Request): The request object. diff --git a/app/routes/socket/history.py b/app/routes/socket/history.py index 3904d218..39421469 100644 --- a/app/routes/socket/history.py +++ b/app/routes/socket/history.py @@ -1,38 +1,13 @@ import logging -import time from app.library.DownloadQueue import DownloadQueue from app.library.Events import EventBus, Events from app.library.ItemDTO import Item from app.library.router import RouteType, route -from app.library.Utils import archive_add, archive_read, get_archive_id -from app.library.YTDLPOpts import YTDLPOpts LOG: logging.Logger = logging.getLogger(__name__) -@route(RouteType.SOCKET, "pause", "pause_downloads") -async def pause(notify: EventBus, queue: DownloadQueue): - queue.pause() - await notify.emit( - Events.PAUSED, - data={"paused": True, "at": time.time()}, - title="Downloads Paused", - message="Non-active downloads have been paused.", - ) - - -@route(RouteType.SOCKET, "resume", "resume_downloads") -async def resume(notify: EventBus, queue: DownloadQueue): - queue.resume() - await notify.emit( - Events.RESUMED, - data={"paused": False, "at": time.time()}, - title="Downloads Resumed", - message="Resumed all downloads.", - ) - - @route(RouteType.SOCKET, "add_url", "add_url") async def add_url(queue: DownloadQueue, notify: EventBus, sid: str, data: dict): data = data if isinstance(data, dict) else {} @@ -74,40 +49,6 @@ async def item_delete(queue: DownloadQueue, notify: EventBus, sid: str, data: di await queue.clear([id], remove_file=bool(data.get("remove_file", False))) -@route(RouteType.SOCKET, "archive_item", "archive_item") -async def archive_item(data: dict): - if not isinstance(data, dict) or "url" not in data: - return - - params: YTDLPOpts = YTDLPOpts.get_instance() - - if "preset" in data and isinstance(data["preset"], str): - params.preset(name=data["preset"]) - - if "cli" in data and isinstance(data["cli"], str) and len(data["cli"]) > 1: - params.add_cli(data["cli"], from_user=True) - - params = params.get_all() - - if not (file := params.get("download_archive")): - return - - idDict = get_archive_id(url=data["url"]) - if not idDict.get("archive_id"): - LOG.warning(f"URL '{data['url']}' does not have an archive ID.") - return - - archive_id: str = idDict.get("archive_id") - - if len(archive_read(file, [archive_id])) > 0: - LOG.info(f"URL '{data['url']}' already archived.") - return - - archive_add(file, [archive_id]) - - LOG.info(f"Archiving url '{data['url']}' with id '{archive_id}'.") - - @route(RouteType.SOCKET, "item_start", "item_start") async def item_start(queue: DownloadQueue, notify: EventBus, sid: str, data: list | str) -> None: if not data: diff --git a/ui/app/components/GetInfo.vue b/ui/app/components/GetInfo.vue index cc28e18b..5692c13e 100644 --- a/ui/app/components/GetInfo.vue +++ b/ui/app/components/GetInfo.vue @@ -81,7 +81,7 @@ onMounted(async (): Promise => { try { isLoading.value = true - const response = await request(url, { credentials: 'include' }) + const response = await request(url) const body = await response.text() try { diff --git a/ui/app/components/History.vue b/ui/app/components/History.vue index 4c94077d..f3cb585a 100644 --- a/ui/app/components/History.vue +++ b/ui/app/components/History.vue @@ -611,9 +611,6 @@ const deleteSelectedItems = () => { continue } const item = stateStore.get('history', item_id, {} as StoreItem) as StoreItem - if ('finished' === item.status) { - socket.emit('archive_item', item) - } socket.emit('item_delete', { id: item._id, remove_file: config.app.remove_files, @@ -737,10 +734,7 @@ const addArchiveDialog = (item: StoreItem) => { const archiveItem = async (item: StoreItem, opts = {}) => { try { - const req = await request(`/api/history/${item._id}/archive`, { - credentials: 'include', - method: 'POST', - }) + const req = await request(`/api/history/${item._id}/archive`, { method: 'POST' }) const data = await req.json() dialog_confirm.value.visible = false if (!req.ok) { @@ -832,8 +826,7 @@ const downloadSelected = async () => { try { const response = await request('/api/file/download', { method: 'POST', - credentials: 'include', - body: JSON.stringify(files_list), + body: JSON.stringify(files_list) }) const json = await response.json() if (!response.ok) { @@ -871,7 +864,7 @@ const removeFromArchiveDialog = (item: StoreItem) => { const removeFromArchive = async (item: StoreItem, opts?: { re_add?: boolean, remove_history?: boolean }) => { console.log('Removing from archive:', item, opts) try { - const req = await request(`/api/history/${item._id}/archive`, { credentials: 'include', method: 'DELETE' }) + const req = await request(`/api/history/${item._id}/archive`, { method: 'DELETE' }) const data = await req.json() if (!req.ok) { toast.error(data.error) diff --git a/ui/app/components/ImageView.vue b/ui/app/components/ImageView.vue index 1f8cad2d..51e4d4a8 100644 --- a/ui/app/components/ImageView.vue +++ b/ui/app/components/ImageView.vue @@ -50,7 +50,7 @@ onMounted(async () => { try { isLoading.value = true - const imgRequest = await request(url, { credentials: 'include' }) + const imgRequest = await request(url) if (200 !== imgRequest.status) { return } diff --git a/ui/app/components/NewDownload.vue b/ui/app/components/NewDownload.vue index a59a0069..0e5e6fa0 100644 --- a/ui/app/components/NewDownload.vue +++ b/ui/app/components/NewDownload.vue @@ -351,7 +351,6 @@ const addDownload = async () => { try { addInProgress.value = true const response = await request('/api/history', { - credentials: 'include', method: 'POST', body: JSON.stringify(request_data), }) diff --git a/ui/app/components/TaskForm.vue b/ui/app/components/TaskForm.vue index a2401a2d..bffed254 100644 --- a/ui/app/components/TaskForm.vue +++ b/ui/app/components/TaskForm.vue @@ -510,7 +510,7 @@ const convert_url = async (url: string): Promise => { try { convertInProgress.value = true - const resp = await request('/api/yt-dlp/url/info?' + params.toString(), { credentials: 'include' }) + const resp = await request('/api/yt-dlp/url/info?' + params.toString()) const body = await resp.json() const channel_id = ag(body, 'channel_id', null) console.log('convert_url', { url, channel_id, body }) diff --git a/ui/app/components/YTDLPOptions.vue b/ui/app/components/YTDLPOptions.vue index e5c4c1df..19feb297 100644 --- a/ui/app/components/YTDLPOptions.vue +++ b/ui/app/components/YTDLPOptions.vue @@ -170,7 +170,7 @@ const filters = reactive({ const reload = async (): Promise => { try { isLoading.value = true - const resp = await request('/api/yt-dlp/options', { credentials: 'include' }) + const resp = await request('/api/yt-dlp/options') if (!resp.ok) { return } diff --git a/ui/app/pages/index.vue b/ui/app/pages/index.vue index 441343d0..cdfb5eec 100644 --- a/ui/app/pages/index.vue +++ b/ui/app/pages/index.vue @@ -29,8 +29,7 @@ Pause - @@ -174,6 +173,8 @@ watch(() => stateStore.queue, () => { }, { deep: true }) +const resumeDownload = async () => await request('/api/system/resume', { method: 'POST' }) + const pauseDownload = () => { dialog_confirm.value.visible = true dialog_confirm.value.html_message = ` @@ -188,8 +189,8 @@ const pauseDownload = () => {
  • If you are in middle of adding a playlist/channel, it will break and stop adding more items.
  • ` - dialog_confirm.value.confirm = () => { - socket.emit('pause', {}) + dialog_confirm.value.confirm = async () => { + await request('/api/system/pause', { method: 'POST' }) dialog_confirm.value.visible = false } }