web: table update and nfo scan update
Local Docker Build (Dev) / build-dev (push) Successful in 5s

This commit is contained in:
2025-10-26 15:23:35 -04:00
parent 9fbb9e37ab
commit c6b6b0ef64
4 changed files with 168 additions and 42 deletions
+24 -9
View File
@@ -2391,7 +2391,7 @@ def register_routes(app, dependencies: dict):
imdb_id = "unknown"
try:
# Parse the NFO file we already know exists (since grep found it missing dateadded)
# Try to parse the NFO file we already know exists (since grep found it missing dateadded)
tree = ET.parse(nfo_file)
root = tree.getroot()
@@ -2419,7 +2419,27 @@ def register_routes(app, dependencies: dict):
print(f"✅ Found IMDb {imdb_text} in NFO content: {os.path.basename(nfo_file)}")
return imdb_text
# Method 4: Fallback - check folder structure for episodes
except ET.ParseError as e:
# Handle malformed XML by trying text-based search
print(f"⚠️ NFO XML parse error in {os.path.basename(nfo_file)}: {e}")
try:
# Fallback: Read as text and search for IMDb patterns
with open(nfo_file, 'r', encoding='utf-8', errors='ignore') as f:
nfo_text = f.read()
# Search for IMDb patterns in raw text
text_match = re.search(r'(tt\d{7,})', nfo_text)
if text_match:
imdb_text = text_match.group(1)
print(f"✅ Found IMDb {imdb_text} in NFO text content: {os.path.basename(nfo_file)}")
return imdb_text
except Exception as text_error:
print(f"⚠️ Error reading NFO as text {nfo_file}: {text_error}")
except Exception as e:
print(f"⚠️ Unexpected error parsing NFO {nfo_file}: {e}")
# Method 4: Fallback - check folder structure
if is_episode:
series_folder = os.path.dirname(os.path.dirname(nfo_file))
folder_name = os.path.basename(series_folder)
@@ -2436,9 +2456,6 @@ def register_routes(app, dependencies: dict):
print(f"✅ Found IMDb {folder_match.group(1)} in folder: {folder_name}")
return folder_match.group(1)
except Exception as e:
print(f"⚠️ Error parsing NFO for IMDb in {nfo_file}: {e}")
print(f"❌ No IMDb ID found in {os.path.basename(nfo_file)}")
return "unknown"
@@ -2568,7 +2585,7 @@ def register_routes(app, dependencies: dict):
with db.get_connection() as conn:
cursor = conn.cursor()
cursor.execute("""
SELECT dateadded, source, added_by
SELECT dateadded, source
FROM episodes
WHERE imdb_id = %s AND season = %s AND episode = %s
LIMIT 1
@@ -2578,7 +2595,6 @@ def register_routes(app, dependencies: dict):
if result:
episode["dateadded"] = result["dateadded"]
episode["source"] = result.get("source", "database")
episode["added_by"] = result.get("added_by", "unknown")
else:
print(f"⚠️ No database entry for {episode['imdb_id']} S{episode['season']:02d}E{episode['episode']:02d}")
except Exception as e:
@@ -2591,7 +2607,7 @@ def register_routes(app, dependencies: dict):
with db.get_connection() as conn:
cursor = conn.cursor()
cursor.execute("""
SELECT dateadded, source, added_by
SELECT dateadded, source
FROM movies
WHERE imdb_id = %s
LIMIT 1
@@ -2601,7 +2617,6 @@ def register_routes(app, dependencies: dict):
if result:
movie["dateadded"] = result["dateadded"]
movie["source"] = result.get("source", "database")
movie["added_by"] = result.get("added_by", "unknown")
else:
print(f"⚠️ No database entry for movie {movie['imdb_id']}")
except Exception as e:
+91
View File
@@ -958,6 +958,97 @@ body {
border-radius: 0.375rem;
}
/* NFO Repair Table Styling */
.nfo-repair-table-container {
background: white;
border-radius: 0.5rem;
box-shadow: var(--shadow);
overflow-x: auto;
overflow-y: auto;
max-height: 600px;
margin-bottom: 1rem;
border: 1px solid var(--border-color);
}
.nfo-repair-table {
width: 100%;
min-width: 800px;
border-collapse: collapse;
font-size: 0.875rem;
background: white;
}
.nfo-repair-table th {
background-color: var(--dark-color);
color: white;
padding: 0.75rem 0.5rem;
text-align: left;
font-weight: 600;
position: sticky;
top: 0;
z-index: 10;
}
.nfo-repair-table td {
padding: 0.75rem 0.5rem;
border-bottom: 1px solid var(--border-color);
vertical-align: top;
}
.nfo-repair-table tr:hover {
background-color: #f8f9fa;
}
.media-type-badge {
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
}
.media-type-badge.episode {
background-color: #e3f2fd;
color: #1976d2;
}
.media-type-badge.movie {
background-color: #f3e5f5;
color: #7b1fa2;
}
.status-ready {
color: #2e7d32;
font-weight: 600;
font-size: 0.75rem;
}
.status-missing {
color: #d32f2f;
font-weight: 600;
font-size: 0.75rem;
}
.text-center {
text-align: center;
}
.text-muted {
color: #6c757d;
}
.nfo-fix-actions {
margin-top: 1rem;
padding: 1rem;
background-color: #f8f9fa;
border-radius: 0.5rem;
text-align: center;
}
.nfo-fix-actions .btn {
margin-bottom: 0.5rem;
}
.admin-tools {
display: flex;
flex-direction: column;
+2 -2
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NFOGuard - Database Management</title>
<link rel="stylesheet" href="/static/css/styles.css?v=2.8.2-20241026-table-fix">
<link rel="stylesheet" href="/static/css/styles.css?v=2.8.2-20241026-nfo-table-redesign">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
</head>
<body>
@@ -533,6 +533,6 @@
<!-- Toast Notifications -->
<div class="toast-container" id="toast-container"></div>
<script src="/static/js/app.js?v=3.0.1-nfo-repair-movies"></script>
<script src="/static/js/app.js?v=3.0.1-nfo-table-redesign"></script>
</body>
</html>
+37 -17
View File
@@ -1847,17 +1847,18 @@ async function checkMissingNFODates() {
html += `
<div class="missing-episodes">
<h5>Items with missing dateadded (showing first 50):</h5>
<div class="table-container">
<table class="results-table">
<div class="nfo-repair-table-container">
<table class="nfo-repair-table">
<thead>
<tr>
<th>Type</th>
<th>IMDb ID</th>
<th>Season</th>
<th>Episode</th>
<th>Database Date</th>
<th>Source</th>
<th>NFO Path</th>
<th style="width: 8%">Type</th>
<th style="width: 12%">IMDb ID</th>
<th style="width: 8%">Season</th>
<th style="width: 8%">Episode</th>
<th style="width: 15%">Database Date</th>
<th style="width: 10%">Source</th>
<th style="width: 25%">Series/Movie</th>
<th style="width: 14%">Actions</th>
</tr>
</thead>
<tbody>
@@ -1865,20 +1866,39 @@ async function checkMissingNFODates() {
(response.items || response.episodes || []).forEach(item => {
const displayDate = item.dateadded ? new Date(item.dateadded).toLocaleString() : 'None';
const seriesName = item.series_name || item.title || 'Unknown';
const nfoFileName = item.nfo_path ? item.nfo_path.split('/').pop() : 'Unknown';
html += `
<tr>
<td>${item.media_type || 'episode'}</td>
<td>${item.imdb_id}</td>
<td>${item.season || 'N/A'}</td>
<td>${item.episode || 'N/A'}</td>
<td>${displayDate}</td>
<td>${item.source || 'unknown'}</td>
<td><small>${item.nfo_path}</small></td>
<td><span class="media-type-badge ${item.media_type || 'episode'}">${item.media_type || 'episode'}</span></td>
<td><code>${item.imdb_id}</code></td>
<td class="text-center">${item.season || 'N/A'}</td>
<td class="text-center">${item.episode || 'N/A'}</td>
<td><small>${displayDate}</small></td>
<td><small>${item.source || 'unknown'}</small></td>
<td><strong>${seriesName}</strong><br><small class="text-muted">${nfoFileName}</small></td>
<td>
${item.dateadded ?
'<span class="status-ready">✅ Ready to fix</span>' :
'<span class="status-missing">❌ No DB date</span>'
}
</td>
</tr>
`;
});
html += '</tbody></table></div></div>';
html += `
</tbody>
</table>
</div>
<div class="nfo-fix-actions">
<button onclick="fixAllMissingNFODates()" class="btn btn-primary">
🔧 Fix All Missing dateadded Elements
</button>
<p class="text-muted">This will automatically add dateadded elements to NFO files using database values.</p>
</div>
</div>`;
} else {
html += '<div class="success">✅ All NFO files have dateadded elements!</div>';
}