Compare commits

..

2 Commits
v7.9.1 ... main

Author SHA1 Message Date
Yuvi9587
ef9abacc5d Commit 2025-12-28 18:15:30 +05:30
Yuvi9587
6a36179136 Commit 2025-12-28 09:34:49 +05:30
5 changed files with 16 additions and 40 deletions

View File

@ -15,7 +15,6 @@ from ..config.constants import (
STYLE_POST_TITLE_GLOBAL_NUMBERING
)
# --- NEW: Custom Adapter to fix SSL errors ---
class CustomSSLAdapter(HTTPAdapter):
"""
A custom HTTPAdapter that forces check_hostname=False when using SSL.
@ -130,13 +129,13 @@ def fetch_single_post_data(api_domain, service, user_id, post_id, headers, logge
response = scraper.get(post_api_url, headers=headers, timeout=request_timeout, cookies=cookies_dict, proxies=proxies, verify=False)
# --- FIX: Handle 429 Rate Limit explicitly ---
if response.status_code == 429:
wait_time = 20 + (attempt * 10) # 20s, 30s, 40s...
logger(f" ⚠️ Rate Limited (429) on post {post_id}. Waiting {wait_time} seconds before retrying...")
time.sleep(wait_time)
continue # Try loop again
# ---------------------------------------------
response.raise_for_status()
@ -266,11 +265,9 @@ def download_from_api(
if target_post_id and (start_page or end_page):
logger("⚠️ Page range (start/end page) is ignored when a specific post URL is provided (searching all pages for the post).")
# --- FIXED LOGIC HERE ---
# Define which styles require fetching ALL posts first (Sequential Mode)
styles_requiring_fetch_all = [STYLE_DATE_BASED, STYLE_POST_TITLE_GLOBAL_NUMBERING]
# Only enable "fetch all and sort" if the current style is explicitly in the list above
is_manga_mode_fetch_all_and_sort_oldest_first = (
manga_mode and
(manga_filename_style_for_sort_check in styles_requiring_fetch_all) and

View File

@ -1,8 +1,8 @@
import requests
import re
from bs4 import BeautifulSoup # Optional, but regex is faster for this specific site
from bs4 import BeautifulSoup
# Logic derived from NHdownloader.sh 'hentaifox' function
BASE_URL = "https://hentaifox.com"
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
@ -25,11 +25,10 @@ def get_gallery_metadata(gallery_id):
response.raise_for_status()
html = response.text
# Extract Title (Bash: grep -o '<title>.*</title>')
title_match = re.search(r'<title>(.*?)</title>', html)
title = title_match.group(1).replace(" - HentaiFox", "").strip() if title_match else f"Gallery {gallery_id}"
# Extract Total Pages (Bash: grep -Eo 'Pages: [0-9]*')
pages_match = re.search(r'Pages: (\d+)', html)
if not pages_match:
raise ValueError("Could not find total pages count.")

View File

@ -686,7 +686,6 @@ class PostProcessorWorker:
response = requests.get(new_url, headers=file_download_headers, timeout=(30, 300), stream=True, cookies=cookies_to_use_for_file, proxies=self.proxies, verify=False)
response.raise_for_status()
# --- REVISED AND MOVED SIZE CHECK LOGIC ---
total_size_bytes = int(response.headers.get('Content-Length', 0))
if self.skip_file_size_mb is not None:
@ -695,8 +694,7 @@ class PostProcessorWorker:
if file_size_mb < self.skip_file_size_mb:
self.logger(f" -> Skip File (Size): '{api_original_filename}' is {file_size_mb:.2f} MB, which is smaller than the {self.skip_file_size_mb} MB limit.")
return 0, 1, api_original_filename, False, FILE_DOWNLOAD_STATUS_SKIPPED, None
# If Content-Length is missing, we can't check, so we no longer log a warning here and just proceed.
# --- END OF REVISED LOGIC ---
num_parts_for_file = min(self.multipart_parts_count, MAX_PARTS_FOR_MULTIPART_DOWNLOAD)

View File

@ -75,11 +75,6 @@ def add_metadata_page(pdf, post, font_family):
if link_url:
# Styling for clickable link: Blue + Underline
pdf.set_text_color(0, 0, 255)
# Check if font supports underline style directly or just use 'U'
# FPDF standard allows 'U' in style string.
# We use 'U' combined with the font family.
# Note: DejaVu implementation in fpdf2 might handle 'U' automatically or ignore it depending on version,
# but setting text color indicates link clearly enough usually.
pdf.set_font(font_family, 'U', 11)
# Pass the URL to the 'link' parameter
@ -131,9 +126,9 @@ def create_individual_pdf(post_data, output_filename, font_path, add_info_page=F
font_family = _setup_pdf_fonts(pdf, font_path, logger)
if add_info_page:
# add_metadata_page adds the page start itself
add_metadata_page(pdf, post_data, font_family)
# REMOVED: pdf.add_page() <-- This ensures content starts right below the line
else:
pdf.add_page()
@ -210,7 +205,6 @@ def create_single_pdf_from_content(posts_data, output_filename, font_path, add_i
for i, post in enumerate(posts_data):
if add_info_page:
add_metadata_page(pdf, post, font_family)
# REMOVED: pdf.add_page() <-- This ensures content starts right below the line
else:
pdf.add_page()

View File

@ -6636,11 +6636,11 @@ class DownloaderApp (QWidget ):
# Look up the name in the cache, falling back to the ID if not found.
creator_name = self.creator_name_cache.get((service, user_id), user_id)
# Add the new 'creator_name' key to the format_values dictionary.
format_values = {
'id': str(job_details.get('original_post_id_for_log', '')),
'user': user_id,
'creator_name': creator_name, # <-- ADDED
'creator_name': creator_name,
'service': str(job_details.get('service', '')),
'title': post_title,
'name': base,
@ -7075,7 +7075,6 @@ class DownloaderApp (QWidget ):
self.log_signal.emit(f" Fetched a total of {len(all_posts_from_api)} posts from the server.")
# CORRECTED LINE: Assign the list directly without re-filtering
self.new_posts_for_update = all_posts_from_api
if not self.new_posts_for_update:
@ -7103,7 +7102,6 @@ class DownloaderApp (QWidget ):
self.log_signal.emit(f" Update session will save to base folder: {base_download_dir_from_ui}")
raw_character_filters_text = self.character_input.text().strip()
# FIX: Parse both filters and commands from the input string
parsed_character_filter_objects, download_commands = self._parse_character_filters(raw_character_filters_text)
try:
@ -7181,11 +7179,7 @@ class DownloaderApp (QWidget ):
'single_pdf_mode': self.single_pdf_setting,
'project_root_dir': self.app_base_dir,
'processed_post_ids': list(self.active_update_profile['processed_post_ids']),
# FIX: Use the parsed commands dictionary to get the sfp_threshold
'sfp_threshold': download_commands.get('sfp_threshold'),
# FIX: Add all the missing keys
'date_prefix_format': self.date_prefix_format,
'domain_override': download_commands.get('domain_override'),
'archive_only_mode': download_commands.get('archive_only', False),
@ -7218,11 +7212,9 @@ class DownloaderApp (QWidget ):
dialog = EmptyPopupDialog(self.user_data_path, self)
if dialog.exec_() == QDialog.Accepted:
# --- START OF MODIFICATION ---
if hasattr(dialog, 'update_profiles_list') and dialog.update_profiles_list:
self.active_update_profiles_list = dialog.update_profiles_list
# --- NEW LOGIC: Check if user wants to load settings into UI ---
load_settings_requested = getattr(dialog, 'load_settings_into_ui_requested', False)
self.override_update_profile_settings = load_settings_requested
@ -7239,7 +7231,7 @@ class DownloaderApp (QWidget ):
self.link_input.setText(f"{len(self.active_update_profiles_list)} profiles loaded for update check...")
self._start_batch_update_check(self.active_update_profiles_list)
# --- END OF MODIFICATION ---
elif hasattr(dialog, 'selected_creators_for_queue') and dialog.selected_creators_for_queue:
self.active_update_profile = None # Ensure single update mode is off
@ -7488,17 +7480,13 @@ class DownloaderApp (QWidget ):
should_create_artist_folder = False
# --- Check for popup selection scope ---
if item_type == 'creator_popup_selection' and item_scope == EmptyPopupDialog.SCOPE_CREATORS:
should_create_artist_folder = True
# --- Check for global "Artist Folders" scope ---
elif item_type != 'creator_popup_selection' and self.favorite_download_scope == FAVORITE_SCOPE_ARTIST_FOLDERS:
should_create_artist_folder = True
# --- NEW: Check for forced folder flag from batch ---
if self.current_processing_favorite_item_info.get('force_artist_folder'):
should_create_artist_folder = True
# ---------------------------------------------------
if should_create_artist_folder and main_download_dir:
folder_name_key = self.current_processing_favorite_item_info.get('name_for_folder', 'Unknown_Folder')