Small bug fixes and added time to objects.
This commit is contained in:
parent
10a31b5ee8
commit
b7bf9627a1
13 changed files with 82 additions and 26 deletions
3
.vscode/launch.json
vendored
3
.vscode/launch.json
vendored
|
|
@ -33,8 +33,7 @@
|
|||
"YTP_DOWNLOAD_PATH": "${workspaceFolder}/var/downloads",
|
||||
"YTP_TEMP_PATH": "${workspaceFolder}/var/tmp",
|
||||
"YTP_YTDL_OPTIONS_FILE": "${workspaceFolder}/var/config/ytdlp.json",
|
||||
"YTP_URL_HOST": "http://localhost:8081",
|
||||
"YTP_KEEP_ARCHIVE": "true",
|
||||
"YTP_URL_HOST": "http://localhost:8081"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ class Config:
|
|||
|
||||
ytdl_options: dict | str = {}
|
||||
ytdl_options_file: str = ''
|
||||
ytdl_debug: bool = False
|
||||
|
||||
host: str = '0.0.0.0'
|
||||
port: int = 8081
|
||||
|
|
@ -31,7 +32,7 @@ class Config:
|
|||
|
||||
base_path: str = ''
|
||||
|
||||
_boolean_vars: tuple = ('keep_archive')
|
||||
_boolean_vars: tuple = ('keep_archive', 'ytdl_debug')
|
||||
|
||||
def __init__(self):
|
||||
baseDefualtPath: str = os.path.dirname(os.path.dirname(__file__))
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class ItemDTO:
|
|||
ytdlp_cookies: str = None
|
||||
ytdlp_config: dict = field(default_factory=dict)
|
||||
output_template: str = None
|
||||
timestamp: int = time.time_ns()
|
||||
timestamp: float = time.time_ns()
|
||||
is_live: bool = None
|
||||
|
||||
# yt-dlp injected fields.
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class DataStore:
|
|||
with sqlite3.connect(self.db_file) as db:
|
||||
db.row_factory = sqlite3.Row
|
||||
cursor = db.execute(
|
||||
'SELECT "id", "data" FROM "history" WHERE "type" = ? ORDER BY "created_at" ASC',
|
||||
f'SELECT "id", "data" FROM "history" WHERE "type" = ? ORDER BY "created_at" ASC',
|
||||
(self.type,)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ class Download:
|
|||
ytdl_opts: dict = None
|
||||
info: ItemDTO = None
|
||||
default_ytdl_opts: dict = None
|
||||
debug: bool = False
|
||||
|
||||
_ytdlp_fields: tuple = (
|
||||
'tmpfilename',
|
||||
|
|
@ -41,16 +42,19 @@ class Download:
|
|||
download_dir: str,
|
||||
temp_dir: str,
|
||||
output_template_chapter: str,
|
||||
default_ytdl_opts: dict
|
||||
default_ytdl_opts: dict,
|
||||
debug: bool = False
|
||||
):
|
||||
self.download_dir = download_dir
|
||||
self.temp_dir = temp_dir
|
||||
self.output_template_chapter = output_template_chapter
|
||||
self.output_template = info.output_template
|
||||
self.format = get_format(info.format, info.quality)
|
||||
self.ytdl_opts = get_opts(info.format, info.quality, info.ytdlp_config if info.ytdlp_config else {})
|
||||
self.ytdl_opts = get_opts(
|
||||
info.format, info.quality, info.ytdlp_config if info.ytdlp_config else {})
|
||||
self.info = info
|
||||
self.default_ytdl_opts = default_ytdl_opts
|
||||
self.debug = debug
|
||||
|
||||
self.canceled = False
|
||||
self.tmpfilename = None
|
||||
|
|
@ -82,7 +86,6 @@ class Download:
|
|||
)
|
||||
|
||||
params: dict = {
|
||||
'quiet': True,
|
||||
'no_color': True,
|
||||
'format': self.format,
|
||||
'paths': {
|
||||
|
|
@ -99,6 +102,12 @@ class Download:
|
|||
**mergeConfig(self.default_ytdl_opts, self.ytdl_opts),
|
||||
}
|
||||
|
||||
if self.debug:
|
||||
params['verbose'] = True
|
||||
params['logger'] = logging.getLogger('YTPTube-ytdl')
|
||||
else:
|
||||
params['quiet'] = True
|
||||
|
||||
if self.info.ytdlp_cookies:
|
||||
try:
|
||||
data = jsonCookie(json.loads(self.info.ytdlp_cookies))
|
||||
|
|
@ -113,6 +122,8 @@ class Download:
|
|||
logging.error(
|
||||
f'Invalid cookies: was provided for {self.info.title} - {str(e)}')
|
||||
|
||||
logging.debug(
|
||||
f'Downloading {self.info._id} {self.info.title}... {params}')
|
||||
ret = yt_dlp.YoutubeDL(params=params).download([self.info.url])
|
||||
|
||||
self.status_queue.put(
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from src.Notifier import Notifier
|
|||
from src.Download import Download
|
||||
from src.DTO.ItemDTO import ItemDTO
|
||||
from src.DataStore import DataStore
|
||||
from src.Utils import ObjectSerializer, calcDownloadPath, ExtractInfo
|
||||
from src.Utils import ObjectSerializer, calcDownloadPath, ExtractInfo, mergeConfig
|
||||
from datetime import datetime, timezone
|
||||
|
||||
log = logging.getLogger('DownloadQueue')
|
||||
|
|
@ -129,6 +129,7 @@ class DownloadQueue:
|
|||
temp_dir=self.config.temp_path,
|
||||
output_template_chapter=output_chapter,
|
||||
default_ytdl_opts=self.config.ytdl_options,
|
||||
debug=bool(self.config.ytdl_debug)
|
||||
)
|
||||
)
|
||||
|
||||
|
|
@ -163,6 +164,8 @@ class DownloadQueue:
|
|||
output_template: str = '',
|
||||
already=None
|
||||
):
|
||||
ytdlp_config = ytdlp_config if ytdlp_config else {}
|
||||
|
||||
log.info(
|
||||
f'adding {url}: {quality=} {format=} {folder=} {output_template=} {ytdlp_cookies=} {ytdlp_config=}')
|
||||
|
||||
|
|
@ -173,7 +176,19 @@ class DownloadQueue:
|
|||
else:
|
||||
already.add(url)
|
||||
try:
|
||||
entry = await asyncio.get_running_loop().run_in_executor(None, ExtractInfo, self.config.ytdl_options, url)
|
||||
entry = await asyncio.get_running_loop().run_in_executor(
|
||||
None,
|
||||
ExtractInfo,
|
||||
mergeConfig(self.config.ytdl_options, ytdlp_config),
|
||||
url,
|
||||
bool(self.config.ytdl_debug)
|
||||
)
|
||||
if not entry:
|
||||
return {
|
||||
'status': 'error',
|
||||
'msg': 'No metadata, most likely video has been downloaded before.' if self.config.keep_archive else 'Unable to extract info check logs.'
|
||||
}
|
||||
logging.debug(f'entry: extract info says: {entry}')
|
||||
except yt_dlp.utils.YoutubeDLError as exc:
|
||||
return {'status': 'error', 'msg': str(exc)}
|
||||
|
||||
|
|
|
|||
|
|
@ -165,9 +165,8 @@ def calcDownloadPath(basePath: str, folder: str = None) -> str:
|
|||
return download_path
|
||||
|
||||
|
||||
def ExtractInfo(config: dict, url: str) -> dict:
|
||||
def ExtractInfo(config: dict, url: str, debug: bool = False) -> dict:
|
||||
params: dict = {
|
||||
'quiet': True,
|
||||
'no_color': True,
|
||||
'extract_flat': True,
|
||||
'skip_download': True,
|
||||
|
|
@ -176,6 +175,12 @@ def ExtractInfo(config: dict, url: str) -> dict:
|
|||
**config,
|
||||
}
|
||||
|
||||
if debug:
|
||||
params['verbose'] = True
|
||||
params['logger'] = logging.getLogger('YTPTube-ytdl')
|
||||
else:
|
||||
params['quiet'] = True
|
||||
|
||||
return yt_dlp.YoutubeDL(params=params).extract_info(url, download=False)
|
||||
|
||||
|
||||
|
|
|
|||
13
frontend/package-lock.json
generated
13
frontend/package-lock.json
generated
|
|
@ -1,16 +1,17 @@
|
|||
{
|
||||
"name": "frontend",
|
||||
"name": "YTPTube",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "frontend",
|
||||
"name": "YTPTube",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@vueuse/core": "^10.6.1",
|
||||
"bulma": "^0.9.4",
|
||||
"core-js": "^3.8.3",
|
||||
"moment": "^2.29.4",
|
||||
"socket.io-client": "^4.7.2",
|
||||
"vue": "^3.2.13",
|
||||
"vue-toastification": "^2.0.0-rc.5"
|
||||
|
|
@ -8021,6 +8022,14 @@
|
|||
"integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.29.4",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
|
||||
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/mrmime": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
"@vueuse/core": "^10.6.1",
|
||||
"bulma": "^0.9.4",
|
||||
"core-js": "^3.8.3",
|
||||
"moment": "^2.29.4",
|
||||
"socket.io-client": "^4.7.2",
|
||||
"vue": "^3.2.13",
|
||||
"vue-toastification": "^2.0.0-rc.5"
|
||||
|
|
|
|||
|
|
@ -156,12 +156,13 @@ const selectedQuality = useStorage('selectedQuality', '')
|
|||
const ytdlpConfig = useStorage('ytdlp_config', '')
|
||||
const ytdlpCookies = useStorage('ytdlp_cookies', '')
|
||||
const output_template = useStorage('output_template', null)
|
||||
const qualities = ref([])
|
||||
const url = ref('')
|
||||
const downloadPath = ref('')
|
||||
const addInProgress = ref(false)
|
||||
const downloadPath = useStorage('downloadPath', null)
|
||||
const url = useStorage('downloadUrl', null)
|
||||
const showAdvanced = useStorage('show_advanced', false)
|
||||
|
||||
const qualities = ref([])
|
||||
const addInProgress = ref(false)
|
||||
|
||||
const updateQualities = () => {
|
||||
for (const key in downloadFormats) {
|
||||
const item = downloadFormats[key];
|
||||
|
|
@ -190,7 +191,7 @@ const addDownload = () => {
|
|||
url: url.value,
|
||||
format: selectedFormat.value,
|
||||
quality: selectedQuality.value,
|
||||
path: downloadPath.value,
|
||||
folder: downloadPath.value,
|
||||
ytdlp_config: ytdlpConfig.value,
|
||||
ytdlp_cookies: ytdlpCookies.value,
|
||||
output_template: output_template.value,
|
||||
|
|
@ -206,6 +207,8 @@ const resetStorage = () => {
|
|||
ytdlpConfig.value = '';
|
||||
ytdlpCookies.value = '';
|
||||
output_template.value = null;
|
||||
url.value = '';
|
||||
downloadPath.value = '';
|
||||
}
|
||||
|
||||
bus.on((event, data) => {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@
|
|||
<div class="column is-12" v-if="item.error">
|
||||
<span class="has-text-danger">{{ item.error }}</span>
|
||||
</div>
|
||||
<div class="column is-half has-text-centered">
|
||||
<div class="column is-4 has-text-centered">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i v-if="item.status == 'finished'" class="has-text-success fa-solid fa-circle-check"></i>
|
||||
|
|
@ -83,7 +83,12 @@
|
|||
<span>{{ capitalize(item.status) }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="column is-half has-text-centered">
|
||||
<div class="column is-4 has-text-centered">
|
||||
<span :data-tooltip="moment(item.timestamp / 1000000).format('MMMM Do YYYY, h:mm:ss a')">
|
||||
{{ moment(item.timestamp / 1000000).fromNow() }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="column is-4 has-text-centered">
|
||||
<label class="checkbox is-block">
|
||||
<input class="completed-checkbox" type="checkbox" v-model="selectedElms" :id="'checkbox-' + item._id"
|
||||
:value="item._id">
|
||||
|
|
@ -159,6 +164,7 @@
|
|||
|
||||
<script setup>
|
||||
import { defineProps, computed, ref, watch, defineEmits } from 'vue';
|
||||
import moment from "moment";
|
||||
|
||||
const emits = defineEmits(['deleteItem', 'addItem']);
|
||||
|
||||
|
|
@ -287,7 +293,7 @@ const reQueueItem = (id, item) => {
|
|||
url: item.url,
|
||||
format: item.format,
|
||||
quality: item.quality,
|
||||
path: item.folder,
|
||||
folder: item.folder,
|
||||
ytdlp_config: item.ytdlp_config,
|
||||
ytdlp_cookies: item.ytdlp_cookies,
|
||||
output_template: item.output_template,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
:value="item.percent ? percentPipe(item.percent) : ''" max="100">
|
||||
</progress>
|
||||
</div>
|
||||
<div class="column is-half has-text-centered">
|
||||
<div class="column is-4 has-text-centered">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i v-if="item.status == 'finished'" class="has-text-success fa-solid fa-circle-check"></i>
|
||||
|
|
@ -52,7 +52,12 @@
|
|||
<span>{{ capitalize(item.status) }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="column is-half has-text-centered">
|
||||
<div class="column is-4 has-text-centered">
|
||||
<span :data-tooltip="moment(item.timestamp / 1000000).format('MMMM Do YYYY, h:mm:ss a')">
|
||||
{{ moment(item.timestamp / 1000000).fromNow() }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="column is-4 has-text-centered">
|
||||
<label class="checkbox is-block">
|
||||
<input class="completed-checkbox" type="checkbox" v-model="selectedElms" :value="item._id">
|
||||
Select
|
||||
|
|
@ -61,8 +66,7 @@
|
|||
</div>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<a class="button is-danger is-fullwidth"
|
||||
@click="$emit('deleteItem', 'queue', item._id)">
|
||||
<a class="button is-danger is-fullwidth" @click="$emit('deleteItem', 'queue', item._id)">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-trash-can"></i>
|
||||
|
|
@ -107,6 +111,7 @@
|
|||
|
||||
<script setup>
|
||||
import { defineProps, defineEmits, ref, watch, computed } from 'vue';
|
||||
import moment from "moment";
|
||||
|
||||
defineEmits(['deleteItem']);
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ app.config.globalProperties.makeDownload = (config, item) => {
|
|||
|
||||
app.use(Toast, {
|
||||
transition: "Vue-Toastification__bounce",
|
||||
position: "bottom-right",
|
||||
maxToasts: 5,
|
||||
newestOnTop: true
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue