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,
QTableWidgetItem, QHeaderView, QDialog, QDialogButtonBox,
QTextEdit, QGroupBox, QToolBar, QSplitter, QFormLayout,
QListWidgetItem)
QListWidgetItem, QCheckBox)
from PyQt5.QtCore import Qt, QTimer
# Logging Konfiguration
@@ -83,6 +83,11 @@ class NewSeriesDialog(QDialog):
self.date_pref.addItems(["Bevorzuge Erstausstrahlung", "Bevorzuge TV", "Bevorzuge Streaming", "Bevorzuge deutsche Synchro"])
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)
layout.addWidget(settings_group)
@@ -145,7 +150,8 @@ class NewSeriesDialog(QDialog):
'mode': self.staffel_mode.currentText(),
'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):
@@ -224,6 +230,11 @@ class SeriesEditDialog(QDialog):
self.date_pref.addItems(["Bevorzuge Erstausstrahlung", "Bevorzuge TV", "Bevorzuge Streaming", "Bevorzuge deutsche Synchro"])
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
save_button = QPushButton("Einstellungen speichern")
save_button.clicked.connect(self.save_settings)
@@ -269,7 +280,8 @@ class SeriesEditDialog(QDialog):
'mode': self.staffel_mode.currentText(),
'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!")
@@ -328,6 +340,9 @@ class SeriesEditDialog(QDialog):
if index >= 0:
self.date_pref.setCurrentIndex(index)
# Keine Staffeln Checkbox laden
self.no_seasons_check.setChecked(data.get('no_seasons', False))
def delete_series(self):
"""Löscht die ausgewählte Serie"""
current_item = self.series_list.currentItem()
@@ -592,14 +607,25 @@ class SerienChecker(QMainWindow):
# Alternative: Suche in der Episoden-Zeile
episode_info = episode.find('div', {'itemprop': 'episodeNumber'})
if episode_info and episode_info.text:
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}")
# Prüfe auf "Folge X" Format
folge_match = re.search(r'Folge (\d+)', episode_info.text)
if folge_match:
folge = int(folge_match.group(1))
# Bei Serien ohne Staffeln setzen wir Staffel auf 1
staffel = 1
logging.debug(f"Gefundene Folge aus 'Folge X' Format: {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
if episode_link:
@@ -649,34 +675,74 @@ class SerienChecker(QMainWindow):
soup = BeautifulSoup(response.text, 'html.parser')
staffel_links = []
for link in soup.find_all('a', href=True):
# Suche nach Staffel-Links und extrahiere die ID
if 'staffel-' in link['href']:
match = re.search(r'/staffel-(\d+)/(\d+)$', link['href'])
if match:
s_nr = int(match.group(1))
serie_id = match.group(2)
staffel_links.append((s_nr, serie_id))
logging.debug(f"Gefundene Staffel: {s_nr} mit ID: {serie_id}")
headers = soup.find_all('h2', class_='header-2015')
for header in headers:
link = header.find('a', class_='fs-linkable')
if not link or not link.get('href'):
continue
href = link['href']
# 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:
logging.warning("Keine Staffeln gefunden!")
logging.warning("Keine Staffeln oder Episodengruppen gefunden!")
return None
if staffel_nr:
# Suche nach der gewünschten Staffel
for s_nr, serie_id in staffel_links:
if s_nr == staffel_nr:
# Suche nach der gewünschten Staffel (nur für normale Staffeln)
for typ, nr, serie_id in staffel_links:
if typ == 'staffel' and nr == staffel_nr:
url = f"https://www.fernsehserien.de/{slug}/episodenguide/staffel-{staffel_nr}/{serie_id}"
logging.debug(f"Generierte URL für spezifische Staffel: {url}")
return url
logging.warning(f"Staffel {staffel_nr} nicht gefunden!")
return None
else:
# Nehme die neueste Staffel
newest_staffel, serie_id = max(staffel_links, key=lambda x: x[0])
url = f"https://www.fernsehserien.de/{slug}/episodenguide/staffel-{newest_staffel}/{serie_id}"
logging.debug(f"Generierte URL für neueste Staffel ({newest_staffel}): {url}")
# Nehme den neuesten Eintrag
if not staffel_links:
return None
# 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
except Exception as e:
@@ -728,21 +794,53 @@ class SerienChecker(QMainWindow):
logging.error(error_msg)
return
logging.debug(f"Hole Episoden von: {url}")
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
episodes = []
for episode in soup.find_all('section', {'itemprop': 'episode'}):
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
})
page = 1
# Prüfe ob die Serie als "ohne klassische Staffeln" markiert ist
no_seasons = selected_data.get('no_seasons', False)
while True:
current_url = f"{url}/{page}" if page > 1 and no_seasons else url
logging.debug(f"Hole Episoden von: {current_url}")
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:
self.episodes_table.setRowCount(1)
@@ -760,8 +858,8 @@ class SerienChecker(QMainWindow):
x['folge']
))
# Zeige maximal 20 Episoden an
episodes = episodes[:20]
# Zeige alle gefundenen Episoden an
# episodes = episodes[:20] # Alte Begrenzung entfernt
# Aktualisiere die Tabelle
self.episodes_table.setRowCount(len(episodes))