4 Commits

Author SHA1 Message Date
Yuvi9587
f41f354737 Update main_window.py 2025-07-13 21:46:34 -07:00
Yuvi9587
6b57ee099d Commit 2025-07-13 21:45:30 -07:00
Yuvi9587
21ecb60cb5 commit 2025-07-13 20:21:17 -07:00
Yuvi9587
ee00019f2e Update workers.py 2025-07-13 18:42:56 -07:00
3 changed files with 54 additions and 20 deletions

View File

@@ -893,6 +893,7 @@ class PostProcessorWorker:
total_downloaded_this_post =0 total_downloaded_this_post =0
total_skipped_this_post =0 total_skipped_this_post =0
history_data_for_this_post =None history_data_for_this_post =None
temp_filepath_for_return = None
parsed_api_url =urlparse (self .api_url_input ) parsed_api_url =urlparse (self .api_url_input )
referer_url =f"https://{parsed_api_url .netloc }/" referer_url =f"https://{parsed_api_url .netloc }/"
@@ -1297,10 +1298,12 @@ class PostProcessorWorker:
with open(temp_filepath, 'w', encoding='utf-8') as f: with open(temp_filepath, 'w', encoding='utf-8') as f:
json.dump(content_data, f, indent=2) json.dump(content_data, f, indent=2)
self.logger(f" Saved temporary text for '{post_title}' for single PDF compilation.") self.logger(f" Saved temporary text for '{post_title}' for single PDF compilation.")
return 0, 0, [], [], [], None, temp_filepath self._emit_signal('worker_finished', (0, 0, [], [], [], None, temp_filepath)) # <--- CHANGE THIS
return (0, 0, [], [], [], None, temp_filepath)
except Exception as e: except Exception as e:
self.logger(f" ❌ Failed to write temporary file for single PDF: {e}") self.logger(f" ❌ Failed to write temporary file for single PDF: {e}")
return 0, 0, [], [], [], None, None self._emit_signal('worker_finished', (0, 0, [], [], [], [], None))
return (0, 0, [], [], [], [], None)
# --- Logic for Individual File Saving --- # --- Logic for Individual File Saving ---
else: else:
@@ -1320,7 +1323,9 @@ class PostProcessorWorker:
if FPDF: if FPDF:
self.logger(f" Converting to PDF...") self.logger(f" Converting to PDF...")
pdf = PDF() pdf = PDF()
font_path = os.path.join(self.app_base_dir, 'data', 'dejavu-sans', 'DejaVuSans.ttf') font_path = ""
if self.project_root_dir:
font_path = os.path.join(self.project_root_dir, 'data', 'dejavu-sans', 'DejaVuSans.ttf')
try: try:
if not os.path.exists(font_path): raise RuntimeError(f"Font file not found: {font_path}") if not os.path.exists(font_path): raise RuntimeError(f"Font file not found: {font_path}")
pdf.add_font('DejaVu', '', font_path, uni=True) pdf.add_font('DejaVu', '', font_path, uni=True)
@@ -1745,12 +1750,8 @@ class PostProcessorWorker:
permanent_failures_this_post, history_data_for_this_post, permanent_failures_this_post, history_data_for_this_post,
None) # The 7th item is None because we already saved the temp file None) # The 7th item is None because we already saved the temp file
# In Single PDF mode, the 7th item is the temp file path we created.
if self.single_pdf_mode and os.path.exists(temp_filepath):
result_tuple = (0, 0, [], [], [], None, temp_filepath)
self._emit_signal('worker_finished', result_tuple) self._emit_signal('worker_finished', result_tuple)
return # The method now returns nothing. return result_tuple
class DownloadThread (QThread ): class DownloadThread (QThread ):
progress_signal =pyqtSignal (str ) progress_signal =pyqtSignal (str )
@@ -1887,27 +1888,59 @@ class DownloadThread (QThread ):
self .skip_current_file_flag .set () self .skip_current_file_flag .set ()
else :self .logger (" Skip file: No download active or skip flag not available for current context.") else :self .logger (" Skip file: No download active or skip flag not available for current context.")
def run (self ): def run(self):
""" """
The main execution method for the single-threaded download process. The main execution method for the single-threaded download process.
This version is corrected to handle 7 return values from the worker and This version is corrected to handle 7 return values from the worker and
to pass the 'single_pdf_mode' setting correctly. to pass the 'single_pdf_mode' setting correctly.
""" """
grand_total_downloaded_files =0 grand_total_downloaded_files = 0
grand_total_skipped_files =0 grand_total_skipped_files = 0
grand_list_of_kept_original_filenames =[] grand_list_of_kept_original_filenames = []
was_process_cancelled =False was_process_cancelled = False
# This block for initializing manga mode counters remains unchanged # This block for initializing manga mode counters remains unchanged
if self .manga_mode_active and self .manga_filename_style ==STYLE_DATE_BASED and not self .extract_links_only and self .manga_date_file_counter_ref is None : if self.manga_mode_active and self.manga_filename_style == STYLE_DATE_BASED and not self.extract_links_only and self.manga_date_file_counter_ref is None:
# ... (existing manga counter initialization logic) ... # Determine the directory to scan for existing numbered files
series_scan_dir = self.output_dir
if self.use_subfolders :
if self.filter_character_list_objects_initial and self.filter_character_list_objects_initial [0] and self.filter_character_list_objects_initial[0].get("name"):
series_folder_name = clean_folder_name(self.filter_character_list_objects_initial[0]["name"])
series_scan_dir = os.path.join(series_scan_dir, series_folder_name)
elif self.service and self.user_id :
creator_based_folder_name = clean_folder_name(str(self.user_id))
series_scan_dir = os.path.join(series_scan_dir, creator_based_folder_name)
highest_num = 0
if os.path.isdir(series_scan_dir):
self.logger(f" [Thread] Manga Date Mode: Scanning for existing files in '{series_scan_dir}'...")
for dirpath, _, filenames_in_dir in os.walk(series_scan_dir):
for filename_to_check in filenames_in_dir:
# Check for an optional prefix defined by the user
prefix_to_check = clean_filename(self.manga_date_prefix.strip()) if self.manga_date_prefix and self.manga_date_prefix.strip() else ""
name_part_to_match = filename_to_check
if prefix_to_check and name_part_to_match.startswith(prefix_to_check):
name_part_to_match = name_part_to_match[len(prefix_to_check):].lstrip()
# Use regex to find the number at the start of the filename
base_name_no_ext = os.path.splitext(name_part_to_match)[0]
match = re.match(r"(\d+)", base_name_no_ext)
if match:
highest_num = max(highest_num, int(match.group(1)))
# Initialize the shared counter to the next number, protected by a thread lock
self.manga_date_file_counter_ref = [highest_num + 1, threading.Lock()]
self.logger(f" [Thread] Manga Date Mode: Initialized date-based counter at {self.manga_date_file_counter_ref[0]}.")
pass pass
if self .manga_mode_active and self .manga_filename_style ==STYLE_POST_TITLE_GLOBAL_NUMBERING and not self .extract_links_only and self .manga_global_file_counter_ref is None :
# ... (existing manga counter initialization logic) ... if self.manga_mode_active and self.manga_filename_style == STYLE_POST_TITLE_GLOBAL_NUMBERING and not self.extract_links_only and self.manga_global_file_counter_ref is None:
# Initialize the shared counter at 1, protected by a thread lock
self.manga_global_file_counter_ref = [1, threading.Lock()]
self.logger(f" [Thread] Manga Title+GlobalNum Mode: Initialized global counter at {self.manga_global_file_counter_ref[0]}.")
pass pass
worker_signals_obj = PostProcessorSignals() worker_signals_obj = PostProcessorSignals()
try : try:
# Connect signals # Connect signals
worker_signals_obj.progress_signal.connect(self.progress_signal) worker_signals_obj.progress_signal.connect(self.progress_signal)
worker_signals_obj.file_download_status_signal.connect(self.file_download_status_signal) worker_signals_obj.file_download_status_signal.connect(self.file_download_status_signal)
@@ -2052,6 +2085,7 @@ class DownloadThread (QThread ):
# Emit the final signal with all collected results # Emit the final signal with all collected results
self.finished_signal.emit(grand_total_downloaded_files, grand_total_skipped_files, self.isInterruptionRequested(), grand_list_of_kept_original_filenames) self.finished_signal.emit(grand_total_downloaded_files, grand_total_skipped_files, self.isInterruptionRequested(), grand_list_of_kept_original_filenames)
def receive_add_character_result (self ,result ): def receive_add_character_result (self ,result ):
with QMutexLocker (self .prompt_mutex ): with QMutexLocker (self .prompt_mutex ):
self ._add_character_response =result self ._add_character_response =result

