This commit is contained in:
+38
-23
@@ -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()
|
||||
|
||||
@@ -2418,26 +2418,43 @@ def register_routes(app, dependencies: dict):
|
||||
imdb_text = content_match.group(1)
|
||||
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
|
||||
if is_episode:
|
||||
series_folder = os.path.dirname(os.path.dirname(nfo_file))
|
||||
folder_name = os.path.basename(series_folder)
|
||||
folder_match = re.search(r'\[imdb-(tt\d+)\]', folder_name, re.IGNORECASE)
|
||||
if folder_match:
|
||||
print(f"✅ Found IMDb {folder_match.group(1)} in folder: {folder_name}")
|
||||
return folder_match.group(1)
|
||||
else:
|
||||
# For movies, check movie folder
|
||||
movie_folder = os.path.dirname(nfo_file)
|
||||
folder_name = os.path.basename(movie_folder)
|
||||
folder_match = re.search(r'\[imdb-(tt\d+)\]', folder_name, re.IGNORECASE)
|
||||
if folder_match:
|
||||
print(f"✅ Found IMDb {folder_match.group(1)} in folder: {folder_name}")
|
||||
return folder_match.group(1)
|
||||
|
||||
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"⚠️ Error parsing NFO for IMDb in {nfo_file}: {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)
|
||||
folder_match = re.search(r'\[imdb-(tt\d+)\]', folder_name, re.IGNORECASE)
|
||||
if folder_match:
|
||||
print(f"✅ Found IMDb {folder_match.group(1)} in folder: {folder_name}")
|
||||
return folder_match.group(1)
|
||||
else:
|
||||
# For movies, check movie folder
|
||||
movie_folder = os.path.dirname(nfo_file)
|
||||
folder_name = os.path.basename(movie_folder)
|
||||
folder_match = re.search(r'\[imdb-(tt\d+)\]', folder_name, re.IGNORECASE)
|
||||
if folder_match:
|
||||
print(f"✅ Found IMDb {folder_match.group(1)} in folder: {folder_name}")
|
||||
return folder_match.group(1)
|
||||
|
||||
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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
@@ -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>';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user