feat(nfo): implement NFO diagnostics and repair
- Add NFO API endpoints: diagnostics, repair, validate, needs-repair - Create /settings/nfo page with full NFO management UI - Add NFO status section to edit modal with repair functionality - Add anime details API for edit modal pre-fill data - Fix auth test fixtures in test_nfo_diagnostics_repair.py Implements NFO diagnostics when editing anime series via right-click menu. Users can now check NFO status, see missing tags, and repair NFOs directly from the edit modal or the dedicated NFO settings page.
This commit is contained in:
@@ -520,6 +520,16 @@
|
||||
<span data-text="test-tmdb">Test TMDB Connection</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="config-item" style="margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--color-border);">
|
||||
<a href="/settings/nfo" class="btn btn-secondary" style="text-decoration: none;">
|
||||
<i class="fas fa-file-lines"></i>
|
||||
<span data-text="open-nfo-diagnostics">Open NFO Diagnostics</span>
|
||||
</a>
|
||||
<small class="config-hint" data-text="nfo-diagnostics-hint">
|
||||
View and repair NFO files for all series
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Backup Configuration -->
|
||||
@@ -652,6 +662,41 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="edit-metadata-form" onsubmit="return false;">
|
||||
<!-- Series Info Section (Read-only) -->
|
||||
<div class="edit-section">
|
||||
<h4><i class="fa-solid fa-info-circle"></i> Series Info</h4>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<label>Name</label>
|
||||
<span id="edit-name" class="info-value">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>Year</label>
|
||||
<span id="edit-year" class="info-value">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>Status</label>
|
||||
<span id="edit-status" class="info-value">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>Premiered</label>
|
||||
<span id="edit-premiered" class="info-value">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>Genres</label>
|
||||
<span id="edit-genres" class="info-value">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>Studio</label>
|
||||
<span id="edit-studio" class="info-value">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>Rating</label>
|
||||
<span id="edit-rating" class="info-value">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Identity Section -->
|
||||
<div class="edit-section">
|
||||
<h4><i class="fa-solid fa-key"></i> Identity</h4>
|
||||
@@ -674,8 +719,13 @@
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="edit-tmdb-id">TMDB ID</label>
|
||||
<input type="number" id="edit-tmdb-id" class="input-field"
|
||||
placeholder="e.g. 1429" min="1">
|
||||
<div class="input-with-action">
|
||||
<input type="number" id="edit-tmdb-id" class="input-field"
|
||||
placeholder="e.g. 1429" min="1">
|
||||
<button type="button" id="btn-fetch-tmdb" class="btn btn-secondary btn-fetch-tmdb" style="display:none;">
|
||||
<i class="fas fa-search"></i> Fetch from TMDB
|
||||
</button>
|
||||
</div>
|
||||
<span class="field-error" style="display:none;"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@@ -685,6 +735,7 @@
|
||||
<span class="field-error" style="display:none;"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tmdb-search-results" class="tmdb-search-results" style="display:none;"></div>
|
||||
</div>
|
||||
|
||||
<!-- NFO Status Section -->
|
||||
@@ -702,6 +753,9 @@
|
||||
<button type="button" id="btn-repair-nfo" class="btn btn-secondary btn-repair">
|
||||
<i class="fa-solid fa-wrench"></i> Repair NFO
|
||||
</button>
|
||||
<a id="btn-open-nfo-diagnostics" class="btn btn-secondary btn-open-diagnostics" href="#" style="display:none; text-decoration: none; margin-top: 0.5rem;">
|
||||
<i class="fa-solid fa-external-link-alt"></i> Open Full Diagnostics
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
183
src/server/web/templates/nfo-settings.html
Normal file
183
src/server/web/templates/nfo-settings.html
Normal file
@@ -0,0 +1,183 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title data-text="nfo-diagnostics-title">NFO Diagnostics - Aniworld</title>
|
||||
<link rel="stylesheet" href="/static/css/base/variables.css?v={{ static_version('css/base/variables.css') }}">
|
||||
<link rel="stylesheet" href="/static/css/base/reset.css?v={{ static_version('css/base/reset.css') }}">
|
||||
<link rel="stylesheet" href="/static/css/base/typography.css?v={{ static_version('css/base/typography.css') }}">
|
||||
<link rel="stylesheet" href="/static/css/components/buttons.css?v={{ static_version('css/components/buttons.css') }}">
|
||||
<link rel="stylesheet" href="/static/css/components/modals.css?v={{ static_version('css/components/modals.css') }}">
|
||||
<link rel="stylesheet" href="/static/css/components/forms.css?v={{ static_version('css/components/forms.css') }}">
|
||||
<link rel="stylesheet" href="/static/css/components/cards.css?v={{ static_version('css/components/cards.css') }}">
|
||||
<link rel="stylesheet" href="/static/css/components/notifications.css?v={{ static_version('css/components/notifications.css') }}">
|
||||
<link rel="stylesheet" href="/static/css/layout/page.css?v={{ static_version('css/layout/page.css') }}">
|
||||
<link rel="stylesheet" href="/static/css/pages/nfo-settings.css?v={{ static_version('css/pages/nfo-settings.css') }}">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- Header -->
|
||||
<header class="page-header">
|
||||
<div class="header-left">
|
||||
<a href="/" class="back-link">
|
||||
<i class="fas fa-arrow-left"></i>
|
||||
<span data-text="back-to-library">Back to Library</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<h1 data-text="nfo-diagnostics-title">NFO Diagnostics & Repair</h1>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<button id="btn-scan-all" class="btn btn-secondary">
|
||||
<i class="fas fa-search"></i>
|
||||
<span data-text="scan-all">Scan All</span>
|
||||
</button>
|
||||
<button id="btn-repair-all" class="btn btn-primary">
|
||||
<i class="fas fa-wrench"></i>
|
||||
<span data-text="repair-all">Repair All</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Stats Bar -->
|
||||
<div class="stats-bar">
|
||||
<div class="stat-item">
|
||||
<span class="stat-value" id="total-series">0</span>
|
||||
<span class="stat-label" data-text="total-series">Total Series</span>
|
||||
</div>
|
||||
<div class="stat-item stat-missing">
|
||||
<span class="stat-value" id="missing-nfo">0</span>
|
||||
<span class="stat-label" data-text="missing-nfo">Missing NFO</span>
|
||||
</div>
|
||||
<div class="stat-item stat-incomplete">
|
||||
<span class="stat-value" id="incomplete-nfo">0</span>
|
||||
<span class="stat-label" data-text="incomplete-nfo">Incomplete NFO</span>
|
||||
</div>
|
||||
<div class="stat-item stat-complete">
|
||||
<span class="stat-value" id="complete-nfo">0</span>
|
||||
<span class="stat-label" data-text="complete-nfo">Complete</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search and Filter -->
|
||||
<div class="toolbar">
|
||||
<div class="search-box">
|
||||
<i class="fas fa-search"></i>
|
||||
<input type="text" id="search-input" class="input-field"
|
||||
placeholder="Search series..." data-text="search-placeholder">
|
||||
</div>
|
||||
<div class="filter-buttons">
|
||||
<button class="filter-btn active" data-filter="all">
|
||||
<span data-text="filter-all">All</span>
|
||||
<span class="count" id="filter-all-count">0</span>
|
||||
</button>
|
||||
<button class="filter-btn" data-filter="missing">
|
||||
<i class="fas fa-exclamation-circle"></i>
|
||||
<span data-text="filter-missing">Missing</span>
|
||||
<span class="count" id="filter-missing-count">0</span>
|
||||
</button>
|
||||
<button class="filter-btn" data-filter="incomplete">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<span data-text="filter-incomplete">Incomplete</span>
|
||||
<span class="count" id="filter-incomplete-count">0</span>
|
||||
</button>
|
||||
<button class="filter-btn" data-filter="complete">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span data-text="filter-complete">Complete</span>
|
||||
<span class="count" id="filter-complete-count">0</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Series List -->
|
||||
<div class="series-list-container">
|
||||
<div id="series-list" class="series-list">
|
||||
<!-- Loading state -->
|
||||
<div class="loading-state" id="loading-state">
|
||||
<i class="fas fa-spinner fa-spin"></i>
|
||||
<span data-text="loading">Loading...</span>
|
||||
</div>
|
||||
|
||||
<!-- Empty state -->
|
||||
<div class="empty-state hidden" id="empty-state">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span data-text="all-nfo-complete">All NFO files are complete!</span>
|
||||
</div>
|
||||
|
||||
<!-- Series cards will be rendered here -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Detail Panel (slide-out) -->
|
||||
<div id="detail-panel" class="detail-panel hidden">
|
||||
<div class="panel-overlay"></div>
|
||||
<div class="panel-content">
|
||||
<div class="panel-header">
|
||||
<h3 id="panel-title">Series Name</h3>
|
||||
<button id="btn-close-panel" class="btn btn-icon">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<!-- NFO Status -->
|
||||
<div class="detail-section">
|
||||
<h4 data-text="nfo-status">NFO Status</h4>
|
||||
<div class="status-display">
|
||||
<span id="panel-status-badge" class="nfo-status-badge">-</span>
|
||||
<span id="panel-nfo-path" class="nfo-path"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Missing Tags -->
|
||||
<div class="detail-section" id="missing-tags-section">
|
||||
<h4 data-text="missing-tags">Missing Tags</h4>
|
||||
<div id="panel-missing-tags" class="missing-tags-list">
|
||||
<!-- Tags will be rendered here -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="detail-section">
|
||||
<h4 data-text="actions">Actions</h4>
|
||||
<div class="action-buttons">
|
||||
<button id="btn-repair-single" class="btn btn-primary">
|
||||
<i class="fas fa-wrench"></i>
|
||||
<span data-text="repair-nfo">Repair NFO</span>
|
||||
</button>
|
||||
<button id="btn-validate" class="btn btn-secondary">
|
||||
<i class="fas fa-check"></i>
|
||||
<span data-text="validate-nfo">Validate XML</span>
|
||||
</button>
|
||||
<button id="btn-view-nfo" class="btn btn-secondary">
|
||||
<i class="fas fa-file-code"></i>
|
||||
<span data-text="view-nfo">View NFO</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- NFO Content Preview -->
|
||||
<div class="detail-section" id="nfo-preview-section">
|
||||
<h4 data-text="nfo-preview">NFO Preview</h4>
|
||||
<pre id="nfo-preview-content" class="nfo-preview"><code></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast Notifications -->
|
||||
<div id="toast-container" class="toast-container"></div>
|
||||
</div>
|
||||
|
||||
<!-- Shared Modules -->
|
||||
<script src="/static/js/shared/constants.js?v={{ static_version('js/shared/constants.js') }}"></script>
|
||||
<script src="/static/js/shared/auth.js?v={{ static_version('js/shared/auth.js') }}"></script>
|
||||
<script src="/static/js/shared/api-client.js?v={{ static_version('js/shared/api-client.js') }}"></script>
|
||||
<script src="/static/js/shared/theme.js?v={{ static_version('js/shared/theme.js') }}"></script>
|
||||
<script src="/static/js/shared/ui-utils.js?v={{ static_version('js/shared/ui-utils.js') }}"></script>
|
||||
|
||||
<!-- Page Module -->
|
||||
<script src="/static/js/pages/nfo-settings.js?v={{ static_version('js/pages/nfo-settings.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user