diff --git a/downloader_utils.py b/downloader_utils.py
index 9060db8..053afa6 100644
--- a/downloader_utils.py
+++ b/downloader_utils.py
@@ -13,16 +13,15 @@ from PyQt5 .QtCore import QObject ,pyqtSignal ,QThread ,QMutex ,QMutexLocker
from urllib .parse import urlparse
try :
from mega import Mega
- # Import download functions from drive.py
- # Assuming drive.py is in the same directory
- try:
- from drive import download_mega_file as drive_download_mega_file, \
- download_gdrive_file, download_dropbox_file
- # To avoid confusion, we'll use drive_download_mega_file internally when calling from main
- # and ensure this module exports it as download_mega_file for compatibility if needed,
- # or main.py can be updated to call drive_download_mega_file.
- except ImportError as drive_import_err:
- print(f"ERROR importing from drive.py: {drive_import_err}. External drive downloads will fail.")
+
+
+ try :
+ from drive import download_mega_file as drive_download_mega_file ,download_gdrive_file ,download_dropbox_file
+
+
+
+ except ImportError as drive_import_err :
+ print (f"ERROR importing from drive.py: {drive_import_err }. External drive downloads will fail.")
except ImportError :
print ("ERROR: mega.py library not found. Please install it: pip install mega.py")
try :
@@ -57,6 +56,7 @@ FILE_DOWNLOAD_STATUS_FAILED_PERMANENTLY_THIS_SESSION ="failed_permanent_session"
fastapi_app =None
KNOWN_NAMES =[]
MIN_SIZE_FOR_MULTIPART_DOWNLOAD =10 *1024 *1024
+GOFILE_GUEST_TOKEN =None
MAX_PARTS_FOR_MULTIPART_DOWNLOAD =15
MAX_FILENAME_COMPONENT_LENGTH =150
IMAGE_EXTENSIONS ={
@@ -704,6 +704,7 @@ def get_link_platform (url ):
if 'mega.nz'in domain or 'mega.io'in domain :return 'mega'
if 'dropbox.com'in domain :return 'dropbox'
if 'patreon.com'in domain :return 'patreon'
+ if 'gofile.io'in domain :return 'gofile'
if 'instagram.com'in domain :return 'instagram'
if 'twitter.com'in domain or 'x.com'in domain :return 'twitter/x'
if 'discord.gg'in domain or 'discord.com/invite'in domain :return 'discord invite'
@@ -2133,47 +2134,47 @@ def download_mega_file (mega_link ,download_path =".",logger_func =print ):
try :
- # Pre-flight check for link validity and attributes
- logger_func(f" Verifying Mega link and fetching attributes: {mega_link}")
- file_attributes = m.get_public_url_info(mega_link)
- if not file_attributes or not isinstance(file_attributes, dict):
- logger_func(f"❌ Error: Could not retrieve valid file information for the Mega link. Link might be invalid, expired, or a folder. Info received: {file_attributes}")
- raise ValueError(f"Invalid or inaccessible Mega link. get_public_url_info returned: {file_attributes}")
+ logger_func (f" Verifying Mega link and fetching attributes: {mega_link }")
+ file_attributes =m .get_public_url_info (mega_link )
- expected_filename = file_attributes.get('name') # Changed from 'n'
- file_size = file_attributes.get('size') # Changed from 's'
+ if not file_attributes or not isinstance (file_attributes ,dict ):
+ logger_func (f"❌ Error: Could not retrieve valid file information for the Mega link. Link might be invalid, expired, or a folder. Info received: {file_attributes }")
+ raise ValueError (f"Invalid or inaccessible Mega link. get_public_url_info returned: {file_attributes }")
- if not expected_filename:
- logger_func(f"⚠️ Critical: File name ('name') not found in Mega link attributes. Attributes: {file_attributes}") # Updated log
- raise ValueError(f"File name ('name') not found in Mega link attributes: {file_attributes}") # Updated ValueError
+ expected_filename =file_attributes .get ('name')
+ file_size =file_attributes .get ('size')
- logger_func(f" Link verified. Expected filename: '{expected_filename}'. Size: {file_size if file_size is not None else 'Unknown'} bytes.")
+ if not expected_filename :
+ logger_func (f"⚠️ Critical: File name ('name') not found in Mega link attributes. Attributes: {file_attributes }")
+ raise ValueError (f"File name ('name') not found in Mega link attributes: {file_attributes }")
+
+ logger_func (f" Link verified. Expected filename: '{expected_filename }'. Size: {file_size if file_size is not None else 'Unknown'} bytes.")
if not os .path .exists (download_path ):
logger_func (f"Download path '{download_path }' does not exist. Creating it...")
os .makedirs (download_path ,exist_ok =True )
- logger_func(f"Starting download of '{expected_filename}' to '{download_path}'...")
-
- # m.download_url returns a tuple (filepath, filename) on success for mega.py 1.0.8
- download_result = m.download_url(mega_link, dest_path=download_path, dest_filename=None)
-
- if download_result and isinstance(download_result, tuple) and len(download_result) == 2:
- saved_filepath, saved_filename = download_result
- # Ensure saved_filepath is an absolute path if dest_path was relative
- if not os.path.isabs(saved_filepath) and dest_path:
- saved_filepath = os.path.join(os.path.abspath(dest_path), saved_filename)
-
- logger_func(f"File downloaded successfully! Saved as: {saved_filepath}")
- if not os.path.exists(saved_filepath):
- logger_func(f"⚠️ Warning: mega.py reported success but file '{saved_filepath}' not found on disk.")
- # Optionally, verify filename if needed, though saved_filename should be correct
- if saved_filename != expected_filename:
- logger_func(f" Note: Saved filename '{saved_filename}' differs from initially expected '{expected_filename}'. This is usually fine.")
+ logger_func (f"Starting download of '{expected_filename }' to '{download_path }'...")
+
+
+ download_result =m .download_url (mega_link ,dest_path =download_path ,dest_filename =None )
+
+ if download_result and isinstance (download_result ,tuple )and len (download_result )==2 :
+ saved_filepath ,saved_filename =download_result
+
+ if not os .path .isabs (saved_filepath )and dest_path :
+ saved_filepath =os .path .join (os .path .abspath (dest_path ),saved_filename )
+
+ logger_func (f"File downloaded successfully! Saved as: {saved_filepath }")
+ if not os .path .exists (saved_filepath ):
+ logger_func (f"⚠️ Warning: mega.py reported success but file '{saved_filepath }' not found on disk.")
+
+ if saved_filename !=expected_filename :
+ logger_func (f" Note: Saved filename '{saved_filename }' differs from initially expected '{expected_filename }'. This is usually fine.")
else :
- logger_func(f"Download failed. The download_url method returned: {download_result}")
- raise Exception(f"Mega download_url did not return expected result or failed. Result: {download_result}")
+ logger_func (f"Download failed. The download_url method returned: {download_result }")
+ raise Exception (f"Mega download_url did not return expected result or failed. Result: {download_result }")
except PermissionError :
logger_func (f"Error: Permission denied to write to '{download_path }'. Please check permissions.")
@@ -2184,11 +2185,11 @@ def download_mega_file (mega_link ,download_path =".",logger_func =print ):
except requests .exceptions .RequestException as e :
logger_func (f"Error during request to Mega (network issue, etc.): {e }")
raise
- except ValueError as ve: # Catch our custom ValueError from pre-flight
- logger_func(f"ValueError during Mega processing (likely invalid link): {ve}")
+ except ValueError as ve :
+ logger_func (f"ValueError during Mega processing (likely invalid link): {ve }")
raise
except Exception as e :
- if isinstance(e, TypeError) and "'bool' object is not subscriptable" in str(e):
- logger_func(" This specific TypeError occurred despite pre-flight checks. This might indicate a deeper issue with the mega.py library or a very transient API problem for this link.")
+ if isinstance (e ,TypeError )and "'bool' object is not subscriptable"in str (e ):
+ logger_func (" This specific TypeError occurred despite pre-flight checks. This might indicate a deeper issue with the mega.py library or a very transient API problem for this link.")
traceback .print_exc ()
raise
\ No newline at end of file
diff --git a/main.py b/main.py
index 115155c..6d76854 100644
--- a/main.py
+++ b/main.py
@@ -61,9 +61,9 @@ try :
STYLE_DATE_BASED ,
STYLE_POST_TITLE_GLOBAL_NUMBERING ,
CREATOR_DOWNLOAD_DEFAULT_FOLDER_IGNORE_WORDS ,
- download_mega_file as drive_download_mega_file,
- download_gdrive_file,
- download_dropbox_file
+ download_mega_file as drive_download_mega_file ,
+ download_gdrive_file ,
+ download_dropbox_file
)
print ("Successfully imported names from downloader_utils.")
except ImportError as e :
@@ -97,9 +97,9 @@ except ImportError as e :
STYLE_DATE_BASED ="date_based"
STYLE_POST_TITLE_GLOBAL_NUMBERING ="post_title_global_numbering"
CREATOR_DOWNLOAD_DEFAULT_FOLDER_IGNORE_WORDS =set ()
- def drive_download_mega_file(*args, **kwargs): print("drive_download_mega_file (stub)"); pass
- def download_gdrive_file(*args, **kwargs): print("download_gdrive_file (stub)"); pass
- def download_dropbox_file(*args, **kwargs): print("download_dropbox_file (stub)"); pass
+ def drive_download_mega_file (*args ,**kwargs ):print ("drive_download_mega_file (stub)");pass
+ def download_gdrive_file (*args ,**kwargs ):print ("download_gdrive_file (stub)");pass
+ def download_dropbox_file (*args ,**kwargs ):print ("download_dropbox_file (stub)");pass
except Exception as e :
print (f"--- UNEXPECTED IMPORT ERROR ---")
@@ -141,11 +141,11 @@ FAVORITE_SCOPE_SELECTED_LOCATION ="selected_location"
FAVORITE_SCOPE_ARTIST_FOLDERS ="artist_folders"
CONFIRM_ADD_ALL_SKIP_ADDING =2
CONFIRM_ADD_ALL_CANCEL_DOWNLOAD =3
-LOG_DISPLAY_LINKS = "links"
-LOG_DISPLAY_DOWNLOAD_PROGRESS = "download_progress"
+LOG_DISPLAY_LINKS ="links"
+LOG_DISPLAY_DOWNLOAD_PROGRESS ="download_progress"
-from collections import defaultdict
-class DownloadExtractedLinksDialog(QDialog):
+from collections import defaultdict
+class DownloadExtractedLinksDialog (QDialog ):
"""A dialog to select and initiate download for extracted supported links."""
download_requested =pyqtSignal (list )
@@ -154,19 +154,19 @@ class DownloadExtractedLinksDialog(QDialog):
super ().__init__ (parent )
- self .links_data = links_data
+ self .links_data =links_data
self .setWindowTitle ("Download Selected External Links")
- # Adjust dialog size relative to parent
- if parent:
- parent_width = parent.width()
- parent_height = parent.height()
- dialog_width = int(parent_width * 0.6) # 60% of parent width
- dialog_height = int(parent_height * 0.7) # 70% of parent height
- min_w, min_h = 500, 400 # Keep a reasonable minimum
- self.resize(max(dialog_width, min_w), max(dialog_height, min_h))
- else:
- self.setMinimumSize(500, 400) # Fallback if no parent
+
+ if parent :
+ parent_width =parent .width ()
+ parent_height =parent .height ()
+ dialog_width =int (parent_width *0.6 )
+ dialog_height =int (parent_height *0.7 )
+ min_w ,min_h =500 ,400
+ self .resize (max (dialog_width ,min_w ),max (dialog_height ,min_h ))
+ else :
+ self .setMinimumSize (500 ,400 )
@@ -179,39 +179,39 @@ class DownloadExtractedLinksDialog(QDialog):
self .links_list_widget =QListWidget ()
self .links_list_widget .setSelectionMode (QAbstractItemView .NoSelection )
- grouped_links = defaultdict(list)
- for link_info_item in self.links_data:
- post_title_for_group = link_info_item.get('title', 'Untitled Post')
- grouped_links[post_title_for_group].append(link_info_item)
+ grouped_links =defaultdict (list )
+ for link_info_item in self .links_data :
+ post_title_for_group =link_info_item .get ('title','Untitled Post')
+ grouped_links [post_title_for_group ].append (link_info_item )
+
+
+ sorted_post_titles =sorted (grouped_links .keys (),key =lambda x :x .lower ())
+
+ for post_title_key in sorted_post_titles :
+
+ header_item =QListWidgetItem (f"{post_title_key }")
+ header_item .setFlags (Qt .NoItemFlags )
+ font =header_item .font ()
+ font .setBold (True )
+ font .setPointSize (font .pointSize ()+1 )
+ header_item .setFont (font )
+ if parent and hasattr (parent ,'current_theme')and parent .current_theme =="dark":
+ header_item .setForeground (Qt .cyan )
+ else :
+ header_item .setForeground (Qt .blue )
+ self .links_list_widget .addItem (header_item )
+
+ for link_info_data in grouped_links [post_title_key ]:
+ platform_display =link_info_data .get ('platform','unknown').upper ()
+ display_text =f" [{platform_display }] {link_info_data ['link_text']} ({link_info_data ['url']})"
+ item =QListWidgetItem (display_text )
+ item .setData (Qt .UserRole ,link_info_data )
+ item .setFlags (item .flags ()|Qt .ItemIsUserCheckable )
+ item .setCheckState (Qt .Checked )
+ self .links_list_widget .addItem (item )
- # Sort by post title for consistent order
- sorted_post_titles = sorted(grouped_links.keys(), key=lambda x: x.lower())
- for post_title_key in sorted_post_titles:
- # Add header for post_title
- header_item = QListWidgetItem(f"{post_title_key}")
- header_item.setFlags(Qt.NoItemFlags) # Not selectable, not checkable
- font = header_item.font()
- font.setBold(True)
- font.setPointSize(font.pointSize() + 1) # Slightly larger
- header_item.setFont(font)
- if parent and hasattr(parent, 'current_theme') and parent.current_theme == "dark":
- header_item.setForeground(Qt.cyan)
- else: # Light theme or no theme info
- header_item.setForeground(Qt.blue)
- self.links_list_widget.addItem(header_item)
- for link_info_data in grouped_links[post_title_key]:
- platform_display = link_info_data.get('platform', 'unknown').upper()
- display_text = f" [{platform_display}] {link_info_data['link_text']} ({link_info_data['url']})"
- item = QListWidgetItem(display_text)
- item.setData(Qt.UserRole, link_info_data)
- item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
- item.setCheckState(Qt.Checked)
- self.links_list_widget.addItem(item)
-
- # Add a little space after each group, or a separator item if preferred
- # self.links_list_widget.addItem(QListWidgetItem("")) # Simple spacer
layout .addWidget (self .links_list_widget )
@@ -240,19 +240,17 @@ class DownloadExtractedLinksDialog(QDialog):
def _set_all_items_checked (self ,check_state ):
for i in range (self .links_list_widget .count ()):
- item = self.links_list_widget.item(i)
- if item.flags() & Qt.ItemIsUserCheckable: # Only operate on checkable items
- item.setCheckState(check_state)
+ item =self .links_list_widget .item (i )
+ if item .flags ()&Qt .ItemIsUserCheckable :
+ item .setCheckState (check_state )
def _handle_download_selected (self ):
selected_links =[]
for i in range (self .links_list_widget .count ()):
item =self .links_list_widget .item (i )
- # Ensure item is checkable, actually checked, and has data (is a link item)
- if item.flags() & Qt.ItemIsUserCheckable and \
- item.checkState() == Qt.Checked and \
- item.data(Qt.UserRole) is not None:
- selected_links.append(item.data(Qt.UserRole))
+
+ if item .flags ()&Qt .ItemIsUserCheckable and item .checkState ()==Qt .Checked and item .data (Qt .UserRole )is not None :
+ selected_links .append (item .data (Qt .UserRole ))
if selected_links :
self .download_requested .emit (selected_links )
self .accept ()
@@ -2328,59 +2326,59 @@ class TourDialog (QDialog ):
print (f"[Tour] CRITICAL ERROR in run_tour_if_needed: {e }")
return QDialog .Rejected
-class ExternalLinkDownloadThread(QThread):
+class ExternalLinkDownloadThread (QThread ):
"""A QThread to handle downloading multiple external links sequentially."""
- progress_signal =pyqtSignal (str )
+ progress_signal =pyqtSignal (str )
file_complete_signal =pyqtSignal (str ,bool )
finished_signal =pyqtSignal ()
- def __init__ (self ,tasks_to_download ,download_base_path ,parent_logger_func ,parent =None):
+ def __init__ (self ,tasks_to_download ,download_base_path ,parent_logger_func ,parent =None ):
super ().__init__ (parent )
self .tasks =tasks_to_download
self .download_base_path =download_base_path
self .parent_logger_func =parent_logger_func
self .is_cancelled =False
- def run(self):
- self.progress_signal.emit(f"ℹ️ Starting external link download thread for {len(self.tasks)} link(s).")
+ def run (self ):
+ self .progress_signal .emit (f"ℹ️ Starting external link download thread for {len (self .tasks )} link(s).")
for i ,task_info in enumerate (self .tasks ):
if self .is_cancelled :
- self.progress_signal.emit("External link download cancelled by user.")
+ self .progress_signal .emit ("External link download cancelled by user.")
break
- platform = task_info.get('platform', 'unknown').lower()
+ platform =task_info .get ('platform','unknown').lower ()
full_mega_url =task_info ['url']
post_title =task_info ['title']
- key = task_info.get('key', '') # Primarily for Mega
+ key =task_info .get ('key','')
+
+ self .progress_signal .emit (f"Download ({i +1 }/{len (self .tasks )}): Starting '{post_title }' ({platform .upper ()}) from {full_mega_url }")
- self.progress_signal.emit(f"Download ({i + 1}/{len(self.tasks)}): Starting '{post_title}' ({platform.upper()}) from {full_mega_url}")
-
try :
- if platform == 'mega':
- # Ensure key is part of the URL for mega.py
- if key:
- parsed_original_url = urlparse(full_mega_url)
- if key not in parsed_original_url.fragment:
- base_url_no_fragment = full_mega_url.split('#')[0]
- full_mega_url_with_key = f"{base_url_no_fragment}#{key}"
- self.progress_signal.emit(f" Adjusted Mega URL with key: {full_mega_url_with_key}")
- else:
- full_mega_url_with_key = full_mega_url
- else: # No key provided, use URL as is (might fail if key is required and not in fragment)
- full_mega_url_with_key = full_mega_url
- drive_download_mega_file(full_mega_url_with_key, self.download_base_path, logger_func=self.parent_logger_func)
- elif platform == 'google drive':
- download_gdrive_file(full_mega_url, self.download_base_path, logger_func=self.parent_logger_func)
- elif platform == 'dropbox':
- download_dropbox_file(full_mega_url, self.download_base_path, logger_func=self.parent_logger_func)
- else:
- self.progress_signal.emit(f"⚠️ Unsupported platform '{platform}' for link: {full_mega_url}")
- self.file_complete_signal.emit(full_mega_url, False)
- continue
- self.file_complete_signal.emit(full_mega_url, True)
+ if platform =='mega':
+
+ if key :
+ parsed_original_url =urlparse (full_mega_url )
+ if key not in parsed_original_url .fragment :
+ base_url_no_fragment =full_mega_url .split ('#')[0 ]
+ full_mega_url_with_key =f"{base_url_no_fragment }#{key }"
+ self .progress_signal .emit (f" Adjusted Mega URL with key: {full_mega_url_with_key }")
+ else :
+ full_mega_url_with_key =full_mega_url
+ else :
+ full_mega_url_with_key =full_mega_url
+ drive_download_mega_file (full_mega_url_with_key ,self .download_base_path ,logger_func =self .parent_logger_func )
+ elif platform =='google drive':
+ download_gdrive_file (full_mega_url ,self .download_base_path ,logger_func =self .parent_logger_func )
+ elif platform =='dropbox':
+ download_dropbox_file (full_mega_url ,self .download_base_path ,logger_func =self .parent_logger_func )
+ else :
+ self .progress_signal .emit (f"⚠️ Unsupported platform '{platform }' for link: {full_mega_url }")
+ self .file_complete_signal .emit (full_mega_url ,False )
+ continue
+ self .file_complete_signal .emit (full_mega_url ,True )
except Exception as e :
- self.progress_signal.emit(f"❌ Error downloading ({platform.upper()}) link '{full_mega_url}' (from post '{post_title}'): {e}")
- self.file_complete_signal.emit(full_mega_url, False)
+ self .progress_signal .emit (f"❌ Error downloading ({platform .upper ()}) link '{full_mega_url }' (from post '{post_title }'): {e }")
+ self .file_complete_signal .emit (full_mega_url ,False )
self .finished_signal .emit ()
def cancel (self ):
@@ -2507,8 +2505,8 @@ class DownloaderApp (QWidget ):
self .char_filter_scope =CHAR_SCOPE_TITLE
self .manga_filename_style =self .settings .value (MANGA_FILENAME_STYLE_KEY ,STYLE_POST_TITLE ,type =str )
self .current_theme =self .settings .value (THEME_KEY ,"dark",type =str )
- self .only_links_log_display_mode = LOG_DISPLAY_LINKS # New state variable
- self .mega_download_log_preserved_once = False
+ self .only_links_log_display_mode =LOG_DISPLAY_LINKS
+ self .mega_download_log_preserved_once =False
self .allow_multipart_download_setting =False
self .use_cookie_setting =False
self .scan_content_images_setting =self .settings .value (SCAN_CONTENT_IMAGES_KEY ,False ,type =bool )
@@ -2618,8 +2616,8 @@ class DownloaderApp (QWidget ):
if hasattr (self ,'download_extracted_links_button'):
self .download_extracted_links_button .clicked .connect (self ._show_download_extracted_links_dialog )
- if hasattr(self, 'log_display_mode_toggle_button'):
- self.log_display_mode_toggle_button.clicked.connect(self._toggle_log_display_mode)
+ if hasattr (self ,'log_display_mode_toggle_button'):
+ self .log_display_mode_toggle_button .clicked .connect (self ._toggle_log_display_mode )
if self .manga_rename_toggle_button :self .manga_rename_toggle_button .clicked .connect (self ._toggle_manga_filename_style )
@@ -3441,12 +3439,12 @@ class DownloaderApp (QWidget ):
self .download_extracted_links_button .setEnabled (False )
self .download_extracted_links_button .setVisible (False )
export_button_layout .addWidget (self .download_extracted_links_button )
- self.log_display_mode_toggle_button = QPushButton("🔗 Links View")
- self.log_display_mode_toggle_button.setToolTip("Toggle log display mode for 'Only Links'")
- self.log_display_mode_toggle_button.setFixedWidth(120)
- self.log_display_mode_toggle_button.setStyleSheet("padding: 4px 8px; margin-top: 5px;")
- self.log_display_mode_toggle_button.setVisible(False) # Initially hidden
- export_button_layout.addWidget(self.log_display_mode_toggle_button)
+ self .log_display_mode_toggle_button =QPushButton ("🔗 Links View")
+ self .log_display_mode_toggle_button .setToolTip ("Toggle log display mode for 'Only Links'")
+ self .log_display_mode_toggle_button .setFixedWidth (120 )
+ self .log_display_mode_toggle_button .setStyleSheet ("padding: 4px 8px; margin-top: 5px;")
+ self .log_display_mode_toggle_button .setVisible (False )
+ export_button_layout .addWidget (self .log_display_mode_toggle_button )
right_layout .addLayout (export_button_layout )
@@ -3500,18 +3498,18 @@ class DownloaderApp (QWidget ):
if hasattr (self ,'link_input'):
self .last_link_input_text_for_queue_sync =self .link_input .text ()
- def _update_download_extracted_links_button_state(self):
- if hasattr(self, 'download_extracted_links_button') and self.download_extracted_links_button:
- is_only_links = self.radio_only_links and self.radio_only_links.isChecked()
- if not is_only_links:
- self.download_extracted_links_button.setEnabled(False)
- return
+ def _update_download_extracted_links_button_state (self ):
+ if hasattr (self ,'download_extracted_links_button')and self .download_extracted_links_button :
+ is_only_links =self .radio_only_links and self .radio_only_links .isChecked ()
+ if not is_only_links :
+ self .download_extracted_links_button .setEnabled (False )
+ return
- supported_platforms_for_button = {'mega', 'google drive', 'dropbox'}
- has_supported_links = any(
- link_info[3].lower() in supported_platforms_for_button for link_info in self.extracted_links_cache
+ supported_platforms_for_button ={'mega','google drive','dropbox'}
+ has_supported_links =any (
+ link_info [3 ].lower ()in supported_platforms_for_button for link_info in self .extracted_links_cache
)
- self.download_extracted_links_button.setEnabled(is_only_links and has_supported_links)
+ self .download_extracted_links_button .setEnabled (is_only_links and has_supported_links )
def _show_download_extracted_links_dialog (self ):
"""Shows the placeholder dialog for downloading extracted links."""
@@ -3519,16 +3517,16 @@ class DownloaderApp (QWidget ):
self .log_signal .emit ("ℹ️ Download extracted links button clicked, but not in 'Only Links' mode.")
return
- supported_platforms = {'mega', 'google drive', 'dropbox'}
+ supported_platforms ={'mega','google drive','dropbox'}
links_to_show_in_dialog =[]
for link_data_tuple in self .extracted_links_cache :
- platform = link_data_tuple[3].lower()
- if platform in supported_platforms:
- links_to_show_in_dialog.append ({
+ platform =link_data_tuple [3 ].lower ()
+ if platform in supported_platforms :
+ links_to_show_in_dialog .append ({
'title':link_data_tuple [0 ],
'link_text':link_data_tuple [1 ],
'url':link_data_tuple [2 ],
- 'platform':platform,
+ 'platform':platform ,
'key':link_data_tuple [4 ]
})
@@ -3536,34 +3534,33 @@ class DownloaderApp (QWidget ):
QMessageBox .information (self ,"No Supported Links","No Mega, Google Drive, or Dropbox links were found in the extracted links.")
return
- dialog = DownloadExtractedLinksDialog(links_to_show_in_dialog, self)
+ dialog =DownloadExtractedLinksDialog (links_to_show_in_dialog ,self )
dialog .download_requested .connect (self ._handle_extracted_links_download_request )
dialog .exec_ ()
- def _handle_extracted_links_download_request(self, selected_links_info):
+ def _handle_extracted_links_download_request (self ,selected_links_info ):
if not selected_links_info :
- self.log_signal.emit("ℹ️ No links selected for download from dialog.")
+ self .log_signal .emit ("ℹ️ No links selected for download from dialog.")
return
- # Preserve log logic (might need adjustment if GDrive/Dropbox have different log styles)
- if self.radio_only_links and self.radio_only_links.isChecked() and \
- self.only_links_log_display_mode == LOG_DISPLAY_DOWNLOAD_PROGRESS:
- self.main_log_output.clear()
- self.log_signal.emit("ℹ️ Displaying Mega download progress (extracted links hidden)...")
- self.mega_download_log_preserved_once = False # Ensure no append logic triggers
+
+ if self .radio_only_links and self .radio_only_links .isChecked ()and self .only_links_log_display_mode ==LOG_DISPLAY_DOWNLOAD_PROGRESS :
+ self .main_log_output .clear ()
+ self .log_signal .emit ("ℹ️ Displaying Mega download progress (extracted links hidden)...")
+ self .mega_download_log_preserved_once =False
current_main_dir =self .dir_input .text ().strip ()
download_dir_for_mega =""
if current_main_dir and os .path .isdir (current_main_dir ):
download_dir_for_mega =current_main_dir
- self.log_signal.emit(f"ℹ️ Using existing main download location for external links: {download_dir_for_mega}")
+ self .log_signal .emit (f"ℹ️ Using existing main download location for external links: {download_dir_for_mega }")
else :
if not current_main_dir :
- self.log_signal.emit("ℹ️ Main download location is empty. Prompting for download folder.")
+ self .log_signal .emit ("ℹ️ Main download location is empty. Prompting for download folder.")
else :
- self.log_signal.emit(
- f"⚠️ Main download location '{current_main_dir}' is not a valid directory. Prompting for download folder.")
+ self .log_signal .emit (
+ f"⚠️ Main download location '{current_main_dir }' is not a valid directory. Prompting for download folder.")
suggestion_path =current_main_dir if current_main_dir else QStandardPaths .writableLocation (QStandardPaths .DownloadLocation )
@@ -3571,73 +3568,73 @@ class DownloaderApp (QWidget ):
chosen_dir =QFileDialog .getExistingDirectory (
self ,
"Select Download Folder for Mega Links",
- suggestion_path,
- options=QFileDialog.ShowDirsOnly | QFileDialog.DontUseNativeDialog # Added DontUseNativeDialog for consistency
+ suggestion_path ,
+ options =QFileDialog .ShowDirsOnly |QFileDialog .DontUseNativeDialog
)
if not chosen_dir :
- self.log_signal.emit("ℹ️ External links download cancelled - no download directory selected from prompt.")
+ self .log_signal .emit ("ℹ️ External links download cancelled - no download directory selected from prompt.")
return
download_dir_for_mega =chosen_dir
- self.log_signal.emit(f"ℹ️ Preparing to download {len(selected_links_info)} selected external link(s) to: {download_dir_for_mega}")
+ self .log_signal .emit (f"ℹ️ Preparing to download {len (selected_links_info )} selected external link(s) to: {download_dir_for_mega }")
if not os .path .exists (download_dir_for_mega ):
- self.log_signal.emit(f"❌ Critical Error: Selected download directory '{download_dir_for_mega}' does not exist.")
+ self .log_signal .emit (f"❌ Critical Error: Selected download directory '{download_dir_for_mega }' does not exist.")
return
- # selected_links_info already contains dicts with 'url', 'title', 'platform', 'key'
- tasks_for_thread = selected_links_info
- if self.external_link_download_thread and self.external_link_download_thread.isRunning():
- QMessageBox.warning(self, "Busy", "Another external link download is already in progress.")
- return
+ tasks_for_thread =selected_links_info
- self.external_link_download_thread = ExternalLinkDownloadThread(
- tasks_for_thread,
- download_dir_for_mega,
- self.log_signal.emit,
- self
+ if self .external_link_download_thread and self .external_link_download_thread .isRunning ():
+ QMessageBox .warning (self ,"Busy","Another external link download is already in progress.")
+ return
+
+ self .external_link_download_thread =ExternalLinkDownloadThread (
+ tasks_for_thread ,
+ download_dir_for_mega ,
+ self .log_signal .emit ,
+ self
)
- self.external_link_download_thread.finished.connect(self._on_external_link_download_thread_finished)
- # Connect progress_signal if ExternalLinkDownloadThread has it (it does)
- self.external_link_download_thread.progress_signal.connect(self.handle_main_log)
- self.external_link_download_thread.file_complete_signal.connect(self._on_single_external_file_complete)
+ self .external_link_download_thread .finished .connect (self ._on_external_link_download_thread_finished )
+
+ self .external_link_download_thread .progress_signal .connect (self .handle_main_log )
+ self .external_link_download_thread .file_complete_signal .connect (self ._on_single_external_file_complete )
self .set_ui_enabled (False )
- self.progress_label.setText(f"Downloading External Links (0/{len(tasks_for_thread)})...")
- self.external_link_download_thread.start()
+ self .progress_label .setText (f"Downloading External Links (0/{len (tasks_for_thread )})...")
+ self .external_link_download_thread .start ()
- def _on_external_link_download_thread_finished(self):
- self.log_signal.emit("✅ External link download thread finished.")
- self.progress_label.setText("External link downloads complete. Ready for new task.")
-
- self.mega_download_log_preserved_once = True # Mark that a mega download just finished
- self.log_signal.emit("INTERNAL: mega_download_log_preserved_once SET to True.") # Debug
+ def _on_external_link_download_thread_finished (self ):
+ self .log_signal .emit ("✅ External link download thread finished.")
+ self .progress_label .setText ("External link downloads complete. Ready for new task.")
- if self.radio_only_links and self.radio_only_links.isChecked():
- self.log_signal.emit(HTML_PREFIX + "