diff --git a/index.html b/index.html
index 3b9067e..91604f2 100644
--- a/index.html
+++ b/index.html
@@ -178,6 +178,11 @@
diff --git a/main.js b/main.js
index 09d25fb..11fe32d 100644
--- a/main.js
+++ b/main.js
@@ -184,6 +184,163 @@ ipcMain.handle('search-tvdb', async (event, query) => {
}
});
+// IPC handler for getting show details including seasons
+ipcMain.handle('get-show-details', async (event, showId) => {
+ try {
+ // Import required modules
+ const axios = require('axios');
+
+ // Get API key from environment
+ const apiKey = process.env.TVDB_API_KEY || process.env.API_KEY;
+
+ if (!apiKey) {
+ throw new Error('TVDB_API_KEY not found in environment variables');
+ }
+
+ // For TVDB v4 API, we need to first get an authentication token
+ let token = null;
+
+ // Try to get token from cache or login
+ try {
+ const loginResponse = await axios.post('https://api4.thetvdb.com/v4/login', {
+ apikey: apiKey
+ }, {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json'
+ }
+ });
+
+ token = loginResponse.data.data.token;
+ } catch (loginError) {
+ console.error('TVDB Login Error:', loginError.message);
+ throw new Error('Failed to authenticate with TVDB API: ' + loginError.message);
+ }
+
+ // Make API request to get show extended details including seasons
+ const response = await axios.get(`https://api4.thetvdb.com/v4/series/${showId}/extended`, {
+ headers: {
+ 'Authorization': `Bearer ${token}`,
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json'
+ }
+ });
+
+ if (response.data && response.data.data) {
+ const showData = response.data.data;
+
+ // Process seasons - TVDB v4 API returns seasons in the show data
+ const seasons = (showData.seasons || []).map(season => ({
+ id: season.id,
+ name: season.name,
+ number: season.number,
+ type: season.type?.name,
+ episodeCount: season.episodeCount
+ }));
+
+ return {
+ success: true,
+ data: {
+ id: showData.id,
+ name: showData.name,
+ status: showData.status?.name,
+ firstAired: showData.firstAired,
+ overview: showData.overview,
+ image: showData.image,
+ slug: showData.slug,
+ seasons: seasons
+ }
+ };
+ } else {
+ throw new Error('Invalid response structure from TVDB API');
+ }
+ } catch (error) {
+ console.error('TVDB API Error getting show details:', error.message);
+ console.error('Error status:', error.response?.status);
+ console.error('Error data:', error.response?.data);
+
+ return { success: false, error: 'Failed to fetch show details from TVDB API: ' + error.message };
+ }
+});
+
+// IPC handler for getting season episodes
+ipcMain.handle('get-season-episodes', async (event, showId, seasonNumber) => {
+ try {
+ // Import required modules
+ const axios = require('axios');
+
+ // Get API key from environment
+ const apiKey = process.env.TVDB_API_KEY || process.env.API_KEY;
+
+ if (!apiKey) {
+ throw new Error('TVDB_API_KEY not found in environment variables');
+ }
+
+ // For TVDB v4 API, we need to first get an authentication token
+ let token = null;
+
+ // Try to get token from cache or login
+ try {
+ const loginResponse = await axios.post('https://api4.thetvdb.com/v4/login', {
+ apikey: apiKey
+ }, {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json'
+ }
+ });
+
+ token = loginResponse.data.data.token;
+ } catch (loginError) {
+ console.error('TVDB Login Error:', loginError.message);
+ throw new Error('Failed to authenticate with TVDB API: ' + loginError.message);
+ }
+
+ // Make API request to get season episodes
+ // Note: The API endpoint structure may vary, so we'll try different approaches
+ const response = await axios.get(`https://api4.thetvdb.com/v4/series/${showId}/episodes/default`, {
+ headers: {
+ 'Authorization': `Bearer ${token}`,
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json'
+ },
+ params: {
+ page: 0
+ }
+ });
+
+ if (response.data && response.data.data) {
+ // Process episodes
+ const episodes = response.data.data.episodes ? response.data.data.episodes.map(episode => ({
+ id: episode.id,
+ name: episode.name,
+ number: episode.number,
+ seasonNumber: episode.seasonNumber,
+ aired: episode.aired,
+ overview: episode.overview,
+ runtime: episode.runtime
+ })) : [];
+
+ return {
+ success: true,
+ data: {
+ showId: showId,
+ seasonNumber: seasonNumber,
+ episodes: episodes
+ }
+ };
+ } else {
+ throw new Error('Invalid response structure from TVDB API');
+ }
+ } catch (error) {
+ console.error('TVDB API Error getting season episodes:', error.message);
+ console.error('Error status:', error.response?.status);
+ console.error('Error data:', error.response?.data);
+
+ return { success: false, error: 'Failed to fetch season episodes from TVDB API: ' + error.message };
+ }
+});
+
// Test function to verify API connectivity
ipcMain.handle('test-tvdb-api', async () => {
try {
diff --git a/renderer.js b/renderer.js
index 66ae0cc..d7f038d 100644
--- a/renderer.js
+++ b/renderer.js
@@ -7,10 +7,14 @@ const selectedDirEl = document.getElementById('selected-dir');
const searchInput = document.getElementById('search-input');
const searchResultsEl = document.getElementById('search-results');
const fileListEl = document.getElementById('file-list');
+const showDetailsEl = document.getElementById('show-details');
// Current state
let currentDirectory = null;
let currentFiles = [];
+let currentShow = null;
+let currentSeasons = [];
+let currentEpisodes = [];
// Event Listeners
selectDirBtn.addEventListener('click', selectDirectory);
@@ -241,10 +245,144 @@ function displaySearchResults(results) {
}
// Select a show and display more details
-function selectShow(show) {
+async function selectShow(show) {
console.log('Selected show:', show);
- // In a real implementation, this would fetch show details and display seasons
- alert(`Selected show: ${show.seriesName}\nStatus: ${show.status || 'N/A'}\nFirst Aired: ${show.firstAired || 'N/A'}`);
+ currentShow = show;
+
+ // Display show title
+ document.getElementById('show-title').textContent = show.seriesName || show.name;
+
+ // Fetch show details including seasons
+ try {
+ const result = await ipcRenderer.invoke('get-show-details', show.id);
+
+ if (result.success && result.data) {
+ const showData = result.data;
+ currentSeasons = showData.seasons || [];
+
+ // Display seasons
+ displaySeasons(currentSeasons);
+ } else {
+ console.error('Failed to fetch show details:', result.error);
+ document.getElementById('seasons-container').innerHTML = '
Error loading seasons: ' + (result.error || 'Unknown error') + '
';
+ }
+ } catch (error) {
+ console.error('Error fetching show details:', error);
+ document.getElementById('seasons-container').innerHTML = '
Error loading seasons: ' + error.message + '
';
+ }
+}
+
+// Display seasons
+function displaySeasons(seasons) {
+ const seasonsContainer = document.getElementById('seasons-container');
+ seasonsContainer.innerHTML = '';
+
+ if (!seasons || seasons.length === 0) {
+ seasonsContainer.innerHTML = '
No seasons available.
';
+ return;
+ }
+
+ // Create a container for seasons
+ const seasonsList = document.createElement('div');
+ seasonsList.style.marginTop = '10px';
+
+ seasons.forEach(season => {
+ const seasonItem = document.createElement('div');
+ seasonItem.className = 'season-item';
+ seasonItem.style.padding = '8px';
+ seasonItem.style.margin = '5px 0';
+ seasonItem.style.border = '1px solid #ddd';
+ seasonItem.style.borderRadius = '4px';
+ seasonItem.style.cursor = 'pointer';
+ seasonItem.style.backgroundColor = '#f8f9fa';
+
+ // Format season display
+ let seasonDisplay = `Season ${season.number}`;
+ if (season.name && season.name !== `Season ${season.number}`) {
+ seasonDisplay += ` - ${season.name}`;
+ }
+ if (season.type) {
+ seasonDisplay += ` (${season.type})`;
+ }
+ if (season.episodeCount) {
+ seasonDisplay += ` (${season.episodeCount} episodes)`;
+ }
+
+ seasonItem.textContent = seasonDisplay;
+
+ // Add click event to fetch episodes
+ seasonItem.addEventListener('click', () => {
+ fetchAndDisplayEpisodes(currentShow.id, season.number);
+ });
+
+ seasonsList.appendChild(seasonItem);
+ });
+
+ seasonsContainer.appendChild(seasonsList);
+}
+
+// Fetch and display episodes for a season
+async function fetchAndDisplayEpisodes(showId, seasonNumber) {
+ try {
+ const result = await ipcRenderer.invoke('get-season-episodes', showId, seasonNumber);
+
+ if (result.success && result.data) {
+ const episodes = result.data.episodes || [];
+ displayEpisodes(episodes);
+ } else {
+ console.error('Failed to fetch episodes:', result.error);
+ document.getElementById('seasons-container').innerHTML = '
Error loading episodes: ' + (result.error || 'Unknown error') + '
';
+ }
+ } catch (error) {
+ console.error('Error fetching episodes:', error);
+ document.getElementById('seasons-container').innerHTML = '
Error loading episodes: ' + error.message + '
';
+ }
+}
+
+// Display episodes
+function displayEpisodes(episodes) {
+ const seasonsContainer = document.getElementById('seasons-container');
+ seasonsContainer.innerHTML = '';
+
+ if (!episodes || episodes.length === 0) {
+ seasonsContainer.innerHTML = '
No episodes available.
';
+ return;
+ }
+
+ // Create a container for episodes
+ const episodesList = document.createElement('div');
+ episodesList.style.marginTop = '10px';
+
+ episodes.forEach(episode => {
+ const episodeItem = document.createElement('div');
+ episodeItem.className = 'episode-item';
+ episodeItem.style.padding = '8px';
+ episodeItem.style.margin = '5px 0';
+ episodeItem.style.border = '1px solid #ddd';
+ episodeItem.style.borderRadius = '4px';
+ episodeItem.style.cursor = 'pointer';
+ episodeItem.style.backgroundColor = '#fff';
+
+ // Format episode display
+ let episodeDisplay = `Episode ${episode.number}: ${episode.name || 'Untitled'}`;
+ if (episode.aired) {
+ episodeDisplay += ` (${episode.aired})`;
+ }
+ if (episode.runtime) {
+ episodeDisplay += ` (${episode.runtime} min)`;
+ }
+
+ episodeItem.textContent = episodeDisplay;
+
+ // Add click event (could show more details)
+ episodeItem.addEventListener('click', () => {
+ alert(`Episode: ${episode.name || 'Untitled'}\nRuntime: ${episode.runtime || 'N/A'} min\nAired: ${episode.aired || 'N/A'}`);
+ });
+
+ episodesList.appendChild(episodeItem);
+ });
+
+ seasonsContainer.appendChild(episodesList);
}
// Debounce function for search input