Skip to content

Commit 9c44127

Browse files
committed
udpate
1 parent f258958 commit 9c44127

File tree

2 files changed

+146
-27
lines changed

2 files changed

+146
-27
lines changed

frontend/static/css/requestarr.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,25 @@ input:checked + .toggle-slider:before {
699699
font-weight: 600;
700700
}
701701

702+
.requested-badge {
703+
background: rgba(255, 152, 0, 0.8);
704+
color: #fff;
705+
padding: 2px 8px;
706+
border-radius: 12px;
707+
font-size: 11px;
708+
font-weight: 600;
709+
}
710+
711+
.season-item.season-requested {
712+
opacity: 0.6;
713+
background: rgba(255, 152, 0, 0.1);
714+
}
715+
716+
.episode-item.episode-requested {
717+
opacity: 0.6;
718+
background: rgba(255, 152, 0, 0.05);
719+
}
720+
702721
.season-expand-btn {
703722
background: none;
704723
border: none;

frontend/static/js/requestarr.js

Lines changed: 127 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ class RequestarrModule {
575575
<div class="seasons-container">
576576
<h4>Select Seasons & Episodes</h4>
577577
<div class="seasons-list">
578-
${this.createSeasonsHTML(seriesDetails.seasons, isMobile)}
578+
${this.createSeasonsHTML(seriesDetails.seasons, isMobile, item.tmdb_id)}
579579
</div>
580580
</div>
581581
<div class="granular-modal-actions">
@@ -600,61 +600,83 @@ class RequestarrModule {
600600
});
601601
}
602602

