Merge pull request #107 from arabcoders/dev
Added option to archive failing download from WebUI
This commit is contained in:
commit
7d34eeb3a9
4 changed files with 67 additions and 24 deletions
21
app/main.py
21
app/main.py
|
|
@ -9,7 +9,7 @@ import selectors
|
||||||
import time
|
import time
|
||||||
from Config import Config
|
from Config import Config
|
||||||
from DownloadQueue import DownloadQueue
|
from DownloadQueue import DownloadQueue
|
||||||
from Utils import ObjectSerializer, Notifier, load_file
|
from Utils import ObjectSerializer, Notifier, isDownloaded, load_file
|
||||||
from aiohttp import web, client
|
from aiohttp import web, client
|
||||||
from aiohttp.web import Request, Response
|
from aiohttp.web import Request, Response
|
||||||
from Webhooks import Webhooks
|
from Webhooks import Webhooks
|
||||||
|
|
@ -550,6 +550,25 @@ class Main:
|
||||||
})
|
})
|
||||||
await self.sio.emit('cli_close', {'exitcode': -1})
|
await self.sio.emit('cli_close', {'exitcode': -1})
|
||||||
|
|
||||||
|
@self.sio.event()
|
||||||
|
async def archive_item(sid, data):
|
||||||
|
if not isinstance(data, dict) or 'url' not in data or not self.config.keep_archive:
|
||||||
|
return
|
||||||
|
|
||||||
|
file: str = self.config.ytdl_options.get('download_archive', None)
|
||||||
|
|
||||||
|
if not file:
|
||||||
|
return
|
||||||
|
|
||||||
|
exists, idDict = isDownloaded(file, data['url'])
|
||||||
|
if exists or 'archive_id' not in idDict or idDict['archive_id'] is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
with open(file, 'a') as f:
|
||||||
|
f.write(f"{idDict['archive_id']}\n")
|
||||||
|
|
||||||
|
LOG.info(f'Archiving item: {data["url"]=}')
|
||||||
|
|
||||||
@self.sio.event()
|
@self.sio.event()
|
||||||
async def connect(sid, environ):
|
async def connect(sid, environ):
|
||||||
await self.connect(sid, environ)
|
await self.connect(sid, environ)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
<pageTasks v-if="showTasks" :tasks="config.tasks" />
|
<pageTasks v-if="showTasks" :tasks="config.tasks" />
|
||||||
<DownloadingList :config="config" :queue="downloading" @deleteItem="deleteItem" />
|
<DownloadingList :config="config" :queue="downloading" @deleteItem="deleteItem" />
|
||||||
<PageCompleted :config="config" :completed="completed" @deleteItem="deleteItem" @addItem="addItem"
|
<PageCompleted :config="config" :completed="completed" @deleteItem="deleteItem" @addItem="addItem"
|
||||||
@playItem="playItem" />
|
@playItem="playItem" @archiveItem="archiveItem" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="modal is-active" v-if="video_link">
|
<div class="modal is-active" v-if="video_link">
|
||||||
|
|
@ -64,6 +64,18 @@ const runCommand = (args) => {
|
||||||
socket.value.emit('cli_post', args);
|
socket.value.emit('cli_post', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sendData = (type, data, stringify = false) => {
|
||||||
|
if (!socket.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true === Boolean(stringify)) {
|
||||||
|
data = JSON.stringify(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.value.emit(type, data);
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
socket.value = io(process.env.VUE_APP_BASE_URL, {
|
socket.value = io(process.env.VUE_APP_BASE_URL, {
|
||||||
path: document.location.pathname + 'socket.io',
|
path: document.location.pathname + 'socket.io',
|
||||||
|
|
@ -141,12 +153,17 @@ onMounted(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.value.on('cli_close', () => cli_isLoading.value = false);
|
socket.value.on('cli_close', () => cli_isLoading.value = false);
|
||||||
socket.value.on('cli_output', stream => {
|
socket.value.on('cli_output', s => cli_output.value.push(s));
|
||||||
cli_output.value.push(stream)
|
|
||||||
console.log(stream);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const archiveItem = (type, item) => {
|
||||||
|
if (!confirm(`Archive '${item.title ?? item.id ?? item.url ?? '??'}'?`)){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sendData('archive_item', item);
|
||||||
|
deleteItem(type, item._id);
|
||||||
|
}
|
||||||
|
|
||||||
const deleteItem = (type, item) => {
|
const deleteItem = (type, item) => {
|
||||||
const items = []
|
const items = []
|
||||||
|
|
||||||
|
|
@ -234,5 +251,4 @@ bus.on((event, data) => {
|
||||||
setTimeout(() => bus.emit('task_edit', data), 500);
|
setTimeout(() => bus.emit('task_edit', data), 500);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -77,15 +77,22 @@
|
||||||
|
|
||||||
<div class="columns is-multiline">
|
<div class="columns is-multiline">
|
||||||
<LazyLoader :unrender="true" :min-height="210" class="column is-6" v-for="item in sortCompleted" :key="item._id">
|
<LazyLoader :unrender="true" :min-height="210" class="column is-6" v-for="item in sortCompleted" :key="item._id">
|
||||||
<div class="card" :class="{ 'is-bordered-danger': item.status === 'error', 'is-bordered-info': item.live_in || item.is_live }">
|
<div class="card"
|
||||||
<header class="card-header has-tooltip" v-tooltip="item.title">
|
:class="{ 'is-bordered-danger': item.status === 'error', 'is-bordered-info': item.live_in || item.is_live }">
|
||||||
<div class="card-header-title has-text-centered is-text-overflow is-block">
|
<header class="card-header has-tooltip">
|
||||||
|
<div class="card-header-title is-text-overflow is-block" v-tooltip="item.title">
|
||||||
<a v-if="item.filename" referrerpolicy="no-referrer" :href="makeDownload(config, item, 'm3u8')"
|
<a v-if="item.filename" referrerpolicy="no-referrer" :href="makeDownload(config, item, 'm3u8')"
|
||||||
@click.prevent="$emit('playItem', item)">
|
@click.prevent="$emit('playItem', item)">
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</a>
|
</a>
|
||||||
<span v-else>{{ item.title }}</span>
|
<span v-else>{{ item.title }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-header-icon" v-if="item.filename">
|
||||||
|
<a :href="makeDownload(config, item)" :download="item.filename?.split('/').reverse()[0]" class="has-text-primary"
|
||||||
|
v-tooltip="'Download item.'">
|
||||||
|
<span class="icon"><font-awesome-icon icon="fa-solid fa-download" /></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="columns is-mobile is-multiline">
|
<div class="columns is-mobile is-multiline">
|
||||||
|
|
@ -154,17 +161,6 @@
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-half-mobile" v-if="item.filename">
|
|
||||||
<a class="button is-fullwidth is-primary" :href="makeDownload(config, item)"
|
|
||||||
:download="item.filename?.split('/').reverse()[0]">
|
|
||||||
<span class="icon-text is-block">
|
|
||||||
<span class="icon">
|
|
||||||
<font-awesome-icon icon="fa-solid fa-download" />
|
|
||||||
</span>
|
|
||||||
<span>Download</span>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="column is-half-mobile">
|
<div class="column is-half-mobile">
|
||||||
<a class="button is-danger is-fullwidth" @click="$emit('deleteItem', 'completed', item._id)">
|
<a class="button is-danger is-fullwidth" @click="$emit('deleteItem', 'completed', item._id)">
|
||||||
<span class="icon-text is-block">
|
<span class="icon-text is-block">
|
||||||
|
|
@ -175,6 +171,17 @@
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="column is-half-mobile" v-if="config.app?.keep_archive && item.status != 'finished'">
|
||||||
|
<a class="button is-danger is-light is-fullwidth" v-tooltip="'Add link to archive.'"
|
||||||
|
@click="$emit('archiveItem', 'completed', item)">
|
||||||
|
<span class="icon-text is-block">
|
||||||
|
<span class="icon">
|
||||||
|
<font-awesome-icon icon="fa-solid fa-box-archive" />
|
||||||
|
</span>
|
||||||
|
<span>Archive</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<div class="column is-half-mobile">
|
<div class="column is-half-mobile">
|
||||||
<a referrerpolicy="no-referrer" class="button is-link is-fullwidth" target="_blank" :href="item.url">
|
<a referrerpolicy="no-referrer" class="button is-link is-fullwidth" target="_blank" :href="item.url">
|
||||||
<span class="icon-text is-block">
|
<span class="icon-text is-block">
|
||||||
|
|
@ -218,7 +225,7 @@ import moment from "moment";
|
||||||
import { useStorage } from '@vueuse/core'
|
import { useStorage } from '@vueuse/core'
|
||||||
import LazyLoader from './Lazy-Loader'
|
import LazyLoader from './Lazy-Loader'
|
||||||
|
|
||||||
const emits = defineEmits(['deleteItem', 'addItem', 'playItem']);
|
const emits = defineEmits(['deleteItem', 'addItem', 'playItem', 'archiveItem']);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
completed: {
|
completed: {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ import {
|
||||||
faBroom,
|
faBroom,
|
||||||
faServer,
|
faServer,
|
||||||
faPowerOff,
|
faPowerOff,
|
||||||
faPaperPlane
|
faPaperPlane,
|
||||||
|
faBoxArchive
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
import { faSquare, faSquareCheck } from '@fortawesome/free-regular-svg-icons'
|
import { faSquare, faSquareCheck } from '@fortawesome/free-regular-svg-icons'
|
||||||
|
|
@ -24,7 +25,7 @@ import 'floating-vue/dist/style.css'
|
||||||
library.add(faCog, faTrash, faLink, faPlus, faTrashCan, faCircleXmark, faCircleCheck, faRotateRight, faDownload,
|
library.add(faCog, faTrash, faLink, faPlus, faTrashCan, faCircleXmark, faCircleCheck, faRotateRight, faDownload,
|
||||||
faUpRightFromSquare, faSquare, faSquareCheck, faSpinner, faArrowUp, faArrowDown, faTasks, faCalendar, faArrowUpAZ,
|
faUpRightFromSquare, faSquare, faSquareCheck, faSpinner, faArrowUp, faArrowDown, faTasks, faCalendar, faArrowUpAZ,
|
||||||
faArrowDownAZ, faEject, faGlobe, faMoon, faSun, faTerminal, faBroom, faServer, faPowerOff, faBroom, faServer,
|
faArrowDownAZ, faEject, faGlobe, faMoon, faSun, faTerminal, faBroom, faServer, faPowerOff, faBroom, faServer,
|
||||||
faPowerOff, faPaperPlane)
|
faPowerOff, faPaperPlane, faBoxArchive)
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|
||||||
app.config.globalProperties.capitalize = s => s && s[0].toUpperCase() + s.slice(1);
|
app.config.globalProperties.capitalize = s => s && s[0].toUpperCase() + s.slice(1);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue