Add delete tag, episode count matching indicator, fix season episode counts

This commit is contained in:
Jarian Cottingham 2026-02-22 02:33:41 -06:00
parent 83f3ec4ec4
commit f9aee85e4f
3 changed files with 373 additions and 123 deletions

View File

@ -126,7 +126,47 @@
#seasons-container { #seasons-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 8px; gap: 6px;
}
.season-item {
padding: 12px;
background-color: #1a1a2e;
border: 1px solid #16213e;
border-radius: 6px;
color: #fff;
cursor: pointer;
transition: all 0.2s;
}
.season-item:hover {
background-color: #e94560;
border-color: #e94560;
}
.season-item.selected {
background-color: #0f3460;
border-color: #e94560;
}
#episodes-container {
margin-top: 10px;
display: flex;
flex-direction: column;
gap: 4px;
}
.episode-item {
padding: 10px;
background-color: #0f3460;
border-radius: 4px;
color: #ccc;
font-size: 13px;
}
.episode-item:hover {
background-color: #16213e;
color: #fff;
} }
/* Main Content - Files */ /* Main Content - Files */
@ -218,13 +258,53 @@
padding: 12px 15px; padding: 12px 15px;
background-color: #16213e; background-color: #16213e;
border-radius: 8px; border-radius: 8px;
transition: background-color 0.2s; transition: all 0.2s;
cursor: grab;
} }
.file-item:hover { .file-item:hover {
background-color: #0f3460; background-color: #0f3460;
} }
.file-item.dragging {
opacity: 0.5;
cursor: grabbing;
}
.file-item.drag-over {
border: 2px dashed #e94560;
background-color: #0f3460;
}
.file-item.folder-item {
cursor: pointer;
}
.episode-number {
min-width: 40px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
background-color: #e94560;
color: white;
font-weight: 600;
font-size: 12px;
border-radius: 4px;
margin-right: 12px;
}
.drag-handle {
color: #666;
margin-right: 10px;
cursor: grab;
font-size: 16px;
}
.drag-handle:hover {
color: #e94560;
}
.file-name { .file-name {
flex: 1; flex: 1;
cursor: pointer; cursor: pointer;
@ -273,6 +353,10 @@
transform: scale(1.2); transform: scale(1.2);
} }
.delete-tag:hover {
color: #dc3545;
}
.play-button { .play-button {
background: none; background: none;
border: none; border: none;

36
main.js
View File

@ -213,14 +213,20 @@ ipcMain.handle('move-file-to-folder', async (event, { filePath, folderName }) =>
// Validate folder name and map to actual folder names // Validate folder name and map to actual folder names
// "extra" maps to "extras" for Jellyfin compatibility // "extra" maps to "extras" for Jellyfin compatibility
if (folderName !== 'extra' && folderName !== 'commentary') { const validFolders = ['extra', 'commentary', 'delete'];
const error = 'Invalid folder name. Must be "extra" or "commentary"'; if (!validFolders.includes(folderName)) {
const error = 'Invalid folder name. Must be "extra", "commentary", or "delete"';
writeLog(`ERROR: ${error}`); writeLog(`ERROR: ${error}`);
return { success: false, error: error }; return { success: false, error: error };
} }
// Map folder names to actual directory names // Map folder names to actual directory names
const actualFolderName = folderName === 'extra' ? 'extras' : 'commentary'; let actualFolderName;
if (folderName === 'extra') {
actualFolderName = 'extras';
} else {
actualFolderName = folderName; // 'commentary' and 'delete' stay as-is
}
// Get directory containing the file // Get directory containing the file
const fileDir = path.dirname(filePath); const fileDir = path.dirname(filePath);
@ -421,6 +427,28 @@ ipcMain.handle('get-show-details', async (event, showId) => {
if (response.data && response.data.data) { if (response.data && response.data.data) {
const showData = response.data.data; const showData = response.data.data;
// Fetch episodes to count per season
let episodeCounts = {};
try {
const episodesResponse = await axios.get(`https://api4.thetvdb.com/v4/series/${numericId}/episodes/default`, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
params: { page: 0 }
});
if (episodesResponse.data?.data?.episodes) {
episodesResponse.data.data.episodes.forEach(ep => {
const sn = ep.seasonNumber;
episodeCounts[sn] = (episodeCounts[sn] || 0) + 1;
});
}
} catch (epError) {
console.log('Could not fetch episodes for count:', epError.message);
}
// Extract season information properly // Extract season information properly
let seasons = []; let seasons = [];
if (showData.seasons && Array.isArray(showData.seasons)) { if (showData.seasons && Array.isArray(showData.seasons)) {
@ -428,7 +456,7 @@ ipcMain.handle('get-show-details', async (event, showId) => {
id: season.id, id: season.id,
number: season.number, number: season.number,
type: season.type?.name || 'Unknown', type: season.type?.name || 'Unknown',
episodeCount: season.episodeCount || (season.episodes ? season.episodes.length : 0) episodeCount: episodeCounts[season.number] || 0
})); }));
} }

View File

@ -18,6 +18,7 @@ let currentFiles = [];
let currentShow = null; let currentShow = null;
let currentSeasons = []; let currentSeasons = [];
let currentEpisodes = []; let currentEpisodes = [];
let selectedSeasonEpisodeCount = 0;
// Event Listeners // Event Listeners
selectDirBtn.addEventListener('click', selectDirectory); selectDirBtn.addEventListener('click', selectDirectory);
@ -177,14 +178,17 @@ function displayFiles(files) {
return; return;
} }
files.forEach(file => { // Separate folders from media files
const fileItem = document.createElement('div'); const folders = files.filter(f => f.isFolder);
fileItem.className = 'file-item'; const mediaFiles = files.filter(f => !f.isFolder);
// Handle folders differently from media files // Track episode number for media files only
if (file.isFolder) { let episodeNumber = 1;
fileItem.classList.add('folder-item');
fileItem.style.cursor = 'pointer'; // Display folders first (not draggable, no episode number)
folders.forEach(file => {
const fileItem = document.createElement('div');
fileItem.className = 'file-item folder-item';
fileItem.innerHTML = ` fileItem.innerHTML = `
<div style="font-size: 18px; margin-right: 10px;">📁</div> <div style="font-size: 18px; margin-right: 10px;">📁</div>
<div class="file-name folder-name" data-file-path="${file.path}">${file.name}</div> <div class="file-name folder-name" data-file-path="${file.path}">${file.name}</div>
@ -200,8 +204,15 @@ function displayFiles(files) {
}); });
fileListEl.appendChild(fileItem); fileListEl.appendChild(fileItem);
return; });
}
// Display media files with episode numbers and drag/drop
mediaFiles.forEach((file, index) => {
const fileItem = document.createElement('div');
fileItem.className = 'file-item';
fileItem.draggable = true;
fileItem.dataset.index = index;
fileItem.dataset.filePath = file.path;
// Use actual duration from file metadata // Use actual duration from file metadata
const duration = file.duration || '00:00'; const duration = file.duration || '00:00';
@ -212,6 +223,8 @@ function displayFiles(files) {
const problemLabel = file.isProblematic ? '<span class="problematic-label">⚠️</span> ' : ''; const problemLabel = file.isProblematic ? '<span class="problematic-label">⚠️</span> ' : '';
fileItem.innerHTML = ` fileItem.innerHTML = `
<div class="drag-handle"></div>
<div class="episode-number" data-episode="${episodeNumber}">${episodeNumber}</div>
<div class="file-name" data-file-path="${file.path}">${file.name}</div> <div class="file-name" data-file-path="${file.path}">${file.name}</div>
<div class="file-duration">${duration}</div> <div class="file-duration">${duration}</div>
<div class="file-quality">${quality}</div> <div class="file-quality">${quality}</div>
@ -219,14 +232,23 @@ function displayFiles(files) {
<div class="file-tags"> <div class="file-tags">
<span class="tag-icon extra-tag" data-file-path="${file.path}" title="Mark as Extra">🏷</span> <span class="tag-icon extra-tag" data-file-path="${file.path}" title="Mark as Extra">🏷</span>
<span class="tag-icon commentary-tag" data-file-path="${file.path}" title="Add Commentary">💬</span> <span class="tag-icon commentary-tag" data-file-path="${file.path}" title="Add Commentary">💬</span>
<span class="tag-icon delete-tag" data-file-path="${file.path}" title="Mark for Deletion">🗑</span>
<span class="video-preview-btn" data-file-path="${file.path}" title="Preview Video">🎬</span> <span class="video-preview-btn" data-file-path="${file.path}" title="Preview Video">🎬</span>
<button class="play-button" style="opacity: 0.3; cursor: default; flex-shrink: 0;" data-file-path="${file.path}" disabled></button> <button class="play-button" style="opacity: 0.3; cursor: default; flex-shrink: 0;" data-file-path="${file.path}" disabled></button>
</div> </div>
`; `;
// Add drag and drop event listeners
fileItem.addEventListener('dragstart', handleDragStart);
fileItem.addEventListener('dragend', handleDragEnd);
fileItem.addEventListener('dragover', handleDragOver);
fileItem.addEventListener('dragleave', handleDragLeave);
fileItem.addEventListener('drop', handleDrop);
// Add click event to make file name editable // Add click event to make file name editable
const fileNameElement = fileItem.querySelector('.file-name'); const fileNameElement = fileItem.querySelector('.file-name');
fileNameElement.addEventListener('click', function(e) { fileNameElement.addEventListener('click', function(e) {
e.stopPropagation();
makeEditable(e.target); makeEditable(e.target);
}); });
@ -247,7 +269,16 @@ function displayFiles(files) {
icon.addEventListener('click', function(e) { icon.addEventListener('click', function(e) {
e.stopPropagation(); // Prevent event bubbling e.stopPropagation(); // Prevent event bubbling
const filePath = this.dataset.filePath; const filePath = this.dataset.filePath;
const tagType = this.classList.contains('extra-tag') ? 'extra' : 'commentary'; let tagType;
if (this.classList.contains('extra-tag')) {
tagType = 'extra';
} else if (this.classList.contains('commentary-tag')) {
tagType = 'commentary';
} else if (this.classList.contains('delete-tag')) {
tagType = 'delete';
} else {
return;
}
// Check if file is already tagged with this type // Check if file is already tagged with this type
const fileItem = this.closest('.file-item'); const fileItem = this.closest('.file-item');
@ -257,11 +288,12 @@ function displayFiles(files) {
// Untag the file // Untag the file
untagFile(filePath, tagType); untagFile(filePath, tagType);
} else { } else {
// If tagging this type, untag any existing tag of the other type // If tagging this type, untag any existing tag of other types
const otherTagType = tagType === 'extra' ? 'commentary' : 'extra'; ['extra', 'commentary', 'delete'].forEach(otherType => {
if (fileItem.hasAttribute('data-tagged-' + otherTagType)) { if (otherType !== tagType && fileItem.hasAttribute('data-tagged-' + otherType)) {
untagFile(filePath, otherTagType); untagFile(filePath, otherType);
} }
});
// Tag the file // Tag the file
addTagToEpisode(filePath, tagType); addTagToEpisode(filePath, tagType);
} }
@ -284,8 +316,14 @@ function displayFiles(files) {
// Get the file item and tag type // Get the file item and tag type
const fileItemEl = this.closest('.file-item'); const fileItemEl = this.closest('.file-item');
const tagType = fileItemEl.hasAttribute('data-tagged-extra') ? 'extra' : let tagType = null;
fileItemEl.hasAttribute('data-tagged-commentary') ? 'commentary' : null; if (fileItemEl.hasAttribute('data-tagged-extra')) {
tagType = 'extra';
} else if (fileItemEl.hasAttribute('data-tagged-commentary')) {
tagType = 'commentary';
} else if (fileItemEl.hasAttribute('data-tagged-delete')) {
tagType = 'delete';
}
console.log('Tag type determined:', tagType); console.log('Tag type determined:', tagType);
if (tagType) { if (tagType) {
@ -295,6 +333,8 @@ function displayFiles(files) {
// Remove the item from the file list after successful move // Remove the item from the file list after successful move
fileItemEl.remove(); fileItemEl.remove();
updateTaggedCount(); updateTaggedCount();
updateEpisodeNumbers();
checkEpisodeCountMatch();
} }
} else { } else {
console.log('No tag type found for file'); console.log('No tag type found for file');
@ -302,6 +342,81 @@ function displayFiles(files) {
}); });
fileListEl.appendChild(fileItem); fileListEl.appendChild(fileItem);
episodeNumber++;
});
// Check if episode count matches after displaying files
checkEpisodeCountMatch();
}
// Drag and drop handlers
let draggedItem = null;
function handleDragStart(e) {
draggedItem = this;
this.classList.add('dragging');
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/plain', this.dataset.index);
}
function handleDragEnd(e) {
this.classList.remove('dragging');
// Remove drag-over class from all items
document.querySelectorAll('.file-item').forEach(item => {
item.classList.remove('drag-over');
});
draggedItem = null;
}
function handleDragOver(e) {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
// Only show drag-over for non-folder items
if (!this.classList.contains('folder-item') && this !== draggedItem) {
this.classList.add('drag-over');
}
}
function handleDragLeave(e) {
this.classList.remove('drag-over');
}
function handleDrop(e) {
e.preventDefault();
this.classList.remove('drag-over');
if (this === draggedItem || this.classList.contains('folder-item')) return;
// Get all media file items (not folders)
const fileItems = Array.from(fileListEl.querySelectorAll('.file-item:not(.folder-item)'));
const draggedIndex = fileItems.indexOf(draggedItem);
const dropIndex = fileItems.indexOf(this);
if (draggedIndex === -1 || dropIndex === -1) return;
// Move the dragged item in the DOM
if (draggedIndex < dropIndex) {
this.parentNode.insertBefore(draggedItem, this.nextSibling);
} else {
this.parentNode.insertBefore(draggedItem, this);
}
// Update episode numbers
updateEpisodeNumbers();
}
function updateEpisodeNumbers() {
const fileItems = fileListEl.querySelectorAll('.file-item:not(.folder-item)');
let episodeNum = 1;
fileItems.forEach(item => {
const episodeEl = item.querySelector('.episode-number');
if (episodeEl) {
episodeEl.textContent = episodeNum;
episodeEl.dataset.episode = episodeNum;
episodeNum++;
}
}); });
} }
@ -384,13 +499,22 @@ function addTagToEpisode(filePath, tagType) {
// Add visual indication of tagging using data attribute for CSS styling // Add visual indication of tagging using data attribute for CSS styling
const tagIcon = item.querySelector(`.${tagType}-tag`); const tagIcon = item.querySelector(`.${tagType}-tag`);
if (tagIcon) { if (tagIcon) {
// Make the icon fully saturated and highlight in bright yellow with very strong visual effect // Set color based on tag type
let tagColor;
if (tagType === 'extra') {
tagColor = '#FFD700'; // Yellow
} else if (tagType === 'commentary') {
tagColor = '#17a2b8'; // Teal
} else if (tagType === 'delete') {
tagColor = '#dc3545'; // Red
}
// Make the icon fully saturated and highlight
tagIcon.style.opacity = '1'; tagIcon.style.opacity = '1';
tagIcon.style.filter = 'none'; tagIcon.style.filter = 'none';
tagIcon.style.color = tagType === 'extra' ? '#FFD700' : '#17a2b8'; // Brighter yellow or teal color tagIcon.style.color = tagColor;
tagIcon.style.textShadow = '0 0 15px rgba(255, 215, 0, 1)'; // Very bright yellow glow (for extra tags) tagIcon.style.textShadow = `0 0 15px ${tagColor}`;
tagIcon.style.transform = 'scale(1.3)'; // More pronounced enlargement tagIcon.style.transform = 'scale(1.3)';
tagIcon.style.boxShadow = '0 0 10px rgba(255, 215, 0, 0.8)'; // Additional glow effect
// Add a data attribute to track that this file is tagged // Add a data attribute to track that this file is tagged
item.setAttribute('data-tagged-' + tagType, 'true'); item.setAttribute('data-tagged-' + tagType, 'true');
@ -448,7 +572,7 @@ function moveTaggedFile(filePath, tagType) {
// Function to move all tagged files at once // Function to move all tagged files at once
async function moveAllTaggedFiles() { async function moveAllTaggedFiles() {
const taggedItems = document.querySelectorAll('.file-item[data-tagged-extra], .file-item[data-tagged-commentary]'); const taggedItems = document.querySelectorAll('.file-item[data-tagged-extra], .file-item[data-tagged-commentary], .file-item[data-tagged-delete]');
if (taggedItems.length === 0) { if (taggedItems.length === 0) {
console.log('[RENDERER] No tagged files to move'); console.log('[RENDERER] No tagged files to move');
@ -467,7 +591,14 @@ async function moveAllTaggedFiles() {
const results = []; const results = [];
for (const item of taggedItems) { for (const item of taggedItems) {
const filePath = item.querySelector('.file-name').dataset.filePath; const filePath = item.querySelector('.file-name').dataset.filePath;
const tagType = item.hasAttribute('data-tagged-extra') ? 'extra' : 'commentary'; let tagType;
if (item.hasAttribute('data-tagged-extra')) {
tagType = 'extra';
} else if (item.hasAttribute('data-tagged-commentary')) {
tagType = 'commentary';
} else if (item.hasAttribute('data-tagged-delete')) {
tagType = 'delete';
}
const result = await moveTaggedFile(filePath, tagType); const result = await moveTaggedFile(filePath, tagType);
results.push(result); results.push(result);
@ -486,6 +617,8 @@ async function moveAllTaggedFiles() {
// Update the tagged count after all moves // Update the tagged count after all moves
updateTaggedCount(); updateTaggedCount();
updateEpisodeNumbers();
checkEpisodeCountMatch();
// Summary of results // Summary of results
const successful = results.filter(r => r.success).length; const successful = results.filter(r => r.success).length;
@ -517,9 +650,20 @@ function displayCreatedFolder(folderName) {
folderItem.className = 'folder-item'; folderItem.className = 'folder-item';
folderItem.setAttribute('data-folder-name', folderName); folderItem.setAttribute('data-folder-name', folderName);
const displayName = folderName === 'extra' ? 'extras' : 'commentary'; let displayName, folderIcon, folderColor;
const folderIcon = folderName === 'extra' ? '📁' : '💬'; if (folderName === 'extra') {
const folderColor = folderName === 'extra' ? '#FFD700' : '#17a2b8'; displayName = 'extras';
folderIcon = '📁';
folderColor = '#FFD700';
} else if (folderName === 'commentary') {
displayName = 'commentary';
folderIcon = '💬';
folderColor = '#17a2b8';
} else if (folderName === 'delete') {
displayName = 'delete';
folderIcon = '🗑️';
folderColor = '#dc3545';
}
folderItem.innerHTML = ` folderItem.innerHTML = `
<div class="folder-icon" style="font-size: 24px;">${folderIcon}</div> <div class="folder-icon" style="font-size: 24px;">${folderIcon}</div>
@ -533,7 +677,7 @@ function displayCreatedFolder(folderName) {
gap: 10px; gap: 10px;
padding: 12px; padding: 12px;
margin-bottom: 8px; margin-bottom: 8px;
background-color: #f8f9fa; background-color: #16213e;
border: 2px solid ${folderColor}; border: 2px solid ${folderColor};
border-radius: 8px; border-radius: 8px;
cursor: pointer; cursor: pointer;
@ -579,7 +723,11 @@ function untagFile(filePath, tagType) {
// Remove the data attribute // Remove the data attribute
item.removeAttribute('data-tagged-' + tagType); item.removeAttribute('data-tagged-' + tagType);
// Disable the play button when untagging // Disable the play button when untagging (only if no other tags)
const hasOtherTags = item.hasAttribute('data-tagged-extra') ||
item.hasAttribute('data-tagged-commentary') ||
item.hasAttribute('data-tagged-delete');
if (!hasOtherTags) {
const playButton = item.querySelector('.play-button'); const playButton = item.querySelector('.play-button');
if (playButton) { if (playButton) {
playButton.style.opacity = '0.3'; playButton.style.opacity = '0.3';
@ -589,6 +737,7 @@ function untagFile(filePath, tagType) {
} }
} }
} }
}
}); });
// Update the tagged count display // Update the tagged count display
@ -601,7 +750,7 @@ function untagFile(filePath, tagType) {
// Function to update the tagged items count display // Function to update the tagged items count display
function updateTaggedCount() { function updateTaggedCount() {
const taggedItems = document.querySelectorAll('.file-item[data-tagged-extra], .file-item[data-tagged-commentary]'); const taggedItems = document.querySelectorAll('.file-item[data-tagged-extra], .file-item[data-tagged-commentary], .file-item[data-tagged-delete]');
const count = taggedItems.length; const count = taggedItems.length;
const taggedCircle = document.getElementById('tagged-circle'); const taggedCircle = document.getElementById('tagged-circle');
const taggedCount = document.getElementById('tagged-count'); const taggedCount = document.getElementById('tagged-count');
@ -624,6 +773,24 @@ function updateTaggedCount() {
} }
} }
// Function to check if media file count matches selected season episode count
function checkEpisodeCountMatch() {
const fileList = document.getElementById('file-list');
// Count only actual media files (not folders)
const mediaFiles = document.querySelectorAll('.file-item:not(.folder-item)');
const mediaCount = mediaFiles.length;
if (selectedSeasonEpisodeCount > 0 && mediaCount === selectedSeasonEpisodeCount) {
// Perfect match - add green outline
fileList.style.border = '3px solid #28a745';
fileList.style.boxShadow = '0 0 15px rgba(40, 167, 69, 0.4)';
} else {
// No match or no season selected - remove green outline
fileList.style.border = '';
fileList.style.boxShadow = '';
}
}
// Initialize tagged count on page load // Initialize tagged count on page load
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
updateTaggedCount(); updateTaggedCount();
@ -769,26 +936,13 @@ function displaySeasons(seasons) {
seasonsContainer.innerHTML = ''; seasonsContainer.innerHTML = '';
if (!seasons || seasons.length === 0) { if (!seasons || seasons.length === 0) {
seasonsContainer.innerHTML = '<p>No seasons available.</p>'; seasonsContainer.innerHTML = '<p style="color: #888;">No seasons available.</p>';
return; return;
} }
// Create a container for seasons
const seasonsList = document.createElement('div');
seasonsList.style.marginTop = '10px';
seasons.forEach(season => { seasons.forEach(season => {
const seasonItem = document.createElement('div'); const seasonItem = document.createElement('div');
seasonItem.className = 'season-item'; seasonItem.className = 'season-item';
seasonItem.style.padding = '12px';
seasonItem.style.margin = '8px 0';
seasonItem.style.border = '1px solid #ddd';
seasonItem.style.borderRadius = '6px';
seasonItem.style.cursor = 'pointer';
seasonItem.style.backgroundColor = '#f8f9fa';
seasonItem.style.display = 'flex';
seasonItem.style.justifyContent = 'space-between';
seasonItem.style.alignItems = 'center';
// Format season display with episode count // Format season display with episode count
let seasonDisplay = `Season ${season.number}`; let seasonDisplay = `Season ${season.number}`;
@ -799,21 +953,25 @@ function displaySeasons(seasons) {
const episodeCount = season.episodeCount || 0; const episodeCount = season.episodeCount || 0;
seasonItem.innerHTML = ` seasonItem.innerHTML = `
<div style="display: flex; justify-content: space-between; align-items: center;">
<span>${seasonDisplay}</span> <span>${seasonDisplay}</span>
<span style="background-color: #007bff; color: white; padding: 4px 8px; border-radius: 12px; font-size: 12px;"> <span style="background-color: #e94560; color: white; padding: 4px 8px; border-radius: 12px; font-size: 11px;">
${episodeCount} episodes ${episodeCount} eps
</span> </span>
</div>
`; `;
// Add click event to fetch episodes // Add click event to fetch episodes
seasonItem.addEventListener('click', () => { seasonItem.addEventListener('click', () => {
// Remove selected class from all seasons
document.querySelectorAll('.season-item').forEach(item => item.classList.remove('selected'));
// Add selected class to clicked season
seasonItem.classList.add('selected');
fetchAndDisplayEpisodes(currentShow.id, season.number); fetchAndDisplayEpisodes(currentShow.id, season.number);
}); });
seasonsList.appendChild(seasonItem); seasonsContainer.appendChild(seasonItem);
}); });
seasonsContainer.appendChild(seasonsList);
} }
// Fetch and display episodes for a season // Fetch and display episodes for a season
@ -849,70 +1007,50 @@ function displayEpisodes(episodes) {
seasonsContainer.innerHTML = ''; seasonsContainer.innerHTML = '';
if (!episodes || episodes.length === 0) { if (!episodes || episodes.length === 0) {
seasonsContainer.innerHTML = '<p>No episodes available.</p>'; seasonsContainer.innerHTML = '<p style="color: #888;">No episodes available.</p>';
selectedSeasonEpisodeCount = 0;
checkEpisodeCountMatch();
return; return;
} }
// Create a container for episodes table // Store the episode count for this season
const episodesTable = document.createElement('div'); selectedSeasonEpisodeCount = episodes.length;
episodesTable.style.marginTop = '10px'; checkEpisodeCountMatch();
episodesTable.style.border = '1px solid #ddd';
episodesTable.style.borderRadius = '6px';
episodesTable.style.overflow = 'hidden';
// Create table header // Create a back button to return to seasons
const tableHeader = document.createElement('div'); const backButton = document.createElement('div');
tableHeader.style.display = 'grid'; backButton.className = 'season-item';
tableHeader.style.gridTemplateColumns = '1fr 1fr'; backButton.innerHTML = '← Back to Seasons';
tableHeader.style.backgroundColor = '#f8f9fa'; backButton.addEventListener('click', () => {
tableHeader.style.padding = '10px'; selectedSeasonEpisodeCount = 0;
tableHeader.style.fontWeight = 'bold'; checkEpisodeCountMatch();
tableHeader.style.borderBottom = '1px solid #ddd'; displaySeasons(currentSeasons);
});
seasonsContainer.appendChild(backButton);
tableHeader.innerHTML = ` // Create episodes container
<div>Episode Name</div> const episodesContainer = document.createElement('div');
<div>Runtime</div> episodesContainer.id = 'episodes-container';
`;
episodesTable.appendChild(tableHeader);
episodes.forEach(episode => { episodes.forEach(episode => {
const episodeRow = document.createElement('div'); const episodeRow = document.createElement('div');
episodeRow.className = 'episode-item'; episodeRow.className = 'episode-item';
episodeRow.style.display = 'grid';
episodeRow.style.gridTemplateColumns = '1fr 1fr';
episodeRow.style.padding = '10px';
episodeRow.style.borderBottom = '1px solid #eee';
episodeRow.style.backgroundColor = '#fff';
episodeRow.style.cursor = 'pointer';
episodeRow.style.transition = 'background-color 0.2s';
episodeRow.addEventListener('mouseenter', () => {
episodeRow.style.backgroundColor = '#f5f5f5';
});
episodeRow.addEventListener('mouseleave', () => {
episodeRow.style.backgroundColor = '#fff';
});
// Format episode display // Format episode display
const episodeName = episode.name || 'Untitled'; const episodeName = episode.name || 'Untitled';
const episodeRuntime = episode.runtime ? `${episode.runtime} min` : 'N/A'; const episodeRuntime = episode.runtime ? `${episode.runtime}m` : '';
episodeRow.innerHTML = ` episodeRow.innerHTML = `
<div style="font-weight: 500;">Episode ${episode.number}: ${episodeName}</div> <div style="display: flex; justify-content: space-between; align-items: center;">
<div style="color: #666;">${episodeRuntime}</div> <span><strong>E${episode.number}</strong> ${episodeName}</span>
${episodeRuntime ? `<span style="color: #888; font-size: 11px;">${episodeRuntime}</span>` : ''}
</div>
`; `;
// Add click event (could show more details) episodesContainer.appendChild(episodeRow);
episodeRow.addEventListener('click', () => {
alert(`Episode: ${episode.name || 'Untitled'}\nRuntime: ${episode.runtime || 'N/A'} min\nAired: ${episode.aired || 'N/A'}`);
}); });
episodesTable.appendChild(episodeRow); seasonsContainer.appendChild(episodesContainer);
});
seasonsContainer.appendChild(episodesTable);
// Also update the main file list to show episode matching information // Also update the main file list to show episode matching information
updateFileListWithEpisodeInfo(episodes); updateFileListWithEpisodeInfo(episodes);