From 7e5dc71720523c2d3c8670a5a6d86c90b18855cd Mon Sep 17 00:00:00 2001
From: Yuvi9587 <114073886+Yuvi9587@users.noreply.github.com>
Date: Fri, 23 May 2025 18:06:47 +0530
Subject: [PATCH] Commit
---
main.py | 193 ++++++++++++++++++++++++++++++++++++++----------------
readme.md | 43 ++++++++----
2 files changed, 165 insertions(+), 71 deletions(-)
diff --git a/main.py b/main.py
index b96f73c..56321ef 100644
--- a/main.py
+++ b/main.py
@@ -21,7 +21,7 @@ from PyQt5.QtGui import (
from PyQt5.QtWidgets import (
QApplication, QWidget, QLabel, QLineEdit, QTextEdit, QPushButton,
QVBoxLayout, QHBoxLayout, QFileDialog, QMessageBox, QListWidget, QRadioButton, QButtonGroup, QCheckBox, QSplitter,
- QDialog, QStackedWidget, QScrollArea,
+ QDialog, QStackedWidget, QScrollArea, QListWidgetItem,
QAbstractItemView, # Added for QListWidget.NoSelection
QFrame,
QAbstractButton
@@ -114,11 +114,11 @@ CONFIRM_ADD_ALL_CANCEL_DOWNLOAD = 3
class ConfirmAddAllDialog(QDialog):
"""A dialog to confirm adding multiple new names to Known.txt."""
- def __init__(self, new_names_list, parent=None):
+ def __init__(self, new_filter_objects_list, parent=None):
super().__init__(parent)
self.setWindowTitle("Confirm Adding New Names")
self.setModal(True)
- self.new_names_list = new_names_list
+ self.new_filter_objects_list = new_filter_objects_list
self.user_choice = CONFIRM_ADD_ALL_CANCEL_DOWNLOAD # Default to cancel if closed
main_layout = QVBoxLayout(self)
@@ -132,20 +132,41 @@ class ConfirmAddAllDialog(QDialog):
main_layout.addWidget(info_label)
self.names_list_widget = QListWidget()
- self.names_list_widget.addItems(self.new_names_list)
- self.names_list_widget.setSelectionMode(QAbstractItemView.NoSelection) # Just for display
+ for filter_obj in self.new_filter_objects_list:
+ item_text = filter_obj["name"]
+ # Optionally, make group display more informative
+ # if filter_obj["is_group"]:
+ # item_text += f" (Group with aliases: {', '.join(filter_obj['aliases'])})"
+
+ list_item = QListWidgetItem(item_text)
+ list_item.setFlags(list_item.flags() | Qt.ItemIsUserCheckable)
+ list_item.setCheckState(Qt.Checked) # Default to checked
+ list_item.setData(Qt.UserRole, filter_obj) # Store the full filter object
+ self.names_list_widget.addItem(list_item)
+
main_layout.addWidget(self.names_list_widget)
+ selection_buttons_layout = QHBoxLayout()
+ self.select_all_button = QPushButton("Select All")
+ self.select_all_button.clicked.connect(self._select_all_items)
+ selection_buttons_layout.addWidget(self.select_all_button)
+
+ self.deselect_all_button = QPushButton("Deselect All")
+ self.deselect_all_button.clicked.connect(self._deselect_all_items)
+ selection_buttons_layout.addWidget(self.deselect_all_button)
+ selection_buttons_layout.addStretch()
+ main_layout.addLayout(selection_buttons_layout)
+
+
buttons_layout = QHBoxLayout()
- self.add_all_button = QPushButton("Add All to Known.txt")
- self.add_all_button.clicked.connect(self._accept_add_all)
- buttons_layout.addWidget(self.add_all_button)
+ self.add_selected_button = QPushButton("Add Selected to Known.txt")
+ self.add_selected_button.clicked.connect(self._accept_add_selected)
+ buttons_layout.addWidget(self.add_selected_button)
self.skip_adding_button = QPushButton("Skip Adding These")
self.skip_adding_button.clicked.connect(self._reject_skip_adding)
buttons_layout.addWidget(self.skip_adding_button)
-
buttons_layout.addStretch()
self.cancel_download_button = QPushButton("Cancel Download")
@@ -158,10 +179,27 @@ class ConfirmAddAllDialog(QDialog):
self.setMinimumHeight(350)
if parent and hasattr(parent, 'get_dark_theme'):
self.setStyleSheet(parent.get_dark_theme())
- self.add_all_button.setDefault(True)
+ self.add_selected_button.setDefault(True)
- def _accept_add_all(self):
- self.user_choice = CONFIRM_ADD_ALL_ACCEPTED
+ def _select_all_items(self):
+ for i in range(self.names_list_widget.count()):
+ self.names_list_widget.item(i).setCheckState(Qt.Checked)
+
+ def _deselect_all_items(self):
+ for i in range(self.names_list_widget.count()):
+ self.names_list_widget.item(i).setCheckState(Qt.Unchecked)
+
+ def _accept_add_selected(self):
+ selected_objects = []
+ for i in range(self.names_list_widget.count()):
+ item = self.names_list_widget.item(i)
+ if item.checkState() == Qt.Checked:
+ filter_obj = item.data(Qt.UserRole)
+ if filter_obj: # Should always be true if populated correctly
+ selected_objects.append(filter_obj)
+
+ # self.user_choice will be the list of selected filter_obj, or empty list if none selected
+ self.user_choice = selected_objects
self.accept()
def _reject_skip_adding(self):
@@ -174,6 +212,10 @@ class ConfirmAddAllDialog(QDialog):
def exec_(self):
super().exec_()
+ # If user accepted but selected nothing, treat it as skipping addition
+ if isinstance(self.user_choice, list) and not self.user_choice:
+ QMessageBox.information(self, "No Selection", "No names were selected to be added. Skipping addition.")
+ return CONFIRM_ADD_ALL_SKIP_ADDING
return self.user_choice
class TourStepWidget(QWidget):
"""A single step/page in the tour."""
@@ -289,10 +331,13 @@ class TourDialog(QDialog):
step1_content = (
"Hello! This quick tour will walk you through the main features of the Kemono Downloader, including recent updates like enhanced filtering, manga mode improvements, and cookie management."
"
"
- "- My goal is to help you easily download content from Kemono and Coomer.
"
- "- Use the Next and Back buttons to navigate.
"
- "- Many options have tooltips if you hover over them for more details.
"
- "- Click Skip Tour to close this guide at any time.
"
+ "- My goal is to help you easily download content from Kemono and Coomer.
"
+ "- Important Tip: App '(Not Responding)'?
"
+ " After clicking 'Start Download', especially for large creator feeds or with many threads, the application might temporarily show as '(Not Responding)'. Your operating system (Windows, macOS, Linux) might even suggest you 'End Process' or 'Force Quit'.
"
+ " Please be patient! The app is often still working hard in the background. Before force-closing, try checking your chosen 'Download Location' in your file explorer. If you see new folders being created or files appearing, it means the download is progressing correctly. Give it some time to become responsive again.
"
+ "- Use the Next and Back buttons to navigate.
"
+ "- Many options have tooltips if you hover over them for more details.
"
+ "- Click Skip Tour to close this guide at any time.
"
"- Check 'Never show this tour again' if you don't want to see this on future startups.
"
"
"
)
@@ -304,6 +349,7 @@ class TourDialog(QDialog):
"π Kemono Creator/Post URL:
"
" Paste the full web address (URL) of a creator's page (e.g., https://kemono.su/patreon/user/12345) "
"or a specific post (e.g., .../post/98765).
"
+ " or a Coomer creator (e.g., https://coomer.su/onlyfans/user/artistname) "
"π Download Location:
"
" Click 'Browse...' to choose a folder on your computer where all downloaded files will be saved. "
"This is required unless you are using 'Only Links' mode.
"
@@ -315,28 +361,28 @@ class TourDialog(QDialog):
self.step2 = TourStepWidget("β Getting Started", step2_content)
step3_content = (
- "Refine what you download with these filters:"
+ "Refine what you download with these filters (most are disabled in 'Only Links' or 'Only Archives' modes):"
""
"- π― Filter by Character(s):
"
- " Enter character names, comma-separated (e.g., Tifa, Aerith). Group aliases for a combined folder name: (alias1, alias2) becomes folder 'alias1 alias2'.
"
- " Enter character names, comma-separated (e.g., Tifa, Aerith). Group aliases for a combined folder name: (alias1, alias2, alias3) becomes folder 'alias1 alias2 alias3' (after cleaning).\nAll names in the group are used as aliases for matching.\n"
- " - Filter: Files: Checks individual filenames. A post is kept if any file matches; only matching files are downloaded. Folder naming uses the character from the matching filename.
"
- " - Filter: Title: Checks post titles. All files from a matching post are downloaded. Folder naming uses the character from the matching post title.
"
- " - Filter: Both: Checks post title first. If it matches, all files are downloaded. If not, it then checks filenames, and only matching files are downloaded. Folder naming prioritizes title match, then file match.
"
+ " Enter character names, comma-separated (e.g., Tifa, Aerith). Group aliases for a combined folder name: (alias1, alias2, alias3) becomes folder 'alias1 alias2 alias3' (after cleaning). All names in the group are used as aliases for matching.
"
+ " The 'Filter: [Type]' button (next to this input) cycles how this filter applies:"
+ " - Filter: Files: Checks individual filenames. A post is kept if any file matches; only matching files are downloaded. Folder naming uses the character from the matching filename (if 'Separate Folders' is on).
"
+ " - Filter: Title: Checks post titles. All files from a matching post are downloaded. Folder naming uses the character from the matching post title.
"
+ " - Filter: Both: Checks post title first. If it matches, all files are downloaded. If not, it then checks filenames, and only matching files are downloaded. Folder naming prioritizes title match, then file match.
"
" - Filter: Comments (Beta): Checks filenames first. If a file matches, all files from the post are downloaded. If no file match, it then checks post comments. If a comment matches, all files are downloaded. (Uses more API requests). Folder naming prioritizes file match, then comment match.
"
" This filter also influences folder naming if 'Separate Folders by Name/Title' is enabled.
"
"- π« Skip with Words:
"
" Enter words, comma-separated (e.g., WIP, sketch, preview). "
" The 'Scope: [Type]' button (next to this input) cycles how this filter applies:"
- " - Scope: Files: Skips files if their names contain any of these words.
"
- " - Scope: Posts: Skips entire posts if their titles contain any of these words.
"
+ " - Scope: Files: Skips files if their names contain any of these words.
"
+ " - Scope: Posts: Skips entire posts if their titles contain any of these words.
"
" - Scope: Both: Applies both file and post title skipping (post first, then files).
"
"- Filter Files (Radio Buttons): Choose what to download:"
"
"
- " - All: Downloads all file types found.
"
- " - Images/GIFs: Only common image formats and GIFs.
"
- " - Videos: Only common video formats.
"
- " - π¦ Only Archives: Exclusively downloads .zip and .rar files. When selected, 'Skip .zip' and 'Skip .rar' checkboxes are automatically disabled and unchecked. 'Show External Links' is also disabled.
"
+ " - All: Downloads all file types found.
"
+ " - Images/GIFs: Only common image formats and GIFs.
"
+ " - Videos: Only common video formats.
"
+ " - π¦ Only Archives: Exclusively downloads .zip and .rar files. When selected, 'Skip .zip' and 'Skip .rar' checkboxes are automatically disabled and unchecked. 'Show External Links' is also disabled.
"
" - π Only Links: Extracts and displays external links from post descriptions instead of downloading files. Download-related options and 'Show External Links' are disabled.
"
"
"
"
"
@@ -355,10 +401,11 @@ class TourDialog(QDialog):
"ποΈ Custom Folder Name (Single Post Only):
"
" If you are downloading a single specific post URL AND 'Separate Folders by Name/Title' is enabled, "
"you can enter a custom name here for that post's download folder.
"
- "πͺ Use Cookie: Check this to use cookies for requests. You can either:"
- " - Enter a cookie string directly into the text field (e.g., name1=value1; name2=value2).
"
+ "- πͺ Use Cookie: Check this to use cookies for requests. You can either:" # This
- is the parent of a sub-ul
+ "
- Enter a cookie string directly into the text field (e.g., name1=value1; name2=value2).
"
" - Click 'Browse...' to select a cookies.txt file (Netscape format). The path will appear in the text field.
"
- " This is useful for accessing content that requires login. The text field takes precedence if filled. "
+ " This is useful for accessing content that requires login. The text field takes precedence if filled. "
+ "If 'Use Cookie' is checked but both the text field and browsed file are empty, it will try to load 'cookies.txt' from the app's directory.
"
""
)
self.step4 = TourStepWidget("β’ Fine-Tuning Downloads", step4_content)
@@ -366,61 +413,87 @@ class TourDialog(QDialog):
step5_content = (
"Organize your downloads and manage performance:"
""
- "- βοΈ Separate Folders by Name/Title: Creates subfolders based on the 'Filter by Character(s)' input or post titles (can use the 'Known Shows/Characters' list as a fallback for folder names).
"
+ "- βοΈ Separate Folders by Name/Title: Creates subfolders based on the 'Filter by Character(s)' input or post titles (can use the Known.txt list as a fallback for folder names).
"
"- Subfolder per Post: If 'Separate Folders' is on, this creates an additional subfolder for each individual post inside the main character/title folder.
"
"- π Use Multithreading (Threads): Enables faster operations. The number in 'Threads' input means:"
- "
- For Creator Feeds: Number of posts to process simultaneously. Files within each post are downloaded sequentially by its worker (unless 'Date Based' manga naming is on, which forces 1 post worker).
"
+ " - For Creator Feeds: Number of posts to process simultaneously. Files within each post are downloaded sequentially by its worker (unless 'Date Based' manga naming is on, which forces 1 post worker).
"
" - For Single Post URLs: Number of files to download concurrently from that single post.
"
" If unchecked, 1 thread is used. High thread counts (e.g., >40) may show an advisory.
"
"- Multi-part Download Toggle (Top-right of log area):
"
" The 'Multi-part: [ON/OFF]' button allows enabling/disabling multi-segment downloads for individual large files. "
- " - ON: Can speed up large file downloads (e.g., videos) but may increase UI choppiness or log spam with many small files. An advisory will appear when enabling. If a multi-part download fails, it retries as single-stream.
"
+ " - ON: Can speed up large file downloads (e.g., videos) but may increase UI choppiness or log spam with many small files. An advisory will appear when enabling. If a multi-part download fails, it retries as single-stream.
"
" - OFF (Default): Files are downloaded in a single stream.
"
" This is disabled if 'Only Links' or 'Only Archives' mode is active.
"
"- π Manga/Comic Mode (Creator URLs only): Tailored for sequential content."
"
"
- " - Downloads posts from oldest to newest.
"
- " - The 'Page Range' input is disabled as all posts are fetched.
"
+ " - Downloads posts from oldest to newest.
"
+ " - The 'Page Range' input is disabled as all posts are fetched.
"
" - A filename style toggle button (e.g., 'Name: Post Title') appears in the top-right of the log area when this mode is active for a creator feed. Click it to cycle through naming styles:"
"
"
- " - Name: Post Title (Default): The first file in a post is named after the post's title. Subsequent files in the same post keep original names.
"
- " - Name: Original File: All files attempt to keep their original filenames.
"
+ " - Name: Post Title (Default): The first file in a post is named after the post's title. Subsequent files in the same post keep original names.
"
+ " - Name: Original File: All files attempt to keep their original filenames.
"
" - Name: Date Based: Files are named sequentially (001.ext, 002.ext, ...) based on post publication order. Multithreading for post processing is automatically disabled for this style.
"
"
"
- " "
+ "
"
" - For best results with 'Name: Post Title' or 'Name: Date Based' styles, use the 'Filter by Character(s)' field with the manga/series title for folder organization.
"
"
"
"π Known.txt for Smart Folder Organization:
"
- " Fine-grained control over automatic folder organization using a personalized list in Known.txt."
+ " Known.txt (in the app's directory) allows fine-grained control over automatic folder organization when 'Separate Folders by Name/Title' is active."
" "
- " - Grouped Entries (Aliases): Define a set of aliases that should all map to a single folder name. For example, an entry like
(Power, powwr, pwr, Blood devil) in Known.txt means any post matching \"Power\", \"powwr\", etc. (based on your filter scope) will be saved into a folder named \"Power powwr pwr Blood devil\" (after cleaning). Simple entries like My Series are also supported. The folder name for a group is derived from the *entire content* inside the parentheses, with commas replaced by spaces before cleaning. "
- " - Intelligent Fallback: When 'Separate Folders by Name/Title' is active, and if a post doesn't match any specific 'Filter by Character(s)' input, the downloader consults
Known.txt to find a matching primary name for folder creation. "
- " - User-Friendly Management: Add or remove primary names directly through the UI list below. For advanced editing (like setting up aliases or defining the primary name for a group), click 'Open Known.txt' to edit the file directly.
"
+ " - How it Works: Each line in
Known.txt is an entry. "
+ " - A simple line like
My Awesome Series means content matching this will go into a folder named \"My Awesome Series\".
"
+ " - A grouped line like
(Character A, Char A, Alt Name A) means content matching \"Character A\", \"Char A\", OR \"Alt Name A\" will ALL go into a single folder named \"Character A Char A Alt Name A\" (after cleaning). All terms in the parentheses become aliases for that folder.
"
+ " - Intelligent Fallback: When 'Separate Folders by Name/Title' is active, and if a post doesn't match any specific 'Filter by Character(s)' input, the downloader consults
Known.txt to find a matching primary name for folder creation.
"
+ " - User-Friendly Management: Add simple (non-grouped) names via the UI list below. For advanced editing (like creating/modifying grouped aliases), click 'Open Known.txt' to edit the file in your text editor. The app reloads it on next use or startup.
"
"
"
""
""
)
self.step5 = TourStepWidget("β£ Organization & Performance", step5_content)
- step6_content = (
+ step6_errors_content = (
+ "Sometimes, downloads might encounter issues. Here are a few common ones:"
+ ""
+ "- 502 Bad Gateway / 503 Service Unavailable / 504 Gateway Timeout:
"
+ " These usually indicate temporary server-side problems with Kemono/Coomer. The site might be overloaded, down for maintenance, or experiencing issues.
"
+ " Solution: Wait a while (e.g., 30 minutes to a few hours) and try again later. Check the site directly in your browser.
"
+ "- Connection Lost / Connection Refused / Timeout (during file download):
"
+ " This can happen due to your internet connection, server instability, or if the server drops the connection for a large file.
"
+ " Solution: Check your internet. Try reducing the number of 'Threads' if it's high. The app might prompt to retry some failed files at the end of a session.
"
+ "- IncompleteRead Error:
"
+ " The server sent less data than expected. Often a temporary network hiccup or server issue.
"
+ " Solution: The app will often mark these files for a retry attempt at the end of the download session.
"
+ "- 403 Forbidden / 401 Unauthorized (less common for public posts):
"
+ " You might not have permission to access the content. For some paywalled or private content, using the 'Use Cookie' option with valid cookies from your browser session might help. Ensure your cookies are fresh.
"
+ "- 404 Not Found:
"
+ " The post or file URL is incorrect, or the content has been removed from the site. Double-check the URL.
"
+ "- 'No posts found' / 'Target post not found':
"
+ " Ensure the URL is correct and the creator/post exists. If using page ranges, make sure they are valid for the creator. For very new posts, there might be a slight delay before they appear in the API.
"
+ "- General Slowness / App '(Not Responding)':
"
+ " As mentioned in Step 1, if the app seems to hang after starting, especially with large creator feeds or many threads, please give it time. It's likely processing data in the background. Reducing thread count can sometimes improve responsiveness if this is frequent. "
+ "
"
+ )
+ self.step6_errors = TourStepWidget("β₯ Common Errors & Troubleshooting", step6_errors_content)
+
+ step7_final_controls_content = (
"Monitoring and Controls:"
""
"- π Progress Log / Extracted Links Log: Shows detailed download messages. If 'π Only Links' mode is active, this area displays the extracted links.
"
"- Show External Links in Log: If checked, a secondary log panel appears below the main log to display any external links found in post descriptions. (This is disabled if 'π Only Links' or 'π¦ Only Archives' mode is active).
"
"- Log View Toggle (ποΈ / π Button):
"
" This button (top-right of log area) switches the main log view:"
- " - ποΈ Progress Log (Default): Shows all download activity, errors, and summaries.
"
- " - π Missed Character Log: Displays a summarized list of key terms from post titles that were skipped due to your 'Filter by Character(s)' settings. Useful for identifying content you might be unintentionally missing.
"
+ " - ποΈ Progress Log (Default): Shows all download activity, errors, and summaries.
"
+ " - π Missed Character Log: Displays a list of key terms from post titles that were skipped due to your 'Filter by Character(s)' settings. Useful for identifying content you might be unintentionally missing.
"
"- π Reset: Clears all input fields, logs, and resets temporary settings to their defaults. Can only be used when no download is active.
"
"- β¬οΈ Start Download / π Extract Links / βΈοΈ Pause / β Cancel: These buttons control the process. 'Cancel & Reset UI' stops the current operation and performs a soft UI reset, preserving your URL and Directory inputs. 'Pause/Resume' allows temporarily halting and continuing.
"
"- If some files fail with recoverable errors (like 'IncompleteRead'), you might be prompted to retry them at the end of a session.
"
"
"
"
You're all set! Click 'Finish' to close the tour and start using the downloader."
)
- self.step6 = TourStepWidget("β€ Logs & Final Controls", step6_content)
+ self.step7_final_controls = TourStepWidget("β¦ Logs & Final Controls", step7_final_controls_content)
- self.tour_steps = [self.step1, self.step2, self.step3, self.step4, self.step5, self.step6]
+ self.tour_steps = [self.step1, self.step2, self.step3, self.step4, self.step5, self.step6_errors, self.step7_final_controls]
for step_widget in self.tour_steps:
self.stacked_widget.addWidget(step_widget)
@@ -2605,24 +2678,30 @@ class DownloaderApp(QWidget):
self.log_signal.emit(f"βΉοΈ Manga Mode: Using filter '{item_primary_name}' for this session without adding to Known Names.")
if filter_objects_to_potentially_add_to_known_list:
- display_names_for_dialog = [obj["name"] for obj in filter_objects_to_potentially_add_to_known_list]
- confirm_dialog = ConfirmAddAllDialog(display_names_for_dialog, self)
+ # Pass the list of full filter objects to the dialog
+ confirm_dialog = ConfirmAddAllDialog(filter_objects_to_potentially_add_to_known_list, self)
dialog_result = confirm_dialog.exec_()
+
if dialog_result == CONFIRM_ADD_ALL_CANCEL_DOWNLOAD:
self.log_signal.emit("β Download cancelled by user at new name confirmation stage.")
self.set_ui_enabled(True); return
- elif dialog_result == CONFIRM_ADD_ALL_ACCEPTED:
- self.log_signal.emit(f"βΉοΈ User chose to add {len(filter_objects_to_potentially_add_to_known_list)} new entry/entries to Known.txt.")
- for filter_obj_to_add in filter_objects_to_potentially_add_to_known_list:
- self.add_new_character(name_to_add=filter_obj_to_add["name"], is_group_to_add=filter_obj_to_add["is_group"], aliases_to_add=filter_obj_to_add["aliases"], suppress_similarity_prompt=True)
+ elif isinstance(dialog_result, list): # User chose to add selected items
+ if dialog_result: # If the list of selected filter_objects is not empty
+ self.log_signal.emit(f"βΉοΈ User chose to add {len(dialog_result)} new entry/entries to Known.txt.")
+ for filter_obj_to_add in dialog_result: # dialog_result is the list of selected filter_obj
+ self.add_new_character(
+ name_to_add=filter_obj_to_add["name"],
+ is_group_to_add=filter_obj_to_add["is_group"],
+ aliases_to_add=filter_obj_to_add["aliases"],
+ suppress_similarity_prompt=True # Suppress for batch adding
+ )
+ else: # Empty list means user selected "Add Selected" but had nothing checked (dialog handles this by returning SKIP_ADDING)
+ self.log_signal.emit("βΉοΈ User confirmed adding, but no names were selected in the dialog. No new names added to Known.txt.")
elif dialog_result == CONFIRM_ADD_ALL_SKIP_ADDING:
self.log_signal.emit("βΉοΈ User chose not to add new names to Known.txt for this session.")
# --- End of Known.txt prompting logic ---
else: # extract_links_only is true
self.log_signal.emit(f"βΉοΈ Using character filters for link extraction: {', '.join(item['name'] for item in actual_filters_to_use_for_run)}")
- else: # No character filters typed by user
- self.log_signal.emit("βΉοΈ No character filters provided. All content (matching other criteria) will be processed.")
- # actual_filters_to_use_for_run remains []
if manga_mode and not actual_filters_to_use_for_run and not extract_links_only:
diff --git a/readme.md b/readme.md
index 12e4fba..d463758 100644
--- a/readme.md
+++ b/readme.md
@@ -29,10 +29,25 @@ Version 3.5.0 focuses on enhancing access to content and providing even smarter
### Advanced `Known.txt` for Smart Folder Organization
-- **Fine-Grained Control:** Take your automatic folder organization to the next level with a personalized list of names, series titles, and keywords in `Known.txt`.
-- **Primary Names & Aliases:** Define a main folder name and link multiple aliases to it. For example, `([Power], powwr, pwr, Blood devil)` ensures any post matching "Power" or "powwr" (in title or filename, depending on settings) gets saved into a "Power" folder. Simple entries like `My Series` are also supported.
-- **Intelligent Fallback:** When "Separate Folders by Name/Title" is active, and if a post doesn't match any specific "Filter by Character(s)" input, the downloader consults `Known.txt` to find a matching primary name for folder creation.
-- **User-Friendly Management:** Add or remove primary names directly through the UI, or click "Open Known.txt" for advanced editing (e.g., setting up aliases).
+The `Known.txt` system has been revamped for improved performance and stability. The previous method of handling known names could become resource-intensive with large lists, potentially leading to application slowdowns or crashes. This new, streamlined system offers more direct control and robust organization.
+
+- **Fine-Grained Control:** `Known.txt`, located in the application's directory, allows you to create a personalized list of names, series titles, and keywords for precise automatic folder organization when "Separate Folders by Name/Title" is enabled.
+
+- **How It Works (Syntax and Behavior):**
+ Each line in `Known.txt` represents an entry:
+ - **Simple Entries:** A line like `My Awesome Series` defines both the term to match in content (post titles, filenames, etc., based on your filter scope) and the name of the folder where matching content will be saved ("My Awesome Series").
+ - **Grouped Entries (Primary Folder Name & Aliases):** To group multiple search terms under a single, specific folder name, use parentheses. The format is `(FolderName, alias1, alias2, ...)`.
+ - The **first item** inside the parentheses explicitly defines the name of the folder.
+ - All items within the parentheses (including the first one) are used as aliases to match against content.
+ - **Example:** An entry like `(Chainsaw Man, Denji, Pochita, Makima)` means:
+ - Matching content (containing "Chainsaw Man", "Denji", "Pochita", or "Makima") will be saved into a folder named "Chainsaw Man".
+ - **Another Example:** `(Power, powwr, pwr, Blood Devil)` will create a folder named "Power" for content matching any of those terms.
+
+- **Intelligent Fallback:** If "Separate Folders by Name/Title" is active, and a post's content doesn't match any terms provided in the main "Filter by Character(s)" UI input, the downloader will then consult `Known.txt`. If a match is found in `Known.txt`, the content will be organized into the folder defined by that `Known.txt` entry.
+
+- **User-Friendly Management:**
+ - You can add new simple (non-grouped) entries to `Known.txt` directly using the list and "Add" button in the UI.
+ - To create or modify grouped entries, or to make more complex changes, click the "Open Known.txt" button. This will open the file in your system's default text editor. The application reloads `Known.txt` on startup or when a download process begins.
---
## What's in v3.4.0? (Previous Update)
@@ -208,14 +223,14 @@ This version brings significant enhancements to manga/comic downloading, filteri
### Config System
-- **`Known.txt` for Smart Folder Naming:**
- - A user-editable file (`Known.txt`) stores a list of preferred names, series titles, or keywords.
- - Used as a fallback for folder creation when "Separate Folders by Name/Title" is enabled, helping to group content logically even without explicit character filters.
- - **Supports primary names and aliases:**
- - Simple entries: `My Favorite Series`
- - Grouped entries with a primary name for the folder: `([Primary Name], alias1, alias2)`
+- **`Known.txt` for Smart Folder Naming (Located in App Directory):**
+ - A user-editable file that stores a list of preferred names, series titles, or keywords.
+ - It's primarily used as an intelligent fallback for folder creation when "Separate Folders by Name/Title" is enabled.
+ - **Syntax:**
+ - Simple entries: `My Favorite Series` (creates folder "My Favorite Series", matches "My Favorite Series").
+ - Grouped entries: `(Desired Folder Name, alias1, alias2)` (creates folder "Desired Folder Name"; matches "Desired Folder Name", "alias1", or "alias2").
-- **Stored in Standard App Data Path**
+- **Settings Stored in App Directory**
- **Editable Within GUI**
@@ -258,9 +273,9 @@ pyinstaller --name "Kemono Downloader" --onefile --windowed --icon="Kemono.ico"
***
## ** Config Files**
-
-- `Known.txt` β character/show names used for folder organization
-- Supports simple names (e.g., `My Series`) and grouped names with a primary folder name and aliases (e.g., `([Primary Folder Name], alias1, alias2)`).
+- `settings.json` β Stores your UI preferences and settings.
+- `Known.txt` β Stores character names, series titles, or keywords for organizing downloaded content into specific folders.
+ - Supports simple entries (e.g., `My Series`) and grouped entries for aliases (e.g., `(Folder Name, alias1, alias2)` where "Folder Name" is the name of the created folder, and all terms are used for matching).
***