Initial WebUI code not exposed to public yet.
This commit is contained in:
49
NEWS.md
Normal file
49
NEWS.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Old Updates
|
||||||
|
|
||||||
|
### 2024-03-08
|
||||||
|
|
||||||
|
This update include breaking changes to how we process commands, we have streamlined the command interface to accept
|
||||||
|
some consistent flags and options. Notably, we have added `-s, --select-backend` flag to all commands that accept it.
|
||||||
|
commands that were accepting comma separated list of backends now needs to be separate option call for example
|
||||||
|
`--select-backend home_plex --select-backend home_jellyfin` instead of `--select-backend home_plex,home_jellyfin`.
|
||||||
|
|
||||||
|
All commands that was accepting backend name as argument now accepts `-s, --select-backend` flag. This change is to make
|
||||||
|
the command interface more consistent and easier to use.
|
||||||
|
|
||||||
|
Another breaking change is the removal of the `-c, --config` flag from all commands that was accepting it. This flag was
|
||||||
|
used to override the default `servers.yaml` file. This was not working as expected as there are more than just the `servers.yaml`
|
||||||
|
to consider like, the state of cache, and the state of the database. As such, we have removed this flag. However, we have
|
||||||
|
added a new environment variable called `WS_BACKENDS_FILE` which can be used to override the default `servers.yaml` file.
|
||||||
|
We strongly recommend not to use it as it might lead to unexpected behavior.
|
||||||
|
|
||||||
|
We started working on a `Web API` which hopefully will lead to a `web frontend` to manage the tool. This is a long
|
||||||
|
term goal, and it's not expected to be ready soon. However, the `Web API` is expected within 3rd quarter of 2024.
|
||||||
|
|
||||||
|
### 2023-11-11
|
||||||
|
|
||||||
|
We added new feature `watch progress tracking` YAY which works exclusively via webhooks at the moment to keep tracking
|
||||||
|
of your play progress.
|
||||||
|
As this feature is quite **EXPERIMENTAL** we have separate command and task for it `state:progress` will send back
|
||||||
|
progress to your backends.
|
||||||
|
However, Sadly this feature is not working at the moment with `Jellyfin` once they accept
|
||||||
|
my [PR #10573](https://github.com/jellyfin/jellyfin/pull/10573) i'll add support for it. However,
|
||||||
|
The feature works well with both `Plex` and `Emby`.
|
||||||
|
|
||||||
|
The support via `webhooks` is excellent, and it's the recommended way to track your progress. However, if you cant use
|
||||||
|
webhooks, the `state:import` command
|
||||||
|
will pull the progress from your backends. however at reduced rate due to the nature of the command. If you want faster
|
||||||
|
progress tracking, you should use `webhooks`.
|
||||||
|
|
||||||
|
To sync the progress update, You have to use `state:progress` command, it will push the update to all `export` enabled
|
||||||
|
backends.
|
||||||
|
This feature is disabled by default like the other features. To enable it add new environment variable
|
||||||
|
called`WS_CRON_PROGRESS=1`.
|
||||||
|
We push progress update every `45 minutes`, to change it like other features add `WS_CRON_PROGRESS_AT="*/45 * * * *"`
|
||||||
|
This is the default timer.
|
||||||
|
|
||||||
|
On another point, we have decided to enable backup by default. To disable it simply add new environment
|
||||||
|
variable `WS_CRON_BACKUP=0`.
|
||||||
|
|
||||||
|
### 2023-10-31
|
||||||
|
|
||||||
|
We added new command called `db:parity` which will check if your backends are reporting the same data.
|
||||||
50
README.md
50
README.md
@@ -9,53 +9,13 @@ out of the box, this tool support `Jellyfin`, `Plex` and `Emby` media servers.
|
|||||||
|
|
||||||
## updates
|
## updates
|
||||||
|
|
||||||
### 2024-03-08
|
### 2024-04-30 - [BREAKING CHANGE]
|
||||||
|
|
||||||
This update include breaking changes to how we process commands, we have streamlined the command interface to accept
|
We are going to retire the old webhooks endpoint, please refer to the [FAQ](FAQ.md#how-to-add-webhooks) to know how to update
|
||||||
some consistent flags and options. Notably, we have added `-s, --select-backend` flag to all commands that accept it.
|
to the new API endpoint. We are going to include `WebUI` for alpha testing after two weeks from today `2024-05-15`. Which most likely means the old webhooks
|
||||||
commands that were accepting comma separated list of backends now needs to be separate option call for example
|
endpoint will be removed. We will try to preseve the old endpoint for a while, but it's not guaranteed we will be able to.
|
||||||
`--select-backend home_plex --select-backend home_jellyfin` instead of `--select-backend home_plex,home_jellyfin`.
|
|
||||||
|
|
||||||
All commands that was accepting backend name as argument now accepts `-s, --select-backend` flag. This change is to make
|
Refer to [NEWS](NEWS.md) for old updates.
|
||||||
the command interface more consistent and easier to use.
|
|
||||||
|
|
||||||
Another breaking change is the removal of the `-c, --config` flag from all commands that was accepting it. This flag was
|
|
||||||
used to override the default `servers.yaml` file. This was not working as expected as there are more than just the `servers.yaml`
|
|
||||||
to consider like, the state of cache, and the state of the database. As such, we have removed this flag. However, we have
|
|
||||||
added a new environment variable called `WS_BACKENDS_FILE` which can be used to override the default `servers.yaml` file.
|
|
||||||
We strongly recommend not to use it as it might lead to unexpected behavior.
|
|
||||||
|
|
||||||
We started working on a `Web API` which hopefully will lead to a `web frontend` to manage the tool. This is a long
|
|
||||||
term goal, and it's not expected to be ready soon. However, the `Web API` is expected within 3rd quarter of 2024.
|
|
||||||
|
|
||||||
### 2023-11-11
|
|
||||||
|
|
||||||
We added new feature `watch progress tracking` YAY which works exclusively via webhooks at the moment to keep tracking
|
|
||||||
of your play progress.
|
|
||||||
As this feature is quite **EXPERIMENTAL** we have separate command and task for it `state:progress` will send back
|
|
||||||
progress to your backends.
|
|
||||||
However, Sadly this feature is not working at the moment with `Jellyfin` once they accept
|
|
||||||
my [PR #10573](https://github.com/jellyfin/jellyfin/pull/10573) i'll add support for it. However,
|
|
||||||
The feature works well with both `Plex` and `Emby`.
|
|
||||||
|
|
||||||
The support via `webhooks` is excellent, and it's the recommended way to track your progress. However, if you cant use
|
|
||||||
webhooks, the `state:import` command
|
|
||||||
will pull the progress from your backends. however at reduced rate due to the nature of the command. If you want faster
|
|
||||||
progress tracking, you should use `webhooks`.
|
|
||||||
|
|
||||||
To sync the progress update, You have to use `state:progress` command, it will push the update to all `export` enabled
|
|
||||||
backends.
|
|
||||||
This feature is disabled by default like the other features. To enable it add new environment variable
|
|
||||||
called`WS_CRON_PROGRESS=1`.
|
|
||||||
We push progress update every `45 minutes`, to change it like other features add `WS_CRON_PROGRESS_AT="*/45 * * * *"`
|
|
||||||
This is the default timer.
|
|
||||||
|
|
||||||
On another point, we have decided to enable backup by default. To disable it simply add new environment
|
|
||||||
variable `WS_CRON_BACKUP=0`.
|
|
||||||
|
|
||||||
### 2023-10-31
|
|
||||||
|
|
||||||
We added new command called `db:parity` which will check if your backends are reporting the same data.
|
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
|
||||||
|
|||||||
24
frontend/.gitignore
vendored
Normal file
24
frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Nuxt dev/build outputs
|
||||||
|
.output
|
||||||
|
.data
|
||||||
|
.nuxt
|
||||||
|
.nitro
|
||||||
|
.cache
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Node dependencies
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.DS_Store
|
||||||
|
.fleet
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Local env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
10607
frontend/assets/css/all.css
Normal file
10607
frontend/assets/css/all.css
Normal file
File diff suppressed because it is too large
Load Diff
24826
frontend/assets/css/bulma.css
vendored
Normal file
24826
frontend/assets/css/bulma.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
109
frontend/assets/css/style.css
Normal file
109
frontend/assets/css/style.css
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
* {
|
||||||
|
unicode-bidi: plaintext;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 1em;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container,
|
||||||
|
.card,
|
||||||
|
.box,
|
||||||
|
.navbar {
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-bordered-danger {
|
||||||
|
border: 1px solid red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-bordered-info {
|
||||||
|
border: 1px solid #3e8ed0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
background-color: #eaeaea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-unselectable {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-text-overflow {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
* {
|
||||||
|
unicode-bidi: plaintext;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 1em;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container,
|
||||||
|
.card,
|
||||||
|
.box,
|
||||||
|
.navbar {
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-bordered-danger {
|
||||||
|
border: 1px solid red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-bordered-info {
|
||||||
|
border: 1px solid #3e8ed0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
background-color: #0f1010;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-unselectable {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-text-overflow {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-borderless {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-marginless {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-paddingless {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
BIN
frontend/assets/webfonts/fa-brands-400.ttf
Normal file
BIN
frontend/assets/webfonts/fa-brands-400.ttf
Normal file
Binary file not shown.
BIN
frontend/assets/webfonts/fa-brands-400.woff2
Normal file
BIN
frontend/assets/webfonts/fa-brands-400.woff2
Normal file
Binary file not shown.
BIN
frontend/assets/webfonts/fa-regular-400.ttf
Normal file
BIN
frontend/assets/webfonts/fa-regular-400.ttf
Normal file
Binary file not shown.
BIN
frontend/assets/webfonts/fa-regular-400.woff2
Normal file
BIN
frontend/assets/webfonts/fa-regular-400.woff2
Normal file
Binary file not shown.
BIN
frontend/assets/webfonts/fa-solid-900.ttf
Normal file
BIN
frontend/assets/webfonts/fa-solid-900.ttf
Normal file
Binary file not shown.
BIN
frontend/assets/webfonts/fa-solid-900.woff2
Normal file
BIN
frontend/assets/webfonts/fa-solid-900.woff2
Normal file
Binary file not shown.
BIN
frontend/assets/webfonts/fa-v4compatibility.ttf
Normal file
BIN
frontend/assets/webfonts/fa-v4compatibility.ttf
Normal file
Binary file not shown.
BIN
frontend/assets/webfonts/fa-v4compatibility.woff2
Normal file
BIN
frontend/assets/webfonts/fa-v4compatibility.woff2
Normal file
Binary file not shown.
142
frontend/layouts/default.vue
Normal file
142
frontend/layouts/default.vue
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<nav class="navbar is-dark">
|
||||||
|
<div class="navbar-brand pl-5">
|
||||||
|
<NuxtLink class="navbar-item" href="/">
|
||||||
|
<span class="icon-text">
|
||||||
|
<span class="icon"><i class="fas fa-home"></i></span>
|
||||||
|
<span>Home</span>
|
||||||
|
</span>
|
||||||
|
</NuxtLink>
|
||||||
|
|
||||||
|
<button class="navbar-burger burger" @click="showMenu = !showMenu">
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="navbar-menu" :class="{'is-active':showMenu}">
|
||||||
|
<div class="navbar-start">
|
||||||
|
<a class="navbar-item" href="/backends">
|
||||||
|
<span class="icon-text">
|
||||||
|
<span class="icon"><i class="fas fa-server"></i></span>
|
||||||
|
<span>Backends</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a class="navbar-item" href="/history">
|
||||||
|
<span class="icon-text">
|
||||||
|
<span class="icon"><i class="fas fa-history"></i></span>
|
||||||
|
<span>History</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a class="navbar-item" href="/logs">
|
||||||
|
<span class="icon-text">
|
||||||
|
<span class="icon"><i class="fas fa-globe"></i></span>
|
||||||
|
<span>Logs</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="navbar-end">
|
||||||
|
<div class="navbar-item">
|
||||||
|
<button class="button is-dark has-tooltip-bottom" @click="selectedTheme = 'light'"
|
||||||
|
v-if="'dark' === selectedTheme">
|
||||||
|
<span class="icon is-small is-left has-text-warning">
|
||||||
|
<i class="fas fa-sun"></i>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button class="button is-dark has-tooltip-bottom" @click="selectedTheme = 'dark'"
|
||||||
|
v-if="'light' === selectedTheme">
|
||||||
|
<span class="icon is-small is-left">
|
||||||
|
<i class="fas fa-moon"></i>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="columns">
|
||||||
|
<div class="column is-12">
|
||||||
|
<slot/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="columns mt-3 is-mobile">
|
||||||
|
<div class="column is-8-mobile">
|
||||||
|
<div class="has-text-left">
|
||||||
|
© {{ Year }} - <a href="https://github.com/arabcoders/watchstate" target="_blank">WatchState</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref} from 'vue'
|
||||||
|
import 'assets/css/bulma.css'
|
||||||
|
import 'assets/css/style.css'
|
||||||
|
import 'assets/css/all.css'
|
||||||
|
import {useStorage} from '@vueuse/core'
|
||||||
|
|
||||||
|
const selectedTheme = useStorage('theme', (() => window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')());
|
||||||
|
|
||||||
|
const Year = ref(new Date().getFullYear())
|
||||||
|
const showMenu = ref(false)
|
||||||
|
|
||||||
|
const applyPreferredColorScheme = (scheme) => {
|
||||||
|
for (let s = 0; s < document.styleSheets.length; s++) {
|
||||||
|
for (let i = 0; i < document.styleSheets[s].cssRules.length; i++) {
|
||||||
|
try {
|
||||||
|
const rule = document.styleSheets[s].cssRules[i];
|
||||||
|
if (rule && rule.media && rule.media.mediaText.includes("prefers-color-scheme")) {
|
||||||
|
switch (scheme) {
|
||||||
|
case "light":
|
||||||
|
rule.media.appendMedium("original-prefers-color-scheme");
|
||||||
|
if (rule.media.mediaText.includes("light")) {
|
||||||
|
rule.media.deleteMedium("(prefers-color-scheme: light)");
|
||||||
|
}
|
||||||
|
if (rule.media.mediaText.includes("dark")) {
|
||||||
|
rule.media.deleteMedium("(prefers-color-scheme: dark)");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "dark":
|
||||||
|
rule.media.appendMedium("(prefers-color-scheme: light)");
|
||||||
|
rule.media.appendMedium("(prefers-color-scheme: dark)");
|
||||||
|
if (rule.media.mediaText.includes("original")) {
|
||||||
|
rule.media.deleteMedium("original-prefers-color-scheme");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rule.media.appendMedium("(prefers-color-scheme: dark)");
|
||||||
|
if (rule.media.mediaText.includes("light")) {
|
||||||
|
rule.media.deleteMedium("(prefers-color-scheme: light)");
|
||||||
|
}
|
||||||
|
if (rule.media.mediaText.includes("original")) {
|
||||||
|
rule.media.deleteMedium("original-prefers-color-scheme");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.debug(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
try {
|
||||||
|
applyPreferredColorScheme(selectedTheme.value);
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(selectedTheme, (value) => {
|
||||||
|
try {
|
||||||
|
applyPreferredColorScheme(value);
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
31
frontend/nuxt.config.ts
Normal file
31
frontend/nuxt.config.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
|
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
export default defineNuxtConfig({
|
||||||
|
ssr: false,
|
||||||
|
devtools: {enabled: true},
|
||||||
|
app: {
|
||||||
|
head: {
|
||||||
|
"meta": [
|
||||||
|
{"charset": "utf-8"},
|
||||||
|
{"name": "viewport", "content": "width=device-width, initial-scale=1.0, maximum-scale=1.0"},
|
||||||
|
{"name": "theme-color", "content": "#000000"}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
buildAssetsDir: "assets",
|
||||||
|
},
|
||||||
|
router: {
|
||||||
|
options: {
|
||||||
|
linkActiveClass: "is-active",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modules: [
|
||||||
|
'@vueuse/nuxt',
|
||||||
|
],
|
||||||
|
nitro: {
|
||||||
|
output: {
|
||||||
|
publicDir: path.join(__dirname, 'exported')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
19
frontend/package.json
Normal file
19
frontend/package.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "nuxt-app",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"build": "nuxt build",
|
||||||
|
"dev": "nuxt dev",
|
||||||
|
"generate": "nuxt generate",
|
||||||
|
"preview": "nuxt preview",
|
||||||
|
"postinstall": "nuxt prepare"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@vueuse/core": "^10.9.0",
|
||||||
|
"@vueuse/nuxt": "^10.9.0",
|
||||||
|
"nuxt": "^3.11.2",
|
||||||
|
"vue": "^3.4.21",
|
||||||
|
"vue-router": "^4.3.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
3
frontend/pages/backends/index.vue
Normal file
3
frontend/pages/backends/index.vue
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<template>
|
||||||
|
<p>NYI</p>
|
||||||
|
</template>
|
||||||
5
frontend/pages/history/index.vue
Normal file
5
frontend/pages/history/index.vue
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<template>
|
||||||
|
<p>NYI</p>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
</script>
|
||||||
3
frontend/pages/index.vue
Normal file
3
frontend/pages/index.vue
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<template>
|
||||||
|
<p>foo</p>
|
||||||
|
</template>
|
||||||
BIN
frontend/public/favicon.ico
Normal file
BIN
frontend/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
4
frontend/tsconfig.json
Normal file
4
frontend/tsconfig.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
// https://nuxt.com/docs/guide/concepts/typescript
|
||||||
|
"extends": "./.nuxt/tsconfig.json"
|
||||||
|
}
|
||||||
5811
frontend/yarn.lock
Normal file
5811
frontend/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user