PlanOpticon

1
"""Base interface for cloud source integrations."""
2
3
import logging
4
from abc import ABC, abstractmethod
5
from pathlib import Path
6
from typing import List, Optional
7
8
from pydantic import BaseModel, Field
9
10
logger = logging.getLogger(__name__)
11
12
13
class SourceFile(BaseModel):
14
"""A file available in a cloud source."""
15
16
name: str = Field(description="File name")
17
id: str = Field(description="Provider-specific file identifier")
18
size_bytes: Optional[int] = Field(default=None, description="File size in bytes")
19
mime_type: Optional[str] = Field(default=None, description="MIME type")
20
modified_at: Optional[str] = Field(default=None, description="Last modified timestamp")
21
path: Optional[str] = Field(default=None, description="Path within the source folder")
22
23
24
class BaseSource(ABC):
25
"""Abstract base class for cloud source integrations."""
26
27
@abstractmethod
28
def authenticate(self) -> bool:
29
"""Authenticate with the cloud provider. Returns True on success."""
30
...
31
32
@abstractmethod
33
def list_videos(
34
self,
35
folder_id: Optional[str] = None,
36
folder_path: Optional[str] = None,
37
patterns: Optional[List[str]] = None,
38
) -> List[SourceFile]:
39
"""List video files in a folder."""
40
...
41
42
@abstractmethod
43
def download(
44
self,
45
file: SourceFile,
46
destination: Path,
47
) -> Path:
48
"""Download a file to a local path. Returns the local path."""
49
...
50
51
def download_all(
52
self,
53
files: List[SourceFile],
54
destination_dir: Path,
55
) -> List[Path]:
56
"""Download multiple files to a directory, preserving subfolder structure."""
57
destination_dir.mkdir(parents=True, exist_ok=True)
58
paths = []
59
for f in files:
60
# Use path (with subfolder) if available, otherwise just name
61
relative = f.path if f.path else f.name
62
dest = destination_dir / relative
63
try:
64
local_path = self.download(f, dest)
65
paths.append(local_path)
66
logger.info(f"Downloaded: {relative}")
67
except Exception as e:
68
logger.error(f"Failed to download {relative}: {e}")
69
return paths
70

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button