Python API for accessing and downloading content from JMComic with Cloudflare bypass and plugin system.
—
Multi-client architecture with web scraping and mobile API clients, automatic domain switching, retry mechanisms, and Cloudflare bypass capabilities. Provides robust access to JMComic content through multiple access methods.
from typing import Dict, Any, List, Optional, Union, Callable, IteratorCore client implementations providing different access methods to JMComic content.
class AbstractJmClient:
"""
Base client with retry logic, domain switching, and common functionality.
Attributes:
- domains: List[str] - List of available domains
- current_domain: str - Currently active domain
- retry_count: int - Number of retry attempts
- timeout: int - Request timeout in seconds
- headers: Dict[str, str] - HTTP headers for requests
Methods:
- switch_domain(): Switch to next available domain
- retry_request(func, *args, **kwargs): Retry request with domain switching
- get_current_url(path): Build URL with current domain
"""
class JmHtmlClient(AbstractJmClient):
"""
Web scraping client for HTML pages with Cloudflare bypass.
Provides access to JMComic through web scraping with automatic
Cloudflare anti-bot bypass mechanisms and HTML parsing.
Methods:
- get_album_detail(album_id): Get album details from web page
- get_photo_detail(photo_id): Get photo details from web page
- search_album(keyword, page=1): Search for albums
- get_category_page(category_id, page=1): Browse category pages
- login(username, password): Login with credentials
- get_favorites(page=1): Get user favorites
"""
def get_album_detail(self, album_id: Union[str, int]) -> 'JmAlbumDetail':
"""
Get album details by scraping the web page.
Parameters:
- album_id: str or int - Album ID
Returns:
JmAlbumDetail - Album with metadata and episode list
"""
def get_photo_detail(self, photo_id: Union[str, int]) -> 'JmPhotoDetail':
"""
Get photo details by scraping the web page.
Parameters:
- photo_id: str or int - Photo ID
Returns:
JmPhotoDetail - Photo with metadata and image list
"""
def search_album(self, keyword: str, page: int = 1) -> 'JmSearchPage':
"""
Search for albums using web interface.
Parameters:
- keyword: str - Search keyword
- page: int - Page number (default: 1)
Returns:
JmSearchPage - Search results with albums and pagination
"""
class JmApiClient(AbstractJmClient):
"""
Mobile API client with encryption/decryption support.
Provides access to JMComic mobile API with built-in encryption
handling and API response decoding.
Methods:
- get_album_detail(album_id): Get album via mobile API
- get_photo_detail(photo_id): Get photo via mobile API
- search_album(keyword, page=1): Search via mobile API
- login_api(username, password): API login
- get_favorites_api(page=1): Get favorites via API
"""
def get_album_detail(self, album_id: Union[str, int]) -> 'JmAlbumDetail':
"""
Get album details via mobile API.
Parameters:
- album_id: str or int - Album ID
Returns:
JmAlbumDetail - Album from API response
"""
def get_photo_detail(self, photo_id: Union[str, int]) -> 'JmPhotoDetail':
"""
Get photo details via mobile API.
Parameters:
- photo_id: str or int - Photo ID
Returns:
JmPhotoDetail - Photo from API response
"""
class PhotoConcurrentFetcherProxy:
"""
Concurrent photo fetching proxy for improved performance.
Wraps client instances to provide concurrent fetching of multiple
photos with thread pooling and error handling.
Attributes:
- client: JmcomicClient - Underlying client instance
- max_workers: int - Maximum concurrent workers
Methods:
- fetch_photos(photo_ids): Fetch multiple photos concurrently
- fetch_photos_from_album(album): Fetch all photos in album concurrently
"""
def __init__(self, client: 'JmcomicClient', max_workers: int = 4):
"""
Initialize concurrent fetcher proxy.
Parameters:
- client: JmcomicClient - Client to wrap
- max_workers: int - Maximum concurrent workers
"""
def fetch_photos(self, photo_ids: List[Union[str, int]]) -> List['JmPhotoDetail']:
"""
Fetch multiple photos concurrently.
Parameters:
- photo_ids: list - List of photo IDs
Returns:
List[JmPhotoDetail] - List of fetched photos
"""
def fetch_photos_from_album(self, album: 'JmAlbumDetail') -> List['JmPhotoDetail']:
"""
Fetch all photos from an album concurrently.
Parameters:
- album: JmAlbumDetail - Album containing photos to fetch
Returns:
List[JmPhotoDetail] - List of fetched photos
"""Interface definitions that combine multiple client capabilities into unified APIs.
class JmDetailClient:
"""
Interface for album and photo detail fetching operations.
Methods:
- get_album_detail(album_id): Get detailed album information
- get_photo_detail(photo_id): Get detailed photo information
"""
class JmUserClient:
"""
Interface for user operations including login and favorites.
Methods:
- login(username, password): User authentication
- get_favorites(page=1): Get user's favorite albums
- add_favorite(album_id): Add album to favorites
- remove_favorite(album_id): Remove album from favorites
"""
class JmImageClient:
"""
Interface for image downloading and processing operations.
Methods:
- download_image(image_detail): Download individual image
- get_image_bytes(image_url): Get image data as bytes
- process_image(image_data): Process/decrypt image data
"""
class JmSearchAlbumClient:
"""
Interface for search functionality and filtering.
Methods:
- search_album(keyword, page=1): Search for albums
- search_by_tag(tag, page=1): Search albums by tag
- search_by_author(author, page=1): Search albums by author
"""
class JmCategoryClient:
"""
Interface for category browsing and navigation.
Methods:
- get_category_page(category_id, page=1): Browse category
- get_categories(): Get available categories
- get_popular_albums(page=1): Get popular albums
"""
class JmcomicClient(JmDetailClient, JmUserClient, JmImageClient,
JmSearchAlbumClient, JmCategoryClient):
"""
Main client interface combining all capabilities.
Provides unified access to all JMComic functionality through
a single interface that combines all specialized client interfaces.
"""Classes that wrap and process HTTP responses from different client types.
class JmResp:
"""
Base HTTP response wrapper with error handling.
Attributes:
- status_code: int - HTTP status code
- content: bytes - Response content
- text: str - Response text
- headers: Dict[str, str] - Response headers
- url: str - Request URL
Methods:
- json(): Parse response as JSON
- raise_for_status(): Raise exception for HTTP errors
- is_success(): Check if response is successful
"""
def json(self) -> Dict[str, Any]:
"""
Parse response content as JSON.
Returns:
dict - Parsed JSON data
Raises:
JsonResolveFailException - If JSON parsing fails
"""
def raise_for_status(self):
"""
Raise exception for HTTP error status codes.
Raises:
ResponseUnexpectedException - For HTTP errors
"""
class JmImageResp(JmResp):
"""
Image response with transfer and processing capabilities.
Additional Methods:
- save_to_file(filepath): Save image to file
- get_image_data(): Get processed image data
- decrypt_if_needed(): Decrypt scrambled images
"""
def save_to_file(self, filepath: str) -> bool:
"""
Save image response to file.
Parameters:
- filepath: str - Target file path
Returns:
bool - True if save successful
"""
def get_image_data(self) -> bytes:
"""
Get processed image data (decrypted if needed).
Returns:
bytes - Image data ready for use
"""
class JmJsonResp(JmResp):
"""
JSON response parser and validator.
Additional Methods:
- validate_structure(): Validate JSON structure
- extract_data(path): Extract data using JSONPath
"""
class JmApiResp(JmResp):
"""
Encrypted API response decoder for mobile API.
Additional Methods:
- decrypt_response(): Decrypt encrypted API response
- parse_api_data(): Parse decrypted API data
"""
class JmAlbumCommentResp(JmResp):
"""
Album comment submission response handler.
Additional Methods:
- get_comment_id(): Get submitted comment ID
- is_comment_accepted(): Check if comment was accepted
"""Usage examples:
# Create and use HTML client
html_client = JmHtmlClient()
album = html_client.get_album_detail("123456")
search_results = html_client.search_album("keyword")
# Create and use API client
api_client = JmApiClient()
album = api_client.get_album_detail("123456")
# Use concurrent fetcher
concurrent_fetcher = PhotoConcurrentFetcherProxy(html_client, max_workers=8)
photos = concurrent_fetcher.fetch_photos(["456789", "012345", "678901"])
# Handle responses
try:
response = html_client.get_raw_response("/some/path")
response.raise_for_status()
data = response.json()
except ResponseUnexpectedException as e:
print(f"HTTP error: {e}")
except JsonResolveFailException as e:
print(f"JSON parsing error: {e}")
# Process image response
image_response = html_client.download_image_response(image_detail)
image_response.decrypt_if_needed()
image_response.save_to_file("image.jpg")The client system automatically selects the best client based on configuration and availability:
# Configure client preferences in JmOption
option = JmOption.default()
option.client['preferred_client'] = 'html' # or 'api'
option.client['fallback_enabled'] = True
option.client['retry_count'] = 3
# Client will automatically switch between HTML and API clients
# based on availability and success rates
downloader = JmDownloader(option)
album = downloader.download_album("123456")All clients implement comprehensive error handling:
Install with Tessl CLI
npx tessl i tessl/pypi-jmcomic