Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions cloudglue/client/resources/data_connectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,17 +131,40 @@ def sync_file(self, connector_id: str, url: str):
"""Sync a file from a connected data source into Cloudglue.

Imports the file at the given connector URI, returning the resulting
Cloudglue file (creating it if it does not already exist).
Cloudglue file (creating it if it does not already exist). Idempotent:
syncing the same URI returns the existing file.

Besides the connector URIs emitted by `list_files()` (`s3://`,
`gs://`, `gdrive://file/<id>`, `dropbox://<path>`, `zoom://`,
`grain://recording/<id>`, ...), the server resolves these share links
via the connector's OAuth:
- Google Drive share links (`drive.google.com/file/d/<id>`,
`/open?id=<id>`)
- Dropbox file share links (`dropbox.com/scl/fi/...`, `/s/...` —
works for login-gated files; folder links return 400)
- Zoom links (`https://*.zoom.us/{j|s|recording/detail|rec/share}`).
`rec/share` links resolve best-effort: Zoom often mints a new
share token each time a link is copied, so fresh links may 404 —
the reliable form is the recording-detail link
(`zoom.us/recording/detail?meeting_id=<uuid>`).

Plain http(s), TikTok, and Loom URLs are not connector-syncable —
ingest those via `files.sync_from_url` instead. YouTube URLs can only
be added to a collection (`collections.add_media`).

Args:
connector_id: The ID of the data connector.
url: Connector URI to sync. Must match the connector's type.
url: Connector URI or supported share link to sync. Must match
the connector's type.

Returns:
File object.

Raises:
CloudglueError: If there is an error syncing the file.
CloudglueError: If there is an error syncing the file (e.g. 400
for folder links or type mismatches, 403 for inaccessible
share links, 404 if not found at the source, 429 if the
external service rate-limited the request).
"""
try:
request = SyncDataConnectorFileRequest(url=url)
Expand Down
82 changes: 82 additions & 0 deletions cloudglue/client/resources/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from cloudglue.sdk.models.frame_extraction_uniform_config import FrameExtractionUniformConfig
from cloudglue.sdk.models.frame_extraction_thumbnails_config import FrameExtractionThumbnailsConfig
from cloudglue.sdk.models.create_file_frame_extraction_request import CreateFileFrameExtractionRequest
from cloudglue.sdk.models.sync_file_from_url_request import SyncFileFromUrlRequest
from cloudglue.sdk.rest import ApiException

from cloudglue.client.resources.base import CloudglueError
Expand Down Expand Up @@ -263,6 +264,87 @@ def upload(
except Exception as e:
raise CloudglueError(str(e))

def sync_from_url(
self,
url: str,
metadata: Optional[Dict[str, Any]] = None,
enable_segment_thumbnails: Optional[bool] = None,
wait_until_finish: bool = False,
poll_interval: int = 5,
timeout: int = 600,
):
"""Materialize a publicly accessible URL into a Cloudglue file.

Syncs the media at the given URL without requiring a data connector or
a collection. Idempotent: syncing the same URL returns the existing
file.

Accepted URL forms:
- Direct http(s) video/audio file URLs (e.g. `.mp4`)
- Public Dropbox share links (`dropbox.com/scl/fi/...`, `/s/...`)
- TikTok video URLs (consumes scrape credits)
- Loom share URLs (`https://www.loom.com/share/<id>`)

Not supported here: YouTube URLs (collection-only — use
`collections.add_media`) and connector-native URLs (`s3://`, `gs://`,
`gdrive://`, Zoom/Grain links, ... — use `data_connectors.sync_file`).

Args:
url: Publicly accessible URL to sync.
metadata: Optional user-provided metadata about the file. Ignored
if the URL was already synced (the existing file is returned
unchanged).
enable_segment_thumbnails: Whether to generate per-segment
thumbnails for the file. Defaults to True server-side,
matching file upload.
wait_until_finish: Whether to wait for the file processing to complete.
poll_interval: How often to check the file status (in seconds) if waiting.
timeout: Maximum time to wait for processing (in seconds) if waiting.

Returns:
The synced file object. If wait_until_finish is True, waits for
processing to complete and returns the final file state.

Raises:
CloudglueError: If there is an error syncing or processing the file.
"""
try:
request_kwargs: Dict[str, Any] = {"url": url}
if metadata is not None:
request_kwargs["metadata"] = metadata
if enable_segment_thumbnails is not None:
request_kwargs["enable_segment_thumbnails"] = enable_segment_thumbnails
request = SyncFileFromUrlRequest(**request_kwargs)

response = self.api.sync_file_from_url(sync_file_from_url_request=request)

# If not waiting for completion, return immediately
if not wait_until_finish:
return response

# Otherwise poll until completion or timeout
file_id = response.id
elapsed = 0
terminal_states = ["ready", "completed", "failed", "not_applicable"]

while elapsed < timeout:
status = self.get(file_id=file_id)

if status.status in terminal_states:
return status

time.sleep(poll_interval)
elapsed += poll_interval

raise TimeoutError(
f"File processing did not complete within {timeout} seconds"
)

except ApiException as e:
raise CloudglueError(str(e), e.status, e.data, e.headers, e.reason)
except Exception as e:
raise CloudglueError(str(e))

def list(
self,
status: Optional[str] = None,
Expand Down
4 changes: 3 additions & 1 deletion cloudglue/sdk/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion cloudglue/sdk/__init__.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cloudglue/sdk/api/chat_api.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cloudglue/sdk/api/collections_api.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 10 additions & 4 deletions cloudglue/sdk/api/data_connectors_api.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cloudglue/sdk/api/deep_search_api.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cloudglue/sdk/api/describe_api.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cloudglue/sdk/api/extract_api.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cloudglue/sdk/api/face_detection_api.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cloudglue/sdk/api/face_match_api.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cloudglue/sdk/api/file_segments_api.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading