fixed csv importing and core dump issue

This commit is contained in:
Bernd 2025-07-18 21:57:38 +05:00
parent fbbb7cb8e8
commit 2f2b8a4f29
15 changed files with 70 additions and 38 deletions

Binary file not shown.

View File

@ -84,11 +84,14 @@ class AnimeBackend:
if header:
cursor = self.db.cursor()
for row in reader:
if len(row) < 8:
if len(row) == 7:
name, year_str, season, status, type_, comment, url = row
elif len(row) == 8:
_, name, year_str, season, status, type_, comment, url = row
else:
continue
_, name, year, season, status, type_, comment, url = row
try:
year = int(year)
year = int(year_str)
except ValueError:
continue
cursor.execute(

View File

@ -3,6 +3,7 @@ import os
import random
import re
import hashlib
import html
from datetime import datetime
from PyQt5.QtWidgets import (
QMainWindow, QTabWidget, QWidget, QVBoxLayout, QTableWidget, QTableWidgetItem,
@ -10,7 +11,7 @@ from PyQt5.QtWidgets import (
QComboBox, QTextEdit, QDialogButtonBox, QAction, QFileDialog, QMessageBox,
QInputDialog, QApplication, QAbstractItemView
)
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtCore import Qt, QUrl, QEvent
from PyQt5.QtGui import QColor, QIcon
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
from backend import AnimeBackend
@ -76,6 +77,30 @@ class AnimeDialog(QDialog):
'url': self.url_edit.text()
}
class HoverLabel(QLabel):
def __init__(self, main_window, name, url=None):
super().__init__()
self.main_window = main_window
self.url = url
self.fetched = False
self.image_file = None
if url:
self.image_file = os.path.join(main_window.image_cache_dir, hashlib.md5(url.encode()).hexdigest() + '.jpg')
name_escaped = html.escape(name)
self.setText(f'<a href="{url}">{name_escaped}</a>')
self.setOpenExternalLinks(True)
if os.path.exists(self.image_file):
self.setToolTip(f'<img src="{self.image_file}" width="200">')
self.fetched = True
else:
self.setText(html.escape(name))
def enterEvent(self, event):
if self.url and not self.fetched:
self.main_window.fetch_poster(self.url, self)
self.fetched = True
super().enterEvent(event)
class AnimeTracker(QMainWindow):
def __init__(self):
super().__init__()
@ -113,9 +138,13 @@ class AnimeTracker(QMainWindow):
def load_tabs(self):
self.tab_widget.clear()
# Pre-2010 tab
pre_entries = self.backend.get_pre_2010_entries()
pre_tab = QWidget()
self.setup_table(pre_tab, pre_entries, is_pre=True)
layout = QVBoxLayout(pre_tab)
if pre_entries:
table = self.create_table_widget(pre_entries, is_pre=True)
layout.addWidget(table)
tab_text = "Pre-2010"
completed = False
total = len(pre_entries)
@ -128,25 +157,32 @@ class AnimeTracker(QMainWindow):
index = self.tab_widget.addTab(pre_tab, tab_text)
if completed:
self.tab_widget.tabBar().setTabTextColor(index, QColor('gray'))
# Years >= 2010
years = self.backend.get_years()
for year in years:
year_tab = QWidget()
layout = QVBoxLayout(year_tab)
total_entries = 0
comp_entries = 0
for season in ['winter', 'spring', 'summer', 'fall', '']:
entries = self.backend.get_entries_for_season(year, season)
if entries:
tab = QWidget()
self.setup_table(tab, entries, is_pre=False, year=year, season=season)
s_name = season.capitalize() if season else 'Other'
total = len(entries)
comp = sum(1 for e in entries if e[4] == 'completed')
perc = (comp / total * 100)
tab_text = f"{year} - {s_name} ({perc:.0f}%)"
completed = (comp == total)
index = self.tab_widget.addTab(tab, tab_text)
label = QLabel(s_name)
layout.addWidget(label)
table = self.create_table_widget(entries, is_pre=False)
layout.addWidget(table)
total_entries += len(entries)
comp_entries += sum(1 for e in entries if e[4] == 'completed')
if total_entries > 0:
perc = (comp_entries / total_entries * 100) if total_entries > 0 else 0
tab_text = f"{year} ({perc:.0f}%)"
completed = (comp_entries == total_entries)
index = self.tab_widget.addTab(year_tab, tab_text)
if completed:
self.tab_widget.tabBar().setTabTextColor(index, QColor('gray'))
def setup_table(self, tab, entries, is_pre, year=None, season=None):
layout = QVBoxLayout(tab)
def create_table_widget(self, entries, is_pre):
col_count = 6 if is_pre else 5
table = QTableWidget(len(entries), col_count)
headers = ['Year', 'Name', 'Type', 'Status', 'Comment', 'Actions'] if is_pre else ['Name', 'Type', 'Status', 'Comment', 'Actions']
@ -164,13 +200,7 @@ class AnimeTracker(QMainWindow):
# Name
name = entry[1]
url = entry[7]
name_label = QLabel()
if url:
name_label.setText(f'<a href="{url}">{name}</a>')
name_label.setOpenExternalLinks(True)
self.fetch_poster(url, name_label)
else:
name_label.setText(name)
name_label = HoverLabel(self, name, url)
table.setCellWidget(row, col, name_label)
col += 1
# Type
@ -208,7 +238,7 @@ class AnimeTracker(QMainWindow):
widget = table.cellWidget(r, c)
if widget:
widget.setStyleSheet(f"background-color: {color.name()};")
layout.addWidget(table)
return table
def create_actions_widget(self, anime_id, status):
widget = QWidget()
@ -239,7 +269,7 @@ class AnimeTracker(QMainWindow):
return widget
def fetch_poster(self, url, label):
image_file = os.path.join(self.image_cache_dir, hashlib.md5(url.encode()).hexdigest() + '.jpg')
image_file = label.image_file
if os.path.exists(image_file):
label.setToolTip(f'<img src="{image_file}" width="200">')
return
@ -280,10 +310,9 @@ class AnimeTracker(QMainWindow):
default_year = 2009
default_season = ''
else:
parts = tab_text.split(' - ')
parts = tab_text.split(' (')
default_year = int(parts[0])
s_name = parts[1].split(' (')[0].lower()
default_season = '' if s_name == 'other' else s_name
default_season = ''
dialog = AnimeDialog(self, None, default_year, default_season)
if dialog.exec_() == QDialog.Accepted:
data = dialog.get_data()
@ -321,12 +350,12 @@ class AnimeTracker(QMainWindow):
return
tab_text = self.tab_widget.tabText(self.tab_widget.currentIndex())
is_pre = 'Pre-2010' in tab_text
table = self.tab_widget.currentWidget().findChild(QTableWidget)
if not table:
return
current_widget = self.tab_widget.currentWidget()
tables = current_widget.findChildren(QTableWidget)
name_col = 1 if is_pre else 0
status_col = 3 if is_pre else 2
unwatched = []
for table in tables:
for row in range(table.rowCount()):
status = table.item(row, status_col).text()
if status == 'unwatched':

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB