feat(v3): add Dozzle/Uptime Kuma/Gotify; fix Meilisearch catalogue re-index churn

- docker-compose: add dozzle, uptime-kuma, gotify services with Caddy subdomains
  (logs/uptime/push.libnovel.cc); bind-mount dozzle/users.yml for simple auth
- Caddyfile: add site blocks for logs, uptime, push subdomains
- admin layout: add Logs, Uptime, Push tabs to external tools pill
- CatalogueEntry: add Slug field; populated by novelfire scraper
- meili.Client: add BookExists() to check if a book is already indexed
- catalogue_refresh: skip books already present in Meilisearch to prevent
  redundant re-scraping and re-indexing on every runner restart
- docker-compose runner: set RUNNER_SKIP_INITIAL_CATALOGUE_REFRESH=true
This commit is contained in:
Admin
2026-03-23 16:10:35 +05:00
parent 5b27d501af
commit b9b69cee44
8 changed files with 446 additions and 13 deletions

View File

@@ -0,0 +1,56 @@
<script lang="ts">
import { page } from '$app/state';
const adminTabs = [
{ href: '/admin/scrape', label: 'Scrape' },
{ href: '/admin/audio', label: 'Audio' }
];
const toolTabs = [
{ href: 'https://feedback.libnovel.cc', label: 'Feedback' },
{ href: 'https://errors.libnovel.cc', label: 'Errors' },
{ href: 'https://analytics.libnovel.cc', label: 'Analytics' },
{ href: 'https://logs.libnovel.cc', label: 'Logs' },
{ href: 'https://uptime.libnovel.cc', label: 'Uptime' },
{ href: 'https://push.libnovel.cc', label: 'Push' }
];
interface Props {
children?: import('svelte').Snippet;
}
let { children }: Props = $props();
</script>
<!-- Admin nav: internal pages + external tools -->
<div class="mb-6 flex flex-wrap items-center gap-3">
<!-- Internal admin pages -->
<div class="flex gap-1 bg-zinc-800 rounded-lg p-1 border border-zinc-700">
{#each adminTabs as tab}
<a
href={tab.href}
class="px-4 py-1.5 rounded-md text-sm font-medium transition-colors
{page.url.pathname.startsWith(tab.href)
? 'bg-zinc-700 text-zinc-100'
: 'text-zinc-400 hover:text-zinc-200'}"
>
{tab.label}
</a>
{/each}
</div>
<!-- External tools (open in new tab) -->
<div class="flex gap-1 bg-zinc-800 rounded-lg p-1 border border-zinc-700">
{#each toolTabs as tool}
<a
href={tool.href}
target="_blank"
rel="noopener noreferrer"
class="px-4 py-1.5 rounded-md text-sm font-medium text-zinc-400 hover:text-zinc-200 transition-colors"
>
{tool.label}
</a>
{/each}
</div>
</div>
{@render children?.()}