Standardized how we use the Message component.
This commit is contained in:
@@ -1,23 +1,20 @@
|
||||
<template>
|
||||
<Message title="Important Information" message_class="has-background-warning-80 has-text-dark">
|
||||
<div class="content is-bold">
|
||||
<ul>
|
||||
<li>
|
||||
WatchState is single user tool. It doesn't support syncing multiple users play state.
|
||||
<NuxtLink target="_blank" v-text="'Visit this link'"
|
||||
href="https://github.com/arabcoders/watchstate/blob/master/FAQ.md#is-there-support-for-multi-user-setup"/>
|
||||
to learn more.
|
||||
</li>
|
||||
<li>
|
||||
If you are adding new backend that is fresh and doesn't have your current watch state, you should turn off
|
||||
import and enable only metadata import at the start to prevent overriding your current play state.
|
||||
<NuxtLink
|
||||
href="https://github.com/arabcoders/watchstate/blob/master/FAQ.md#my-new-backend-overriding-my-old-backend-state--my-watch-state-is-not-correct"
|
||||
target="_blank" v-text="'Visit this link'"/>
|
||||
to learn more.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Message title="Important" message_class="has-background-warning-80 has-text-dark" icon="fas fa-exclamation-triangle">
|
||||
<ul>
|
||||
<li>
|
||||
WatchState is single user tool. It doesn't support syncing multiple users play state.
|
||||
<NuxtLink target="_blank" v-text="'Visit this link'"
|
||||
to="https://github.com/arabcoders/watchstate/blob/master/FAQ.md#is-there-support-for-multi-user-setup"/>
|
||||
to learn more.
|
||||
</li>
|
||||
<li>
|
||||
If you are adding new backend that is fresh and doesn't have your current watch state, you should turn off
|
||||
import and enable only metadata import at the start to prevent overriding your current play state.
|
||||
<NuxtLink target="_blank" v-text="'Visit this link'"
|
||||
to="https://github.com/arabcoders/watchstate/blob/master/FAQ.md#my-new-backend-overriding-my-old-backend-state--my-watch-state-is-not-correct"/>
|
||||
to learn more.
|
||||
</li>
|
||||
</ul>
|
||||
</Message>
|
||||
<form id="backend_add_form" @submit.prevent="addBackend" @change="changeStage">
|
||||
<div class="card">
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useStorage} from "@vueuse/core"
|
||||
import {useStorage} from '@vueuse/core'
|
||||
import {marked} from 'marked'
|
||||
import {baseUrl} from 'marked-base-url'
|
||||
|
||||
@@ -23,8 +23,21 @@ onMounted(() => fetch(`${api_url.value}${props.file}`).then(response => response
|
||||
renderer: {
|
||||
text: (text) => {
|
||||
// -- replace github [!] with icon
|
||||
text = text.replace(/\[!IMPORTANT\]/g, '<i class="fas fa-exclamation-triangle has-text-danger"></i>')
|
||||
text = text.replace(/\[!NOTE\]/g, '<i class="fas fa-exclamation-circle has-text-info"></i>')
|
||||
text = text.replace(/\[!IMPORTANT\]/g, `
|
||||
<span class="is-block title is-4">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-exclamation-triangle has-text-danger"></i></span>
|
||||
<span>Important</span>
|
||||
</span>
|
||||
</span>`)
|
||||
|
||||
text = text.replace(/\[!NOTE\]/g, `
|
||||
<span class="is-block title is-4">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-info-circle has-text-info-50"></i></span>
|
||||
<span>Note</span>
|
||||
</span>
|
||||
</span>`)
|
||||
return text
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,8 +1,26 @@
|
||||
<template>
|
||||
<div class="notification" :class="message_class">
|
||||
<h2 class="title is-5" v-if="title">{{ title }}</h2>
|
||||
<p v-if="message">{{ message }}</p>
|
||||
<slot/>
|
||||
<button class="delete" @click="$emit('close')" v-if="!useToggle && useClose"></button>
|
||||
<div class="is-pulled-right is-unselectable" v-if="useToggle">
|
||||
<span class="icon">
|
||||
<i class="fas" :class="{'fa-arrow-up':toggle,'fa-arrow-down':!toggle}"></i>
|
||||
</span>
|
||||
<span>{{ toggle ? 'Close' : 'Open' }}</span>
|
||||
</div>
|
||||
<div class="notification-title is-unselectable" :class="{'is-clickable':useToggle}" v-if="title || icon"
|
||||
@click="useToggle ? $emit('toggle', toggle):null">
|
||||
<template v-if="icon">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i :class="icon"></i></span>
|
||||
<span>{{ title }}</span>
|
||||
</span>
|
||||
</template>
|
||||
<template v-else>{{ title }}</template>
|
||||
</div>
|
||||
<div class="notification-content content" v-if="false === useToggle || toggle">
|
||||
<template v-if="message">{{ message }}</template>
|
||||
<slot/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -13,6 +31,11 @@ defineProps({
|
||||
default: null,
|
||||
required: false
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: null,
|
||||
required: false
|
||||
},
|
||||
message: {
|
||||
type: String,
|
||||
default: null,
|
||||
@@ -22,6 +45,23 @@ defineProps({
|
||||
type: String,
|
||||
default: 'is-info',
|
||||
required: false
|
||||
},
|
||||
useToggle: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
},
|
||||
toggle: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
},
|
||||
useClose: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
}
|
||||
})
|
||||
|
||||
defineEmits(['toggle', 'close'])
|
||||
</script>
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
<template>
|
||||
<div class="notification has-text-dark is-background-warning-80">
|
||||
<h5 class="title is-5 is-unselectable">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-exclamation-triangle"></i></span>
|
||||
<span>Warning</span>
|
||||
</span>
|
||||
</h5>
|
||||
<div class="content">
|
||||
<p>There is no <em class="is-bold">{{ api_var }}</em> configured.</p>
|
||||
<p>Please configure the API connection using the button <i class="fa fa-cog"></i> in the top right corner of the
|
||||
page.</p>
|
||||
</div>
|
||||
</div>
|
||||
<Message title="Warning" message_class="has-background-warning-80 has-text-dark" icon="fas fa-exclamation-triangle">
|
||||
There is no <em class="is-bold">{{ api_var }}</em> configured. Please configure the API connection using the button
|
||||
<i class="fa fa-cog"></i> in the top right corner of the page.
|
||||
</Message>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">
|
||||
<NuxtLink to="/backends">Backends</NuxtLink>
|
||||
- Edit:
|
||||
@@ -10,13 +10,15 @@
|
||||
<div class="is-pulled-right">
|
||||
<div class="field is-grouped"></div>
|
||||
</div>
|
||||
|
||||
<div class="is-hidden-mobile">
|
||||
<span class="subtitle">Edit the backend settings.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-12" v-if="isLoading">
|
||||
<Message message_class="is-info" title="Information">
|
||||
<span class="icon"><i class="fas fa-spinner fa-pulse"></i></span>
|
||||
<span>Loading backend settings, please wait...</span>
|
||||
</Message>
|
||||
<Message message_class="is-background-info-90 has-text-dark" title="Loading"
|
||||
icon="fas fa-spinner fa-spin" message="Loading backend settings. Please wait..."/>
|
||||
</div>
|
||||
|
||||
<div v-else class="column is-12">
|
||||
@@ -300,12 +302,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="card-footer-item">
|
||||
<button class="button is-fullwidth is-primary" type="submit">
|
||||
<span class="icon"><i class="fas fa-save"></i></span>
|
||||
<span>Save Settings</span>
|
||||
</button>
|
||||
</div>
|
||||
<button class="button card-footer-item is-fullwidth is-primary" type="submit">
|
||||
<span class="icon"><i class="fas fa-save"></i></span>
|
||||
<span>Save Settings</span>
|
||||
</button>
|
||||
<NuxtLink class="card-footer-item button is-fullwidth is-danger" :to="`/backend/${backend}`">
|
||||
<span class="icon"><i class="fas fa-cancel"></i></span>
|
||||
<span>Cancel changes</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">
|
||||
<NuxtLink to="/backends" v-text="'Backends'"/>
|
||||
: {{ backend }}
|
||||
@@ -9,7 +8,7 @@
|
||||
<div class="is-pulled-right">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<NuxtLink class="button is-primary" v-tooltip="'Edit Backend'" :to="`/backend/${backend}/edit`">
|
||||
<NuxtLink class="button is-primary" v-tooltip.bottom="'Edit Backend'" :to="`/backend/${backend}/edit`">
|
||||
<span class="icon"><i class="fas fa-edit"></i></span>
|
||||
</NuxtLink>
|
||||
</p>
|
||||
@@ -27,7 +26,7 @@
|
||||
<h1 class="title is-4">Useful Tools</h1>
|
||||
<ul>
|
||||
<li>
|
||||
<NuxtLink :to="`/backend/${backend}/mismatched`" v-text="'Find possible mismatched content.'"/>
|
||||
<NuxtLink :to="`/backend/${backend}/mismatched`" v-text="'Find possible mis-identified content.'"/>
|
||||
</li>
|
||||
<li>
|
||||
<NuxtLink :to="`/backend/${backend}/unmatched`" v-text="'Find unmatched content.'"/>
|
||||
@@ -49,7 +48,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns is-multiline" v-if="bHistory.length>0">
|
||||
<div class="columns" v-if="bHistory.length<1">
|
||||
<div class="column is-12">
|
||||
<Message message_class="is-background-warning-80 has-text-dark" title="Warning" icon="fas fa-exclamation-circle"
|
||||
message="No items were found. There are probably no items in the local database yet."/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns is-multiline" v-else>
|
||||
<div class="column is-12">
|
||||
<h1 class="title is-4">Recent History</h1>
|
||||
</div>
|
||||
@@ -111,17 +116,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns" v-if="bHistory.length<1">
|
||||
|
||||
<div class="columns is-multiline" v-if="info">
|
||||
<div class="column is-12">
|
||||
<Message message_class="is-warning">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-exclamation"></i></span>
|
||||
<span>No items were found. There are probably no items in the local database yet.</span>
|
||||
</span>
|
||||
</Message>
|
||||
<h1 class="title is-4">Basic info</h1>
|
||||
</div>
|
||||
<div class="column is-12">
|
||||
<div class="content">
|
||||
<code class="is-block is-pre-wrap" v-text="info"></code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -130,11 +135,11 @@ import Message from '~/components/Message.vue'
|
||||
import {formatDuration, notification} from "~/utils/index.js";
|
||||
|
||||
const backend = useRoute().params.backend
|
||||
const historyUrl = `/history/?via=${backend}`
|
||||
|
||||
useHead({title: `Backends: ${backend}`})
|
||||
|
||||
const bHistory = ref([])
|
||||
const info = ref({})
|
||||
|
||||
const loadRecentHistory = async () => {
|
||||
const response = await request(`/history/?perpage=6&via=${backend}`)
|
||||
@@ -148,5 +153,14 @@ const loadRecentHistory = async () => {
|
||||
bHistory.value = json.history
|
||||
};
|
||||
|
||||
onMounted(() => loadRecentHistory())
|
||||
const loadInfo = async () => {
|
||||
const response = await request(`/backend/${backend}/info`)
|
||||
info.value = await response.json()
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await loadInfo();
|
||||
await loadRecentHistory()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<span class="title is-4">
|
||||
<NuxtLink to="/backends">Backends</NuxtLink>
|
||||
-
|
||||
<NuxtLink :to="'/backend/' + backend">{{ backend }}</NuxtLink>
|
||||
: Info
|
||||
</span>
|
||||
|
||||
<div class="is-pulled-right">
|
||||
<div class="field is-grouped"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-12" v-if="info">
|
||||
<code class="box logs-container">
|
||||
{{ JSON.stringify(info, null, 2) }}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.logs-container {
|
||||
min-height: 40vh;
|
||||
overflow-y: auto;
|
||||
white-space: pre;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script setup>
|
||||
const backend = useRoute().params.backend
|
||||
const info = ref()
|
||||
|
||||
const loadContent = async () => {
|
||||
const response = await request(`/backend/${backend}/info`)
|
||||
info.value = await response.json()
|
||||
}
|
||||
|
||||
onMounted(() => loadContent())
|
||||
|
||||
</script>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">
|
||||
<NuxtLink to="/backends">Backends</NuxtLink>
|
||||
-
|
||||
@@ -11,8 +11,7 @@
|
||||
<div class="is-pulled-right">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<button class="button is-info" @click.prevent="loadContent" :disabled="isLoading"
|
||||
:class="{'is-loading':isLoading}">
|
||||
<button class="button is-info" @click="loadContent" :disabled="isLoading" :class="{'is-loading':isLoading}">
|
||||
<span class="icon"><i class="fas fa-sync"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
@@ -25,16 +24,11 @@
|
||||
</div>
|
||||
|
||||
<div class="column is-12" v-if="items.length < 1">
|
||||
<Message message_class="has-background-info-90 has-text-dark" title="No Libraries">
|
||||
<span class="icon-text" v-if="isLoading">
|
||||
<span class="icon"><i class="fas fa-spinner fa-spin"></i></span>
|
||||
<span>Loading libraries list. Please wait...</span>
|
||||
</span>
|
||||
<span class="icon-text" v-else>
|
||||
<span class="icon"><i class="fas fa-info-circle"></i></span>
|
||||
<span>No libraries found in the backend.</span>
|
||||
</span>
|
||||
</Message>
|
||||
<Message message_class="has-background-info-90 has-text-dark" title="Loading" icon="fas fa-spinner fa-spin"
|
||||
message="Loading libraries list. Please wait..." v-if="isLoading"/>
|
||||
<Message v-else message_class="has-background-warning-80 has-text-dark" title="Warning"
|
||||
icon="fas fa-exclamation-circle"
|
||||
message="WatchState was unable to get any libraries from the backend."/>
|
||||
</div>
|
||||
|
||||
<div class="column is-6" v-for="item in items" :key="`library-${item.id}`">
|
||||
@@ -82,31 +76,14 @@
|
||||
</div>
|
||||
|
||||
<div class="column is-12">
|
||||
<Message message_class="has-background-info-90 has-text-dark">
|
||||
<div class="is-pulled-right">
|
||||
<NuxtLink @click="show_page_tips=false" v-if="show_page_tips">
|
||||
<span class="icon"><i class="fas fa-arrow-up"></i></span>
|
||||
<span>Close</span>
|
||||
</NuxtLink>
|
||||
<NuxtLink @click="show_page_tips=true" v-else>
|
||||
<span class="icon"><i class="fas fa-arrow-down"></i></span>
|
||||
<span>Open</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<h5 class="title is-5 is-unselectable">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-info-circle"></i></span>
|
||||
<span>Tips</span>
|
||||
</span>
|
||||
</h5>
|
||||
<div class="content" v-if="show_page_tips">
|
||||
<ul>
|
||||
<li>Ignoring library will prevent any content from being added to the local database from that library
|
||||
during import process, and via webhook events.
|
||||
</li>
|
||||
<li>Libraries that shows <code>Supported: No</code> will not be processed by the system.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Message message_class="has-background-info-90 has-text-dark" title="Tips" icon="fas fa-info-circle"
|
||||
:toggle="show_page_tips" @toggle="show_page_tips = !show_page_tips" :use-toggle="true">
|
||||
<ul>
|
||||
<li>Ignoring library will prevent any content from being added to the local database from the library
|
||||
during import process, and webhook events handling.
|
||||
</li>
|
||||
<li>Libraries that shows <code>Supported: No</code> will not be processed by <code>WatchState</code>.</li>
|
||||
</ul>
|
||||
</Message>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,162 +1,132 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">
|
||||
<NuxtLink to="/backends">Backends</NuxtLink>
|
||||
-
|
||||
<NuxtLink :to="'/backend/' + backend">{{ backend }}</NuxtLink>
|
||||
: Mismatched
|
||||
: Misidentified
|
||||
</span>
|
||||
|
||||
<div class="is-pulled-right" v-if="hasLooked">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<button class="button is-info" @click.prevent="loadContent" :disabled="isLoading"
|
||||
:class="{'is-loading':isLoading}">
|
||||
<button class="button is-info" @click="loadContent" :disabled="isLoading" :class="{'is-loading':isLoading}">
|
||||
<span class="icon"><i class="fas fa-sync"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="subtitle is-hidden-mobile">
|
||||
This page will show items that <code>WatchState</code> thinks are possible mismatches.
|
||||
This page will show items that <code>WatchState</code> thinks are possibly mis-identified in your backend.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-if="false === hasLooked">
|
||||
<div class="column is-12" v-if="false === hasLooked">
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
<p class="card-header-title is-justify-center">Request Analyze</p>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
<div class="content">
|
||||
<ul>
|
||||
<li>
|
||||
Checking the items will take time, you will see the spinner while <code>WatchState</code> is analyzing
|
||||
the entire backend libraries content. Do not reload the page.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-fullwidth is-primary" @click="loadContent" :disabled="isLoading">
|
||||
<span class="icon"><i class="fas fa-check"></i></span>
|
||||
<span>Initiate The process</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-12" v-if="items.length < 1">
|
||||
<Message v-if="isLoading" message_class="is-background-info-90 has-text-dark"
|
||||
title="Analyzing" icon="fas fa-spinner fa-spin"
|
||||
message="Analyzing the backend content. Please wait. It will take a while..."/>
|
||||
<Message v-else-if="!isLoading && hasLooked" message_class="has-background-success-90 has-text-dark"
|
||||
title="Success!" icon="fas fa-check"
|
||||
message="WatchState did not find any possible mismatched items in the libraries we looked at."/>
|
||||
</div>
|
||||
|
||||
<template v-if="items.length > 1">
|
||||
<div class="column is-12">
|
||||
<Message class="has-background-warning-80 has-text-dark" title="Warning" icon="fas fa-exclamation-triangle"
|
||||
message="WatchState found some items that might be mis-identified in your backend. Please review the results."/>
|
||||
</div>
|
||||
|
||||
<div class="column is-6" v-for="item in items">
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
<p class="card-header-title is-justify-center">Request Analyze</p>
|
||||
<p class="card-header-title is-text-overflow">
|
||||
<NuxtLink target="_blank" :to="item.webUrl" v-if="item.webUrl" v-text="item.title"/>
|
||||
<span v-else>{{ item.title }}</span>
|
||||
</p>
|
||||
<div class="card-header-icon" @click="item.showItem = !item.showItem">
|
||||
<span class="icon has-tooltip">
|
||||
<i class="fas fa-film" :class="{'fa-film': 'Movie' === item.type,'fa-tv': 'Movie' !== item.type}"></i>
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
<div class="content">
|
||||
<ul>
|
||||
<li>
|
||||
Checking the items will take time, you will see the spinner while <code>WatchState</code> is analyzing
|
||||
the entire backend libraries content. Do not reload the page.
|
||||
</li>
|
||||
</ul>
|
||||
<div class="columns is-mobile is-multiline">
|
||||
<div class="column is-6">
|
||||
<strong class="is-unselectable">Library:</strong> {{ item.library }}
|
||||
</div>
|
||||
<div class="column is-6 has-text-right">
|
||||
<strong class="is-unselectable">Type:</strong> {{ item.type }}
|
||||
</div>
|
||||
<div class="column is-6">
|
||||
<strong class="is-unselectable">Year:</strong> {{ item.year ?? '???' }}
|
||||
</div>
|
||||
<div class="column is-6 has-text-right">
|
||||
<strong class="is-unselectable">Percent:</strong> <span :class="percentColor(item.percent)">
|
||||
{{ item.percent.toFixed(2) }}%
|
||||
</span>
|
||||
</div>
|
||||
<div class="column is-12" v-if="item.path"
|
||||
@click="(e) => e.target.firstChild?.classList?.toggle('is-text-overflow')">
|
||||
<div class="is-text-overflow">
|
||||
<strong class="is-unselectable">Path: </strong>
|
||||
<NuxtLink :to="makeSearchLink('path',item.path)" v-text="item.path"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-fullwidth is-primary" @click="loadContent" :disabled="isLoading">
|
||||
<span class="icon"><i class="fas fa-check"></i></span>
|
||||
<span>Initiate The process</span>
|
||||
</button>
|
||||
<div class="card-content p-0 m-0" v-if="item?.showItem">
|
||||
<pre><code>{{ JSON.stringify(item, null, 2) }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div class="column is-12" v-if="isLoading && items.length < 1">
|
||||
<Message message_class="is-info" title="Analyzing">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-spinner fa-spin"></i></span>
|
||||
<span>Analyzing the backend content. Please wait. It will take a while...</span>
|
||||
</span>
|
||||
</Message>
|
||||
</div>
|
||||
<div class="column is-12" v-else-if="hasLooked && items.length < 1">
|
||||
<Message message_class="has-background-success-90 has-text-dark" title="Success!">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-check"></i></span>
|
||||
<span>WatchState did not find possible mismatched items in the libraries we looked at.</span>
|
||||
</span>
|
||||
</Message>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<div class="column is-12">
|
||||
<h1 class="title is-4">
|
||||
<span class="icon-text">
|
||||
<span class="icon has-text-warning"><i class="fas fa-exclamation-triangle"></i></span>
|
||||
<span>Possible Mismatches</span>
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="column is-6" v-for="item in items">
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
<p class="card-header-title is-text-overflow">
|
||||
<NuxtLink target="_blank" :to="item.webUrl" v-if="item.webUrl" v-text="item.title"/>
|
||||
<span v-else>{{ item.title }}</span>
|
||||
</p>
|
||||
<div class="card-header-icon" @click="item.showItem = !item.showItem">
|
||||
<span class="icon has-tooltip">
|
||||
<i class="fas fa-film" :class="{'fa-film': 'Movie' === item.type,'fa-tv': 'Movie' !== item.type}"></i>
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
<div class="columns is-mobile is-multiline">
|
||||
<div class="column is-6">
|
||||
<strong class="is-unselectable">Library:</strong> {{ item.library }}
|
||||
</div>
|
||||
<div class="column is-6 has-text-right">
|
||||
<strong class="is-unselectable">Type:</strong> {{ item.type }}
|
||||
</div>
|
||||
<div class="column is-6">
|
||||
<strong class="is-unselectable">Year:</strong> {{ item.year ?? '???' }}
|
||||
</div>
|
||||
<div class="column is-6 has-text-right">
|
||||
<strong class="is-unselectable">Percent:</strong> <span :class="percentColor(item.percent)">
|
||||
{{ item.percent.toFixed(2) }}%
|
||||
</span>
|
||||
</div>
|
||||
<div class="column is-12" v-if="item.path"
|
||||
@click="(e) => e.target.firstChild?.classList?.toggle('is-text-overflow')">
|
||||
<div class="is-text-overflow">
|
||||
<strong class="is-unselectable">Path: </strong>
|
||||
<NuxtLink :to="makeSearchLink('path',item.path)" v-text="item.path"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-content p-0 m-0" v-if="item?.showItem">
|
||||
<pre><code>{{ JSON.stringify(item, null, 2) }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
|
||||
<div class="column is-12">
|
||||
<Message message_class="has-background-info-90 has-text-dark">
|
||||
<div class="is-pulled-right">
|
||||
<NuxtLink @click="show_page_tips=false" v-if="show_page_tips">
|
||||
<span class="icon"><i class="fas fa-arrow-up"></i></span>
|
||||
<span>Close</span>
|
||||
</NuxtLink>
|
||||
<NuxtLink @click="show_page_tips=true" v-else>
|
||||
<span class="icon"><i class="fas fa-arrow-down"></i></span>
|
||||
<span>Open</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<h5 class="title is-5 is-unselectable">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-info-circle"></i></span>
|
||||
<span>Tips</span>
|
||||
</span>
|
||||
</h5>
|
||||
<div class="content" v-if="show_page_tips">
|
||||
<ul>
|
||||
<li>
|
||||
This service expects standard plex naming conventions. So if you libraries doesn't follow the same
|
||||
conventions, you will see a lot of items being reported as mismatches.
|
||||
</li>
|
||||
<li>
|
||||
If you see a lot of mismatches, you might want to check the that the source directory matches the item.
|
||||
</li>
|
||||
<li>
|
||||
Clicking on the icon next to the title will show you the raw data that was used to generate the report.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Message message_class="has-background-info-90 has-text-dark" :toggle="show_page_tips"
|
||||
@toggle="show_page_tips = !show_page_tips" :use-toggle="true" title="Tips" icon="fas fa-info-circle">
|
||||
<ul>
|
||||
<li>
|
||||
This service expects standard plex naming conventions
|
||||
<NuxtLink target="_blank" to="https://support.plex.tv/articles/naming-and-organizing-your-tv-show-files/"
|
||||
v-text="'for series'"/>
|
||||
, and
|
||||
<NuxtLink target="_blank"
|
||||
to="https://support.plex.tv/articles/naming-and-organizing-your-movie-media-files/"
|
||||
v-text="'for movies'"/>
|
||||
. So if you libraries doesn't follow the same conventions, you will see a lot of items being reported as
|
||||
misidentified.
|
||||
</li>
|
||||
<li>
|
||||
If you see a lot of misidentified items, you might want to check the that the source directory matches the
|
||||
item.
|
||||
</li>
|
||||
<li>
|
||||
Clicking on the icon next to the title will show you the raw data that was used to generate the report.
|
||||
</li>
|
||||
</ul>
|
||||
</Message>
|
||||
</div>
|
||||
</div>
|
||||
@@ -165,6 +135,7 @@
|
||||
<script setup>
|
||||
import {makeSearchLink, notification} from "~/utils/index.js";
|
||||
import {useStorage} from "@vueuse/core";
|
||||
import Message from "~/components/Message.vue";
|
||||
|
||||
const backend = useRoute().params.backend
|
||||
const items = ref([])
|
||||
@@ -172,6 +143,7 @@ const isLoading = ref(false)
|
||||
const hasLooked = ref(false)
|
||||
const show_page_tips = useStorage('show_page_tips', true)
|
||||
|
||||
useHead({title: `Backends: ${backend} - Misidentified items`})
|
||||
const loadContent = async () => {
|
||||
hasLooked.value = true
|
||||
isLoading.value = true
|
||||
@@ -181,30 +153,20 @@ const loadContent = async () => {
|
||||
|
||||
try {
|
||||
response = await request(`/backend/${backend}/mismatched`)
|
||||
} catch (e) {
|
||||
isLoading.value = false
|
||||
return notification('error', 'Error', e.message)
|
||||
}
|
||||
|
||||
try {
|
||||
json = await response.json()
|
||||
} catch (e) {
|
||||
json = {
|
||||
error: {
|
||||
code: response.status,
|
||||
message: response.statusText
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
notification('error', 'Error', `${json.error.code ?? response.status}: ${json.error.message ?? response.statusText}`)
|
||||
return
|
||||
}
|
||||
|
||||
items.value = json
|
||||
} catch (e) {
|
||||
hasLooked.value = false
|
||||
return notification('error', 'Error', e.message)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
isLoading.value = false
|
||||
|
||||
if (!response.ok) {
|
||||
notification('error', 'Error', `${json.error.code}: ${json.error.message}`)
|
||||
return
|
||||
}
|
||||
|
||||
items.value = json
|
||||
}
|
||||
|
||||
const percentColor = (percent) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<span class="title is-4 is-unselectable">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">
|
||||
<NuxtLink to="/backends">Backends</NuxtLink>
|
||||
-
|
||||
<NuxtLink :to="'/backend/' + backend">{{ backend }}</NuxtLink>
|
||||
@@ -10,15 +10,14 @@
|
||||
<div class="is-pulled-right">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<button class="button is-info" @click.prevent="searchContent">
|
||||
<span class="icon">
|
||||
<i class="fas fa-sync"></i>
|
||||
</span>
|
||||
<button class="button is-info" @click="searchContent" :disabled="isLoading || !searchField || !query"
|
||||
:class="{'is-loading':isLoading}">
|
||||
<span class="icon"><i class="fas fa-sync"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="is-hidden-mobile is-unselectable">
|
||||
<div class="is-hidden-mobile">
|
||||
<span class="subtitle">This page search the remote backend data not the locally stored data.</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -89,27 +88,16 @@
|
||||
</div>
|
||||
|
||||
<div class="column is-12" v-if="items?.length<1 && hasSearched">
|
||||
<Message message_class="is-info" v-if="true === isLoading">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-spinner fa-pulse"></i></span>
|
||||
<span>Loading data please wait...</span>
|
||||
</span>
|
||||
</Message>
|
||||
<Message v-else class="has-background-warning-80 has-text-dark">
|
||||
<button v-if="query" class="delete" @click="clearSearch"></button>
|
||||
|
||||
<div class="icon-text">
|
||||
<span class="icon"><i class="fas fa-info"></i></span>
|
||||
<Message v-if="isLoading" message_class="is-background-info-90 has-text-dark" icon="fas fa-spinner fa-spin"
|
||||
title="Loading" message="Loading data please wait..."/>
|
||||
<Message v-else class="has-background-warning-80 has-text-dark" title="Warning"
|
||||
icon="fas fa-exclamation-triangle" :use-close="true" @close="clearSearch">
|
||||
<span v-if="error?.message" v-text="error.message"></span>
|
||||
<template v-else>
|
||||
<span>No items found.</span>
|
||||
<span v-if="query">For <code><strong>{{ searchField }}</strong> : <strong>{{ query }}</strong></code></span>
|
||||
</div>
|
||||
<template v-if="error">
|
||||
<div class="content mt-4">
|
||||
<h5 class="has-text-dark">API Response ({{ error?.code ?? 0 }})</h5>
|
||||
<code class="is-pre-wrap is-block mt-4">
|
||||
{{ error?.message ?? error }}
|
||||
</code>
|
||||
</div>
|
||||
<span v-if="query">
|
||||
Search query <code><strong>{{ searchField }}</strong> : <strong>{{ query }}</strong></code>
|
||||
</span>
|
||||
</template>
|
||||
</Message>
|
||||
</div>
|
||||
@@ -141,9 +129,11 @@
|
||||
</div>
|
||||
<div class="column is-12 is-clickable has-text-left" v-if="item?.path"
|
||||
@click="(e) => e.target.firstChild?.classList?.toggle('is-text-overflow')">
|
||||
<span class="icon"><i class="fas fa-file"></i></span>
|
||||
<span class="is-hidden-mobile">Path: </span>
|
||||
<NuxtLink :to="makeSearchLink('path',item.path)" v-text="item.path"/>
|
||||
<div class="is-text-overflow">
|
||||
<span class="icon"><i class="fas fa-file"></i></span>
|
||||
<span class="is-hidden-mobile">Path: </span>
|
||||
<NuxtLink :to="makeSearchLink('path',item.path)" v-text="item.path"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -184,37 +174,20 @@
|
||||
</div>
|
||||
|
||||
<div class="column is-12">
|
||||
<Message message_class="has-background-info-90 has-text-dark">
|
||||
<div class="is-pulled-right">
|
||||
<NuxtLink @click="show_page_tips=false" v-if="show_page_tips">
|
||||
<span class="icon"><i class="fas fa-arrow-up"></i></span>
|
||||
<span>Close</span>
|
||||
</NuxtLink>
|
||||
<NuxtLink @click="show_page_tips=true" v-else>
|
||||
<span class="icon"><i class="fas fa-arrow-down"></i></span>
|
||||
<span>Open</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<h5 class="title is-5 is-unselectable">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-info-circle"></i></span>
|
||||
<span>Tips</span>
|
||||
</span>
|
||||
</h5>
|
||||
<div class="content" v-if="show_page_tips">
|
||||
<ul>
|
||||
<li>
|
||||
Items with <code>Referenced locally</code> link are items we were able to find local match for. While
|
||||
items with <code>Not referenced locally</code> are items we were not able to link locally.
|
||||
</li>
|
||||
<li>
|
||||
The items shown here are from the remote backend data queried directly.
|
||||
</li>
|
||||
<li>Clicking directly on the <code>item title</code> will take you to the page associated with that link in
|
||||
the backend. While clicking <code>Referenced locally</code> will take you to the local item page.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Message message_class="has-background-info-90 has-text-dark" title="Tips" icon="fas fa-info-circle"
|
||||
:toggle="show_page_tips" @toggle="show_page_tips = !show_page_tips" :use-toggle="true">
|
||||
<ul>
|
||||
<li>
|
||||
Items with <code>Referenced locally</code> link are items we were able to find local match for. While
|
||||
items with <code>Not referenced locally</code> are items we were not able to link locally.
|
||||
</li>
|
||||
<li>
|
||||
The items shown here are from the remote backend data queried directly.
|
||||
</li>
|
||||
<li>Clicking directly on the <code>item title</code> will take you to the page associated with that link in
|
||||
the backend. While clicking <code>Referenced locally</code> will take you to the local item page.
|
||||
</li>
|
||||
</ul>
|
||||
</Message>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">
|
||||
<NuxtLink to="/backends">Backends</NuxtLink>
|
||||
-
|
||||
@@ -11,8 +11,7 @@
|
||||
<div class="is-pulled-right">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<button class="button is-info" @click.prevent="loadContent" :disabled="isLoading"
|
||||
:class="{'is-loading':isLoading}">
|
||||
<button class="button is-info" @click="loadContent" :disabled="isLoading" :class="{'is-loading':isLoading}">
|
||||
<span class="icon"><i class="fas fa-sync"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
@@ -25,18 +24,10 @@
|
||||
</div>
|
||||
|
||||
<div class="column is-12" v-if="items.length < 1">
|
||||
<Message message_class="is-info" title="Loading..." v-if="isLoading">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-spinner fa-spin"></i></span>
|
||||
<span>Requesting active play sessions. Please wait...</span>
|
||||
</span>
|
||||
</Message>
|
||||
<Message message_class="has-background-success-90 has-text-dark" title="Information" v-else>
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-check"></i></span>
|
||||
<span>There are no active play sessions currently running.</span>
|
||||
</span>
|
||||
</Message>
|
||||
<Message message_class="is-background-info-90 has-text-dark" title="Loading" icon="fas fa-spinner fa-spin"
|
||||
v-if="isLoading" message="Requesting active play sessions. Please wait..."/>
|
||||
<Message v-else message_class="has-background-success-90 has-text-dark" title="Information"
|
||||
icon="fa fa-info-circle" message="There are no active play sessions currently running."/>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="column is-12">
|
||||
@@ -122,6 +113,4 @@ const makeItemLink = (item) => {
|
||||
return `/history?${params.toString()}`
|
||||
}
|
||||
onMounted(async () => loadContent())
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">
|
||||
<NuxtLink to="/backends">Backends</NuxtLink>
|
||||
-
|
||||
<NuxtLink :to="'/backend/' + backend">{{ backend }}</NuxtLink>
|
||||
: Unmatched
|
||||
</span>
|
||||
|
||||
<div class="is-pulled-right" v-if="hasLooked">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
@@ -18,127 +17,112 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="subtitle is-hidden-mobile">
|
||||
In this page you will find items <code>WatchState</code> knows that are un-matched in your backend.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-if="false === hasLooked">
|
||||
<div class="column is-12">
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
<p class="card-header-title is-justify-center">Request Analyze</p>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
<div class="content">
|
||||
<ul>
|
||||
<li>
|
||||
Checking the items will take time, you will see the spinner while <code>WatchState</code> is analyzing
|
||||
the entire backend libraries content. Do not reload the page.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-fullwidth is-primary" @click="loadContent" :disabled="isLoading">
|
||||
<span class="icon"><i class="fas fa-check"></i></span>
|
||||
<span>Initiate The process</span>
|
||||
</button>
|
||||
<div class="column is-12" v-if="false === hasLooked">
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
<p class="card-header-title is-justify-center">Request Analyze</p>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
<div class="content">
|
||||
<ul>
|
||||
<li>
|
||||
Checking the items will take time, you will see the spinner while <code>WatchState</code> is analyzing
|
||||
the entire backend libraries content. Do not reload the page.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="column is-12" v-if="isLoading && items.length < 1">
|
||||
<Message message_class="is-info" title="Analyzing">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-spinner fa-spin"></i></span>
|
||||
<span>Analyzing the backend content. Please wait. It will take a while...</span>
|
||||
</span>
|
||||
</Message>
|
||||
</div>
|
||||
<div class="column is-12" v-else-if="hasLooked && items.length < 1">
|
||||
<Message message_class="has-background-success-90 has-text-dark" title="Success!">
|
||||
<span class="icon-text">
|
||||
<div class="control">
|
||||
<button class="button is-fullwidth is-primary" @click="loadContent" :disabled="isLoading">
|
||||
<span class="icon"><i class="fas fa-check"></i></span>
|
||||
<span>There are no unmatched content in the libraries we looked at.</span>
|
||||
</span>
|
||||
</Message>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<div class="column is-12">
|
||||
<h1 class="title is-4">
|
||||
<span class="icon-text">
|
||||
<span class="icon has-text-danger"><i class="fas fa-exclamation-triangle"></i></span>
|
||||
<span>Unmatched Content</span>
|
||||
</span>
|
||||
</h1>
|
||||
<span>Initiate The process</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-6" v-for="item in items">
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
<p class="card-header-title is-text-overflow">
|
||||
<NuxtLink target="_blank" :to="item.webUrl ?? item.url">{{ item.title }}</NuxtLink>
|
||||
</p>
|
||||
<div class="card-header-icon" @click="item.showItem = !item.showItem">
|
||||
<span class="icon has-tooltip" v-tooltip="'Toggle raw data'">
|
||||
<i class="fas fa-film" :class="{'fa-film': 'Movie' === item.type,'fa-tv': 'Movie' !== item.type}"></i>
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
<div class="columns is-mobile is-multiline">
|
||||
<div class="column is-6">
|
||||
<strong class="is-unselectable">Library:</strong> {{ item.library ?? 'Unknown' }}
|
||||
</div>
|
||||
<div class="column is-6 has-text-right">
|
||||
<strong class="is-unselectable">Type:</strong> <span class="is-capitalized">{{
|
||||
item.type ?? 'Unknown'
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="column is-6" v-if="0 !== item.year && item.year">
|
||||
<strong class="is-unselectable">Year:</strong> {{ item.year ?? 'Unknown' }}
|
||||
</div>
|
||||
<div class="column is-12 is-clickable has-text-left" v-if="item?.path"
|
||||
@click="(e) => e.target.firstChild?.classList?.toggle('is-text-overflow')">
|
||||
<div class="is-text-overflow">
|
||||
<strong class="is-unselectable">Path: </strong>
|
||||
<NuxtLink :to="makeSearchLink('path',item.path)" v-text="item.path"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-12" v-if="items.length < 1">
|
||||
<Message v-if="isLoading" message_class="has-background-info-90 has-text-dark"
|
||||
title="Analyzing" icon="fas fa-spinner fa-spin"
|
||||
message="Analyzing the backend content. Please wait. It will take a while..."/>
|
||||
<Message v-if="!isLoading && hasLooked" message_class="has-background-success-90 has-text-dark"
|
||||
title="Success!" icon="fas fa-check"
|
||||
message="WatchState did not find any unmatched content in the libraries we looked at."/>
|
||||
</div>
|
||||
|
||||
<div class="column is-12" v-if="items.length > 1">
|
||||
<h1 class="title is-4">
|
||||
<span class="icon-text">
|
||||
<span class="icon has-text-danger"><i class="fas fa-exclamation-triangle"></i></span>
|
||||
<span>Unmatched Content</span>
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="column is-6" v-for="item in items">
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
<p class="card-header-title is-text-overflow">
|
||||
<NuxtLink target="_blank" :to="item.webUrl ?? item.url">{{ item.title }}</NuxtLink>
|
||||
</p>
|
||||
<div class="card-header-icon" @click="item.showItem = !item.showItem">
|
||||
<span class="icon has-tooltip" v-tooltip="'Toggle raw data'">
|
||||
<i class="fas fa-film" :class="{'fa-film': 'Movie' === item.type,'fa-tv': 'Movie' !== item.type}"></i>
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
<div class="columns is-mobile is-multiline">
|
||||
<div class="column is-6">
|
||||
<strong class="is-unselectable">Library:</strong> {{ item.library ?? 'Unknown' }}
|
||||
</div>
|
||||
<div class="card-content p-0 m-0" v-if="item?.showItem">
|
||||
<pre><code>{{ JSON.stringify(item, null, 2) }}</code></pre>
|
||||
<div class="column is-6 has-text-right">
|
||||
<strong class="is-unselectable">Type:</strong> <span class="is-capitalized">{{
|
||||
item.type ?? 'Unknown'
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="card-footer-item">
|
||||
<NuxtLink target="_blank" :to="`https://www.imdb.com/find/?q=${fixTitle(item.title)}`">
|
||||
<span class="icon"><i class="fas fa-search"></i></span>
|
||||
<span>IMDb</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<div class="card-footer-item">
|
||||
<NuxtLink target="_blank" :to="`https://www.themoviedb.org/search?query=${fixTitle(item.title)}`">
|
||||
<span class="icon"><i class="fas fa-search"></i></span>
|
||||
<span>TMDB</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<div class="card-footer-item">
|
||||
<NuxtLink target="_blank" :to="`https://thetvdb.com/search?query=${fixTitle(item.title)}`">
|
||||
<span class="icon"><i class="fas fa-search"></i></span>
|
||||
<span>TVDB</span>
|
||||
</NuxtLink>
|
||||
<div class="column is-6" v-if="0 !== item.year && item.year">
|
||||
<strong class="is-unselectable">Year:</strong> {{ item.year ?? 'Unknown' }}
|
||||
</div>
|
||||
<div class="column is-12 is-clickable has-text-left" v-if="item?.path"
|
||||
@click="(e) => e.target.firstChild?.classList?.toggle('is-text-overflow')">
|
||||
<div class="is-text-overflow">
|
||||
<strong class="is-unselectable">Path: </strong>
|
||||
<NuxtLink :to="makeSearchLink('path',item.path)" v-text="item.path"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<div class="card-content p-0 m-0" v-if="item?.showItem">
|
||||
<pre><code>{{ JSON.stringify(item, null, 2) }}</code></pre>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="card-footer-item">
|
||||
<NuxtLink target="_blank" :to="`https://www.imdb.com/find/?q=${fixTitle(item.title)}`">
|
||||
<span class="icon"><i class="fas fa-search"></i></span>
|
||||
<span>IMDb</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<div class="card-footer-item">
|
||||
<NuxtLink target="_blank" :to="`https://www.themoviedb.org/search?query=${fixTitle(item.title)}`">
|
||||
<span class="icon"><i class="fas fa-search"></i></span>
|
||||
<span>TMDB</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<div class="card-footer-item">
|
||||
<NuxtLink target="_blank" :to="`https://thetvdb.com/search?query=${fixTitle(item.title)}`">
|
||||
<span class="icon"><i class="fas fa-search"></i></span>
|
||||
<span>TVDB</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -150,6 +134,8 @@ const items = ref([])
|
||||
const isLoading = ref(false)
|
||||
const hasLooked = ref(false)
|
||||
|
||||
useHead({title: `Backends: ${backend} - Unmatched items.`})
|
||||
|
||||
const loadContent = async () => {
|
||||
hasLooked.value = true
|
||||
isLoading.value = true
|
||||
|
||||
@@ -1,43 +1,35 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">
|
||||
<NuxtLink to="/backends">Backends</NuxtLink>
|
||||
-
|
||||
<NuxtLink :to="'/backend/' + backend">{{ backend }}</NuxtLink>
|
||||
: Users
|
||||
</span>
|
||||
|
||||
<div class="is-pulled-right">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<button class="button is-info" @click.prevent="loadContent" :disabled="isLoading"
|
||||
:class="{'is-loading':isLoading}">
|
||||
<button class="button is-info" @click="loadContent" :disabled="isLoading" :class="{'is-loading':isLoading}">
|
||||
<span class="icon"><i class="fas fa-sync"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="subtitle is-hidden-mobile">
|
||||
Show all users that are available in the backend.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-12" v-if="items.length < 1">
|
||||
<Message message_class="has-background-info-90 has-text-dark" title="No Libraries">
|
||||
<span class="icon-text" v-if="isLoading">
|
||||
<span class="icon"><i class="fas fa-spinner fa-spin"></i></span>
|
||||
<span>Loading users list. Please wait...</span>
|
||||
</span>
|
||||
<span class="icon-text" v-else>
|
||||
<span class="icon"><i class="fas fa-info-circle"></i></span>
|
||||
<span>No users found in the backend. This is expected if the backend is plex and the token is limited.</span>
|
||||
</span>
|
||||
</Message>
|
||||
<Message message_class="has-background-info-90 has-text-dark" title="Loading" icon="fas fa-spinner fa-spin"
|
||||
message="Loading users list. Please wait..." v-if="isLoading"/>
|
||||
<Message v-else message_class="has-background-warning-80 has-text-dark" title="Warning"
|
||||
icon="fas fa-exclamation-circle"
|
||||
message="WatchState was unable to get any users from the backend. This is expected if the backend is plex and the token is limited."/>
|
||||
</div>
|
||||
|
||||
<div class="column is-6" v-for="item in items" :key="`library-${item.id}`">
|
||||
<div class="column is-6" v-for="item in items" :key="`users-${item.id}`">
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
<p class="card-header-title is-text-overflow">
|
||||
@@ -76,24 +68,9 @@
|
||||
</div>
|
||||
|
||||
<div class="column is-12">
|
||||
<Message message_class="has-background-info-90 has-text-dark">
|
||||
<div class="is-pulled-right">
|
||||
<NuxtLink @click="show_page_tips=false" v-if="show_page_tips">
|
||||
<span class="icon"><i class="fas fa-arrow-up"></i></span>
|
||||
<span>Close</span>
|
||||
</NuxtLink>
|
||||
<NuxtLink @click="show_page_tips=true" v-else>
|
||||
<span class="icon"><i class="fas fa-arrow-down"></i></span>
|
||||
<span>Open</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<h5 class="title is-5 is-unselectable">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-info-circle"></i></span>
|
||||
<span>Tips</span>
|
||||
</span>
|
||||
</h5>
|
||||
<div class="content" v-if="show_page_tips">
|
||||
<Message message_class="has-background-info-90 has-text-dark" :toggle="show_page_tips"
|
||||
@toggle="show_page_tips = !show_page_tips" :use-toggle="true" title="Tips" icon="fas fa-info-circle">
|
||||
<div class="notification-content content" v-if="show_page_tips">
|
||||
<ul>
|
||||
<li>For <code>Plex</code> backends, if the <code>X-Plex-Token</code> is limited one, the users will not show
|
||||
up. This is a limitation of the Plex API.
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">Backends</span>
|
||||
<div class="is-pulled-right">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<button class="button is-primary" v-tooltip="'Add New Backend'" @click="toggleForm = !toggleForm">
|
||||
<button class="button is-primary" v-tooltip.bottom="'Add New Backend'"
|
||||
@click="toggleForm = !toggleForm" :disabled="isLoading">
|
||||
<span class="icon"><i class="fas fa-add"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
<p class="control">
|
||||
<button class="button is-info" @click.prevent="loadContent">
|
||||
<button class="button is-info" @click="loadContent" :disabled="isLoading" :class="{'is-loading':isLoading}">
|
||||
<span class="icon"><i class="fas fa-sync"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
@@ -25,16 +26,15 @@
|
||||
<BackendAdd @addBackend="toggleForm = false; loadContent()" :backends="backends"/>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="column is-12" v-if="backends.length<1 && !toggleForm">
|
||||
<Message message_class="is-warning" title="Warning">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-exclamation"></i></span>
|
||||
<span>
|
||||
No backends found. Please add new backends to start using the tool. You can add new backend by
|
||||
<NuxtLink @click="toggleForm=true" v-text="'clicking here'"/>
|
||||
or by clicking the <span class="icon is-small"><i class="fas fa-add"></i></span> button above.
|
||||
</span>
|
||||
</span>
|
||||
<div class="column is-12" v-if="backends.length<1">
|
||||
<Message v-if="isLoading" message_class="has-background-info-90 has-text-dark" title="Loading"
|
||||
icon="fas fa-spinner fa-spin" message="Requesting active play sessions. Please wait..."/>
|
||||
<Message v-else message_class="is-background-warning-80 has-text-dark" title="Warning"
|
||||
icon="fas fa-exclamation-circle">
|
||||
No backends found. Please add new backends to start using the tool. You can add new backend by
|
||||
<NuxtLink @click="toggleForm=true" v-text="'clicking here'"/>
|
||||
or by clicking the <span class="icon is-clickable" @click="toggleForm=true"><i class="fas fa-add"></i></span>
|
||||
button above.
|
||||
</Message>
|
||||
</div>
|
||||
|
||||
@@ -94,58 +94,41 @@
|
||||
</template>
|
||||
|
||||
<div class="column is-12">
|
||||
<Message message_class="has-background-info-90 has-text-dark">
|
||||
<div class="is-pulled-right">
|
||||
<NuxtLink @click="show_page_tips=false" v-if="show_page_tips">
|
||||
<span class="icon"><i class="fas fa-arrow-up"></i></span>
|
||||
<span>Close</span>
|
||||
</NuxtLink>
|
||||
<NuxtLink @click="show_page_tips=true" v-else>
|
||||
<span class="icon"><i class="fas fa-arrow-down"></i></span>
|
||||
<span>Open</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<h5 class="title is-5 is-unselectable">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-info-circle"></i></span>
|
||||
<span>Tips</span>
|
||||
</span>
|
||||
</h5>
|
||||
<div class="content" v-if="show_page_tips">
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Import</strong> means pulling data from the backends into the local database.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Export</strong> means pushing data from the local database to the backends.
|
||||
</li>
|
||||
<li>
|
||||
WatchState is single user tool. It doesn't support syncing multiple users play state.
|
||||
<NuxtLink target="_blank" v-text="'Visit this link'"
|
||||
to="https://github.com/arabcoders/watchstate/blob/master/FAQ.md#is-there-support-for-multi-user-setup"/>
|
||||
to learn more.
|
||||
</li>
|
||||
<li>
|
||||
If you are adding new backend that is fresh and doesn't have your correct watch state, you should
|
||||
turn off import and enable only metadata import at the start to prevent overriding your current play
|
||||
state.
|
||||
<NuxtLink
|
||||
to="https://github.com/arabcoders/watchstate/blob/master/FAQ.md#my-new-backend-overriding-my-old-backend-state--my-watch-state-is-not-correct"
|
||||
target="_blank" v-text="'Visit this link'"/>
|
||||
to learn more.
|
||||
</li>
|
||||
<li>
|
||||
Deleting backend is not available via <code>WebUI</code> yet. You can do it via the
|
||||
<NuxtLink :to="makeConsoleCommand('config:delete -n -s backend_name')">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-terminal"></i></span>
|
||||
<span>Console</span>
|
||||
</span>
|
||||
</NuxtLink>
|
||||
page, or using the the following command <code>config:delete -s backend_name</code> in shell.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Message message_class="has-background-info-90 has-text-dark" :toggle="show_page_tips"
|
||||
@toggle="show_page_tips = !show_page_tips" :use-toggle="true" title="Tips" icon="fas fa-info-circle">
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Import</strong> means pulling data from the backends into the local database.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Export</strong> means pushing data from the local database to the backends.
|
||||
</li>
|
||||
<li>
|
||||
WatchState is single user tool. It doesn't support syncing multiple users play state.
|
||||
<NuxtLink target="_blank" v-text="'Visit this link'"
|
||||
to="https://github.com/arabcoders/watchstate/blob/master/FAQ.md#is-there-support-for-multi-user-setup"/>
|
||||
to learn more.
|
||||
</li>
|
||||
<li>
|
||||
If you are adding new backend that is fresh and doesn't have your correct watch state, you should
|
||||
turn off import and enable only metadata import at the start to prevent overriding your current play
|
||||
state.
|
||||
<NuxtLink
|
||||
to="https://github.com/arabcoders/watchstate/blob/master/FAQ.md#my-new-backend-overriding-my-old-backend-state--my-watch-state-is-not-correct"
|
||||
target="_blank" v-text="'Visit this link'"/>
|
||||
to learn more.
|
||||
</li>
|
||||
<li>
|
||||
Deleting backend is not available via <code>WebUI</code> yet. You can do it via the
|
||||
<NuxtLink :to="makeConsoleCommand('config:delete -n -s backend_name')">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-terminal"></i></span>
|
||||
<span>Console</span>
|
||||
</span>
|
||||
</NuxtLink>
|
||||
page, or using the the following command <code>config:delete -s backend_name</code> in shell.
|
||||
</li>
|
||||
</ul>
|
||||
</Message>
|
||||
</div>
|
||||
</div>
|
||||
@@ -156,8 +139,9 @@ import 'assets/css/bulma-switch.css'
|
||||
import moment from 'moment'
|
||||
import request from '~/utils/request.js'
|
||||
import BackendAdd from '~/components/BackendAdd.vue'
|
||||
import {copyText, makeConsoleCommand} from '~/utils/index.js'
|
||||
import {copyText, makeConsoleCommand, notification} from '~/utils/index.js'
|
||||
import {useStorage} from "@vueuse/core";
|
||||
import Message from "~/components/Message.vue";
|
||||
|
||||
useHead({title: 'Backends'})
|
||||
|
||||
@@ -165,11 +149,19 @@ const backends = ref([])
|
||||
const toggleForm = ref(false)
|
||||
const api_url = useStorage('api_url', '')
|
||||
const show_page_tips = useStorage('show_page_tips', true)
|
||||
const isLoading = ref(false)
|
||||
|
||||
const loadContent = async () => {
|
||||
backends.value = []
|
||||
const response = await request('/backends')
|
||||
backends.value = await response.json()
|
||||
isLoading.value = true
|
||||
try {
|
||||
const response = await request('/backends')
|
||||
backends.value = await response.json()
|
||||
} catch (e) {
|
||||
notification('error', 'Error', `Failed to load backends. ${e.message}`)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => loadContent())
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<h1 class="title is-4">Console</h1>
|
||||
<div class="subtitle">
|
||||
You can execute <strong>non-interactive</strong> commands here. This interface is jailed to <code>console</code>
|
||||
@@ -69,44 +69,27 @@
|
||||
</div>
|
||||
|
||||
<div class="column is-12">
|
||||
<Message message_class="has-background-info-90 has-text-dark">
|
||||
<div class="is-pulled-right">
|
||||
<NuxtLink @click="show_page_tips=false" v-if="show_page_tips">
|
||||
<span class="icon"><i class="fas fa-arrow-up"></i></span>
|
||||
<span>Close</span>
|
||||
</NuxtLink>
|
||||
<NuxtLink @click="show_page_tips=true" v-else>
|
||||
<span class="icon"><i class="fas fa-arrow-down"></i></span>
|
||||
<span>Open</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<h5 class="title is-5 is-unselectable">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-info-circle"></i></span>
|
||||
<span>Tips</span>
|
||||
</span>
|
||||
</h5>
|
||||
<div class="content" v-if="show_page_tips">
|
||||
<ul>
|
||||
<li>
|
||||
You can also run a command from the task page by clicking on the <strong>Run via console</strong>. The
|
||||
command will be pre-filled for you.
|
||||
</li>
|
||||
<li>
|
||||
Clicking close connection does not stop the command. It only stops the output from being displayed. The
|
||||
command will continue to run until it finishes.
|
||||
</li>
|
||||
<li>
|
||||
The majority of the commands will not show any output unless error has occurred or important information
|
||||
needs to be communicated. To see all output, add the <code>-vvv</code> flag.
|
||||
</li>
|
||||
<li>
|
||||
There is no need to write <code>console</code> or <code>docker exec -ti watchstate console</code> Using
|
||||
this interface. Use the command followed by the options directly. For example, <code>db:list --output
|
||||
yaml</code>.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Message message_class="has-background-info-90 has-text-dark" :toggle="show_page_tips"
|
||||
@toggle="show_page_tips = !show_page_tips" :use-toggle="true" title="Tips" icon="fas fa-info-circle">
|
||||
<ul>
|
||||
<li>
|
||||
You can also run a command from the task page by clicking on the <strong>Run via console</strong>. The
|
||||
command will be pre-filled for you.
|
||||
</li>
|
||||
<li>
|
||||
Clicking close connection does not stop the command. It only stops the output from being displayed. The
|
||||
command will continue to run until it finishes.
|
||||
</li>
|
||||
<li>
|
||||
The majority of the commands will not show any output unless error has occurred or important information
|
||||
needs to be communicated. To see all output, add the <code>-vvv</code> flag.
|
||||
</li>
|
||||
<li>
|
||||
There is no need to write <code>console</code> or <code>docker exec -ti watchstate console</code> Using
|
||||
this interface. Use the command followed by the options directly. For example, <code>db:list --output
|
||||
yaml</code>.
|
||||
</li>
|
||||
</ul>
|
||||
</Message>
|
||||
</div>
|
||||
</div>
|
||||
@@ -114,8 +97,9 @@
|
||||
|
||||
<script setup>
|
||||
|
||||
import {useStorage} from "@vueuse/core";
|
||||
import {notification} from "~/utils/index.js";
|
||||
import {useStorage} from '@vueuse/core'
|
||||
import {notification} from '~/utils/index.js'
|
||||
import Message from '~/components/Message.vue'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<span id="env_page_title" class="title is-4">Environment Variables</span>
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span id="env_page_title" class="title is-4">Environment variables</span>
|
||||
<div class="is-pulled-right">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<button class="button is-primary" v-tooltip="'Add New Variable'" @click="toggleForm = !toggleForm">
|
||||
<button class="button is-primary" v-tooltip.bottom="'Add new variable'" @click="toggleForm = !toggleForm">
|
||||
<span class="icon">
|
||||
<i class="fas fa-add"></i>
|
||||
</span>
|
||||
@@ -13,9 +13,7 @@
|
||||
</p>
|
||||
<p class="control">
|
||||
<button class="button is-info" @click="loadContent">
|
||||
<span class="icon">
|
||||
<i class="fas fa-sync"></i>
|
||||
</span>
|
||||
<span class="icon"><i class="fas fa-sync"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
@@ -161,39 +159,22 @@
|
||||
</div>
|
||||
|
||||
<div class="column is-12">
|
||||
<Message message_class="has-background-info-90 has-text-dark">
|
||||
<div class="is-pulled-right">
|
||||
<NuxtLink @click="show_page_tips=false" v-if="show_page_tips">
|
||||
<span class="icon"><i class="fas fa-arrow-up"></i></span>
|
||||
<span>Close</span>
|
||||
</NuxtLink>
|
||||
<NuxtLink @click="show_page_tips=true" v-else>
|
||||
<span class="icon"><i class="fas fa-arrow-down"></i></span>
|
||||
<span>Open</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<h5 class="title is-5 is-unselectable">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-info-circle"></i></span>
|
||||
<span>Tips</span>
|
||||
</span>
|
||||
</h5>
|
||||
<div class="content" v-if="show_page_tips">
|
||||
<ul>
|
||||
<li>
|
||||
Some variables values are masked, to unmask them click on icon <i class="fa fa-unlock"></i>.
|
||||
</li>
|
||||
<li>
|
||||
Some values are too large to fit into the view, clicking on the value will show the full value.
|
||||
</li>
|
||||
<li>
|
||||
These environment variables are loaded from the <code>{{ file }}</code> file.
|
||||
</li>
|
||||
<li>
|
||||
To add a new variable click on the <i class="fa fa-add"></i> button.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Message message_class="has-background-info-90 has-text-dark" :toggle="show_page_tips"
|
||||
@toggle="show_page_tips = !show_page_tips" :use-toggle="true" title="Tips" icon="fas fa-info-circle">
|
||||
<ul>
|
||||
<li>
|
||||
Some variables values are masked, to unmask them click on icon <i class="fa fa-unlock"></i>.
|
||||
</li>
|
||||
<li>
|
||||
Some values are too large to fit into the view, clicking on the value will show the full value.
|
||||
</li>
|
||||
<li>
|
||||
These environment variables are loaded from the <code>{{ file }}</code> file.
|
||||
</li>
|
||||
<li>
|
||||
To add a new variable click on the <i class="fa fa-add"></i> button.
|
||||
</li>
|
||||
</ul>
|
||||
</Message>
|
||||
</div>
|
||||
</div>
|
||||
@@ -204,6 +185,7 @@ import 'assets/css/bulma-switch.css'
|
||||
import request from '~/utils/request.js'
|
||||
import {awaitElement, copyText, notification} from '~/utils/index.js'
|
||||
import {useStorage} from '@vueuse/core'
|
||||
import Message from "~/components/Message.vue"
|
||||
|
||||
useHead({title: 'Environment Variables'})
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">
|
||||
<NuxtLink to="/history">History</NuxtLink>
|
||||
: {{ data?.full_title ?? data?.title ?? id }}
|
||||
: {{ headerTitle }}
|
||||
</span>
|
||||
<div class="is-pulled-right" v-if="data?.via">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<button class="button" @click="toggleWatched"
|
||||
:class="{ 'is-success': !data.watched, 'is-danger': data.watched }"
|
||||
v-tooltip="'Toggle played/unplayed'">
|
||||
v-tooltip.bottom="'Toggle watch state'">
|
||||
<span class="icon">
|
||||
<i class="fas" :class="{'fa-eye-slash':data.watched,'fa-eye':!data.watched}"></i>
|
||||
</span>
|
||||
@@ -23,60 +23,46 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="subtitle" v-if="data?.via && getTitle !== data.title">
|
||||
{{ getTitle }}
|
||||
<div class="subtitle is-5" v-if="data?.via && headerTitle !== data?.title">
|
||||
<span class="icon">
|
||||
<i class="fas fa-tv" :class="{ 'fa-tv': 'episode' === data.type, 'fa-film': 'movie' === data.type }"></i>
|
||||
</span>
|
||||
{{ data?.title }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-12" v-if="!data?.via && isLoading">
|
||||
<Message>
|
||||
<span class="icon"><i class="fas fa-spinner fa-pulse"></i></span>
|
||||
<span>Loading data. Please wait...</span>
|
||||
</Message>
|
||||
<Message message_class="has-background-info-90 has-text-dark" title="Loading"
|
||||
icon="fas fa-spinner fa-spin" message="Loading data. Please wait..."/>
|
||||
</div>
|
||||
|
||||
<div class="column is-12" v-if="data?.not_reported_by && data.not_reported_by.length>0">
|
||||
<Message message_class="has-background-warning-80 has-text-dark">
|
||||
<div class="is-pulled-right">
|
||||
<NuxtLink @click="show_history_page_warning=false" v-if="show_history_page_warning">
|
||||
<span class="icon"><i class="fas fa-arrow-up"></i></span>
|
||||
<span>Close</span>
|
||||
</NuxtLink>
|
||||
<NuxtLink @click="show_history_page_warning=true" v-else>
|
||||
<span class="icon"><i class="fas fa-arrow-down"></i></span>
|
||||
<span>Open</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<h5 class="title is-5 is-unselectable">
|
||||
<Message message_class="has-background-warning-80 has-text-dark" icon="fas fa-exclamation-triangle"
|
||||
:toggle="show_history_page_warning" title="Warning" :use-toggle="true"
|
||||
@toggle="show_history_page_warning=!show_history_page_warning">
|
||||
<p>
|
||||
<span class="icon"><i class="fas fa-exclamation"></i></span>
|
||||
There are no metadata regarding this <strong>{{ data.type }}</strong> from (
|
||||
<span class="tag mr-1 has-text-dark" v-for="backend in data.not_reported_by" :key="`nr-${backend}`">
|
||||
<NuxtLink :to="`/backend/${backend}`" v-text="backend"/>
|
||||
</span>).
|
||||
</p>
|
||||
<h5 class="has-text-dark">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-exclamation-triangle"></i></span>
|
||||
<span>Warning</span>
|
||||
<span class="icon"><i class="fas fa-question-circle"></i></span>
|
||||
<span>Possible reasons</span>
|
||||
</span>
|
||||
</h5>
|
||||
<div class="content" v-if="show_history_page_warning">
|
||||
<p>
|
||||
<span class="icon"><i class="fas fa-exclamation"></i></span>
|
||||
There are no metadata regarding this <strong>{{ data.type }}</strong> from (
|
||||
<span class="tag mr-1" v-for="backend in data.not_reported_by" :key="`nr-${backend}`">
|
||||
<NuxtLink :to="`/backend/${backend}`" v-text="backend"/>
|
||||
</span>).
|
||||
</p>
|
||||
<h5 class="has-text-dark">Possible reasons:</h5>
|
||||
<ul>
|
||||
<li>Delayed import operation. Might be yet to be imported due to webhooks not being used, or the backend
|
||||
doesn't support webhooks.
|
||||
</li>
|
||||
<li>Item mismatched at the source backend.</li>
|
||||
<li>
|
||||
There are no matching <code>{{ 'episode' === data.type ? 'Series GUIDs' : 'GUIDs' }}</code> in common
|
||||
being reported, And thus it was treated as separate item.
|
||||
</li>
|
||||
</ul>
|
||||
<p class="has-text-danger-50">
|
||||
<span class="icon"><i class="fas fa-info"></i></span> To see if your media backends are reporting different
|
||||
metadata for the same file, click on the file link which will filter your history based on that file.
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li>Delayed import operation. Might be yet to be imported due to webhooks not being used, or the backend
|
||||
doesn't support webhooks.
|
||||
</li>
|
||||
<li>Item mismatched at the source backend.</li>
|
||||
<li>
|
||||
There are no matching <code>{{ 'episode' === data.type ? 'Series GUIDs' : 'GUIDs' }}</code> in common
|
||||
being reported, And thus it was treated as separate item.
|
||||
</li>
|
||||
</ul>
|
||||
</Message>
|
||||
</div>
|
||||
|
||||
@@ -406,48 +392,35 @@
|
||||
</div>
|
||||
|
||||
<div class="column is-12">
|
||||
<Message message_class="has-background-info-90 has-text-dark">
|
||||
<div class="is-pulled-right">
|
||||
<NuxtLink @click="show_page_tips=false" v-if="show_page_tips">
|
||||
<span class="icon"><i class="fas fa-arrow-up"></i></span>
|
||||
<span>Close</span>
|
||||
</NuxtLink>
|
||||
<NuxtLink @click="show_page_tips=true" v-else>
|
||||
<span class="icon"><i class="fas fa-arrow-down"></i></span>
|
||||
<span>Open</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<h5 class="title is-5 is-unselectable">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-info-circle"></i></span>
|
||||
<span>Tips</span>
|
||||
</span>
|
||||
</h5>
|
||||
<div class="content" v-if="show_page_tips">
|
||||
<ul>
|
||||
<li>Clicking on the ID in <code>metadata via</code> boxes will take you directly to the item in the source
|
||||
backend. While clicking on the GUIDs will take you to that source link, similarly clicking on the series
|
||||
GUIDs will take you to the series link that was provided by the external source.
|
||||
</li>
|
||||
<Message message_class="has-background-info-90 has-text-dark" :toggle="show_page_tips"
|
||||
@toggle="show_page_tips = !show_page_tips" :use-toggle="true" title="Tips" icon="fas fa-info-circle">
|
||||
<ul>
|
||||
<li>
|
||||
To see if your media backends are reporting different metadata for the same file, click on the file link
|
||||
which will filter your history based on that file.
|
||||
</li>
|
||||
<li>Clicking on the ID in <code>metadata via</code> boxes will take you directly to the item in the source
|
||||
backend. While clicking on the GUIDs will take you to that source link, similarly clicking on the series
|
||||
GUIDs will take you to the series link that was provided by the external source.
|
||||
</li>
|
||||
<li>
|
||||
<code>rGUIDSs</code> are relative globally unique identifiers for episodes based on <code>series
|
||||
GUID</code>. They are formatted as <code>GUID://seriesID/season_number/episode_number</code>. We use
|
||||
<code>rGUIDs</code>, to identify specific episode. This is more reliable than using episode specific
|
||||
<code>GUID</code>, as they are often misreported in the source data.
|
||||
</li>
|
||||
<template v-if="data?.not_reported_by && data.not_reported_by.length > 0">
|
||||
<li>
|
||||
<code>rGUIDSs</code> are relative globally unique identifiers for episodes based on <code>series
|
||||
GUID</code>. They are formatted as <code>GUID://seriesID/season_number/episode_number</code>. We use
|
||||
<code>rGUIDs</code>, to identify specific episode. This is more reliable than using episode specific
|
||||
<code>GUID</code>, as they are often misreported in the source data.
|
||||
The warning on top of the page usually is accurate, and it is recommended to check the backend metadata
|
||||
for the item.
|
||||
<template v-if="'episode' === data.type">
|
||||
For episodes, we use <code>rGUIDs</code> to identify the episode, and <strong>important part</strong>
|
||||
of that GUID is the <code>series GUID</code>. We need at least one reported series GUIDs to match
|
||||
between your backends. If none are matching, it will be treated as separate series.
|
||||
</template>
|
||||
</li>
|
||||
<template v-if="data?.not_reported_by && data.not_reported_by.length > 0">
|
||||
<li>
|
||||
The warning on top of the page usually is accurate, and it is recommended to check the backend metadata
|
||||
for the item.
|
||||
<template v-if="'episode' === data.type">
|
||||
For episodes, we use <code>rGUIDs</code> to identify the episode, and <strong>important part</strong>
|
||||
of that GUID is the <code>series GUID</code>. We need at least one reported series GUIDs to match
|
||||
between your backends. If none are matching, it will be treated as separate series.
|
||||
</template>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
</ul>
|
||||
</Message>
|
||||
</div>
|
||||
</div>
|
||||
@@ -458,6 +431,7 @@ import request from '~/utils/request.js'
|
||||
import {ag, formatDuration, makeGUIDLink, makeSearchLink, notification, ucFirst} from '~/utils/index.js'
|
||||
import moment from 'moment'
|
||||
import {useStorage} from "@vueuse/core";
|
||||
import Message from "~/components/Message.vue";
|
||||
|
||||
const id = useRoute().params.id
|
||||
|
||||
@@ -537,5 +511,7 @@ const toggleWatched = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const headerTitle = computed(() => `${data.value?.full_title ?? data.value?.title ?? id}`)
|
||||
|
||||
onMounted(async () => loadContent(id))
|
||||
</script>
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">History</span>
|
||||
<div class="is-pulled-right">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<button class="button is-primary" @click.prevent="searchForm = !searchForm">
|
||||
<button class="button is-primary" @click="searchForm = !searchForm">
|
||||
<span class="icon">
|
||||
<i class="fas fa-search"></i>
|
||||
</span>
|
||||
</button>
|
||||
</p>
|
||||
<p class="control">
|
||||
<button class="button is-info" @click.prevent="loadContent(page, true)">
|
||||
<button class="button is-info" @click="loadContent(page, true)">
|
||||
<span class="icon">
|
||||
<i class="fas fa-sync"></i>
|
||||
</span>
|
||||
@@ -73,7 +73,7 @@
|
||||
<select v-model="searchField" class="is-capitalized" :disabled="isLoading">
|
||||
<option value="">Select Field</option>
|
||||
<option v-for="field in searchable" :key="'search-' + field.key" :value="field.key">
|
||||
{{ field.key }}
|
||||
{{ field.display ?? field.key }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
@@ -189,18 +189,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-12" v-else>
|
||||
<Message message_class="is-info" v-if="true === isLoading">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-spinner fa-pulse"></i></span>
|
||||
<span>Loading data please wait...</span>
|
||||
</span>
|
||||
</Message>
|
||||
<Message v-else message_class="is-warning">
|
||||
<button v-if="query" class="delete" @click="clearSearch"></button>
|
||||
|
||||
<Message v-if="isLoading" message_class="has-background-info-90 has-text-dark" title="Loading"
|
||||
icon="fas fa-spinner fa-spin" message="Loading data. Please wait..."/>
|
||||
<Message v-else class="has-background-warning-80 has-text-dark" title="Warning"
|
||||
icon="fas fa-exclamation-triangle" :use-close="true" @close="clearSearch">
|
||||
<div class="icon-text">
|
||||
<span class="icon"><i class="fas fa-info"></i></span>
|
||||
<span>No items found.</span>
|
||||
No items found.
|
||||
<span v-if="query">For <code><strong>{{ searchField }}</strong> : <strong>{{ query }}</strong></code></span>
|
||||
</div>
|
||||
<code class="is-block mt-4" v-if="error">{{ error }}</code>
|
||||
@@ -231,7 +225,7 @@ const total = ref(0)
|
||||
const last_page = computed(() => Math.ceil(total.value / perpage.value))
|
||||
|
||||
const query = ref(route.query.q ?? '')
|
||||
const searchField = ref(route.query.key ?? '')
|
||||
const searchField = ref(route.query.key ?? 'title')
|
||||
const isLoading = ref(false)
|
||||
const searchForm = ref(false)
|
||||
|
||||
@@ -340,7 +334,6 @@ const makePagination = () => {
|
||||
|
||||
const clearSearch = () => {
|
||||
query.value = ''
|
||||
searchField.value = ''
|
||||
searchForm.value = false
|
||||
loadContent(1)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span id="env_page_title" class="title is-4">Ignored GUIDs</span>
|
||||
<div class="is-pulled-right">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<button class="button is-primary" v-tooltip="'Add New Ignore'" @click="toggleForm = !toggleForm">
|
||||
<button class="button is-primary" v-tooltip.bottom="'Add New Ignore rule'"
|
||||
@click="toggleForm = !toggleForm">
|
||||
<span class="icon">
|
||||
<i class="fas fa-add"></i>
|
||||
</span>
|
||||
@@ -244,53 +245,29 @@
|
||||
</div>
|
||||
|
||||
<div class="column is-12" v-if="items.length < 1">
|
||||
<Message message_class="is-info" title="Loading..." v-if="isLoading">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-spinner fa-spin"></i></span>
|
||||
<span>Request ignore list. Please wait...</span>
|
||||
</span>
|
||||
</Message>
|
||||
<Message message_class="has-background-success-90 has-text-dark" title="Information" v-else>
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-check"></i></span>
|
||||
<span>
|
||||
There are no ignore rules currently set. You can add new ignore rules by clicking on the <i
|
||||
class="fas fa-add"></i> button.
|
||||
</span>
|
||||
</span>
|
||||
<Message v-if="isLoading" message_class="has-background-info-90 has-text-dark" title="Loading"
|
||||
icon="fas fa-spinner fa-spin" message="Loading data. Please wait..."/>
|
||||
<Message v-else message_class="has-background-success-90 has-text-dark" title="Information" icon="fas fa-check">
|
||||
There are no ignore rules configured. You can add new ignore rules by clicking on the
|
||||
<i @click="toggleForm=true" class="is-clickable fas fa-add"></i> button.
|
||||
</Message>
|
||||
</div>
|
||||
|
||||
<div class="column is-12">
|
||||
<Message message_class="has-background-info-90 has-text-dark">
|
||||
<div class="is-pulled-right">
|
||||
<NuxtLink @click="show_page_tips=false" v-if="show_page_tips">
|
||||
<span class="icon"><i class="fas fa-arrow-up"></i></span>
|
||||
<span>Close</span>
|
||||
</NuxtLink>
|
||||
<NuxtLink @click="show_page_tips=true" v-else>
|
||||
<span class="icon"><i class="fas fa-arrow-down"></i></span>
|
||||
<span>Open</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<h5 class="title is-5 is-unselectable">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-info-circle"></i></span>
|
||||
<span>Tips</span>
|
||||
</span>
|
||||
</h5>
|
||||
<div class="content" v-if="show_page_tips">
|
||||
<ul>
|
||||
<li>Ignoring specific GUID sometimes helps in preventing incorrect data being added to WatchState, due to
|
||||
incorrect metadata being provided by backends.
|
||||
</li>
|
||||
<li>
|
||||
<code>GUID</code> means in terms of WatchState is the unique identifier for a specific item in the
|
||||
external data source.
|
||||
</li>
|
||||
<li>To add a new ignore rule click on the <i class="fa fa-add"></i> button.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Message message_class="has-background-info-90 has-text-dark" :toggle="show_page_tips"
|
||||
@toggle="show_page_tips = !show_page_tips" :use-toggle="true" title="Tips" icon="fas fa-info-circle">
|
||||
<ul>
|
||||
<li>Ignoring specific GUID sometimes helps in preventing incorrect data being added to WatchState, due to
|
||||
incorrect metadata being provided by backends.
|
||||
</li>
|
||||
<li>
|
||||
<code>GUID</code> means in terms of WatchState is the unique identifier for a specific item in the
|
||||
external data source.
|
||||
</li>
|
||||
<li>To add a new ignore rule click on the <i @click="toggleForm=true" class="is-clickable fa fa-add"></i>
|
||||
button.
|
||||
</li>
|
||||
</ul>
|
||||
</Message>
|
||||
</div>
|
||||
</div>
|
||||
@@ -302,6 +279,7 @@ import {awaitElement, copyText, notification, stringToRegex} from '~/utils/index
|
||||
import {useStorage} from '@vueuse/core'
|
||||
import moment from 'moment'
|
||||
import 'assets/css/bulma-switch.css'
|
||||
import Message from "~/components/Message.vue";
|
||||
|
||||
useHead({title: 'Ignored GUIDs'})
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</div>
|
||||
|
||||
<div class="column is-12">
|
||||
<div class="columns is-multiline" v-if="lastHistory.length>0">
|
||||
<div class="columns is-multiline" v-if="lastHistory.length>1">
|
||||
<div class="column is-6-tablet" v-for="history in lastHistory" :key="history.id">
|
||||
<div class="card" :class="{ 'is-success': history.watched }">
|
||||
<header class="card-header">
|
||||
@@ -58,11 +58,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-12" v-else>
|
||||
<Message message_class="is-warning">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-exclamation"></i></span>
|
||||
<span>No items were found. There are probably no items in the local database yet.</span>
|
||||
</span>
|
||||
<Message title="Warning" message_class="has-background-warning-90 has-text-dark"
|
||||
icon="fas fa-exclamation-triangle"
|
||||
message="No items were found. There are probably no items in the local database yet.">
|
||||
</Message>
|
||||
</div>
|
||||
</div>
|
||||
@@ -80,7 +78,7 @@
|
||||
|
||||
<div class="column is-12">
|
||||
<div class="content">
|
||||
<Message message_class="has-background-info-90 has-text-dark">
|
||||
<Message title="Welcome" message_class="has-background-info-90 has-text-dark" icon="fas fa-heart">
|
||||
If you have question, or want clarification on something, or just want to chat with other users, you are
|
||||
welcome to join our <span class="icon-text is-underlined">
|
||||
<span class="icon"><i class="fas fa-brands fa-discord"></i></span>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">
|
||||
<NuxtLink to="/logs">Logs</NuxtLink>
|
||||
: {{ filename }}
|
||||
@@ -10,33 +10,33 @@
|
||||
<div class="field is-grouped">
|
||||
|
||||
<p class="control">
|
||||
<button class="button is-danger" v-tooltip="'Delete Logfile.'" @click="deleteFile">
|
||||
<button class="button is-danger" v-tooltip.bottom="'Delete Logfile.'" @click="deleteFile">
|
||||
<span class="icon"><i class="fas fa-trash"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
|
||||
<p class="control">
|
||||
<button class="button is-danger is-light" v-tooltip="'Download the entire logfile.'" @click="downloadFile"
|
||||
:class="{'is-loading':isDownloading}">
|
||||
<button class="button is-danger is-light" v-tooltip.bottom="'Download the entire logfile.'"
|
||||
@click="downloadFile" :class="{'is-loading':isDownloading}">
|
||||
<span class="icon"><i class="fas fa-download"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
|
||||
<p class="control" v-if="filename.includes(moment().format('YYYYMMDD'))">
|
||||
<button class="button" v-tooltip="'Watch log'" @click="watchLog"
|
||||
<button class="button" v-tooltip.bottom="'Watch log'" @click="watchLog"
|
||||
:class="{'is-primary':!stream,'is-danger':stream}">
|
||||
<span class="icon"><i class="fas fa-stream"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
|
||||
<p class="control">
|
||||
<button class="button is-warning" @click.prevent="wrapLines = !wrapLines" v-tooltip="'Toggle wrap line'">
|
||||
<button class="button is-warning" @click="wrapLines = !wrapLines" v-tooltip.bottom="'Toggle wrap line'">
|
||||
<span class="icon"><i class="fas fa-text-width"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
|
||||
<p class="control">
|
||||
<button class="button is-info" @click.prevent="loadContent">
|
||||
<button class="button is-info" @click="loadContent" :disabled="isLoading" :class="{'is-loading':isLoading}">
|
||||
<span class="icon"><i class="fas fa-sync"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
@@ -46,25 +46,22 @@
|
||||
</div>
|
||||
|
||||
<div class="column is-12">
|
||||
<template v-if="stream">
|
||||
<Message message_class="is-info">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-spinner fa-pulse"></i></span>
|
||||
<span>Streaming log content...</span>
|
||||
</span>
|
||||
</Message>
|
||||
</template>
|
||||
<div class="notification has-background-info-90 has-text-dark" v-if="stream">
|
||||
<button class="delete" @click="watchLog"></button>
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-spinner fa-pulse"></i></span>
|
||||
<span>Streaming log content...</span>
|
||||
</span>
|
||||
</div>
|
||||
<code ref="logContainer" class="box logs-container" v-if="!error"
|
||||
:class="{'is-pre': !wrapLines, 'is-pre-wrap': wrapLines}">
|
||||
<span class="is-log-line is-block" v-for="(item, index) in data" :key="'log_line-'+index">
|
||||
<span class="is-log-line is-block pt-1" v-for="(item, index) in data" :key="'log_line-'+index">
|
||||
{{ item }}
|
||||
</span>
|
||||
</code>
|
||||
<template v-else>
|
||||
<Message title="Request Error" message_class="is-danger" :message="error"/>
|
||||
</template>
|
||||
<Message v-if="error" title="API Error" message_class="has-background-warning-90 has-text-dark"
|
||||
:message="error" :use-close="true" @close="router.push('/logs')"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -84,14 +81,16 @@ import {useStorage} from '@vueuse/core'
|
||||
import {notification} from '~/utils/index.js'
|
||||
import request from '~/utils/request.js'
|
||||
|
||||
const router = useRouter()
|
||||
const filename = useRoute().params.filename
|
||||
|
||||
useHead({title: `Logs : ${filename}`})
|
||||
|
||||
const data = ref([])
|
||||
const error = ref('')
|
||||
const wrapLines = ref(true)
|
||||
const wrapLines = useStorage('logs_wrap_lines', false)
|
||||
const isDownloading = ref(false)
|
||||
const isLoading = ref(false)
|
||||
|
||||
const api_path = useStorage('api_path', '/v1/api')
|
||||
const api_url = useStorage('api_url', '')
|
||||
@@ -105,15 +104,23 @@ const logContainer = ref(null)
|
||||
|
||||
const loadContent = async () => {
|
||||
try {
|
||||
isLoading.value = true
|
||||
const response = await request(`/log/${filename}`)
|
||||
if (response.ok) {
|
||||
const text = await response.text()
|
||||
data.value = text.split('\n')
|
||||
} else {
|
||||
error.value = `${response.status}: ${response.statusText}`
|
||||
try {
|
||||
const json = await response.json();
|
||||
error.value = `${json.error.code}: ${json.error.message}`
|
||||
} catch (e) {
|
||||
error.value = `${response.status}: ${response.statusText}`
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
error.value = e
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,5 +212,10 @@ const deleteFile = async () => {
|
||||
|
||||
const updateScroll = () => logContainer.value.scrollTop = logContainer.value.scrollHeight;
|
||||
|
||||
onUpdated(() => updateScroll());
|
||||
onUpdated(() => {
|
||||
if (error.value) {
|
||||
return
|
||||
}
|
||||
updateScroll()
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="is-pulled-right">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<button class="button is-info" @click.prevent="loadContent">
|
||||
<button class="button is-info" @click="loadContent" :disabled="isLoading" :class="{'is-loading':isLoading}">
|
||||
<span class="icon"><i class="fas fa-sync"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
@@ -18,6 +18,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-12" v-if="logs.length < 1 || isLoading">
|
||||
<Message v-if="isLoading" message_class="is-background-info-90 has-text-dark" icon="fas fa-spinner fa-spin"
|
||||
title="Loading" message="Loading data. Please wait..."/>
|
||||
<Message v-else title="Warning" message_class="is-background-warning-80 has-text-dark"
|
||||
icon="fas fa-exclamation-triangle" message="No logs files found."/>
|
||||
</div>
|
||||
|
||||
<div class="column is-4-tablet" v-for="(item, index) in logs" :key="'log-'+index">
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
@@ -59,19 +66,29 @@
|
||||
import request from "~/utils/request.js";
|
||||
import moment from "moment";
|
||||
import {humanFileSize} from "~/utils/index.js";
|
||||
import Message from "~/components/Message.vue";
|
||||
|
||||
useHead({title: 'Logs'})
|
||||
|
||||
const logs = ref([])
|
||||
const isLoading = ref(false)
|
||||
|
||||
const loadContent = async () => {
|
||||
logs.value = []
|
||||
const response = await request('/logs')
|
||||
let data = await response.json();
|
||||
isLoading.value = true
|
||||
|
||||
data.sort((a, b) => new Date(b.modified) - new Date(a.modified));
|
||||
try {
|
||||
const response = await request('/logs')
|
||||
let data = await response.json();
|
||||
|
||||
logs.value = data;
|
||||
data.sort((a, b) => new Date(b.modified) - new Date(a.modified));
|
||||
|
||||
logs.value = data;
|
||||
} catch (e) {
|
||||
notification('error', 'Error', e.message)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => loadContent())
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">Queue</span>
|
||||
<div class="is-pulled-right">
|
||||
<div class="field is-grouped">
|
||||
@@ -18,18 +18,11 @@
|
||||
</div>
|
||||
|
||||
<div class="column is-12" v-if="items.length < 1">
|
||||
<Message message_class="is-info" title="Loading..." v-if="isLoading">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-spinner fa-spin"></i></span>
|
||||
<span>Requesting queued events. Please wait...</span>
|
||||
</span>
|
||||
</Message>
|
||||
<Message message_class="has-background-success-90 has-text-dark" title="Information" v-else>
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-check"></i></span>
|
||||
<span>There are currently no queued events to be sent to backends.</span>
|
||||
</span>
|
||||
</Message>
|
||||
<Message v-if="isLoading" message_class="has-background-info-90 has-text-dark" title="Loading"
|
||||
icon="fas fa-spinner fa-spin" message="Loading data. Please wait..."/>
|
||||
<Message v-else message_class="is-background-success-90 has-text-dark" title="Information"
|
||||
icon="fas fa-info-circle"
|
||||
message="There are currently no queued events."/>
|
||||
</div>
|
||||
|
||||
<div class="column is-4 is-6-tablet" v-for="item in items" :key="item.id">
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">System Report</span>
|
||||
<div class="is-pulled-right" v-if="false === show_report_warning">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<button class="button is-primary" @click="copyText(data.join('\n'))" v-tooltip="'Copy Report'">
|
||||
<button class="button is-primary" @click="copyText(data.join('\n'))" v-tooltip.bottom="'Copy Report'">
|
||||
<span class="icon"><i class="fas fa-copy"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
@@ -18,25 +18,23 @@
|
||||
|
||||
<div class="column is-12">
|
||||
<template v-if="show_report_warning">
|
||||
<Message message_class="has-background-warning-80 has-text-dark" title="Warning">
|
||||
<p>While we try to make sure no sensitive information is leaked via the report, it's possible that
|
||||
something might be missed. Please review the report before posting it. If you notice
|
||||
any sensitive information, please report it to the developers. so we can fix it.</p>
|
||||
<Message message_class="has-background-warning-80 has-text-dark" title="Warning"
|
||||
icon="fas fa-exclamation-triangle">
|
||||
While we try to make sure no sensitive information is leaked via the report, it's possible that something
|
||||
might be missed. Please review the report before posting it. If you notice any sensitive information, please
|
||||
report it to the developers. so we can fix it.
|
||||
</Message>
|
||||
<div class="mt-4">
|
||||
<button class="button is-block is-fullwidth is-primary" @click="show_report_warning = false">
|
||||
<div class="mt-4 has-text-centered">
|
||||
<NuxtLink class="is-block is-fullwidth is-primary" @click="show_report_warning = false">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fas fa-thumbs-up"></i></span>
|
||||
<span>I Understand. Show me the report.</span>
|
||||
</span>
|
||||
</button>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</template>
|
||||
<Message message_class="is-info" v-if="!show_report_warning && data.length < 1">
|
||||
<span class="icon"><i class="fas fa-spinner fa-pulse"></i></span>
|
||||
<span>Generating the report. Please wait...</span>
|
||||
</Message>
|
||||
|
||||
<Message message_class="has-background-info-90 has-text-dark" v-if="!show_report_warning && data.length < 1"
|
||||
title="Loading" icon="fas fa-spinner fa-spin" message="Generating the report. Please wait..."/>
|
||||
<template v-if="!show_report_warning && data.length > 0">
|
||||
<pre style="min-height: 60vh;max-height:70vh; overflow-y: scroll" id="report-content"
|
||||
><code><span v-for="(item, index) in data" :key="index" class="is-block">{{ item }}</span></code></pre>
|
||||
@@ -60,5 +58,4 @@ watch(show_report_warning, async (value) => {
|
||||
const response = await request(`/system/report`)
|
||||
data.value = await response.json()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-12 is-clearfix is-unselectable">
|
||||
<span class="title is-4">Tasks</span>
|
||||
<div class="is-pulled-right">
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<button class="button is-info" @click.prevent="loadContent(true)">
|
||||
<button class="button is-info" @click="loadContent()" :disabled="isLoading"
|
||||
:class="{'is-loading':isLoading}">
|
||||
<span class="icon"><i class="fas fa-sync"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
@@ -19,7 +20,10 @@
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="column is-12" v-if="isLoading">
|
||||
<Message message_class="has-background-info-90 has-text-dark" title="Loading"
|
||||
icon="fas fa-spinner fa-spin" message="Loading data. Please wait..."/>
|
||||
</div>
|
||||
|
||||
<div v-for="task in tasks" :key="task.name" class="column is-6-tablet is-12-mobile">
|
||||
@@ -95,6 +99,23 @@
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-12">
|
||||
<Message message_class="has-background-info-90 has-text-dark" :toggle="show_page_tips"
|
||||
@toggle="show_page_tips = !show_page_tips" :use-toggle="true" title="Tips" icon="fas fa-info-circle">
|
||||
<ul>
|
||||
<li>For long running tasks like <code>Import</code> and <code>Export</code>, you should queue the task to run
|
||||
in background. As running them via web console will take longer if you have many backends and/or has large
|
||||
libraries.
|
||||
</li>
|
||||
<li>Use the switch next to the task enable to enable or disable the task from automatically running.</li>
|
||||
<li>To change when task is scheduled to run, please visit
|
||||
<NuxtLink to="/env" v-text="'Environment variables'"/>
|
||||
page. The <code>WS_CRON_(TASK)_*</code> variables are used to control scheduled tasks.
|
||||
</li>
|
||||
</ul>
|
||||
</Message>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -102,50 +123,67 @@
|
||||
import 'assets/css/bulma-switch.css'
|
||||
import moment from 'moment'
|
||||
import request from '~/utils/request.js'
|
||||
import {notification} from "~/utils/index.js";
|
||||
import {notification} from '~/utils/index.js'
|
||||
import cronstrue from 'cronstrue'
|
||||
import Message from '~/components/Message.vue'
|
||||
import {useStorage} from '@vueuse/core'
|
||||
|
||||
useHead({title: 'Tasks'})
|
||||
|
||||
const tasks = ref([])
|
||||
const queued = ref([])
|
||||
const isLoading = ref(false)
|
||||
const show_page_tips = useStorage('show_page_tips', true)
|
||||
|
||||
const loadContent = async (clear = false) => {
|
||||
if (clear) {
|
||||
tasks.value = []
|
||||
const loadContent = async () => {
|
||||
isLoading.value = true
|
||||
tasks.value = []
|
||||
try {
|
||||
const response = await request('/tasks')
|
||||
const json = await response.json()
|
||||
tasks.value = json.tasks
|
||||
queued.value = json.queued
|
||||
} catch (e) {
|
||||
notification('error', 'Error', `Request error. ${e.message}`)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
const response = await request('/tasks')
|
||||
const json = await response.json()
|
||||
tasks.value = json.tasks
|
||||
queued.value = json.queued
|
||||
}
|
||||
|
||||
onMounted(() => loadContent())
|
||||
|
||||
const toggleTask = async (task) => {
|
||||
const keyName = `WS_CRON_${task.name.toUpperCase()}`
|
||||
await request(`/system/env/${keyName}`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({"value": !task.enabled})
|
||||
});
|
||||
const toggleTask = async task => {
|
||||
try {
|
||||
const keyName = `WS_CRON_${task.name.toUpperCase()}`
|
||||
await request(`/system/env/${keyName}`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({"value": !task.enabled})
|
||||
});
|
||||
|
||||
const response = await request(`/tasks/${task.name}`)
|
||||
tasks.value[tasks.value.findIndex(b => b.name === task.name)] = await response.json()
|
||||
const response = await request(`/tasks/${task.name}`)
|
||||
tasks.value[tasks.value.findIndex(b => b.name === task.name)] = await response.json()
|
||||
} catch (e) {
|
||||
notification('error', 'Error', `Request error. ${e.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
const queueTask = async (task) => {
|
||||
const queueTask = async task => {
|
||||
if (!confirm(`Queue '${task.name}' to run in background?`)) {
|
||||
return
|
||||
}
|
||||
|
||||
const response = await request(`/tasks/${task.name}/queue`, {method: 'POST'})
|
||||
if (response.ok) {
|
||||
notification('success', 'Success', `Task ${task.name} has been queued.`)
|
||||
await loadContent()
|
||||
try {
|
||||
const response = await request(`/tasks/${task.name}/queue`, {method: 'POST'})
|
||||
if (response.ok) {
|
||||
notification('success', 'Success', `Task ${task.name} has been queued.`)
|
||||
await loadContent()
|
||||
}
|
||||
} catch (e) {
|
||||
notification('error', 'Error', `Request error. ${e.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
const confirmRun = async (task) => {
|
||||
const confirmRun = async task => {
|
||||
if (!confirm(`Are you sure you want to run '${task.name}' via web console now?`)) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -200,6 +200,22 @@ final class Index
|
||||
$filters[iState::COLUMN_META_PATH] = $data->get(iState::COLUMN_META_PATH);
|
||||
}
|
||||
|
||||
if ($data->get('subtitle')) {
|
||||
foreach ($this->getBackends() as $backend) {
|
||||
$bName = $backend['name'];
|
||||
|
||||
if ($data->get('exact')) {
|
||||
$or[] = "json_extract(" . iState::COLUMN_META_DATA . ",'$.{$bName}.extra.title') = :subtitle_{$bName}";
|
||||
} else {
|
||||
$or[] = "json_extract(" . iState::COLUMN_META_DATA . ",'$.{$bName}.extra.title') LIKE \"%\" || :subtitle_{$bName} || \"%\"";
|
||||
}
|
||||
|
||||
$params["subtitle_{$bName}"] = $data->get('subtitle');
|
||||
}
|
||||
|
||||
$filters['subtitle'] = $data->get('subtitle');
|
||||
}
|
||||
|
||||
if ($data->get(iState::COLUMN_EXTRA)) {
|
||||
$sField = $data->get('key');
|
||||
$sValue = $data->get('value');
|
||||
@@ -336,6 +352,7 @@ final class Index
|
||||
],
|
||||
[
|
||||
'key' => 'via',
|
||||
'display' => 'Backend',
|
||||
'description' => 'Search using the backend name.',
|
||||
'type' => 'string',
|
||||
],
|
||||
@@ -369,13 +386,15 @@ final class Index
|
||||
],
|
||||
[
|
||||
'key' => 'parent',
|
||||
'display' => 'Series GUID',
|
||||
'description' => 'Search using the parent GUID.',
|
||||
'type' => 'guid://id',
|
||||
'type' => 'provider://id',
|
||||
],
|
||||
[
|
||||
'key' => 'guids',
|
||||
'display' => 'Content GUID',
|
||||
'description' => 'Search using the GUID.',
|
||||
'type' => 'guid://id',
|
||||
'type' => 'provider://id',
|
||||
],
|
||||
[
|
||||
'key' => 'metadata',
|
||||
@@ -397,6 +416,12 @@ final class Index
|
||||
'description' => 'Search using file path. Searching this field might be slow.',
|
||||
'type' => 'string',
|
||||
],
|
||||
[
|
||||
'key' => 'subtitle',
|
||||
'display' => 'Content title',
|
||||
'description' => 'Search using content title. Searching this field will be slow.',
|
||||
'type' => 'string',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user