diff --git a/README.md b/README.md index 2e40bdf..fe05605 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,14 @@ - **gif.py** - Create an animated gif that plays once. +### Template examples + +- **templates/create.py** - + Save an edit as a re-usable template with placeholders. + +- **templates/render.py** - + Render a template using merge fields to replace placeholders. + ### Polling example - **status.py** - @@ -57,12 +65,15 @@ - **serve-api/destination.py** - Shows how to exclude a render from being sent to the Shotstack hosting destination. +- **mux.py** - + Sends a rendered video to Mux hosting and excludes it from Shotstack. Requires a Mux account. + ### Installation Install the required dependencies including the [Shotstack Python SDK](https://www.npmjs.com/package/shotstack-sdk) ```bash -pip3 install -r requirements.tx +pip install -r requirements.txt ``` ### Set your API key diff --git a/examples/gif.py b/examples/gif.py index 2a36c7f..ae49326 100644 --- a/examples/gif.py +++ b/examples/gif.py @@ -33,23 +33,23 @@ "https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-752036.jpeg" ] - clips = [] - start = 0.0 + clips = [] + start = 0.0 length = 1.5 soundtrack = Soundtrack( - src = "https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/music/gangsta.mp3", - effect = "fadeInFadeOut" + src = "https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/music/gangsta.mp3", + effect = "fadeInFadeOut" ) for image in images: imageAsset = ImageAsset(src = image) - clip = Clip( - asset = imageAsset, - start = start, - length = length, - effect = "zoomIn" + clip = Clip( + asset = imageAsset, + start = start, + length = length, + effect = "zoomIn" ) start = start + length @@ -60,19 +60,19 @@ timeline = Timeline( background = "#000000", soundtrack = soundtrack, - tracks = [track] + tracks = [track] ) output = Output( - format = "gif", - resolution = "preview", - fps = 12.0, - repeat = False + format = "gif", + resolution = "preview", + fps = 12.0, + repeat = False ) edit = Edit( timeline = timeline, - output = output + output = output ) try: @@ -85,4 +85,4 @@ print(">> Now check the progress of your render by running:") print(f">> python examples/status.py {id}") except Exception as e: - print(f"Unable to resolve API call: {e}") \ No newline at end of file + print(f"Unable to resolve API call: {e}") diff --git a/examples/mux.py b/examples/mux.py new file mode 100644 index 0000000..4a43006 --- /dev/null +++ b/examples/mux.py @@ -0,0 +1,110 @@ +# Mux Demo. +# Ensure Mux credentials are configured in the Shotstack dashboard before running this demo. +# See: https://shotstack.io/docs/guide/serving-assets/destinations/mux + +import shotstack_sdk as shotstack +import os + +from shotstack_sdk.model.soundtrack import Soundtrack +from shotstack_sdk.model.image_asset import ImageAsset +from shotstack_sdk.api import edit_api +from shotstack_sdk.model.clip import Clip +from shotstack_sdk.model.track import Track +from shotstack_sdk.model.timeline import Timeline +from shotstack_sdk.model.output import Output +from shotstack_sdk.model.edit import Edit +from shotstack_sdk.model.mux_destination import MuxDestination +from shotstack_sdk.model.mux_destination_options import MuxDestinationOptions +from shotstack_sdk.model.shotstack_destination import ShotstackDestination + +if __name__ == "__main__": + host = "https://api.shotstack.io/stage" + + if os.getenv("SHOTSTACK_HOST") is not None: + host = os.getenv("SHOTSTACK_HOST") + + configuration = shotstack.Configuration(host = host) + + if os.getenv('SHOTSTACK_KEY') is None: + sys.exit("API Key is required. Set using: export SHOTSTACK_KEY=your_key_here") + + configuration.api_key['DeveloperKey'] = os.getenv('SHOTSTACK_KEY') + + with shotstack.ApiClient(configuration) as api_client: + api_instance = edit_api.EditApi(api_client) + + images = [ + "https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-712850.jpeg", + "https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-867452.jpeg", + "https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-752036.jpeg", + ] + + clips = [] + start = 0.0 + length = 4.0 + + soundtrack = Soundtrack( + src = "https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/music/gangsta.mp3", + effect = "fadeInFadeOut", + volume = 1.0, + ) + + for image in images: + imageAsset = ImageAsset(src = image) + + clip = Clip( + asset = imageAsset, + start = start, + length = length, + effect = "zoomIn" + ) + + start = start + length + clips.append(clip) + + track = Track(clips = clips) + + timeline = Timeline( + background = "#000000", + soundtrack = soundtrack, + tracks = [track] + ) + + # Exclude from Shotstack hosting + shotstack_destination = ShotstackDestination( + exclude = True + ) + + # Send to Mux hosting + mux_destination_options = MuxDestinationOptions( + playback_policy = ["public"] + ) + mux_destination = MuxDestination( + options = mux_destination_options + ) + + output = Output( + format = "mp4", + resolution = "sd", + destinations = [ + shotstack_destination, + mux_destination + ] + ) + + edit = Edit( + timeline = timeline, + output = output + ) + + try: + api_response = api_instance.post_render(edit) + + message = api_response['response']['message'] + id = api_response['response']['id'] + + print(f"{message}\n") + print(">> Now check the progress of your render by running:") + print(f">> python examples/status.py {id}") + except Exception as e: + print(f"Unable to resolve API call: {e}") diff --git a/examples/serve-api/asset_id.py b/examples/serve-api/asset_id.py index f8f91d7..1fb3fa4 100644 --- a/examples/serve-api/asset_id.py +++ b/examples/serve-api/asset_id.py @@ -5,10 +5,10 @@ from shotstack_sdk.api import serve_api if __name__ == "__main__": - host = "https://api.shotstack.io/stage" + host = "https://api.shotstack.io/serve/stage" - if os.getenv("SHOTSTACK_HOST") is not None: - host = os.getenv("SHOTSTACK_HOST") + if os.getenv("SHOTSTACK_SERVE_HOST") is not None: + host = os.getenv("SHOTSTACK_SERVE_HOST") configuration = shotstack.Configuration(host = host) @@ -28,15 +28,13 @@ try: api_response = api_instance.get_asset(id) - status = api_response['response']['status'] + data = api_response['data'] - print(f"Status: {status.upper()}\n") - - if status == "failed": - print(">> Something went wrong, rendering has terminated and will not continue.") + if data['attributes']['status'] == "failed": + print(">> Something went wrong, asset could not be copied.") else: - print(f">> Asset CDN URL: {api_response['response']['attributes']['url']}") - print(f">> Asset ID: {api_response['response']['attributes']['id']}") - print(f">> Render ID: {api_response['response']['attributes']['renderId']}") + print(f">> Asset CDN URL: {data['attributes']['url']}") + print(f">> Asset ID: {data['attributes']['id']}") + print(f">> Render ID: {data['attributes']['render_id']}") except Exception as e: print(f"Unable to resolve API call: {e}") \ No newline at end of file diff --git a/examples/serve-api/render_id.py b/examples/serve-api/render_id.py index d31363d..4ea7749 100644 --- a/examples/serve-api/render_id.py +++ b/examples/serve-api/render_id.py @@ -5,10 +5,10 @@ from shotstack_sdk.api import serve_api if __name__ == "__main__": - host = "https://api.shotstack.io/stage" + host = "https://api.shotstack.io/serve/stage" - if os.getenv("SHOTSTACK_HOST") is not None: - host = os.getenv("SHOTSTACK_HOST") + if os.getenv("SHOTSTACK_SERVE_HOST") is not None: + host = os.getenv("SHOTSTACK_SERVE_HOST") configuration = shotstack.Configuration(host = host) @@ -28,15 +28,12 @@ try: api_response = api_instance.get_asset_by_render_id(id) - status = api_response['response']['status'] - - print(f"Status: {status.upper()}\n") - - if status == "failed": - print(">> Something went wrong, rendering has terminated and will not continue.") - else: - print(f">> Asset CDN URL: {api_response['response']['attributes']['url']}") - print(f">> Asset ID: {api_response['response']['attributes']['id']}") - print(f">> Render ID: {api_response['response']['attributes']['renderId']}") + for asset in api_response['data']: + if asset['attributes']['status'] == "failed": + print(">> Something went wrong, asset could not be copied.") + else: + print(f">> Asset CDN URL: {asset['attributes']['url']}") + print(f">> Asset ID: {asset['attributes']['id']}") + print(f">> Render ID: {asset['attributes']['render_id']}") except Exception as e: print(f"Unable to resolve API call: {e}") \ No newline at end of file diff --git a/examples/status.py b/examples/status.py index efc31f5..57282e5 100644 --- a/examples/status.py +++ b/examples/status.py @@ -23,17 +23,19 @@ id = sys.argv[1] if id is None: - sys.exit(">> Please provide the UUID of the render task (i.e. python examples/status.py 2abd5c11-0f3d-4c6d-ba20-235fc9b8e8b7)\n") + sys.exit(">> Please provide the UUID of the render task (i.e. python examples/status.py 2abd5c11-0f3d-4c6d-ba20-235fc9b8e8b7)\n") + + api_response = api_instance.get_render(id, data=False, merged=True) try: api_response = api_instance.get_render(id, data=False, merged=True) status = api_response['response']['status'] - url = api_response['response']['url'] print('Status: ' + status.upper() + '\n') if status == "done": + url = api_response['response']['url'] print(f">> Asset URL: {url}") elif status == 'failed': print(">> Something went wrong, rendering has terminated and will not continue.") diff --git a/examples/templates/create.py b/examples/templates/create.py new file mode 100644 index 0000000..fd19b72 --- /dev/null +++ b/examples/templates/create.py @@ -0,0 +1,74 @@ +import shotstack_sdk as shotstack +import os +import sys + +from shotstack_sdk.api import edit_api +from shotstack_sdk.model.video_asset import VideoAsset +from shotstack_sdk.model.clip import Clip +from shotstack_sdk.model.track import Track +from shotstack_sdk.model.timeline import Timeline +from shotstack_sdk.model.output import Output +from shotstack_sdk.model.edit import Edit +from shotstack_sdk.model.template import Template + + +if __name__ == '__main__': + host = 'https://api.shotstack.io/stage' + + if os.getenv('SHOTSTACK_HOST') is not None: + host = os.getenv('SHOTSTACK_HOST') + + configuration = shotstack.Configuration(host = host) + + if os.getenv('SHOTSTACK_KEY') is None: + sys.exit('API Key is required. Set using: export SHOTSTACK_KEY=your_key_here') + + configuration.api_key['DeveloperKey'] = os.getenv('SHOTSTACK_KEY') + + with shotstack.ApiClient(configuration) as api_client: + api_instance = edit_api.EditApi(api_client) + + video_asset = VideoAsset( + src = '{{ URL }}', + trim = '{{ TRIM }}' + ) + + video_clip = Clip( + asset = video_asset, + start = 0.0, + length = '{{ LENGTH }}' + ) + + track = Track(clips=[video_clip]) + + timeline = Timeline( + background = '#000000', + tracks = [track] + ) + + output = Output( + format = 'mp4', + resolution = 'sd' + ) + + edit = Edit( + timeline = timeline, + output = output + ) + + template = Template( + name = 'Trim Template', + template = edit + ) + + try: + api_response = api_instance.post_template(template) + + message = api_response['response']['message'] + id = api_response['response']['id'] + + print(f"{message}\n") + print(">> Now render the template using the id:") + print(f">> python examples/templates/render.py {id}") + except Exception as e: + print(f"Unable to resolve API call: {e}") diff --git a/examples/templates/render.py b/examples/templates/render.py new file mode 100644 index 0000000..c13dc5e --- /dev/null +++ b/examples/templates/render.py @@ -0,0 +1,65 @@ +import shotstack_sdk as shotstack +import os +import sys + +from shotstack_sdk.api import edit_api +from shotstack_sdk.model.template_render import TemplateRender +from shotstack_sdk.model.merge_field import MergeField + + +if __name__ == '__main__': + host = 'https://api.shotstack.io/stage' + + if os.getenv('SHOTSTACK_HOST') is not None: + host = os.getenv('SHOTSTACK_HOST') + + configuration = shotstack.Configuration(host = host) + + if os.getenv('SHOTSTACK_KEY') is None: + sys.exit('API Key is required. Set using: export SHOTSTACK_KEY=your_key_here') + + configuration.api_key['DeveloperKey'] = os.getenv('SHOTSTACK_KEY') + + with shotstack.ApiClient(configuration) as api_client: + api_instance = edit_api.EditApi(api_client) + + id = sys.argv[1] + + if id is None: + sys.exit(">> Please provide the UUID of the template (i.e. python examples/templates/render.py 7feabb0e-b5eb-8c5e-847d-82297dd4802a)\n") + + merge_field_url = MergeField( + find = 'URL', + replace = 'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/footage/skater.hd.mp4' + ) + + merge_field_trim = MergeField( + find = 'TRIM', + replace = 3 + ) + + merge_field_length = MergeField( + find = 'LENGTH', + replace = 6 + ) + + template = TemplateRender( + id = id, + merge = [ + merge_field_url, + merge_field_trim, + merge_field_length + ] + ) + + try: + api_response = api_instance.post_template_render(template) + + message = api_response['response']['message'] + id = api_response['response']['id'] + + print(f"{message}\n") + print(">> Now check the progress of your render by running:") + print(f">> python examples/status.py {id}") + except Exception as e: + print(f"Unable to resolve API call: {e}") diff --git a/requirements.txt b/requirements.txt index 2ce141a..44b64b4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -shotstack_sdk==0.0.1 +shotstack_sdk==0.2.8