migrating more code to new UI

This commit is contained in:
ArabCoders 2024-12-13 20:55:10 +03:00
parent f7b610434f
commit 06042776e6
4 changed files with 263 additions and 16 deletions

View file

@ -0,0 +1,193 @@
<template>
<main class="columns mt-2">
<div class="column">
<div class="box">
<div class="columns is-multiline">
<div class="column is-12">
<div class="control has-icons-left">
<input type="url" class="input" id="url" placeholder="Video or playlist link"
:disabled="!config.isConnected || addInProgress" v-model="url">
<span class="icon is-small is-left">
<i class="fa-solid fa-link" />
</span>
</div>
</div>
<div class="column is-5">
<div class="field has-addons">
<div class="control">
<a href="#" class="button is-static">Preset</a>
</div>
<div class="control is-expanded">
<div class="select is-fullwidth">
<select id="preset" class="is-fullwidth" :disabled="!config.isConnected" v-model="selectedPreset">
<option v-for="item in downloadFormats" :key="item.id" :value="item.id">
{{ item.text }}
</option>
</select>
</div>
</div>
</div>
</div>
<div class="column is-5">
<div class="field has-addons" v-tooltip="'Download path relative to ' + config.app.download_path">
<div class="control">
<a href="#" class="button is-static">Download Path</a>
</div>
<div class="control is-expanded">
<input type="text" class="input is-fullwidth" id="path" v-model="downloadPath" placeholder="Default"
:disabled="!config.isConnected" list="directories">
</div>
</div>
</div>
<div class="column">
<button type="submit" class="button is-primary" @click="addDownload"
:class="{ 'is-loading': !config.isConnected || addInProgress }"
:disabled="!config.isConnected || addInProgress || !url">
<span class="icon">
<i class="fa-solid fa-plus" />
</span>
<span>Add Link</span>
</button>
</div>
<div class="column">
<button type="submit" class="button is-info" @click="showAdvanced = !showAdvanced"
v-tooltip="'Show advanced options'" :class="{ 'is-loading': !config.isConnected }"
:disabled="!config.isConnected">
<span class="icon">
<i class="fa-solid fa-cog" />
</span>
</button>
</div>
</div>
<div class="columns is-multiline" v-if="showAdvanced">
<div class="column is-12">
<div class="field">
<label class="label is-inline" for="output_format"
v-tooltip="'Default Format: ' + config.app.output_template">
Output Format
</label>
<div class="control">
<input type="text" class="input" v-model="output_template" id="output_format"
placeholder="Uses default format if non is given.">
</div>
<span class="subtitle is-6 has-text-info">
All format options can be found at <a class="has-text-danger" target="_blank"
referrerpolicy="no-referrer" href="https://github.com/yt-dlp/yt-dlp#output-template">this page</a>.
</span>
</div>
</div>
<div class="column is-6">
<div class="field">
<label class="label is-inline" for="ytdlpConfig"
v-tooltip="'Extends current global yt-dlp config. (JSON)'">
JSON yt-dlp config
</label>
<div class="control">
<textarea class="textarea" id="ytdlpConfig" v-model="ytdlpConfig"
:disabled="!config.isConnected"></textarea>
</div>
<span class="subtitle is-6 has-text-info">
Some config fields are ignored like cookiefile, path, and output_format etc.
Available option can be found at <a class="has-text-danger" target="_blank" referrerpolicy="no-referrer"
href="https://github.com/yt-dlp/yt-dlp/blob/a0b19d319a6ce8b7059318fa17a34b144fde1785/yt_dlp/YoutubeDL.py#L194">this
page</a>.
</span>
</div>
</div>
<div class="column is-6">
<div class="field">
<label class="label is-inline" for="ytdlpCookies" v-tooltip="'JSON exported cookies for downloading.'">
yt-dlp Cookies
</label>
<div class="control">
<textarea class="textarea" id="ytdlpCookies" v-model="ytdlpCookies"
:disabled="!config.isConnected"></textarea>
</div>
<span class="subtitle is-6 has-text-info">
Use something like <a class="has-text-danger" href="https://github.com/jrie/flagCookies">flagCookies</a>
to extract cookies as JSON string.
</span>
</div>
</div>
<div class="column is-12 has-text-right">
<div class="field">
<div class="control">
<button type="submit" class="button is-danger" @click="resetConfig" :disabled="!config.isConnected"
v-tooltip="'This configuration are stored locally in your browser.'">
<span class="icon">
<i class="fa-solid fa-trash" />
</span>
<span>Reset Local Configuration</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<datalist id="directories" v-if="config?.directories">
<option v-for="dir in config.directories" :key="dir" :value="dir" />
</datalist>
</main>
</template>
<script setup>
import { defineEmits, defineProps, onMounted, ref } from 'vue'
import { useStorage, useEventBus } from '@vueuse/core'
import { useConfigStore } from '~/store/ConfigStore';
const config = useConfigStore();
const bus = useEventBus('item_added', 'task_edit');
const emits = defineEmits(['addItem']);
const selectedFormat = useStorage('selectedFormat', 'any')
const selectedQuality = useStorage('selectedQuality', '')
const ytdlpConfig = useStorage('ytdlp_config', '')
const ytdlpCookies = useStorage('ytdlp_cookies', '')
const output_template = useStorage('output_template', null)
const downloadPath = useStorage('downloadPath', null)
const url = useStorage('downloadUrl', null)
const showAdvanced = useStorage('show_advanced', false)
const addInProgress = ref(false)
const addDownload = () => {
addInProgress.value = true;
emits('addItem', {
url: url.value,
format: selectedFormat.value,
quality: selectedQuality.value,
folder: downloadPath.value,
ytdlp_config: ytdlpConfig.value,
ytdlp_cookies: ytdlpCookies.value,
output_template: output_template.value,
});
}
const resetConfig = () => {
if (!confirm('Are you sure you want to reset the local configuration? this will NOT delete any downloads or server configuration.')) {
return;
}
selectedFormat.value = 'any';
selectedQuality.value = '';
ytdlpConfig.value = '';
ytdlpCookies.value = '';
output_template.value = null;
url.value = '';
downloadPath.value = '';
}
bus.on((event, data) => {
const allowedEvents = ['item_added'];
if (!allowedEvents.includes(event)) {
return;
}
if ('item_added' === event) {
if (data?.status === 'ok') {
url.value = '';
}
addInProgress.value = false;
}
});
</script>

