Füge Checkbox für Serien ohne klassische Staffeln hinzu und aktualisiere die Logik zur Episodensuche, um auch Jahresformate und "bisher X Folgen" zu unterstützen.

This commit is contained in:
Akamaru
2025-07-30 14:26:37 +02:00
parent 03c3ba2285
commit 692d4fb2fe

View File

@@ -10,7 +10,7 @@ from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
QLabel, QMessageBox, QSpinBox, QComboBox, QTableWidget, QLabel, QMessageBox, QSpinBox, QComboBox, QTableWidget,
QTableWidgetItem, QHeaderView, QDialog, QDialogButtonBox, QTableWidgetItem, QHeaderView, QDialog, QDialogButtonBox,
QTextEdit, QGroupBox, QToolBar, QSplitter, QFormLayout, QTextEdit, QGroupBox, QToolBar, QSplitter, QFormLayout,
QListWidgetItem) QListWidgetItem, QCheckBox)
from PyQt5.QtCore import Qt, QTimer from PyQt5.QtCore import Qt, QTimer
# Logging Konfiguration # Logging Konfiguration
@@ -83,6 +83,11 @@ class NewSeriesDialog(QDialog):
self.date_pref.addItems(["Bevorzuge Erstausstrahlung", "Bevorzuge TV", "Bevorzuge Streaming", "Bevorzuge deutsche Synchro"]) self.date_pref.addItems(["Bevorzuge Erstausstrahlung", "Bevorzuge TV", "Bevorzuge Streaming", "Bevorzuge deutsche Synchro"])
settings_layout.addRow("Datum Präferenz:", self.date_pref) settings_layout.addRow("Datum Präferenz:", self.date_pref)
# Checkbox für Serien ohne klassische Staffeln
self.no_seasons_check = QCheckBox("Serie ohne klassische Staffeln")
self.no_seasons_check.setToolTip("Aktivieren für Serien mit fortlaufender Nummerierung oder Jahresformat")
settings_layout.addRow("", self.no_seasons_check)
settings_group.setLayout(settings_layout) settings_group.setLayout(settings_layout)
layout.addWidget(settings_group) layout.addWidget(settings_group)
@@ -145,7 +150,8 @@ class NewSeriesDialog(QDialog):
'mode': self.staffel_mode.currentText(), 'mode': self.staffel_mode.currentText(),
'staffel': self.staffel_spin.value() 'staffel': self.staffel_spin.value()
}, },
'date_preference': self.date_pref.currentText() 'date_preference': self.date_pref.currentText(),
'no_seasons': self.no_seasons_check.isChecked()
} }
class SeriesEditDialog(QDialog): class SeriesEditDialog(QDialog):
@@ -224,6 +230,11 @@ class SeriesEditDialog(QDialog):
self.date_pref.addItems(["Bevorzuge Erstausstrahlung", "Bevorzuge TV", "Bevorzuge Streaming", "Bevorzuge deutsche Synchro"]) self.date_pref.addItems(["Bevorzuge Erstausstrahlung", "Bevorzuge TV", "Bevorzuge Streaming", "Bevorzuge deutsche Synchro"])
settings_layout.addRow("Datum Präferenz:", self.date_pref) settings_layout.addRow("Datum Präferenz:", self.date_pref)
# Checkbox für Serien ohne klassische Staffeln
self.no_seasons_check = QCheckBox("Serie ohne klassische Staffeln")
self.no_seasons_check.setToolTip("Aktivieren für Serien mit fortlaufender Nummerierung oder Jahresformat")
settings_layout.addRow("", self.no_seasons_check)
# Speichern Button für Einstellungen # Speichern Button für Einstellungen
save_button = QPushButton("Einstellungen speichern") save_button = QPushButton("Einstellungen speichern")
save_button.clicked.connect(self.save_settings) save_button.clicked.connect(self.save_settings)
@@ -269,7 +280,8 @@ class SeriesEditDialog(QDialog):
'mode': self.staffel_mode.currentText(), 'mode': self.staffel_mode.currentText(),
'staffel': self.staffel_spin.value() 'staffel': self.staffel_spin.value()
}, },
'date_preference': self.date_pref.currentText() 'date_preference': self.date_pref.currentText(),
'no_seasons': self.no_seasons_check.isChecked()
}) })
QMessageBox.information(self, "Erfolg", "Einstellungen wurden gespeichert!") QMessageBox.information(self, "Erfolg", "Einstellungen wurden gespeichert!")
@@ -328,6 +340,9 @@ class SeriesEditDialog(QDialog):
if index >= 0: if index >= 0:
self.date_pref.setCurrentIndex(index) self.date_pref.setCurrentIndex(index)
# Keine Staffeln Checkbox laden
self.no_seasons_check.setChecked(data.get('no_seasons', False))
def delete_series(self): def delete_series(self):
"""Löscht die ausgewählte Serie""" """Löscht die ausgewählte Serie"""
current_item = self.series_list.currentItem() current_item = self.series_list.currentItem()
@@ -592,14 +607,25 @@ class SerienChecker(QMainWindow):
# Alternative: Suche in der Episoden-Zeile # Alternative: Suche in der Episoden-Zeile
episode_info = episode.find('div', {'itemprop': 'episodeNumber'}) episode_info = episode.find('div', {'itemprop': 'episodeNumber'})
if episode_info and episode_info.text: if episode_info and episode_info.text:
folge = int(episode_info.text) # Prüfe auf "Folge X" Format
# Staffel aus übergeordnetem Element folge_match = re.search(r'Folge (\d+)', episode_info.text)
staffel_info = episode.find_previous('h2', class_='header-2015') if folge_match:
if staffel_info: folge = int(folge_match.group(1))
staffel_match = re.search(r'Staffel (\d+)', staffel_info.text) # Bei Serien ohne Staffeln setzen wir Staffel auf 1
if staffel_match: staffel = 1
staffel = int(staffel_match.group(1)) logging.debug(f"Gefundene Folge aus 'Folge X' Format: {folge}")
logging.debug(f"Gefundene Staffel/Folge aus Text: {staffel}/{folge}") else:
try:
folge = int(episode_info.text)
# Staffel aus übergeordnetem Element
staffel_info = episode.find_previous('h2', class_='header-2015')
if staffel_info:
staffel_match = re.search(r'Staffel (\d+)', staffel_info.text)
if staffel_match:
staffel = int(staffel_match.group(1))
logging.debug(f"Gefundene Staffel/Folge aus Text: {staffel}/{folge}")
except ValueError:
logging.debug(f"Konnte Folge nicht aus Text extrahieren: {episode_info.text}")
# Suche nach deutschem Titel # Suche nach deutschem Titel
if episode_link: if episode_link:
@@ -649,34 +675,74 @@ class SerienChecker(QMainWindow):
soup = BeautifulSoup(response.text, 'html.parser') soup = BeautifulSoup(response.text, 'html.parser')
staffel_links = [] staffel_links = []
for link in soup.find_all('a', href=True): headers = soup.find_all('h2', class_='header-2015')
# Suche nach Staffel-Links und extrahiere die ID
if 'staffel-' in link['href']: for header in headers:
match = re.search(r'/staffel-(\d+)/(\d+)$', link['href']) link = header.find('a', class_='fs-linkable')
if match: if not link or not link.get('href'):
s_nr = int(match.group(1)) continue
serie_id = match.group(2)
staffel_links.append((s_nr, serie_id)) href = link['href']
logging.debug(f"Gefundene Staffel: {s_nr} mit ID: {serie_id}") # Prüfe auf normale Staffel-Links
match = re.search(r'/staffel-(\d+)/(\d+)$', href)
if match:
s_nr = int(match.group(1))
serie_id = match.group(2)
staffel_links.append(('staffel', s_nr, serie_id))
logging.debug(f"Gefundene Staffel: {s_nr} mit ID: {serie_id}")
continue
# Prüfe auf "bisher X Folgen" oder Jahres-Format
match = re.search(r'episodenguide/(\d+)/(\d+)$', href)
if match:
section_id = match.group(1)
serie_id = match.group(2)
# Prüfe den Text für die Art des Eintrags
text = link.text.strip()
if "bisher" in text and "Folgen" in text:
logging.debug(f"Gefunden 'bisher X Folgen' mit ID: {serie_id}")
staffel_links.append(('folgen', section_id, serie_id))
elif text.isdigit(): # Jahresformat
logging.debug(f"Gefunden Jahr {text} mit ID: {serie_id}")
staffel_links.append(('jahr', section_id, serie_id))
if not staffel_links: if not staffel_links:
logging.warning("Keine Staffeln gefunden!") logging.warning("Keine Staffeln oder Episodengruppen gefunden!")
return None return None
if staffel_nr: if staffel_nr:
# Suche nach der gewünschten Staffel # Suche nach der gewünschten Staffel (nur für normale Staffeln)
for s_nr, serie_id in staffel_links: for typ, nr, serie_id in staffel_links:
if s_nr == staffel_nr: if typ == 'staffel' and nr == staffel_nr:
url = f"https://www.fernsehserien.de/{slug}/episodenguide/staffel-{staffel_nr}/{serie_id}" url = f"https://www.fernsehserien.de/{slug}/episodenguide/staffel-{staffel_nr}/{serie_id}"
logging.debug(f"Generierte URL für spezifische Staffel: {url}") logging.debug(f"Generierte URL für spezifische Staffel: {url}")
return url return url
logging.warning(f"Staffel {staffel_nr} nicht gefunden!") logging.warning(f"Staffel {staffel_nr} nicht gefunden!")
return None return None
else: else:
# Nehme die neueste Staffel # Nehme den neuesten Eintrag
newest_staffel, serie_id = max(staffel_links, key=lambda x: x[0]) if not staffel_links:
url = f"https://www.fernsehserien.de/{slug}/episodenguide/staffel-{newest_staffel}/{serie_id}" return None
logging.debug(f"Generierte URL für neueste Staffel ({newest_staffel}): {url}")
# Sortiere nach Typ und dann nach Nummer/ID
def sort_key(x):
typ, nr, serie_id = x
type_priority = {'staffel': 3, 'jahr': 2, 'folgen': 1}
# Bei Staffeln nach Staffelnummer sortieren, sonst nach section_id
if typ == 'staffel':
return (type_priority.get(typ, 0), int(nr)) # nr ist hier die Staffelnummer
else:
return (type_priority.get(typ, 0), int(nr)) # nr ist hier die section_id
newest = max(staffel_links, key=sort_key)
typ, nr, serie_id = newest
if typ == 'staffel':
url = f"https://www.fernsehserien.de/{slug}/episodenguide/staffel-{nr}/{serie_id}"
logging.debug(f"Generierte URL für neueste Staffel ({nr}): {url}")
else:
url = f"https://www.fernsehserien.de/{slug}/episodenguide/{nr}/{serie_id}"
logging.debug(f"Generierte URL für Episodengruppe: {url}")
return url return url
except Exception as e: except Exception as e:
@@ -728,21 +794,53 @@ class SerienChecker(QMainWindow):
logging.error(error_msg) logging.error(error_msg)
return return
logging.debug(f"Hole Episoden von: {url}")
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
episodes = [] episodes = []
for episode in soup.find_all('section', {'itemprop': 'episode'}): page = 1
staffel, folge, titel = self.get_episode_info(episode) # Prüfe ob die Serie als "ohne klassische Staffeln" markiert ist
if all([staffel, folge, titel]): no_seasons = selected_data.get('no_seasons', False)
datum = self.get_premiere_date(episode)
episodes.append({ while True:
'date': datum, current_url = f"{url}/{page}" if page > 1 and no_seasons else url
'staffel': staffel, logging.debug(f"Hole Episoden von: {current_url}")
'folge': folge,
'titel': titel try:
}) response = requests.get(current_url)
if response.status_code == 404:
logging.debug(f"Seite {page} nicht gefunden, beende Suche")
break
# Bei normalen Staffeln nur eine Seite laden
if not no_seasons:
logging.debug("Serie hat klassische Staffeln, lade nur aktuelle Seite")
response.raise_for_status() # Prüfe auf andere HTTP-Fehler
soup = BeautifulSoup(response.text, 'html.parser')
# Prüfe ob die Seite Episoden enthält
page_episodes = soup.find_all('section', {'itemprop': 'episode'})
if not page_episodes:
logging.debug(f"Keine Episoden auf Seite {page} gefunden, beende Suche")
break
for episode in page_episodes:
staffel, folge, titel = self.get_episode_info(episode)
if all([staffel, folge, titel]):
datum = self.get_premiere_date(episode)
episodes.append({
'date': datum,
'staffel': staffel,
'folge': folge,
'titel': titel
})
# Bei normalen Staffeln nach der ersten Seite aufhören
if not no_seasons:
break
page += 1
except requests.RequestException as e:
logging.error(f"Fehler beim Abrufen von Seite {page}: {str(e)}")
break
if not episodes: if not episodes:
self.episodes_table.setRowCount(1) self.episodes_table.setRowCount(1)
@@ -760,8 +858,8 @@ class SerienChecker(QMainWindow):
x['folge'] x['folge']
)) ))
# Zeige maximal 20 Episoden an # Zeige alle gefundenen Episoden an
episodes = episodes[:20] # episodes = episodes[:20] # Alte Begrenzung entfernt
# Aktualisiere die Tabelle # Aktualisiere die Tabelle
self.episodes_table.setRowCount(len(episodes)) self.episodes_table.setRowCount(len(episodes))