MediaSource类下新增Metadata字段,用来附带缓存状态为ready时视频的元数据
This commit is contained in:
parent
008626e0df
commit
ec455ed3e9
|
|
@ -11,11 +11,13 @@ from pydantic import (BaseModel, Field, field_validator, ValidationError,
|
|||
from pydantic.json_schema import JsonSchemaValue
|
||||
from ..config import WorkerConfig
|
||||
from ..utils.TimeUtils import TimeDelta
|
||||
from ..utils.VideoUtils import VideoMetadata
|
||||
|
||||
config = WorkerConfig()
|
||||
|
||||
s3_region = config.S3_region
|
||||
s3_bucket_name = config.S3_bucket_name
|
||||
s3_mount_point = config.S3_mount_dir
|
||||
|
||||
|
||||
class MediaProtocol(str, Enum):
|
||||
|
|
@ -45,6 +47,8 @@ class MediaSource(BaseModel):
|
|||
expired_at: Optional[datetime] = Field(description="缓存过期时间点, 为None时不会过期(过期处理WIP)", default=None)
|
||||
downloader_id: Optional[str] = Field(description="正在处理下载的Downloader ID", default=None)
|
||||
progress: int = Field(description="缓存进度", default=0)
|
||||
metadata: Optional[VideoMetadata] = Field(description="媒体元数据", default=None)
|
||||
content_length: Optional[int] = Field(description="媒体文件大小", default=None)
|
||||
|
||||
@classmethod
|
||||
def from_str(cls, media_url: str) -> 'MediaSource':
|
||||
|
|
@ -148,6 +152,18 @@ class MediaSource(BaseModel):
|
|||
def file_extension(self) -> Optional[str]:
|
||||
return os.path.basename(self.urn).split('.')[-1]
|
||||
|
||||
@computed_field(description="是否本地可用")
|
||||
@property
|
||||
def local_available(self) -> bool:
|
||||
if self.status == MediaCacheStatus.ready:
|
||||
return os.path.exists(self.local_mount_path)
|
||||
return False
|
||||
|
||||
@computed_field(description="本地挂载地址")
|
||||
@property
|
||||
def local_mount_path(self) -> str:
|
||||
return f"{s3_mount_point}/{self.cache_filepath}"
|
||||
|
||||
@field_serializer('expired_at')
|
||||
def serialize_datetime(self, value: Optional[datetime], info: SerializationInfo) -> Optional[str]:
|
||||
if value:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ from typing import Optional, List
|
|||
import httpx
|
||||
import modal
|
||||
from loguru import logger
|
||||
from ..models.media_model import MediaSource
|
||||
|
||||
from .VideoUtils import VideoMetadata, VideoUtils
|
||||
from ..models.media_model import MediaSource, MediaProtocol
|
||||
|
||||
cf_account_id = os.environ.get("CF_ACCOUNT_ID")
|
||||
cf_kv_api_token = os.environ.get("CF_KV_API_TOKEN")
|
||||
cf_kv_namespace_id = os.environ.get("CF_KV_NAMESPACE_ID")
|
||||
|
|
@ -20,9 +23,22 @@ class KVCache:
|
|||
cache_json = self.kv.get(urn)
|
||||
if not cache_json:
|
||||
return None
|
||||
return MediaSource.model_validate_json(cache_json)
|
||||
media = MediaSource.model_validate_json(cache_json)
|
||||
if media.local_available:
|
||||
try:
|
||||
media.metadata = VideoUtils.ffprobe_media_metadata(media.local_mount_path)
|
||||
media.content_length = os.path.getsize(media.local_mount_path)
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
return media
|
||||
|
||||
def set_cache(self, media: MediaSource):
|
||||
if media.local_available:
|
||||
try:
|
||||
media.metadata = VideoUtils.ffprobe_media_metadata(media.local_mount_path)
|
||||
media.content_length = os.path.getsize(media.local_mount_path)
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
cache_json = media.model_dump_json()
|
||||
self.kv.put(media.urn, cache_json)
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ class SentryUtils:
|
|||
logger.info(f"sentry-trace={sentry_trace_id}, baggage={sentry_baggage}")
|
||||
if sentry_trace_id and sentry_baggage:
|
||||
transaction = sentry_sdk.continue_trace(environ_or_headers={"sentry-trace": sentry_trace_id,
|
||||
"baggage": sentry_baggage, })
|
||||
"baggage": sentry_baggage, },
|
||||
op=op,
|
||||
name=name)
|
||||
else:
|
||||
transaction = sentry_sdk.start_transaction(op='modal.function', name='Modal Function直接调用')
|
||||
with transaction:
|
||||
|
|
|
|||
|
|
@ -306,8 +306,7 @@ class VideoUtils:
|
|||
ffmpeg_cmd = VideoUtils.async_ffmpeg_init()
|
||||
ffmpeg_cmd.input(media_path)
|
||||
filter_complex: List[str] = []
|
||||
outputs: List[Tuple[str, VideoMetadata]] = []
|
||||
|
||||
temp_outputs: List[str] = []
|
||||
if not output_path:
|
||||
output_path = FileUtils.file_path_extend(media_path, "slice")
|
||||
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
||||
|
|
@ -341,10 +340,11 @@ class VideoUtils:
|
|||
crf=16,
|
||||
r=30,
|
||||
)
|
||||
video_metadata = VideoUtils.ffprobe_media_metadata(segment_output_path)
|
||||
outputs.append((segment_output_path, video_metadata))
|
||||
temp_outputs.append(segment_output_path)
|
||||
|
||||
await ffmpeg_cmd.execute()
|
||||
outputs: List[Tuple[str, VideoMetadata]] = [(output, VideoUtils.ffprobe_media_metadata(output)) for output in
|
||||
temp_outputs]
|
||||
return outputs
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -369,8 +369,8 @@ class VideoUtils:
|
|||
reconnect_streamed="1",
|
||||
reconnect_delay_max="5")
|
||||
filter_complex: List[str] = []
|
||||
outputs: List[Tuple[str, VideoMetadata]] = []
|
||||
|
||||
temp_outputs: List[str] = []
|
||||
if not output_path:
|
||||
output_path = FileUtils.file_path_extend(media_path, "slice")
|
||||
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
||||
|
|
@ -402,10 +402,10 @@ class VideoUtils:
|
|||
acodec="aac",
|
||||
crf=16,
|
||||
r=30, )
|
||||
video_metadata = VideoUtils.ffprobe_media_metadata(output_filepath)
|
||||
outputs.append((output_filepath, video_metadata))
|
||||
|
||||
temp_outputs.append(output_filepath)
|
||||
await ffmpeg_cmd.execute()
|
||||
outputs: List[Tuple[str, VideoMetadata]] = [(output, VideoUtils.ffprobe_media_metadata(output)) for output in
|
||||
temp_outputs]
|
||||
return outputs
|
||||
|
||||
@staticmethod
|
||||
|
|
|
|||
Loading…
Reference in New Issue