diff --git a/video-konverter/app/static/tv/css/tv.css b/video-konverter/app/static/tv/css/tv.css
index 0b94c1c..83ff31f 100644
--- a/video-konverter/app/static/tv/css/tv.css
+++ b/video-konverter/app/static/tv/css/tv.css
@@ -1814,6 +1814,31 @@ textarea.input-editing {
font-size: 0.75rem;
}
+/* Serie als gesehen markieren - Button */
+.tv-mark-series-btn {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.4rem;
+ padding: 0.5rem 1rem;
+ background: transparent;
+ border: 1px solid var(--border);
+ color: var(--text);
+ border-radius: var(--radius);
+ cursor: pointer;
+ font-size: 0.9rem;
+ transition: background 0.2s, border-color 0.2s;
+}
+.tv-mark-series-btn:hover,
+.tv-mark-series-btn:focus {
+ background: var(--bg-hover);
+ border-color: var(--accent);
+}
+.tv-mark-series-btn.active {
+ background: var(--accent);
+ color: #000;
+ border-color: var(--accent);
+}
+
/* --- Episode Card-Grid (Phase 5, Plex-Style) --- */
.tv-episode-grid {
display: grid;
diff --git a/video-konverter/app/templates/tv/series_detail.html b/video-konverter/app/templates/tv/series_detail.html
index a10711c..6236be9 100644
--- a/video-konverter/app/templates/tv/series_detail.html
+++ b/video-konverter/app/templates/tv/series_detail.html
@@ -63,6 +63,15 @@
{% if in_watchlist %}♥{% else %}♡{% endif %}
{{ t('series.watchlist') }}
+
+
@@ -254,6 +263,54 @@ function toggleWatched(videoId, btn) {
.catch(() => {});
}
+function markSeriesWatched(btn) {
+ // Alle ungesehenen Episoden aus ALLEN Staffeln sammeln
+ const allCards = document.querySelectorAll('.tv-episode-tile:not(.tv-ep-seen)');
+ const ids = [];
+ allCards.forEach(function(card) {
+ var vid = card.dataset.videoId;
+ if (vid) ids.push(parseInt(vid));
+ });
+ if (ids.length === 0) return;
+
+ // Batch-Request an API (gleiche Methode wie markSeasonWatched)
+ Promise.all(ids.map(function(id) {
+ return fetch('/tv/api/watch-progress', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ video_id: id, position_sec: 100, duration_sec: 100 }),
+ });
+ })).then(function() {
+ // Alle Episoden-Cards als gesehen markieren
+ document.querySelectorAll('.tv-episode-tile').forEach(function(card) {
+ card.classList.add('tv-ep-seen');
+ var markBtn = card.querySelector('.tv-ep-tile-mark');
+ if (markBtn) markBtn.classList.add('active');
+ var thumb = card.querySelector('.tv-ep-thumb');
+ if (thumb && !thumb.querySelector('.tv-ep-watched')) {
+ var check = document.createElement('div');
+ check.className = 'tv-ep-watched';
+ check.innerHTML = '✓';
+ thumb.appendChild(check);
+ }
+ });
+ // Alle Staffel-Tabs als komplett markieren
+ document.querySelectorAll('.tv-tab').forEach(function(tab) {
+ if (!tab.classList.contains('tv-tab-complete')) {
+ tab.classList.add('tv-tab-complete');
+ if (!tab.querySelector('.tv-tab-check')) {
+ var check = document.createElement('span');
+ check.className = 'tv-tab-check';
+ check.innerHTML = ' ✓';
+ tab.appendChild(check);
+ }
+ }
+ });
+ // Button-Zustand aendern
+ btn.classList.add('active');
+ }).catch(function() {});
+}
+
function markSeasonWatched(seriesId, seasonNum) {
const season = document.getElementById('season-' + seasonNum);
if (!season) return;