mirror of
https://github.com/calibrain/shelfmark.git
synced 2026-09-24 22:05:20 +01:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8f21b8f8d |
+6
-18
@@ -144,16 +144,9 @@ def _download_book_with_cancellation(book_id: str, cancel_flag: Event) -> Option
|
||||
if cancel_flag.is_set():
|
||||
logger.info(f"Download cancelled before book manager call: {book_id}")
|
||||
return None
|
||||
|
||||
# Update progress periodically during download
|
||||
progress_thread = threading.Thread(
|
||||
target=_update_download_progress,
|
||||
args=(book_id, cancel_flag),
|
||||
daemon=True
|
||||
)
|
||||
progress_thread.start()
|
||||
|
||||
success = book_manager.download_book(book_info, book_path)
|
||||
|
||||
progress_callback = lambda progress: update_download_progress(book_id, progress)
|
||||
success = book_manager.download_book(book_info, book_path, progress_callback, cancel_flag)
|
||||
|
||||
# Stop progress updates
|
||||
cancel_flag.wait(0.1) # Brief pause for progress thread cleanup
|
||||
@@ -209,14 +202,9 @@ def _download_book_with_cancellation(book_id: str, cancel_flag: Event) -> Option
|
||||
logger.error_trace(f"Error downloading book: {e}")
|
||||
return None
|
||||
|
||||
def _update_download_progress(book_id: str, cancel_flag: Event) -> None:
|
||||
"""Update download progress periodically."""
|
||||
progress = 0.0
|
||||
while not cancel_flag.is_set() and progress < 100.0:
|
||||
# Simulate progress (in real implementation, this would get actual progress)
|
||||
progress = min(100.0, progress + 10.0)
|
||||
book_queue.update_progress(book_id, progress)
|
||||
time.sleep(DOWNLOAD_PROGRESS_UPDATE_INTERVAL)
|
||||
def update_download_progress(book_id: str, progress: float) -> None:
|
||||
"""Update download progress."""
|
||||
book_queue.update_progress(book_id, progress)
|
||||
|
||||
def cancel_download(book_id: str) -> bool:
|
||||
"""Cancel a download.
|
||||
|
||||
+13
-9
@@ -3,7 +3,8 @@
|
||||
import time, json, re
|
||||
from pathlib import Path
|
||||
from urllib.parse import quote
|
||||
from typing import List, Optional, Dict, Union
|
||||
from typing import List, Optional, Dict, Union, Callable
|
||||
from threading import Event
|
||||
from bs4 import BeautifulSoup, Tag, NavigableString, ResultSet
|
||||
|
||||
import downloader
|
||||
@@ -11,10 +12,10 @@ from logger import setup_logger
|
||||
from config import SUPPORTED_FORMATS, BOOK_LANGUAGE, AA_BASE_URL
|
||||
from env import AA_DONATOR_KEY, USE_CF_BYPASS, PRIORITIZE_WELIB
|
||||
from models import BookInfo, SearchFilters
|
||||
|
||||
logger = setup_logger(__name__)
|
||||
|
||||
|
||||
|
||||
def search_books(query: str, filters: SearchFilters) -> List[BookInfo]:
|
||||
"""Search for books matching the query.
|
||||
|
||||
@@ -198,7 +199,7 @@ def _parse_book_info_page(soup: BeautifulSoup, book_id: str) -> BookInfo:
|
||||
):
|
||||
libgen_url = url["href"]
|
||||
# TODO : Temporary fix ? Maybe get URLs from https://open-slum.org/ ?
|
||||
libgen_url = libgen_url = re.sub(r'libgen\.(\w+)', 'libgen.gs', url["href"])
|
||||
libgen_url = libgen_url = re.sub(r'libgen\.(\w+)', 'libgen.la', url["href"])
|
||||
external_urls_libgen.add(libgen_url)
|
||||
elif url.text.strip().lower().startswith("z-lib"):
|
||||
if ".onion/" not in url["href"]:
|
||||
@@ -300,7 +301,7 @@ def _extract_book_metadata(
|
||||
}
|
||||
|
||||
|
||||
def download_book(book_info: BookInfo, book_path: Path) -> bool:
|
||||
def download_book(book_info: BookInfo, book_path: Path, progress_callback: Optional[Callable[[float], None]] = None, cancel_flag: Optional[Event] = None) -> bool:
|
||||
"""Download a book from available sources.
|
||||
|
||||
Args:
|
||||
@@ -324,10 +325,11 @@ def download_book(book_info: BookInfo, book_path: Path) -> bool:
|
||||
|
||||
for link in download_links:
|
||||
try:
|
||||
download_url = _get_download_url(link, book_info.title)
|
||||
download_url = _get_download_url(link, book_info.title, cancel_flag)
|
||||
if download_url != "":
|
||||
logger.info(f"Downloading `{book_info.title}` from `{download_url}`")
|
||||
data = downloader.download_url(download_url, book_info.size or "")
|
||||
|
||||
data = downloader.download_url(download_url, book_info.size or "", progress_callback, cancel_flag)
|
||||
if not data:
|
||||
raise Exception("No data received")
|
||||
|
||||
@@ -344,7 +346,7 @@ def download_book(book_info: BookInfo, book_path: Path) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _get_download_url(link: str, title: str) -> str:
|
||||
def _get_download_url(link: str, title: str, cancel_flag: Optional[Event] = None) -> str:
|
||||
"""Extract actual download URL from various source pages."""
|
||||
|
||||
url = ""
|
||||
@@ -371,8 +373,10 @@ def _get_download_url(link: str, title: str) -> str:
|
||||
if countdown:
|
||||
sleep_time = int(countdown[0].text)
|
||||
logger.info(f"Waiting {sleep_time}s for {title}")
|
||||
time.sleep(sleep_time)
|
||||
url = _get_download_url(link, title)
|
||||
if cancel_flag is not None and cancel_flag.wait(timeout=sleep_time):
|
||||
logger.info(f"Cancelled wait for {title}")
|
||||
return ""
|
||||
url = _get_download_url(link, title, cancel_flag)
|
||||
else:
|
||||
url = download_links[0]["href"]
|
||||
else:
|
||||
|
||||
@@ -80,7 +80,6 @@ def _is_bypassed(sb) -> bool:
|
||||
"please wait",
|
||||
"ddos protection",
|
||||
"security check",
|
||||
"browser check",
|
||||
"moment please",
|
||||
"hold on",
|
||||
"loading",
|
||||
|
||||
+8
-2
@@ -8,7 +8,8 @@ from io import BytesIO
|
||||
from typing import Optional
|
||||
from urllib.parse import urlparse
|
||||
from tqdm import tqdm
|
||||
|
||||
from typing import Callable
|
||||
from threading import Event
|
||||
from logger import setup_logger
|
||||
from config import PROXIES
|
||||
from env import MAX_RETRY, DEFAULT_SLEEP, USE_CF_BYPASS
|
||||
@@ -71,7 +72,7 @@ def html_get_page(url: str, retry: int = MAX_RETRY, use_bypasser: bool = False)
|
||||
time.sleep(sleep_time)
|
||||
return html_get_page(url, retry - 1, use_bypasser)
|
||||
|
||||
def download_url(link: str, size: str = "") -> Optional[BytesIO]:
|
||||
def download_url(link: str, size: str = "", progress_callback: Optional[Callable[[float], None]] = None, cancel_flag: Optional[Event] = None) -> Optional[BytesIO]:
|
||||
"""Download content from URL into a BytesIO buffer.
|
||||
|
||||
Args:
|
||||
@@ -99,6 +100,11 @@ def download_url(link: str, size: str = "") -> Optional[BytesIO]:
|
||||
for chunk in response.iter_content(chunk_size=1000):
|
||||
buffer.write(chunk)
|
||||
pbar.update(len(chunk))
|
||||
if progress_callback is not None:
|
||||
progress_callback(pbar.n * 100.0 / total_size)
|
||||
if cancel_flag is not None and cancel_flag.is_set():
|
||||
logger.info(f"Download cancelled: {link}")
|
||||
return None
|
||||
|
||||
pbar.close()
|
||||
if buffer.tell() * 0.1 < total_size * 0.9:
|
||||
|
||||
Reference in New Issue
Block a user