$ cat node-template.py

Drive Video Reader

// Reads a video file from Drive and outputs it as a Video file.

Input
Storage
template.py
1import os2import sys3import json4import traceback5import requests67EMBLEMA_API_BASE_URL = os.getenv("EMBLEMA_API_BASE_URL")8USER_TOKEN = os.getenv("USER_TOKEN")9OUTPUT_DIR = "/data/output"1011if not EMBLEMA_API_BASE_URL:12    raise ValueError("EMBLEMA_API_BASE_URL environment variable not set")131415def api_request_json(method, path, **kwargs):16    """Make authenticated API request and return JSON response."""17    if not USER_TOKEN:18        raise ValueError("USER_TOKEN environment variable not set")1920    headers = {21        "Authorization": f"Bearer {USER_TOKEN}",22    }23    url = f"{EMBLEMA_API_BASE_URL}{path}"24    response = requests.request(method, url, headers=headers, **kwargs)25    response.raise_for_status()26    if not response.content:27        raise ValueError(f"API returned empty response body for {method} {path} (status {response.status_code})")28    try:29        return response.json()30    except json.JSONDecodeError:31        raise ValueError(32            f"API returned non-JSON response for {method} {path} "33            f"(status {response.status_code}, content-type: {response.headers.get('content-type', 'unknown')}, "34            f"body: {response.text[:200]})"35        )363738def fetch_video(drive_item_id_input) -> str:39    """Fetch a video file from Drive and save it to the output directory.4041    Args:42        drive_item_id_input: Single Drive Item ID (string). Arrays are rejected.4344    Returns:45        The output filename saved to /data/output/46    """47    # Normalize input — reject arrays, this is a single-video reader48    if isinstance(drive_item_id_input, list):49        if len(drive_item_id_input) == 1:50            drive_item_id = drive_item_id_input[0]51        else:52            raise ValueError(53                f"Drive Video Reader accepts a single video file, got {len(drive_item_id_input)} items. "54                "Use one Drive Video Reader per video file."55            )56    elif isinstance(drive_item_id_input, str):57        drive_item_id = drive_item_id_input58    else:59        raise ValueError(f"driveItemId must be a string, got {type(drive_item_id_input).__name__}")6061    if not drive_item_id:62        raise ValueError("No valid Drive Item ID provided")6364    # Get presigned download URL + metadata65    download_info = api_request_json("GET", f"/api/v2/drive/items/{drive_item_id}/download")6667    presigned_url = download_info.get("url")68    file_name = download_info.get("name", "video.mp4")69    mime_type = download_info.get("mimeType", "")7071    if not presigned_url:72        raise ValueError("Download API did not return a presigned URL")7374    # Validate that the file is a video file75    if mime_type and not mime_type.startswith("video/"):76        raise ValueError(77            f"Selected Drive item is not a video file (mimeType: {mime_type}). "78            "Please select a video file."79        )8081    # Download the video binary from presigned URL82    video_response = requests.get(presigned_url, timeout=120)83    video_response.raise_for_status()8485    # Save to output directory86    os.makedirs(OUTPUT_DIR, exist_ok=True)87    out_path = os.path.join(OUTPUT_DIR, file_name)88    with open(out_path, "wb") as f:89        f.write(video_response.content)9091    return file_name929394def main():95    """Main execution function"""96    try:97        input_json = sys.stdin.read().strip()98        if not input_json:99            raise ValueError("No input data received via stdin — executor did not pipe input correctly")100        execution_input = json.loads(input_json)101102        inputs = execution_input.get("inputs", {})103        drive_item_id = inputs.get("driveItemId")104105        if not drive_item_id:106            raise ValueError("Required input 'driveItemId' not provided")107108        filename = fetch_video(drive_item_id)109110        output = {111            "video": filename,112        }113114        print(json.dumps(output, indent=2))115116    except requests.HTTPError as e:117        error_output = {118            "error": f"API request failed: {e}",119            "errorType": "HTTPError",120            "status": e.response.status_code,121            "detail": e.response.text,122        }123        print(json.dumps(error_output), file=sys.stderr)124        sys.exit(1)125    except Exception as e:126        error_output = {127            "error": str(e),128            "errorType": type(e).__name__,129            "traceback": traceback.format_exc(),130        }131        print(json.dumps(error_output), file=sys.stderr)132        sys.exit(1)133134135if __name__ == "__main__":136    main()