603-
createSeasonsHTML(seasons, isMobile) {
603+
createSeasonsHTML(seasons, isMobile, tmdbId) {
604+
const requestedItems = this.getRequestedItems(tmdbId);
605+
604606
return seasons.map(season => {
605607
const isComplete = season.downloaded_episodes >= season.total_episodes && season.total_episodes > 0;
606608
const hasEpisodes = season.episodes && season.episodes.length > 0;
609+
const isRequested = requestedItems.seasons.includes(season.season_number);
610+
const isDisabled = isComplete || isRequested;
611+
612+
let statusBadge = '';
613+
if (isComplete) {
614+
statusBadge = '<span class="complete-badge">Complete</span>';
615+
} else if (isRequested) {
616+
statusBadge = '<span class="requested-badge">Requested</span>';
617+
}
607618

608619
return `
609-
<div class="season-item ${isComplete ? 'season-complete' : ''}" data-season="${season.season_number}">
620+
<div class="season-item ${isComplete ? 'season-complete' : ''} ${isRequested ? 'season-requested' : ''}" data-season="${season.season_number}">
610621
<div class="season-header">
611622
<div class="season-checkbox-container">
612623
<input type="checkbox"
613624
id="season-${season.season_number}"
614625
class="season-checkbox"
615-
${isComplete ? 'disabled' : ''}
626+
${isDisabled ? 'disabled' : ''}
616627
data-season="${season.season_number}">
617628
<label for="season-${season.season_number}" class="season-label">
618629
<span class="season-title">Season ${season.season_number}</span>
619630
<span class="season-stats">${season.downloaded_episodes}/${season.total_episodes} episodes</span>
620-
${isComplete ? '<span class="complete-badge">Complete</span>' : ''}
631+
${statusBadge}
621632
</label>
622633
</div>
623-
${hasEpisodes && !isComplete ? `
634+
${hasEpisodes && !isDisabled ? `
624635
<button class="season-expand-btn" data-season="${season.season_number}">
625636
<span class="expand-icon">▼</span>
626637
</button>
627638
` : ''}
628639
</div>
629-
${hasEpisodes && !isComplete ? `
640+
${hasEpisodes && !isDisabled ? `
630641
<div class="episodes-container" data-season="${season.season_number}" style="display: none;">
631-
${this.createEpisodesHTML(season.episodes, season.season_number, isMobile)}
642+
${this.createEpisodesHTML(season.episodes, season.season_number, isMobile, requestedItems)}
632643
</div>
633644
` : ''}
634645
</div>
635646
`;
636647
}).join('');
637648
}
638649

639-
createEpisodesHTML(episodes, seasonNumber, isMobile) {
650+
createEpisodesHTML(episodes, seasonNumber, isMobile, requestedItems) {
640651
return episodes.map(episode => {
641652
const isDownloaded = episode.has_file;
653+
const isRequested = requestedItems.episodes.some(req =>
654+
req.season === seasonNumber && req.episode === episode.episode_number
655+
);
656+
const isDisabled = isDownloaded || isRequested;
642657
const airDate = episode.air_date ? new Date(episode.air_date).toLocaleDateString() : '';
643658

659+
let statusBadge = '';
660+
if (isDownloaded) {
661+
statusBadge = '<span class="downloaded-badge">Downloaded</span>';
662+
} else if (isRequested) {
663+
statusBadge = '<span class="requested-badge">Requested</span>';
664+
}
665+
644666
return `
645-
<div class="episode-item ${isDownloaded ? 'episode-downloaded' : ''}" data-episode="${episode.episode_number}">
667+
<div class="episode-item ${isDownloaded ? 'episode-downloaded' : ''} ${isRequested ? 'episode-requested' : ''}" data-episode="${episode.episode_number}">
646668
<div class="episode-checkbox-container">
647669
<input type="checkbox"
648670
id="episode-${seasonNumber}-${episode.episode_number}"
649671
class="episode-checkbox"
650-
${isDownloaded ? 'disabled' : ''}
672+
${isDisabled ? 'disabled' : ''}
651673
data-season="${seasonNumber}"
652674
data-episode="${episode.episode_number}">
653675
<label for="episode-${seasonNumber}-${episode.episode_number}" class="episode-label">
654676
<span class="episode-number">S${seasonNumber.toString().padStart(2, '0')}E${episode.episode_number.toString().padStart(2, '0')}</span>
655677
${!isMobile && episode.title ? `<span class="episode-title">${episode.title}</span>` : ''}
656678
${!isMobile && airDate ? `<span class="episode-date">${airDate}</span>` : ''}
657-
${isDownloaded ? '<span class="downloaded-badge">Downloaded</span>' : ''}
679+
${statusBadge}
658680
</label>
659681
</div>
660682
</div>
@@ -816,6 +838,27 @@ class RequestarrModule {
816838
const checkedSeasons = modal.querySelectorAll('.season-checkbox:checked');
817839
const checkedEpisodes = modal.querySelectorAll('.episode-checkbox:checked');
818840

841+
// Track what was requested
842+
const requestedSeasons = [];
843+
const requestedEpisodes = [];
844+
845+
checkedSeasons.forEach(checkbox => {
846+
requestedSeasons.push(parseInt(checkbox.dataset.season));
847+
});
848+
849+
checkedEpisodes.forEach(checkbox => {
850+
const seasonNum = parseInt(checkbox.dataset.season);
851+
const episodeNum = parseInt(checkbox.dataset.episode);
852+
// Only add if the whole season wasn't selected
853+
const seasonCheckbox = modal.querySelector(`.season-checkbox[data-season="${seasonNum}"]`);
854+
if (!seasonCheckbox.checked) {
855+
requestedEpisodes.push({ season: seasonNum, episode: episodeNum });
856+
}
857+
});
858+
859+
// Store the requested items in localStorage
860+
this.saveRequestedItems(item.tmdb_id, requestedSeasons, requestedEpisodes);
861+
819862
// For now, show notification about granular selection and fall back to simple request
820863
const selectedCount = checkedSeasons.length + checkedEpisodes.length;
821864
this.showNotification(`Granular selection (${selectedCount} items) coming soon! Using entire series request for now.`, 'info');
@@ -827,24 +870,81 @@ class RequestarrModule {
827870
const statusElement = card?.querySelector('.availability-status');
828871

829872
if (button && statusElement) {
830-
// Update to show partial request status
831-
button.textContent = 'Request More';
832-
button.className = 'request-btn btn-warning'; // Use warning style to indicate partial
833-
button.disabled = false; // Keep enabled for additional requests
873+
// Check if all seasons are now requested
874+
const allRequestedItems = this.getRequestedItems(item.tmdb_id);
875+
const totalSeasons = modal.querySelectorAll('.season-checkbox').length;
876+
const isFullyRequested = allRequestedItems.seasons.length >= totalSeasons;
834877

835-
statusElement.className = 'availability-status status-partial-request';
836-
statusElement.innerHTML = '<span class="status-icon">📺</span><span class="status-text">Partially Requested</span>';
837-
838-
// Update the item data to reflect partial request
839-
if (this.itemData[cardId]) {
840-
this.itemData[cardId].availability = {
841-
...this.itemData[cardId].availability,
842-
status: 'partially_requested',
843-
message: 'Some episodes requested - click to request more',
844-
supports_granular: true
845-
};
878+
if (isFullyRequested) {
879+
// All seasons requested - show as fully requested
880+
button.textContent = 'Already Requested';
881+
button.className = 'request-btn btn-disabled';
882+
button.disabled = true;
883+
884+
statusElement.className = 'availability-status status-requested';
885+
statusElement.innerHTML = '<span class="status-icon">⏳</span><span class="status-text">Requested</span>';
886+
887+
// Update item data
888+
if (this.itemData[cardId]) {
889+
this.itemData[cardId].availability = {
890+
...this.itemData[cardId].availability,
891+
status: 'requested',
892+
message: 'Previously requested',
893+
supports_granular: false
894+
};
895+
}
896+
} else {
897+
// Partial request - keep button active
898+
button.textContent = 'Request More';
899+
button.className = 'request-btn btn-warning';
900+
button.disabled = false;
901+
902+
statusElement.className = 'availability-status status-partial-request';
903+
statusElement.innerHTML = '<span class="status-icon">📺</span><span class="status-text">Partially Requested</span>';
904+
905+
// Update item data
906+
if (this.itemData[cardId]) {
907+
this.itemData[cardId].availability = {
908+
...this.itemData[cardId].availability,
909+
status: 'partially_requested',
910+
message: 'Some episodes requested - click to request more',
911+
supports_granular: true
912+
};
913+
}
914+
}
915+
}
916+
}
917+
918+
saveRequestedItems(tmdbId, seasons, episodes) {
919+
const key = `requestarr_requested_${tmdbId}`;
920+
const existing = this.getRequestedItems(tmdbId);
921+
922+
// Merge with existing requests
923+
const allSeasons = [...new Set([...existing.seasons, ...seasons])];
924+
const allEpisodes = [...existing.episodes, ...episodes];
925+
926+
const requestData = {
927+
seasons: allSeasons,
928+
episodes: allEpisodes,
929+
timestamp: Date.now()
930+
};
931+
932+
localStorage.setItem(key, JSON.stringify(requestData));
933+
}
934+
935+
getRequestedItems(tmdbId) {
936+
const key = `requestarr_requested_${tmdbId}`;
937+
const stored = localStorage.getItem(key);
938+
939+
if (stored) {
940+
try {
941+
return JSON.parse(stored);
942+
} catch (e) {
943+
console.error('Error parsing requested items:', e);
846944
}
847945
}
946+
947+
return { seasons: [], episodes: [], timestamp: 0 };
848948
}
849949

850950
showNotification(message, type = 'info') {

0 commit comments

Comments
 (0)