CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-jmcomic

Python API for accessing and downloading content from JMComic with Cloudflare bypass and plugin system.

Pending
Overview
Eval results
Files

client-system.mddocs/

Client 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.

Types

from typing import Dict, Any, List, Optional, Union, Callable, Iterator

Capabilities

Client Implementations

Core 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
        """

Client Interfaces

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.
    """

Response Wrappers

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")

Client Selection and Configuration

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")

Error Handling and Retry Logic

All clients implement comprehensive error handling:

  • Domain Switching: Automatically tries different domains on failure
  • Client Fallback: Falls back from API to HTML client if needed
  • Retry Logic: Configurable retry attempts with exponential backoff
  • Cloudflare Handling: Automatic detection and bypass of anti-bot measures

Install with Tessl CLI

npx tessl i tessl/pypi-jmcomic

docs

client-system.md

command-line-interface.md

configuration-management.md

content-entities.md

core-download-api.md

download-system.md

exception-handling.md

index.md

plugin-system.md

text-data-processing.md

tile.json