mirror of
https://github.com/Yuvi9587/Kemono-Downloader.git
synced 2025-12-29 16:14:44 +00:00
Compare commits
2 Commits
5d8737b59e
...
3209770d00
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3209770d00 | ||
|
|
337cdd342c |
24
LICENSE
24
LICENSE
@@ -1,11 +1,21 @@
|
|||||||
Custom License - No Commercial Use
|
MIT License
|
||||||
|
|
||||||
Copyright [Yuvi9587] [2025]
|
Copyright (c) [2025] [Yuvi9587]
|
||||||
|
|
||||||
Permission is hereby granted to any person obtaining a copy of this software and associated documentation files (the "Software"), to use, copy, modify, and distribute the Software for **non-commercial purposes only**, subject to the following conditions:
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
1. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
The above copyright notice and this permission notice shall be included in all
|
||||||
2. Proper credit must be given to the original author in any public use, distribution, or derivative works.
|
copies or substantial portions of the Software.
|
||||||
3. Commercial use, resale, or sublicensing of the Software or any derivative works is strictly prohibited without explicit written permission.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND...
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|||||||
@@ -593,6 +593,33 @@ class PostProcessorWorker:
|
|||||||
os.remove(downloaded_part_file_path)
|
os.remove(downloaded_part_file_path)
|
||||||
except OSError: pass
|
except OSError: pass
|
||||||
return 0, 1, filename_to_save_in_main_path, was_original_name_kept_flag, FILE_DOWNLOAD_STATUS_SKIPPED, None
|
return 0, 1, filename_to_save_in_main_path, was_original_name_kept_flag, FILE_DOWNLOAD_STATUS_SKIPPED, None
|
||||||
|
|
||||||
|
if (self.compress_images and downloaded_part_file_path and
|
||||||
|
is_image(api_original_filename) and
|
||||||
|
os.path.getsize(downloaded_part_file_path) > 1.5 * 1024 * 1024):
|
||||||
|
|
||||||
|
self.logger(f" 🔄 Compressing '{api_original_filename}' to WebP...")
|
||||||
|
try:
|
||||||
|
with Image.open(downloaded_part_file_path) as img:
|
||||||
|
# Convert to RGB to avoid issues with paletted images or alpha channels in WebP
|
||||||
|
if img.mode not in ('RGB', 'RGBA'):
|
||||||
|
img = img.convert('RGBA')
|
||||||
|
|
||||||
|
# Use an in-memory buffer to save the compressed image
|
||||||
|
output_buffer = BytesIO()
|
||||||
|
img.save(output_buffer, format='WebP', quality=85)
|
||||||
|
|
||||||
|
# This buffer now holds the compressed data
|
||||||
|
data_to_write_io = output_buffer
|
||||||
|
|
||||||
|
# Update the filename to use the .webp extension
|
||||||
|
base, _ = os.path.splitext(filename_to_save_in_main_path)
|
||||||
|
filename_to_save_in_main_path = f"{base}.webp"
|
||||||
|
self.logger(f" ✅ Compression successful. New size: {len(data_to_write_io.getvalue()) / (1024*1024):.2f} MB")
|
||||||
|
|
||||||
|
except Exception as e_compress:
|
||||||
|
self.logger(f" ⚠️ Failed to compress '{api_original_filename}': {e_compress}. Saving original file instead.")
|
||||||
|
data_to_write_io = None # Ensure we fall back to saving the original
|
||||||
|
|
||||||
effective_save_folder = target_folder_path
|
effective_save_folder = target_folder_path
|
||||||
base_name, extension = os.path.splitext(filename_to_save_in_main_path)
|
base_name, extension = os.path.splitext(filename_to_save_in_main_path)
|
||||||
@@ -610,15 +637,17 @@ class PostProcessorWorker:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if data_to_write_io:
|
if data_to_write_io:
|
||||||
|
# Write the compressed data from the in-memory buffer
|
||||||
with open(final_save_path, 'wb') as f_out:
|
with open(final_save_path, 'wb') as f_out:
|
||||||
time.sleep(0.05)
|
|
||||||
f_out.write(data_to_write_io.getvalue())
|
f_out.write(data_to_write_io.getvalue())
|
||||||
|
# Clean up the original downloaded part file
|
||||||
if downloaded_part_file_path and os.path.exists(downloaded_part_file_path):
|
if downloaded_part_file_path and os.path.exists(downloaded_part_file_path):
|
||||||
try:
|
try:
|
||||||
os.remove(downloaded_part_file_path)
|
os.remove(downloaded_part_file_path)
|
||||||
except OSError as e_rem:
|
except OSError as e_rem:
|
||||||
self.logger(f" -> Failed to remove .part after compression: {e_rem}")
|
self.logger(f" -> Failed to remove .part after compression: {e_rem}")
|
||||||
else:
|
else:
|
||||||
|
# No compression was done, just rename the original file
|
||||||
if downloaded_part_file_path and os.path.exists(downloaded_part_file_path):
|
if downloaded_part_file_path and os.path.exists(downloaded_part_file_path):
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
os.rename(downloaded_part_file_path, final_save_path)
|
os.rename(downloaded_part_file_path, final_save_path)
|
||||||
@@ -691,7 +720,6 @@ class PostProcessorWorker:
|
|||||||
else:
|
else:
|
||||||
return 0, 1, filename_to_save_in_main_path, was_original_name_kept_flag, FILE_DOWNLOAD_STATUS_FAILED_RETRYABLE_LATER, details_for_failure
|
return 0, 1, filename_to_save_in_main_path, was_original_name_kept_flag, FILE_DOWNLOAD_STATUS_FAILED_RETRYABLE_LATER, details_for_failure
|
||||||
|
|
||||||
|
|
||||||
def process(self):
|
def process(self):
|
||||||
|
|
||||||
result_tuple = (0, 0, [], [], [], None, None)
|
result_tuple = (0, 0, [], [], [], None, None)
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ from PyQt5.QtWidgets import (
|
|||||||
QScrollArea, QListWidgetItem, QSizePolicy, QProgressBar, QAbstractItemView, QFrame,
|
QScrollArea, QListWidgetItem, QSizePolicy, QProgressBar, QAbstractItemView, QFrame,
|
||||||
QMainWindow, QAction, QGridLayout,
|
QMainWindow, QAction, QGridLayout,
|
||||||
)
|
)
|
||||||
|
try:
|
||||||
|
from PIL import Image
|
||||||
|
except ImportError:
|
||||||
|
Image = None
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QObject, QTimer, QSettings, QStandardPaths, QUrl, QSize, QProcess, QMutex, QMutexLocker, QCoreApplication
|
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QObject, QTimer, QSettings, QStandardPaths, QUrl, QSize, QProcess, QMutex, QMutexLocker, QCoreApplication
|
||||||
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
|
||||||
from ..core.workers import DownloadThread as BackendDownloadThread
|
from ..core.workers import DownloadThread as BackendDownloadThread
|
||||||
|
|||||||
Reference in New Issue
Block a user