Initial commit: Add webtoon downloader
This commit is contained in:
0
converter/__init__.py
Normal file
0
converter/__init__.py
Normal file
BIN
converter/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
converter/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
converter/__pycache__/converter.cpython-312.pyc
Normal file
BIN
converter/__pycache__/converter.cpython-312.pyc
Normal file
Binary file not shown.
BIN
converter/__pycache__/delete_declaration_img.cpython-312.pyc
Normal file
BIN
converter/__pycache__/delete_declaration_img.cpython-312.pyc
Normal file
Binary file not shown.
178
converter/converter.py
Normal file
178
converter/converter.py
Normal file
@@ -0,0 +1,178 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
from PIL import Image
|
||||
from data.path_constant import ANDROID_ASSETS, DOWNLOAD_DIR, NETWORK_DIR
|
||||
|
||||
class WebtoonConverter:
|
||||
def __init__(self, webtoon_path: Path):
|
||||
self.webtoon_path = webtoon_path
|
||||
self.webtoon_path_network = NETWORK_DIR / webtoon_path.name
|
||||
self.img_extensions = {'.png', '.jpg', '.jpeg', '.webp'}
|
||||
|
||||
def do_convert(self):
|
||||
if self.webtoon_path.is_dir() and self.has_new_episode():
|
||||
print(self.webtoon_path)
|
||||
self.copy_information()
|
||||
for item_path in self.webtoon_path.iterdir():
|
||||
if item_path.is_dir():
|
||||
episode_path = item_path
|
||||
if self.is_new_episode(episode_path):
|
||||
print(f"new episode: {episode_path}")
|
||||
self.delete_over_width_image(episode_path)
|
||||
self.concat_images(episode_path)
|
||||
elif item_path.suffix.lower() in self.img_extensions:
|
||||
thumbnail_path = item_path
|
||||
self.copy_thumbnail(thumbnail_path)
|
||||
|
||||
|
||||
def has_new_episode(self) -> bool:
|
||||
self.webtoon_path_network.mkdir(parents=True, exist_ok=True)
|
||||
return self._count_episodes(self.webtoon_path) > self._count_episodes(self.webtoon_path_network)
|
||||
|
||||
def _count_episodes(self, path: Path):
|
||||
episodes = [d for d in path.iterdir() if d.is_dir()]
|
||||
return len(episodes)
|
||||
|
||||
def copy_information(self):
|
||||
info_path_local = self.webtoon_path / 'information.json'
|
||||
info_path_network = self.webtoon_path_network / 'information.json'
|
||||
|
||||
self.updateTag(info_path_local)
|
||||
|
||||
copy_necessary = True
|
||||
if info_path_network.exists():
|
||||
with open(info_path_local, "r", encoding='utf-8') as json_file:
|
||||
local_information = json.load(json_file)
|
||||
with open(info_path_network, "r", encoding='utf-8') as json_file:
|
||||
network_information = json.load(json_file)
|
||||
|
||||
if (
|
||||
local_information["title"] == network_information["title"] and
|
||||
local_information["author"] == network_information["author"] and
|
||||
local_information["tag"] == network_information["tag"] and
|
||||
local_information["description"] == network_information["description"] and
|
||||
local_information["thumbnail_name"] == network_information["thumbnail_name"]
|
||||
):
|
||||
copy_necessary = False
|
||||
|
||||
if (copy_necessary):
|
||||
try:
|
||||
shutil.copyfile(info_path_local, info_path_network)
|
||||
print(f"File '{info_path_local}' copied to '{info_path_network}'.")
|
||||
except FileNotFoundError:
|
||||
print(f"Source file '{info_path_local}' not found.")
|
||||
|
||||
def updateTag(self, path: Path):
|
||||
update_necessary = False
|
||||
if path.exists():
|
||||
with open(path, "r", encoding='utf-8') as json_file:
|
||||
existing_information = json.load(json_file)
|
||||
tag = existing_information["tag"]
|
||||
print(tag)
|
||||
if '冒險' in tag and tag != '冒險':
|
||||
tag = '冒險'
|
||||
update_necessary = True
|
||||
elif '愛情' in tag and tag != '愛情':
|
||||
tag = '愛情'
|
||||
update_necessary = True
|
||||
elif 'BL' in tag and tag != 'BL':
|
||||
tag = 'BL'
|
||||
update_necessary = True
|
||||
elif '武俠' in tag:
|
||||
tag = '冒險'
|
||||
update_necessary = True
|
||||
elif '大人系' in tag:
|
||||
tag = '愛情'
|
||||
update_necessary = True
|
||||
elif '驚悚' in tag:
|
||||
tag = '劇情'
|
||||
update_necessary = True
|
||||
elif '奇幻' in tag:
|
||||
tag = '劇情'
|
||||
update_necessary = True
|
||||
elif '宮廷' in tag:
|
||||
tag = '劇情'
|
||||
update_necessary = True
|
||||
elif '懸疑' in tag:
|
||||
tag = '劇情'
|
||||
update_necessary = True
|
||||
|
||||
if update_necessary:
|
||||
information = {
|
||||
"title": existing_information["title"],
|
||||
"author": existing_information["author"],
|
||||
"tag": tag,
|
||||
"description": existing_information["description"],
|
||||
"thumbnail_name": existing_information["thumbnail_name"]
|
||||
}
|
||||
|
||||
with open(path, 'w', encoding='utf-8') as json_file:
|
||||
json.dump(information, json_file, ensure_ascii=False, indent=2)
|
||||
print(f"{path} is saved.")
|
||||
|
||||
def copy_thumbnail(self, thumbnail_path: Path):
|
||||
assets_path = ANDROID_ASSETS / thumbnail_path.name
|
||||
if (not assets_path.exists()):
|
||||
try:
|
||||
shutil.copyfile(thumbnail_path, assets_path)
|
||||
print(f"File '{thumbnail_path}' copied to '{assets_path}'.")
|
||||
except FileNotFoundError:
|
||||
print(f"Source file '{thumbnail_path}' not found.")
|
||||
|
||||
def delete_over_width_image(self, episode_path: Path):
|
||||
for img_path in episode_path.iterdir():
|
||||
if self._is_image_800(img_path):
|
||||
img_path.unlink()
|
||||
print(f"delete {img_path}")
|
||||
|
||||
def _is_image_800(self, image_path: Path) -> bool:
|
||||
try:
|
||||
with Image.open(image_path) as img:
|
||||
return img.width >= 800
|
||||
except Exception as e:
|
||||
print(f"Error opening image {image_path}: {e}")
|
||||
return False
|
||||
|
||||
def is_new_episode(self, episode_path: Path) -> bool:
|
||||
episode_path_network = self.webtoon_path_network / episode_path.name
|
||||
return not episode_path_network.exists()
|
||||
|
||||
|
||||
def concat_images(self, episode_path: Path):
|
||||
episode_path_network = self.webtoon_path_network / episode_path.name
|
||||
episode_path_network.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
result_images = []
|
||||
total_height = 0
|
||||
result_index = 1
|
||||
|
||||
for img_path in episode_path.iterdir():
|
||||
if img_path.suffix.lower() in self.img_extensions:
|
||||
|
||||
with open(img_path, 'rb') as img_file:
|
||||
img = Image.open(img_file)
|
||||
img.load()
|
||||
if total_height + img.height > 28800:
|
||||
self.save_concatenated_image(result_images, episode_path_network, result_index)
|
||||
result_index += 1
|
||||
result_images = []
|
||||
total_height = 0
|
||||
|
||||
result_images.append(img)
|
||||
total_height += img.height
|
||||
if result_images:
|
||||
self.save_concatenated_image(result_images, episode_path_network, result_index)
|
||||
|
||||
def save_concatenated_image(self, images: list, output_episode_path: Path, index: int):
|
||||
img_width = images[0].width # Assuming all images have the same width
|
||||
total_height = sum(img.height for img in images)
|
||||
result_image = Image.new('RGB', (img_width, total_height))
|
||||
y_offset = 0
|
||||
for img in images:
|
||||
result_image.paste(img, (0, y_offset))
|
||||
y_offset += img.height
|
||||
|
||||
output_file = output_episode_path / f"{index}.jpg"
|
||||
print(f"saving '{output_file}'")
|
||||
result_image.save(output_file)
|
||||
Reference in New Issue
Block a user