"""Platform Adapter Base Class Provides an abstract base class for platform-specific content adapters. Each platform (Bilibili, Zhihu, etc.) should implement a concrete adapter that handles metadata extraction and content fetching. Purpose: Define a unified interface for multi-platform content extraction """ from abc import ABC, abstractmethod from typing import Dict, Any class PlatformAdapter(ABC): """Abstract base class for platform-specific content adapters A platform adapter encapsulates the logic for: - Identifying content type from URL (video, article, answer, etc.) - Fetching metadata for a given content ID - Fetching content body in Markdown format - Generating output filenames Subclasses must implement all abstract methods to provide platform-specific functionality. Example: class BilibiliAdapter(PlatformAdapter): def get_content_type(self, url: str) -> str: if '/video/' in url: return 'video' elif '/read/' in url: return 'article' return 'unknown' async def fetch_metadata(self, content_id: str, content_type: str) -> Dict[str, Any]: # Platform-specific implementation ... """ @abstractmethod def get_content_type(self, url: str) -> str: """Identify content type from URL Args: url: The content URL to analyze Returns: Content type string (e.g., "video", "article", "answer", "zhuanlan") Example: adapter.get_content_type("https://www.bilibili.com/video/BV1xx...") -> "video" """ pass @abstractmethod async def fetch_metadata(self, content_id: str, content_type: str) -> Dict[str, Any]: """Fetch metadata for the given content Args: content_id: Platform-specific content identifier (e.g., BV号, CV号) content_type: Type of content ("video", "article", etc.) Returns: Dictionary containing metadata fields. Structure varies by platform and content type, but typically includes: - title: Content title - author: Author name - url: Original content URL - Platform-specific fields Raises: NetworkError: If network request fails AuthError: If authentication fails or quota exceeded """ pass @abstractmethod async def fetch_content(self, content_id: str, content_type: str) -> str: """Fetch content body in Markdown format Args: content_id: Platform-specific content identifier content_type: Type of content Returns: Markdown-formatted content string with YAML frontmatter: --- title: Article Title author: Author Name source_url: https://... platform: bilibili content_type: article fetched_at: 2024-01-15T10:30:00 --- # Article Content... Note: For video content, this may return an empty string or placeholder text, as video content extraction is handled separately (e.g., ASR transcription). """ pass @abstractmethod def get_output_filename(self, content_id: str, content_type: str, suffix: str) -> str: """Generate output filename for content Args: content_id: Platform-specific content identifier content_type: Type of content suffix: Filename suffix (e.g., "metadata.json", "content.md") Returns: Filename string without directory path Example: adapter.get_output_filename("BV1xx...", "video", "metadata.json") -> "bilibili_BV1xx..._metadata.json" """ pass