Files
AI-Video/pixelle_video/services/publishing/__init__.py

135 lines
3.8 KiB
Python

# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Publishing service for multi-platform video distribution.
Supports:
- Format conversion + export (Douyin/Kuaishou)
- API-based upload (Bilibili/YouTube)
"""
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional, List, Dict, Any
from datetime import datetime
class Platform(Enum):
"""Supported publishing platforms"""
EXPORT = "export" # Format conversion only
DOUYIN = "douyin" # 抖音 (via export or CDP)
KUAISHOU = "kuaishou" # 快手 (via export or CDP)
BILIBILI = "bilibili" # B站 (API)
YOUTUBE = "youtube" # YouTube (API)
class PublishStatus(Enum):
"""Publishing task status"""
PENDING = "pending"
CONVERTING = "converting"
UPLOADING = "uploading"
PROCESSING = "processing"
PUBLISHED = "published"
FAILED = "failed"
@dataclass
class VideoMetadata:
"""Video metadata for publishing"""
title: str
description: str = ""
tags: List[str] = field(default_factory=list)
category: Optional[str] = None
cover_path: Optional[str] = None
privacy: str = "public" # public, private, unlisted
# Platform-specific options
platform_options: Dict[str, Any] = field(default_factory=dict)
@dataclass
class PublishResult:
"""Result of a publishing operation"""
success: bool
platform: Platform
status: PublishStatus
# On success
video_url: Optional[str] = None
platform_video_id: Optional[str] = None
# On failure
error_message: Optional[str] = None
# Export result
export_path: Optional[str] = None
# Timestamps
started_at: Optional[datetime] = None
completed_at: Optional[datetime] = None
@dataclass
class PublishTask:
"""A publishing task for background processing"""
id: str
video_path: str
platform: Platform
metadata: VideoMetadata
status: PublishStatus = PublishStatus.PENDING
result: Optional[PublishResult] = None
created_at: datetime = field(default_factory=datetime.now)
updated_at: Optional[datetime] = None
class Publisher(ABC):
"""Abstract base class for platform publishers"""
platform: Platform
@abstractmethod
async def publish(
self,
video_path: str,
metadata: VideoMetadata,
progress_callback: Optional[callable] = None
) -> PublishResult:
"""
Publish a video to the platform.
Args:
video_path: Path to the video file
metadata: Video metadata (title, description, tags, etc.)
progress_callback: Optional callback for progress updates
Returns:
PublishResult with success/failure details
"""
pass
@abstractmethod
async def validate_credentials(self) -> bool:
"""Check if platform credentials are valid"""
pass
def get_platform_requirements(self) -> Dict[str, Any]:
"""Get platform-specific requirements (dimensions, file size, etc.)"""
return {
"max_file_size_mb": 128,
"max_duration_seconds": 900, # 15 minutes
"supported_formats": ["mp4", "webm"],
"recommended_resolution": (1080, 1920), # Portrait 9:16
"recommended_codec": "h264",
}