View File

@@ -22,7 +22,7 @@ class MoreOptionsDialog(QDialog):
layout.addWidget(self.description_label) layout.addWidget(self.description_label)
self.radio_button_group = QButtonGroup(self) self.radio_button_group = QButtonGroup(self)
self.radio_content = QRadioButton("Description/Content") self.radio_content = QRadioButton("Description/Content")
self.radio_comments = QRadioButton("Comments (Not Working)") self.radio_comments = QRadioButton("Comments")
self.radio_button_group.addButton(self.radio_content) self.radio_button_group.addButton(self.radio_content)
self.radio_button_group.addButton(self.radio_comments) self.radio_button_group.addButton(self.radio_comments)
layout.addWidget(self.radio_content) layout.addWidget(self.radio_content)

View File

@@ -26,7 +26,7 @@ from PyQt5.QtWidgets import (
QScrollArea, QListWidgetItem, QSizePolicy, QProgressBar, QAbstractItemView, QFrame, QScrollArea, QListWidgetItem, QSizePolicy, QProgressBar, QAbstractItemView, QFrame,
QMainWindow, QAction, QGridLayout QMainWindow, QAction, QGridLayout
) )
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QObject, QTimer, QSettings, QStandardPaths, QUrl, QSize, QProcess, QMutex, QMutexLocker from PyQt5.QtCore import Qt, QThread, pyqtSignal, QObject, QTimer, QSettings, QStandardPaths, QUrl, QSize, QProcess, QMutex, QMutexLocker, QCoreApplication
# --- Local Application Imports --- # --- Local Application Imports ---
from ..services.drive_downloader import download_mega_file as drive_download_mega_file ,download_gdrive_file ,download_dropbox_file from ..services.drive_downloader import download_mega_file as drive_download_mega_file ,download_gdrive_file ,download_dropbox_file