View file

@ -1,5 +1,5 @@
<template>
<div id="main_container" class="container" :class="{'is-max-fullwidth': expandContainer}">
<div id="main_container" class="container" :class="{ 'is-max-fullwidth': expandContainer }">
<nav class="navbar is-dark mb-5">
<div class="navbar-brand pl-5">
<NuxtLink class="navbar-item" to="/">
@ -20,15 +20,44 @@
</button>
</div>
<div class="navbar-menu is-unselectable" :class="{'is-active':showMenu}">
<div class="navbar-menu is-unselectable" :class="{ 'is-active': showMenu }">
<div class="navbar-end pr-3">
<div class="navbar-item">
<button v-tooltip.bottom="'Toggle Console'" class="button is-dark has-tooltip-bottom"
@click="config.showConsole = !config.showConsole">
<span class="icon">
<i class="fa-solid fa-terminal" />
</span>
<span class="is-hidden-mobile">Console</span>
</button>
</div>
<div class="navbar-item">
<button v-tooltip.bottom="'Toggle Add Form'" class="button is-dark has-tooltip-bottom"
@click="config.showForm = !config.showForm">
<span class="icon"><i class="fa-solid fa-plus" /></span>
<span class="is-hidden-mobile">Add</span>
</button>
</div>
<div class="navbar-item" v-if="config.tasks.length > 0">
<button v-tooltip.bottom="'Toggle Tasks'" class="button is-dark has-tooltip-bottom"
@click="config.showTasks = !config.showTasks">
<span class="icon">
<i class="fa-solid fa-tasks" />
</span>
<span class="is-hidden-mobile">Tasks</span>
</button>
</div>
<div class="navbar-item">
<button class="button is-dark" @click="selectedTheme = 'light'" v-if="'dark' === selectedTheme"
v-tooltip="'Switch to light theme'">
v-tooltip="'Switch to light theme'">
<span class="icon has-text-warning"><i class="fas fa-sun"></i></span>
</button>
<button class="button is-dark" @click="selectedTheme = 'dark'" v-if="'light' === selectedTheme"
v-tooltip="'Switch to dark theme'">
v-tooltip="'Switch to dark theme'">
<span class="icon"><i class="fas fa-moon"></i></span>
</button>
</div>
@ -56,24 +85,25 @@
</div>
</div>
<NuxtNotifications position="top right" :speed="800" :ignoreDuplicates="true" :width="340" :pauseOnHover="true"/>
<NuxtNotifications position="top right" :speed="800" :ignoreDuplicates="true" :width="340" :pauseOnHover="true" />
</div>
</template>
<script setup>
import {ref} from 'vue'
import { ref } from 'vue'
import 'assets/css/bulma.css'
import 'assets/css/style.css'
import 'assets/css/all.css'
import {useStorage} from '@vueuse/core'
import {notification} from '~/utils/index'
import { useStorage } from '@vueuse/core'
import { useConfigStore } from '~/store/ConfigStore'
const runtimeConfig = useRuntimeConfig()
const config = useConfigStore()
const selectedTheme = useStorage('theme', (() => window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')())
const showMenu = ref(false)
const VERSION = ref(runtimeConfig.public.version)
const expandContainer = ref(false)
const bus = useEventBus('show_form')
const applyPreferredColorScheme = scheme => {
for (let s = 0; s < document.styleSheets.length; s++) {
@ -127,9 +157,13 @@ onMounted(async () => {
watch(selectedTheme, value => {
try {
applyPreferredColorScheme(value)
} catch (e) {
}
} catch (e) { }
})
const reloadPage = () => window.location.reload()
const toggleForm = () => {
console.log('emitting show_form');
bus.emit('show_form', { foo: 'bar' })
dEvent('show_form', { foo: 'bar' })
}
</script>

View file

@ -1,5 +1,6 @@
<template>
<div>
<NewDownload v-if="config.showForm" />
<Queue />
<History />
</div>
@ -15,13 +16,24 @@ const config = useConfigStore()
const runtimeConfig = useRuntimeConfig()
const socket = ref()
const downloading = reactive({})
const cli_output = ref([])
const cli_isLoading = ref(false)
const stateStore = useStateStore()
useHead({ title: 'Index' })
bus.on((event, data) => {
console.log({ e: event, d: data })
if (!['show_form'].includes(event)) {
return true;
}
if ('show_form' === event) {
addForm.value = true;
setTimeout(() => bus.emit('task_edit', data), 500);
}
})
useHead({ title: 'Index' })
onMounted(() => {
socket.value = io(runtimeConfig.public.wss, {
path: document.location.pathname + 'socket.io',
@ -45,7 +57,7 @@ onMounted(() => {
socket.value.on('added', stream => {
const item = JSON.parse(stream);
stateStore.add('queue', item);
toast.success(`Item queued successfully: ${downloading[item._id]?.title}`);
toast.success(`Item queued successfully: ${stateStore.get('queue', item._id)?.title}`);
});
socket.value.on('error', stream => {
@ -69,8 +81,11 @@ onMounted(() => {
return
}
toast.info('Download canceled: ' + downloading[id]?.title);
delete downloading[id];
toast.info('Download canceled: ' + stateStore.get('queue', id)?.title);
if (true === stateStore.has('queue', id)) {
stateStore.remove('queue', id);
}
});
socket.value.on('cleared', stream => {
@ -99,4 +114,6 @@ onMounted(() => {
socket.value.on('cli_close', () => cli_isLoading.value = false);
socket.value.on('cli_output', s => cli_output.value.push(s));
});
</script>

View file

@ -2,6 +2,9 @@ import { defineStore } from 'pinia';
const CONFIG_KEYS = {
isConnected: false,
showForm: false,
showConsole: false,
showTasks: false,
tasks: [],
app: {
host: '',