|
import requests |
|
from bs4 import BeautifulSoup |
|
from concurrent.futures import ThreadPoolExecutor, as_completed |
|
import re |
|
import pypub |
|
import os |
|
import time |
|
import gradio as gr |
|
|
|
|
|
def parse_story_url(story_url): |
|
|
|
match = re.search(r"https://truyenfull\.tv/([^/]+)(?:-f\d+)?\.(\d+)/", story_url) |
|
if match: |
|
story_name = match.group(1) |
|
story_id = match.group(3) |
|
api_url = f"https://truyenfull.tv/api/chapters/{story_id}/" |
|
base_url = f"https://truyenfull.tv/{story_name}/chuong-" |
|
return story_name, story_id, api_url, base_url |
|
else: |
|
raise ValueError("URL không hợp lệ") |
|
|
|
|
|
def get_chapter_info(api_url): |
|
response = requests.get(api_url) |
|
response.raise_for_status() |
|
data = response.json() |
|
return data.get('items', []) |
|
|
|
|
|
def get_chapter_content(chapter_index, base_url): |
|
chapter_url = base_url + str(chapter_index) + ".html" |
|
try: |
|
response = requests.get(chapter_url) |
|
response.raise_for_status() |
|
soup = BeautifulSoup(response.content, 'html.parser') |
|
content_div = soup.find('div', id='chapter-c', class_='chapter-c') |
|
return content_div.get_text(separator='\n').strip() if content_div else "Không tìm thấy nội dung chương." |
|
except Exception as e: |
|
print(f"Lỗi khi lấy nội dung chương {chapter_index}: {e}") |
|
return "Không thể lấy nội dung." |
|
|
|
|
|
def get_all_chapters_content(story_url, start_chapter, max_chapters): |
|
story_name, story_id, api_url, base_url = parse_story_url(story_url) |
|
|
|
chapters = get_chapter_info(api_url) |
|
if not chapters: |
|
return "Không tìm thấy chương nào." |
|
|
|
|
|
chapters_to_load = chapters[start_chapter - 1:start_chapter - 1 + max_chapters] |
|
chapter_contents = [] |
|
total_time = 0 |
|
|
|
|
|
with ThreadPoolExecutor(max_workers=10) as executor: |
|
future_to_chapter = {executor.submit(get_chapter_content, idx + 1, base_url): idx + 1 for idx in range(len(chapters_to_load))} |
|
for future in as_completed(future_to_chapter): |
|
chapter_index = future_to_chapter[future] |
|
start_time = time.time() |
|
try: |
|
content = future.result() |
|
|
|
chapter_contents.append((chapter_index, content, chapters[chapter_index - 1]['chapter_name'])) |
|
print(f"Đã lưu chương {chapter_index}") |
|
except Exception as e: |
|
print(f"Lỗi khi lấy nội dung chương {chapter_index}: {e}") |
|
end_time = time.time() |
|
chapter_time = end_time - start_time |
|
total_time += chapter_time |
|
print(f"Thời gian tải chương {chapter_index}: {chapter_time:.2f} giây") |
|
|
|
|
|
avg_time_per_chapter = total_time / max_chapters if max_chapters > 0 else 0 |
|
print(f"Tổng thời gian tải {max_chapters} chương: {total_time:.2f} giây") |
|
print(f"Thời gian trung bình cho mỗi chương: {avg_time_per_chapter:.2f} giây") |
|
|
|
|
|
chapter_contents.sort(key=lambda x: x[0]) |
|
output_file = f"{story_name}.txt" |
|
with open(output_file, 'w', encoding='utf-8') as f: |
|
for chapter_index, content, chapter_title in chapter_contents: |
|
chapter_name = f"{chapter_title}" |
|
f.write(f"{chapter_name}\n\n") |
|
f.write(f"{content}\n") |
|
f.write("-" * 50 + "\n") |
|
|
|
|
|
epubfile=create_epub_from_chapters(chapter_contents, story_name) |
|
|
|
|
|
return [f"Đã tải thành công {max_chapters} chương. Tổng thời gian: {total_time:.2f} giây, Thời gian trung bình: {avg_time_per_chapter:.2f} giây. File TXT: {output_file}",epubfile] |
|
|
|
|
|
def create_epub_from_chapters(chapter_contents, story_name): |
|
try: |
|
|
|
my_epub = pypub.Epub(story_name) |
|
|
|
|
|
for chapter_index, content, chapter_title in chapter_contents: |
|
|
|
my_chapter = pypub.create_chapter_from_text(content, chapter_title) |
|
my_epub.add_chapter(my_chapter) |
|
|
|
|
|
output_directory = f"./{story_name}.epub" |
|
epubfile=my_epub.create(output_directory) |
|
print(f"Đã tạo file EPUB: {output_directory}") |
|
|
|
except Exception as e: |
|
print(f"Lỗi khi tạo file EPUB: {e}") |
|
return epubfile |
|
|
|
def gradio_interface(story_url, start_chapter, max_chapters): |
|
|
|
start_total_time = time.time() |
|
|
|
|
|
result = get_all_chapters_content(story_url, int(start_chapter), int(max_chapters)) |
|
|
|
|
|
end_total_time = time.time() |
|
|
|
|
|
total_process_time = end_total_time - start_total_time |
|
result += f"\nTổng thời gian hoàn thành tất cả các chức năng: {total_process_time:.2f} giây" |
|
return result |
|
|
|
|
|
gr.Interface( |
|
fn=gradio_interface, |
|
inputs=[ |
|
gr.Textbox(label="URL Truyện", placeholder="Nhập URL của truyện từ truyenfull.tv"), |
|
gr.Textbox(label="Số chương bắt đầu", placeholder="Nhập số chương bắt đầu"), |
|
gr.Textbox(label="Số chương muốn tải", placeholder="Nhập số chương muốn tải") |
|
], |
|
outputs=["text","file"], |
|
title="Truyện Full Downloader", |
|
description="Công cụ tải truyện từ truyenfull.tv và tạo file EPUB." |
|
).launch() |
|
|