Last active
February 11, 2026 18:12
-
-
Save cynthia2006/0c6e0e72786ba6a6e5aa655c50ac3eb3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # /// script | |
| # requires-python = ">=3.14" | |
| # dependencies = [ | |
| # "aiofiles>=25.1.0", | |
| # "httpx[http2]>=0.28.1", | |
| # ] | |
| # /// | |
| import asyncio | |
| import sys | |
| from pathlib import PurePath | |
| from signal import SIGINT | |
| import aiofiles | |
| import httpx | |
| MAX_QUEUE_SIZE = 60 | |
| MAX_WORKERS = 10 | |
| stop_now = asyncio.Event() | |
| async def download(client: httpx.AsyncClient, queue: asyncio.Queue): | |
| while True: | |
| if stop_now.is_set(): | |
| break | |
| url, path = await queue.get() | |
| async with ( | |
| aiofiles.open(path, 'wb') as output, | |
| client.stream('GET', url) as r | |
| ): | |
| if r.status_code != 200: | |
| print(f"{url} not found on Pixiv, ignoring", file=sys.stderr) | |
| if size := r.headers.get('Content-Length'): | |
| await output.truncate(int(size)) | |
| async for chunk in r.aiter_bytes(): | |
| await output.write(chunk) | |
| if size: | |
| print(f"Downloaded {url} -> {path}; content-length {size}") | |
| else: | |
| print(f"Downloaded {url} -> {path}; content-length unknown") | |
| async def main(): | |
| loop = asyncio.get_event_loop() | |
| loop.add_signal_handler(SIGINT, lambda: stop_now.set()) | |
| async with ( | |
| httpx.AsyncClient(http2=True, timeout=None) as client, | |
| ): | |
| queue = asyncio.Queue(MAX_QUEUE_SIZE) | |
| tasks = set() | |
| # Shielding is required to prevent premature writes. | |
| for _ in range(MAX_WORKERS): | |
| tasks.add(asyncio.shield(download(client, queue))) | |
| while True: | |
| if stop_now.is_set(): | |
| break | |
| r = await client.get('https://api.lolicon.app/setu/v2?num=20') | |
| if r.status_code != 200: | |
| print(f"Lolicon API returned {r.status_code}", file=sys.stderr) | |
| continue | |
| data = r.json()['data'] | |
| for entry in data: | |
| url = httpx.URL(entry['urls']['original']) | |
| filename = PurePath(url.path).name | |
| await queue.put((url, filename)) | |
| await asyncio.sleep(5) | |
| await asyncio.gather(*tasks) | |
| if __name__ == '__main__': | |
| asyncio.run(main()) | |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
All it takes to run is