mirror of
https://github.com/Yuvi9587/Kemono-Downloader.git
synced 2025-12-29 16:14:44 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef9abacc5d | ||
|
|
6a36179136 |
@ -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
|
||||
|
||||
@ -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.")
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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()
|
||||
|
||||
|
||||
@ -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')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user