diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 10be3471846..d1c7b49c8be 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -103,6 +103,7 @@ /retail/**/* @GoogleCloudPlatform/cloud-retail-team @GoogleCloudPlatform/python-samples-reviewers /billing/**/* @GoogleCloudPlatform/billing-samples-maintainers @GoogleCloudPlatform/python-samples-reviewers /iot/**/* @GoogleCloudPlatform/api-iot @GoogleCloudPlatform/python-samples-reviewers +/video/stitcher/* @GoogleCloudPlatform/cloud-media-team @GoogleCloudPlatform/python-samples-reviewers # Does not have owner /blog/**/* @GoogleCloudPlatform/python-samples-reviewers diff --git a/.github/blunderbuss.yml b/.github/blunderbuss.yml index 94bd237f9f9..23bca271ca5 100644 --- a/.github/blunderbuss.yml +++ b/.github/blunderbuss.yml @@ -304,6 +304,7 @@ assign_prs_by: - GoogleCloudPlatform/cloud-retail-team - labels: - "api: cloudmedia" + - "api: videostitcher" to: - GoogleCloudPlatform/cloud-media-team diff --git a/video/stitcher/cdn_key_test.py b/video/stitcher/cdn_key_test.py new file mode 100644 index 00000000000..24ad85fa0f8 --- /dev/null +++ b/video/stitcher/cdn_key_test.py @@ -0,0 +1,174 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import uuid + +from google.protobuf import timestamp_pb2 +import pytest + +import create_cdn_key +import create_cdn_key_akamai +import delete_cdn_key +import get_cdn_key +import list_cdn_keys +import update_cdn_key +import update_cdn_key_akamai +import utils + +location = "us-central1" +project_id = os.environ["GOOGLE_CLOUD_PROJECT"] +now = timestamp_pb2.Timestamp() +now.GetCurrentTime() + +media_cdn_key_id = f"python-test-media-key-{uuid.uuid4().hex[:5]}-{now.seconds}" +cloud_cdn_key_id = f"python-test-cloud-key-{uuid.uuid4().hex[:5]}-{now.seconds}" +akamai_cdn_key_id = f"python-test-akamai-key-{uuid.uuid4().hex[:5]}-{now.seconds}" + +hostname = "cdn.example.com" +updated_hostname = "updated.example.com" +key_name = "my-key" + +media_cdn_private_key = "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNA" +updated_media_cdn_private_key = ( + "ZZZzNDU2Nzg5MDEyMzQ1Njc4OTAxzg5MDEyMzQ1Njc4OTAxMjM0NTY3DkwMTIZZZ" +) +cloud_cdn_private_key = "VGhpcyBpcyBhIHRlc3Qgc3RyaW5nLg==" +updated_cloud_cdn_private_key = "VGhpcyBpcyBhbiB1cGRhdGVkIHRlc3Qgc3RyaW5nLg==" +akamai_key = cloud_cdn_private_key +updated_akamai_key = updated_cloud_cdn_private_key + + +def test_cdn_key_operations(capsys: pytest.fixture) -> None: + + utils.delete_stale_cdn_keys(project_id, location) + + # Media CDN key tests + + create_cdn_key.create_cdn_key( + project_id, + location, + media_cdn_key_id, + hostname, + key_name, + media_cdn_private_key, + False, + ) + out, _ = capsys.readouterr() + assert media_cdn_key_id in out + + list_cdn_keys.list_cdn_keys(project_id, location) + out, _ = capsys.readouterr() + assert media_cdn_key_id in out + + # Update the hostname and private key; the private key value + # is not returned by the client + response = update_cdn_key.update_cdn_key( + project_id, + location, + media_cdn_key_id, + updated_hostname, + key_name, + updated_media_cdn_private_key, + False, + ) + out, _ = capsys.readouterr() + assert media_cdn_key_id in out + assert updated_hostname in response.hostname + + get_cdn_key.get_cdn_key(project_id, location, media_cdn_key_id) + out, _ = capsys.readouterr() + assert media_cdn_key_id in out + + delete_cdn_key.delete_cdn_key(project_id, location, media_cdn_key_id) + out, _ = capsys.readouterr() + assert "Deleted CDN key" in out + + # Cloud CDN key tests + + create_cdn_key.create_cdn_key( + project_id, + location, + cloud_cdn_key_id, + hostname, + key_name, + cloud_cdn_private_key, + True, + ) + out, _ = capsys.readouterr() + assert cloud_cdn_key_id in out + + list_cdn_keys.list_cdn_keys(project_id, location) + out, _ = capsys.readouterr() + assert cloud_cdn_key_id in out + + # Update the hostname and private key; the private key value + # is not returned by the client + response = update_cdn_key.update_cdn_key( + project_id, + location, + cloud_cdn_key_id, + updated_hostname, + key_name, + updated_cloud_cdn_private_key, + True, + ) + out, _ = capsys.readouterr() + assert cloud_cdn_key_id in out + assert updated_hostname in response.hostname + + get_cdn_key.get_cdn_key(project_id, location, cloud_cdn_key_id) + out, _ = capsys.readouterr() + assert cloud_cdn_key_id in out + + delete_cdn_key.delete_cdn_key(project_id, location, cloud_cdn_key_id) + out, _ = capsys.readouterr() + assert "Deleted CDN key" in out + + # Akamai CDN key tests + + create_cdn_key_akamai.create_cdn_key_akamai( + project_id, + location, + akamai_cdn_key_id, + hostname, + akamai_key, + ) + out, _ = capsys.readouterr() + assert akamai_cdn_key_id in out + + list_cdn_keys.list_cdn_keys(project_id, location) + out, _ = capsys.readouterr() + assert akamai_cdn_key_id in out + + # Update the hostname and private key; the private key value + # is not returned by the client + response = update_cdn_key_akamai.update_cdn_key_akamai( + project_id, + location, + akamai_cdn_key_id, + updated_hostname, + updated_akamai_key, + ) + out, _ = capsys.readouterr() + assert akamai_cdn_key_id in out + assert updated_hostname in response.hostname + + get_cdn_key.get_cdn_key(project_id, location, akamai_cdn_key_id) + out, _ = capsys.readouterr() + assert akamai_cdn_key_id in out + + delete_cdn_key.delete_cdn_key(project_id, location, akamai_cdn_key_id) + out, _ = capsys.readouterr() + assert "Deleted CDN key" in out diff --git a/video/stitcher/create_cdn_key.py b/video/stitcher/create_cdn_key.py new file mode 100644 index 00000000000..ec941cb35db --- /dev/null +++ b/video/stitcher/create_cdn_key.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for creating a Media CDN key +or a Cloud CDN key. A CDN key is used to retrieve protected media. +Example usage: + python create_cdn_key.py --project_id --location \ + --cdn_key_id --hostname \ + --key_name --private_key [--is_cloud_cdn] +""" + +# [START videostitcher_create_cdn_key] + +import argparse + +from google.cloud.video import stitcher_v1 +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def create_cdn_key( + project_id: str, + location: str, + cdn_key_id: str, + hostname: str, + key_name: str, + private_key: str, + is_cloud_cdn: bool, +) -> str: + """Creates a Cloud CDN or Media CDN key. + Args: + project_id: The GCP project ID. + location: The location in which to create the CDN key. + cdn_key_id: The user-defined CDN key ID. + hostname: The hostname to which this CDN key applies. + key_name: For a Media CDN key, this is the keyset name. + For a Cloud CDN key, this is the public name of the CDN key. + private_key: For a Media CDN key, this is a 64-byte Ed25519 private + key encoded as a base64-encoded string. + See https://cloud.google.com/video-stitcher/docs/how-to/managing-cdn-keys#create-private-key-media-cdn + for more information. For a Cloud CDN key, this is a base64-encoded string secret. + is_cloud_cdn: If true, create a Cloud CDN key. If false, create a Media CDN key.""" + + client = VideoStitcherServiceClient() + + parent = f"projects/{project_id}/locations/{location}" + + cdn_key = stitcher_v1.types.CdnKey( + name=cdn_key_id, + hostname=hostname, + ) + + if is_cloud_cdn: + cdn_key.google_cdn_key = stitcher_v1.types.GoogleCdnKey( + key_name=key_name, + private_key=private_key, + ) + else: + cdn_key.media_cdn_key = stitcher_v1.types.MediaCdnKey( + key_name=key_name, + private_key=private_key, + ) + + operation = client.create_cdn_key( + parent=parent, cdn_key_id=cdn_key_id, cdn_key=cdn_key + ) + response = operation.result() + print(f"CDN key: {response.name}") + return response + + +# [END videostitcher_create_cdn_key] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location in which to create the CDN key.", + default="us-central1", + ) + parser.add_argument( + "--cdn_key_id", + help="The user-defined CDN key ID.", + required=True, + ) + parser.add_argument( + "--hostname", + help="The hostname to which this CDN key applies.", + required=True, + ) + parser.add_argument( + "--key_name", + help="For a Media CDN key, this is the keyset name. For a Cloud CDN" + + " key, this is the public name of the CDN key.", + required=True, + ) + parser.add_argument( + "--private_key", + help="For a Media CDN key, this is a 64-byte Ed25519 private key" + + "encoded as a base64-encoded string. See" + + " https://cloud.google.com/video-stitcher/docs/how-to/managing-cdn-keys#create-private-key-media-cdn" + + " for more information. For a Cloud CDN key, this is a" + + " base64-encoded string secret.", + required=True, + ) + parser.add_argument( + "--is_cloud_cdn", + action="store_true", + help="If included, create a Cloud CDN key. If absent, create a Media CDN key.", + ) + args = parser.parse_args() + create_cdn_key( + args.project_id, + args.location, + args.cdn_key_id, + args.hostname, + args.key_name, + args.private_key, + args.is_cloud_cdn, + ) diff --git a/video/stitcher/create_cdn_key_akamai.py b/video/stitcher/create_cdn_key_akamai.py new file mode 100644 index 00000000000..a947cd214a7 --- /dev/null +++ b/video/stitcher/create_cdn_key_akamai.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for creating an Akamai CDN key. A CDN key is used +to retrieve protected media. +Example usage: + python create_cdn_key_akamai.py --project_id --location --cdn_key_id \ + --hostname --akamai_token_key +""" + +# [START videostitcher_create_cdn_key_akamai] + +import argparse + +from google.cloud.video import stitcher_v1 +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def create_cdn_key_akamai( + project_id: str, + location: str, + cdn_key_id: str, + hostname: str, + akamai_token_key: str, +) -> str: + """Creates an Akamai CDN key. + Args: + project_id: The GCP project ID. + location: The location in which to create the CDN key. + cdn_key_id: The user-defined CDN key ID. + hostname: The hostname to which this CDN key applies. + akamai_token_key: A base64-encoded string token key.""" + + client = VideoStitcherServiceClient() + + parent = f"projects/{project_id}/locations/{location}" + + cdn_key = stitcher_v1.types.CdnKey( + name=cdn_key_id, + hostname=hostname, + akamai_cdn_key=stitcher_v1.types.AkamaiCdnKey( + token_key=akamai_token_key, + ), + ) + + operation = client.create_cdn_key( + parent=parent, cdn_key_id=cdn_key_id, cdn_key=cdn_key + ) + response = operation.result() + print(f"CDN key: {response.name}") + return response + + +# [END videostitcher_create_cdn_key_akamai] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location in which to create the CDN key.", + default="us-central1", + ) + parser.add_argument( + "--cdn_key_id", + help="The user-defined CDN key ID.", + required=True, + ) + parser.add_argument( + "--hostname", + help="The hostname to which this CDN key applies.", + required=True, + ) + parser.add_argument( + "--akamai_token_key", + help="The base64-encoded string token key.", + required=True, + ) + args = parser.parse_args() + create_cdn_key_akamai( + args.project_id, + args.location, + args.cdn_key_id, + args.hostname, + args.akamai_token_key, + ) diff --git a/video/stitcher/create_live_config.py b/video/stitcher/create_live_config.py new file mode 100644 index 00000000000..b232402b9cf --- /dev/null +++ b/video/stitcher/create_live_config.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python + +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for creating a live config. Live +configs are used to configure live sessions. +Example usage: + python create_live_config.py --project_id --location \ + --live_config_id --live_stream_uri --ad_tag_uri \ + --slate_id +""" + +# [START videostitcher_create_live_config] + +import argparse + +from google.cloud.video import stitcher_v1 +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def create_live_config( + project_id: str, + location: str, + live_config_id: str, + live_stream_uri: str, + ad_tag_uri: str, + slate_id: str, +) -> str: + """Creates a live config. + Args: + project_id: The GCP project ID. + location: The location in which to create the live config. + live_config_id: The user-defined live config ID. + live_stream_uri: Uri of the livestream to stitch; this URI must reference either an MPEG-DASH + manifest (.mpd) file or an M3U playlist manifest (.m3u8) file. + ad_tag_uri: Uri of the ad tag. + slate_id: The user-defined slate ID of the default slate to use when no slates are specified in an ad break's message.""" + + client = VideoStitcherServiceClient() + + parent = f"projects/{project_id}/locations/{location}" + default_slate = f"projects/{project_id}/locations/{location}/slates/{slate_id}" + + live_config = stitcher_v1.types.LiveConfig( + source_uri=live_stream_uri, + ad_tag_uri=ad_tag_uri, + ad_tracking="SERVER", + default_slate=default_slate, + ) + + operation = client.create_live_config( + parent=parent, live_config_id=live_config_id, live_config=live_config + ) + response = operation.result() + print(f"Live config: {response.name}") + return response + + +# [END videostitcher_create_live_config] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location in which to create the live config.", + default="us-central1", + ) + parser.add_argument( + "--live_config_id", + help="The user-defined live config ID.", + required=True, + ) + parser.add_argument( + "--live_stream_uri", + help="The uri of the livestream to stitch (.mpd or .m3u8 file) in double quotes.", + required=True, + ) + parser.add_argument( + "--ad_tag_uri", + help="Uri of the ad tag in double quotes.", + required=True, + ) + parser.add_argument( + "--slate_id", + help="The user-defined slate ID of the default slate.", + required=True, + ) + args = parser.parse_args() + create_live_config( + args.project_id, + args.location, + args.live_config_id, + args.live_stream_uri, + args.ad_tag_uri, + args.slate_id, + ) diff --git a/video/stitcher/create_live_session.py b/video/stitcher/create_live_session.py new file mode 100644 index 00000000000..d22e8953e00 --- /dev/null +++ b/video/stitcher/create_live_session.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for creating a live stream session in +which to insert ads. +Example usage: + python create_live_session.py --project_id \ + --location --live_config_id +""" + +# [START videostitcher_create_live_session] + +import argparse + +from google.cloud.video import stitcher_v1 +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def create_live_session(project_id: str, location: str, live_config_id: str) -> str: + """Creates a live session. Live sessions are ephemeral resources that expire + after a few minutes. + Args: + project_id: The GCP project ID. + location: The location in which to create the session. + live_config_id: The user-defined live config ID.""" + + client = VideoStitcherServiceClient() + + parent = f"projects/{project_id}/locations/{location}" + live_config = ( + f"projects/{project_id}/locations/{location}/liveConfigs/{live_config_id}" + ) + + live_session = stitcher_v1.types.LiveSession(live_config=live_config) + + response = client.create_live_session(parent=parent, live_session=live_session) + print(f"Live session: {response.name}") + return response + + +# [END videostitcher_create_live_session] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location in which to create the live session.", + default="us-central1", + ) + parser.add_argument( + "--live_config_id", + help="The user-defined live config ID.", + required=True, + ) + args = parser.parse_args() + create_live_session( + args.project_id, + args.location, + args.live_config_id, + ) diff --git a/video/stitcher/create_slate.py b/video/stitcher/create_slate.py new file mode 100644 index 00000000000..98d2252e9e8 --- /dev/null +++ b/video/stitcher/create_slate.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for creating a slate. A slate is displayed +when ads are not available. +Example usage: + python create_slate.py --project_id --location \ + --slate_id --slate_uri +""" + +# [START videostitcher_create_slate] + +import argparse + +from google.cloud.video import stitcher_v1 +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def create_slate(project_id: str, location: str, slate_id: str, slate_uri: str) -> str: + """Creates a slate. + Args: + project_id: The GCP project ID. + location: The location in which to create the slate. + slate_id: The user-defined slate ID. + slate_uri: Uri of the video slate; must be an MP4 video with at least one audio track.""" + + client = VideoStitcherServiceClient() + + parent = f"projects/{project_id}/locations/{location}" + + slate = stitcher_v1.types.Slate( + uri=slate_uri, + ) + + operation = client.create_slate(parent=parent, slate_id=slate_id, slate=slate) + response = operation.result() + print(f"Slate: {response.name}") + return response + + +# [END videostitcher_create_slate] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location in which to create the slate.", + default="us-central1", + ) + parser.add_argument( + "--slate_id", + help="The user-defined slate ID.", + required=True, + ) + parser.add_argument( + "--slate_uri", + help="Uri of the video slate; must be an MP4 video with at least one audio track.", + required=True, + ) + args = parser.parse_args() + create_slate( + args.project_id, + args.location, + args.slate_id, + args.slate_uri, + ) diff --git a/video/stitcher/create_vod_session.py b/video/stitcher/create_vod_session.py new file mode 100644 index 00000000000..f5142035491 --- /dev/null +++ b/video/stitcher/create_vod_session.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for creating a video on demand (VOD) +session in which to insert ads. +Example usage: + python create_vod_session.py --project_id \ + --location --source_uri --ad_tag_uri +""" + +# [START videostitcher_create_vod_session] + +import argparse + +from google.cloud.video import stitcher_v1 +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def create_vod_session( + project_id: str, location: str, source_uri: str, ad_tag_uri: str +) -> str: + """Creates a VOD session. VOD sessions are ephemeral resources that expire + after a few hours. + Args: + project_id: The GCP project ID. + location: The location in which to create the session. + source_uri: Uri of the media to stitch; this URI must reference either an MPEG-DASH + manifest (.mpd) file or an M3U playlist manifest (.m3u8) file. + ad_tag_uri: Uri of the ad tag.""" + + client = VideoStitcherServiceClient() + + parent = f"projects/{project_id}/locations/{location}" + + vod_session = stitcher_v1.types.VodSession( + source_uri=source_uri, ad_tag_uri=ad_tag_uri, ad_tracking="SERVER" + ) + + response = client.create_vod_session(parent=parent, vod_session=vod_session) + print(f"VOD session: {response.name}") + return response + + +# [END videostitcher_create_vod_session] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location in which to create the VOD session.", + default="us-central1", + ) + parser.add_argument( + "--source_uri", + help="The Uri of the media to stitch (.mpd or .m3u8 file) in double quotes.", + required=True, + ) + parser.add_argument( + "--ad_tag_uri", + help="Uri of the ad tag in double quotes.", + required=True, + ) + args = parser.parse_args() + create_vod_session( + args.project_id, + args.location, + args.source_uri, + args.ad_tag_uri, + ) diff --git a/video/stitcher/delete_cdn_key.py b/video/stitcher/delete_cdn_key.py new file mode 100644 index 00000000000..9e944167a08 --- /dev/null +++ b/video/stitcher/delete_cdn_key.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for deleting a CDN key. +Example usage: + python delete_cdn_key.py --project_id --location \ + --cdn_key_id +""" + +# [START videostitcher_delete_cdn_key] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def delete_cdn_key(project_id: str, location: str, cdn_key_id: str) -> str: + """Deletes a CDN key. + Args: + project_id: The GCP project ID. + location: The location of the CDN key. + cdn_key_id: The user-defined CDN key ID.""" + + client = VideoStitcherServiceClient() + + name = f"projects/{project_id}/locations/{location}/cdnKeys/{cdn_key_id}" + operation = client.delete_cdn_key(name=name) + response = operation.result() + print("Deleted CDN key") + return response + + +# [END videostitcher_delete_cdn_key] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location of the CDN key.", + required=True, + ) + parser.add_argument( + "--cdn_key_id", + help="The user-defined CDN key ID.", + required=True, + ) + args = parser.parse_args() + delete_cdn_key( + args.project_id, + args.location, + args.cdn_key_id, + ) diff --git a/video/stitcher/delete_live_config.py b/video/stitcher/delete_live_config.py new file mode 100644 index 00000000000..b6ffa56419e --- /dev/null +++ b/video/stitcher/delete_live_config.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for deleting a live config. +Example usage: + python delete_live_config.py --project_id --location \ + --live_config_id +""" + +# [START videostitcher_delete_live_config] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def delete_live_config(project_id: str, location: str, live_config_id: str) -> str: + """Deletes a live config. + Args: + project_id: The GCP project ID. + location: The location of the live config. + live_config_id: The user-defined live config ID.""" + + client = VideoStitcherServiceClient() + + name = f"projects/{project_id}/locations/{location}/liveConfigs/{live_config_id}" + operation = client.delete_live_config(name=name) + response = operation.result() + print("Deleted live config") + return response + + +# [END videostitcher_delete_live_config] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location of the live config.", + required=True, + ) + parser.add_argument( + "--live_config_id", + help="The user-defined live config ID.", + required=True, + ) + args = parser.parse_args() + delete_live_config( + args.project_id, + args.location, + args.live_config_id, + ) diff --git a/video/stitcher/delete_slate.py b/video/stitcher/delete_slate.py new file mode 100644 index 00000000000..8458e358ec6 --- /dev/null +++ b/video/stitcher/delete_slate.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for deleting a slate. +Example usage: + python delete_slate.py --project_id --location \ + --slate_id +""" + +# [START videostitcher_delete_slate] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def delete_slate(project_id: str, location: str, slate_id: str) -> str: + """Deletes a slate. + Args: + project_id: The GCP project ID. + location: The location of the slate. + slate_id: The user-defined slate ID.""" + + client = VideoStitcherServiceClient() + + name = f"projects/{project_id}/locations/{location}/slates/{slate_id}" + operation = client.delete_slate(name=name) + response = operation.result() + print("Deleted slate") + return response + + +# [END videostitcher_delete_slate] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location of the slate.", + required=True, + ) + parser.add_argument( + "--slate_id", + help="The user-defined slate ID.", + required=True, + ) + args = parser.parse_args() + delete_slate( + args.project_id, + args.location, + args.slate_id, + ) diff --git a/video/stitcher/get_cdn_key.py b/video/stitcher/get_cdn_key.py new file mode 100644 index 00000000000..531ace87c13 --- /dev/null +++ b/video/stitcher/get_cdn_key.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for getting a CDN key. +Example usage: + python get_cdn_key.py --project_id --location \ + --cdn_key_id +""" + +# [START videostitcher_get_cdn_key] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def get_cdn_key(project_id: str, location: str, cdn_key_id: str) -> str: + """Gets a CDN key. + Args: + project_id: The GCP project ID. + location: The location of the CDN key. + cdn_key_id: The user-defined CDN key ID.""" + + client = VideoStitcherServiceClient() + + name = f"projects/{project_id}/locations/{location}/cdnKeys/{cdn_key_id}" + response = client.get_cdn_key(name=name) + print(f"CDN key: {response.name}") + return response + + +# [END videostitcher_get_cdn_key] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location of the CDN key.", + required=True, + ) + parser.add_argument( + "--cdn_key_id", + help="The user-defined CDN key ID.", + required=True, + ) + args = parser.parse_args() + get_cdn_key( + args.project_id, + args.location, + args.cdn_key_id, + ) diff --git a/video/stitcher/get_live_ad_tag_detail.py b/video/stitcher/get_live_ad_tag_detail.py new file mode 100644 index 00000000000..790b233c420 --- /dev/null +++ b/video/stitcher/get_live_ad_tag_detail.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for getting the specified ad tag detail +for a live stream session. +Example usage: + python get_live_ad_tag_detail.py --project_id \ + --location --session_id \ + --ad_tag_details_id +""" + +# [START videostitcher_get_live_ad_tag_detail] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def get_live_ad_tag_detail( + project_id: str, location: str, session_id: str, ad_tag_detail_id: str +) -> str: + """Gets the specified ad tag detail for a live session. + Args: + project_id: The GCP project ID. + location: The location of the session. + session_id: The ID of the live session. + ad_tag_detail_id: The ID of the ad tag details.""" + + client = VideoStitcherServiceClient() + + name = client.live_ad_tag_detail_path( + project_id, location, session_id, ad_tag_detail_id + ) + response = client.get_live_ad_tag_detail(name=name) + print(f"Live ad tag detail: {response.name}") + return response + + +# [END videostitcher_get_live_ad_tag_detail] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", help="The location of the live session.", required=True + ) + parser.add_argument( + "--session_id", help="The ID of the live session.", required=True + ) + parser.add_argument( + "--ad_tag_detail_id", help="The ID of the ad tag details.", required=True + ) + args = parser.parse_args() + get_live_ad_tag_detail( + args.project_id, args.location, args.session_id, args.ad_tag_detail_id + ) diff --git a/video/stitcher/get_live_config.py b/video/stitcher/get_live_config.py new file mode 100644 index 00000000000..74019140483 --- /dev/null +++ b/video/stitcher/get_live_config.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for getting a live config. +Example usage: + python get_live_config.py --project_id --location \ + --live_config_id +""" + +# [START videostitcher_get_live_config] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def get_live_config(project_id: str, location: str, live_config_id: str) -> str: + """Gets a live config. + Args: + project_id: The GCP project ID. + location: The location of the live config. + live_config_id: The user-defined live config ID.""" + + client = VideoStitcherServiceClient() + + name = f"projects/{project_id}/locations/{location}/liveConfigs/{live_config_id}" + response = client.get_live_config(name=name) + print(f"Live config: {response.name}") + return response + + +# [END videostitcher_get_live_config] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location of the live config.", + required=True, + ) + parser.add_argument( + "--live_config_id", + help="The user-defined live config ID.", + required=True, + ) + args = parser.parse_args() + get_live_config( + args.project_id, + args.location, + args.live_config_id, + ) diff --git a/video/stitcher/get_live_session.py b/video/stitcher/get_live_session.py new file mode 100644 index 00000000000..da3d2114d68 --- /dev/null +++ b/video/stitcher/get_live_session.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for getting a live stream session. +Example usage: + python get_live_session.py --project_id --location \ + --session_id +""" + +# [START videostitcher_get_live_session] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def get_live_session(project_id: str, location: str, session_id: str) -> str: + """Gets a live session. Live sessions are ephemeral resources that expire + after a few minutes. + Args: + project_id: The GCP project ID. + location: The location of the session. + session_id: The ID of the live session.""" + + client = VideoStitcherServiceClient() + + name = client.live_session_path(project_id, location, session_id) + response = client.get_live_session(name=name) + print(f"Live session: {response.name}") + return response + + +# [END videostitcher_get_live_session] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", help="The location of the live session.", required=True + ) + parser.add_argument( + "--session_id", help="The ID of the live session.", required=True + ) + args = parser.parse_args() + get_live_session(args.project_id, args.location, args.session_id) diff --git a/video/stitcher/get_slate.py b/video/stitcher/get_slate.py new file mode 100644 index 00000000000..3d3901887fd --- /dev/null +++ b/video/stitcher/get_slate.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for getting a slate. +Example usage: + python get_slate.py --project_id --location \ + --slate_id +""" + +# [START videostitcher_get_slate] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def get_slate(project_id: str, location: str, slate_id: str) -> str: + """Gets a slate. + Args: + project_id: The GCP project ID. + location: The location of the slate. + slate_id: The user-defined slate ID.""" + + client = VideoStitcherServiceClient() + + name = f"projects/{project_id}/locations/{location}/slates/{slate_id}" + response = client.get_slate(name=name) + print(f"Slate: {response.name}") + return response + + +# [END videostitcher_get_slate] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location of the slate.", + required=True, + ) + parser.add_argument( + "--slate_id", + help="The user-defined slate ID.", + required=True, + ) + args = parser.parse_args() + get_slate( + args.project_id, + args.location, + args.slate_id, + ) diff --git a/video/stitcher/get_vod_ad_tag_detail.py b/video/stitcher/get_vod_ad_tag_detail.py new file mode 100644 index 00000000000..cb717842b2e --- /dev/null +++ b/video/stitcher/get_vod_ad_tag_detail.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for getting the specified ad tag detail +for a video on demand (VOD) session. +Example usage: + python get_vod_ad_tag_detail.py --project_id --location --session_id --ad_tag_details_id +""" + +# [START videostitcher_get_vod_ad_tag_detail] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def get_vod_ad_tag_detail( + project_id: str, location: str, session_id: str, ad_tag_detail_id: str +) -> str: + """Gets the specified ad tag detail for a VOD session. + Args: + project_id: The GCP project ID. + location: The location of the session. + session_id: The ID of the VOD session. + ad_tag_detail_id: The ID of the ad tag details.""" + + client = VideoStitcherServiceClient() + + name = client.vod_ad_tag_detail_path( + project_id, location, session_id, ad_tag_detail_id + ) + response = client.get_vod_ad_tag_detail(name=name) + print(f"VOD ad tag detail: {response.name}") + return response + + +# [END videostitcher_get_vod_ad_tag_detail] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", help="The location of the VOD session.", required=True + ) + parser.add_argument( + "--session_id", help="The ID of the VOD session.", required=True + ) + parser.add_argument( + "--ad_tag_detail_id", help="The ID of the ad tag details.", required=True + ) + args = parser.parse_args() + get_vod_ad_tag_detail( + args.project_id, args.location, args.session_id, args.ad_tag_detail_id + ) diff --git a/video/stitcher/get_vod_session.py b/video/stitcher/get_vod_session.py new file mode 100644 index 00000000000..073aeea01b8 --- /dev/null +++ b/video/stitcher/get_vod_session.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for getting a video on demand (VOD) +session. +Example usage: + python get_vod_session.py --project_id --location \ + --session_id +""" + +# [START videostitcher_get_vod_session] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def get_vod_session(project_id: str, location: str, session_id: str) -> str: + """Gets a VOD session. VOD sessions are ephemeral resources that expire + after a few hours. + Args: + project_id: The GCP project ID. + location: The location of the session. + session_id: The ID of the VOD session.""" + + client = VideoStitcherServiceClient() + + name = client.vod_session_path(project_id, location, session_id) + response = client.get_vod_session(name=name) + print(f"VOD session: {response.name}") + return response + + +# [END videostitcher_get_vod_session] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", help="The location of the VOD session.", required=True + ) + parser.add_argument( + "--session_id", help="The ID of the VOD session.", required=True + ) + args = parser.parse_args() + get_vod_session(args.project_id, args.location, args.session_id) diff --git a/video/stitcher/get_vod_stitch_detail.py b/video/stitcher/get_vod_stitch_detail.py new file mode 100644 index 00000000000..2923221b562 --- /dev/null +++ b/video/stitcher/get_vod_stitch_detail.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for getting the specified stitch detail +for a video on demand (VOD) session. +Example usage: + python get_vod_stitch_detail.py --project_id \ + --location --session_id \ + --stitch_details_id +""" + +# [START videostitcher_get_vod_stitch_detail] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def get_vod_stitch_detail( + project_id: str, location: str, session_id: str, stitch_detail_id: str +) -> str: + """Gets the specified stitch detail for a VOD session. + Args: + project_id: The GCP project ID. + location: The location of the session. + session_id: The ID of the VOD session. + stitch_detail_id: The ID of the stitch details.""" + + client = VideoStitcherServiceClient() + + name = client.vod_stitch_detail_path( + project_id, location, session_id, stitch_detail_id + ) + response = client.get_vod_stitch_detail(name=name) + print(f"VOD stitch detail: {response.name}") + return response + + +# [END videostitcher_get_vod_stitch_detail] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", help="The location of the VOD session.", required=True + ) + parser.add_argument( + "--session_id", help="The ID of the VOD session.", required=True + ) + parser.add_argument( + "--stitch_detail_id", help="The ID of the stitch details.", required=True + ) + args = parser.parse_args() + get_vod_stitch_detail( + args.project_id, args.location, args.session_id, args.stitch_detail_id + ) diff --git a/video/stitcher/list_cdn_keys.py b/video/stitcher/list_cdn_keys.py new file mode 100644 index 00000000000..68f628f74a9 --- /dev/null +++ b/video/stitcher/list_cdn_keys.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for listing all CDN keys in a location. +Example usage: + python list_cdn_keys.py --project_id --location +""" + +# [START videostitcher_list_cdn_keys] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def list_cdn_keys(project_id: str, location: str) -> str: + """Lists all CDN keys in a location. + Args: + project_id: The GCP project ID. + location: The location of the CDN keys.""" + + client = VideoStitcherServiceClient() + + parent = f"projects/{project_id}/locations/{location}" + response = client.list_cdn_keys(parent=parent) + print("CDN keys:") + for cdn_key in response.cdn_keys: + print({cdn_key.name}) + + return response + + +# [END videostitcher_list_cdn_keys] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location of the CDN keys.", + required=True, + ) + args = parser.parse_args() + list_cdn_keys( + args.project_id, + args.location, + ) diff --git a/video/stitcher/list_live_ad_tag_details.py b/video/stitcher/list_live_ad_tag_details.py new file mode 100644 index 00000000000..4f1d0568c95 --- /dev/null +++ b/video/stitcher/list_live_ad_tag_details.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for listing the ad tag details for a +live session. +Example usage: + python list_live_ad_tag_details.py --project_id \ + --location --session_id +""" + +# [START videostitcher_list_live_ad_tag_details] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def list_live_ad_tag_details(project_id: str, location: str, session_id: str) -> str: + """Lists the ad tag details for the specified live session. + Args: + project_id: The GCP project ID. + location: The location of the session. + session_id: The ID of the live session.""" + + client = VideoStitcherServiceClient() + + parent = client.live_session_path(project_id, location, session_id) + page_result = client.list_live_ad_tag_details(parent=parent) + print("Live ad tag details:") + for response in page_result: + print(response) + + return page_result + + +# [END videostitcher_list_live_ad_tag_details] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", help="The location of the live session.", required=True + ) + parser.add_argument( + "--session_id", help="The ID of the live session.", required=True + ) + args = parser.parse_args() + list_live_ad_tag_details(args.project_id, args.location, args.session_id) diff --git a/video/stitcher/list_live_configs.py b/video/stitcher/list_live_configs.py new file mode 100644 index 00000000000..24ddc3317f4 --- /dev/null +++ b/video/stitcher/list_live_configs.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python + +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for listing all live configs in a location. +Example usage: + python list_live_configs.py --project_id --location +""" + +# [START videostitcher_list_live_configs] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def list_live_configs(project_id: str, location: str) -> str: + """Lists all live configs in a location. + Args: + project_id: The GCP project ID. + location: The location of the live configs.""" + + client = VideoStitcherServiceClient() + + parent = f"projects/{project_id}/locations/{location}" + response = client.list_live_configs(parent=parent) + print("Live configs:") + for live_config in response.live_configs: + print({live_config.name}) + + return response + + +# [END videostitcher_list_live_configs] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location of the live configs.", + required=True, + ) + args = parser.parse_args() + list_live_configs( + args.project_id, + args.location, + ) diff --git a/video/stitcher/list_slates.py b/video/stitcher/list_slates.py new file mode 100644 index 00000000000..873a2c19ae5 --- /dev/null +++ b/video/stitcher/list_slates.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for listing all slates in a location. +Example usage: + python list_slates.py --project_id --location +""" + +# [START videostitcher_list_slates] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def list_slates(project_id: str, location: str) -> str: + """Lists all slates in a location. + Args: + project_id: The GCP project ID. + location: The location of the slates.""" + + client = VideoStitcherServiceClient() + + parent = f"projects/{project_id}/locations/{location}" + response = client.list_slates(parent=parent) + print("Slates:") + for slate in response.slates: + print({slate.name}) + + return response + + +# [END videostitcher_list_slates] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location of the slates.", + required=True, + ) + args = parser.parse_args() + list_slates( + args.project_id, + args.location, + ) diff --git a/video/stitcher/list_vod_ad_tag_details.py b/video/stitcher/list_vod_ad_tag_details.py new file mode 100644 index 00000000000..4c2b24853ba --- /dev/null +++ b/video/stitcher/list_vod_ad_tag_details.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for listing the ad tag details for a video +on demand (VOD) session. +Example usage: + python list_vod_ad_tag_details.py --project_id \ + --location --session_id +""" + +# [START videostitcher_list_vod_ad_tag_details] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def list_vod_ad_tag_details(project_id: str, location: str, session_id: str) -> str: + """Lists the ad tag details for the specified VOD session. + Args: + project_id: The GCP project ID. + location: The location of the session. + session_id: The ID of the VOD session.""" + + client = VideoStitcherServiceClient() + + parent = client.vod_session_path(project_id, location, session_id) + page_result = client.list_vod_ad_tag_details(parent=parent) + print("VOD ad tag details:") + for response in page_result: + print(response) + + return response + + +# [END videostitcher_list_vod_ad_tag_details] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", help="The location of the VOD session.", required=True + ) + parser.add_argument( + "--session_id", help="The ID of the VOD session.", required=True + ) + args = parser.parse_args() + list_vod_ad_tag_details(args.project_id, args.location, args.session_id) diff --git a/video/stitcher/list_vod_stitch_details.py b/video/stitcher/list_vod_stitch_details.py new file mode 100644 index 00000000000..4a26f2c4d75 --- /dev/null +++ b/video/stitcher/list_vod_stitch_details.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for listing the stitch details for a +video on demand (VOD) session. +Example usage: + python list_vod_stitch_details.py --project_id \ + --location --session_id +""" + +# [START videostitcher_list_vod_stitch_details] + +import argparse + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) + + +def list_vod_stitch_details(project_id: str, location: str, session_id: str) -> str: + """Lists the stitch details for the specified VOD session. + Args: + project_id: The GCP project ID. + location: The location of the session. + session_id: The ID of the VOD session.""" + + client = VideoStitcherServiceClient() + + parent = client.vod_session_path(project_id, location, session_id) + page_result = client.list_vod_stitch_details(parent=parent) + print("VOD stitch details:") + for response in page_result: + print(response) + + return response + + +# [END videostitcher_list_vod_stitch_details] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", help="The location of the VOD session.", required=True + ) + parser.add_argument( + "--session_id", help="The ID of the VOD session.", required=True + ) + args = parser.parse_args() + list_vod_stitch_details(args.project_id, args.location, args.session_id) diff --git a/video/stitcher/live_config_test.py b/video/stitcher/live_config_test.py new file mode 100644 index 00000000000..d1e83ccb9f0 --- /dev/null +++ b/video/stitcher/live_config_test.py @@ -0,0 +1,89 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import uuid + +from google.protobuf import timestamp_pb2 +import pytest + +import create_live_config +import create_slate +import delete_live_config +import delete_slate +import get_live_config +import list_live_configs +import utils + +project_id = os.environ["GOOGLE_CLOUD_PROJECT"] +location = "us-central1" +now = timestamp_pb2.Timestamp() +now.GetCurrentTime() + +live_config_id = f"python-test-live-config-{uuid.uuid4().hex[:5]}-{now.seconds}" + +input_bucket_name = "cloud-samples-data/media/" +input_video_file_name = "hls-live/manifest.m3u8" +live_stream_uri = ( + f"https://storage.googleapis.com/{input_bucket_name}{input_video_file_name}" +) +# Single Inline Linear (https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags) +ad_tag_uri = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_ad_samples&sz=640x480&cust_params=sample_ct%3Dlinear&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=" +slate_id = f"python-test-slate-{uuid.uuid4().hex[:5]}-{now.seconds}" +slate_video_file_name = "ForBiggerJoyrides.mp4" +slate_uri = f"https://storage.googleapis.com/{input_bucket_name}{slate_video_file_name}" + + +def test_live_config_operations(capsys: pytest.fixture) -> None: + + utils.delete_stale_slates(project_id, location) + utils.delete_stale_live_configs(project_id, location) + + # Test setup + + slate_name = f"projects/{project_id}/locations/{location}/slates/{slate_id}" + + create_slate.create_slate(project_id, location, slate_id, slate_uri) + out, _ = capsys.readouterr() + assert slate_name in out + + live_config_name = ( + f"projects/{project_id}/locations/{location}/liveConfigs/{live_config_id}" + ) + + # Tests + + create_live_config.create_live_config( + project_id, location, live_config_id, live_stream_uri, ad_tag_uri, slate_id + ) + out, _ = capsys.readouterr() + assert live_config_name in out + + list_live_configs.list_live_configs(project_id, location) + out, _ = capsys.readouterr() + assert live_config_name in out + + get_live_config.get_live_config(project_id, location, live_config_id) + out, _ = capsys.readouterr() + assert live_config_name in out + + delete_live_config.delete_live_config(project_id, location, live_config_id) + out, _ = capsys.readouterr() + assert "Deleted live config" in out + + # Clean up slate as it is no longer needed + + delete_slate.delete_slate(project_id, location, slate_id) + out, _ = capsys.readouterr() + assert "Deleted slate" in out diff --git a/video/stitcher/live_session_test.py b/video/stitcher/live_session_test.py new file mode 100644 index 00000000000..dd3dfd87881 --- /dev/null +++ b/video/stitcher/live_session_test.py @@ -0,0 +1,147 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import re +import uuid + +from google.protobuf import timestamp_pb2 +import pytest +import requests + +import create_live_config +import create_live_session +import create_slate +import delete_live_config +import delete_slate +import get_live_ad_tag_detail +import get_live_session +import list_live_ad_tag_details + +project_id = os.environ["GOOGLE_CLOUD_PROJECT"] +project_number = os.environ["GOOGLE_CLOUD_PROJECT_NUMBER"] +location = "us-central1" +now = timestamp_pb2.Timestamp() +now.GetCurrentTime() + +live_config_id = f"python-test-live-config-{uuid.uuid4().hex[:5]}-{now.seconds}" +input_bucket_name = "cloud-samples-data/media/" +input_video_file_name = "hls-live/manifest.m3u8" +live_stream_uri = ( + f"https://storage.googleapis.com/{input_bucket_name}{input_video_file_name}" +) +# Single Inline Linear (https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags) +ad_tag_uri = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_ad_samples&sz=640x480&cust_params=sample_ct%3Dlinear&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=" +slate_id = f"python-test-slate-{uuid.uuid4().hex[:5]}-{now.seconds}" +slate_video_file_name = "ForBiggerJoyrides.mp4" +slate_uri = f"https://storage.googleapis.com/{input_bucket_name}{slate_video_file_name}" + + +def test_live_session_operations(capsys: pytest.fixture) -> None: + + # Test setup + + slate_name = f"projects/{project_id}/locations/{location}/slates/{slate_id}" + + create_slate.create_slate(project_id, location, slate_id, slate_uri) + out, _ = capsys.readouterr() + assert slate_name in out + + live_config_name = ( + f"projects/{project_id}/locations/{location}/liveConfigs/{live_config_id}" + ) + + create_live_config.create_live_config( + project_id, location, live_config_id, live_stream_uri, ad_tag_uri, slate_id + ) + out, _ = capsys.readouterr() + assert live_config_name in out + + # Tests + + create_live_session_response = create_live_session.create_live_session( + project_id, location, live_config_id + ) + out, _ = capsys.readouterr() + session_name_prefix = ( + f"projects/{project_number}/locations/{location}/liveSessions/" + ) + assert session_name_prefix in out + + str_slice = out.split("/") + session_id = str_slice[len(str_slice) - 1].rstrip("\n") + session_name = ( + f"projects/{project_number}/locations/{location}/liveSessions/{session_id}" + ) + assert session_name in out + + get_live_session.get_live_session(project_id, location, session_id) + out, _ = capsys.readouterr() + assert session_name in out + + # No list or delete methods for live sessions + + # Ad tag details + + # To get ad tag details, you need to curl the main manifest and + # a rendition first. This supplies media player information to the API. + # + # Curl the play_uri first. The last line of the response will contain a + # renditions location. Curl the live session name with the rendition + # location appended. + + r = requests.get(create_live_session_response.play_uri) + match = re.search("renditions/.*", r.text) + assert match + renditions = match.group() + assert "renditions/" in renditions + + # create_live_session_response.play_uri will be in the following format: + # /projects/{project}/locations/{location}/liveSessions/{session-id}/manifest.m3u8?signature=... + # Replace manifest.m3u8?signature=... with the renditions location. + arr = create_live_session_response.play_uri.split("/") + arr.pop() + tmp = "/".join(arr) + renditions_uri = f"{tmp}/{renditions}" + r = requests.get(renditions_uri) + + list_live_ad_tag_details_response = ( + list_live_ad_tag_details.list_live_ad_tag_details( + project_id, location, session_id + ) + ) + out, _ = capsys.readouterr() + ad_tag_details_name_prefix = f"projects/{project_number}/locations/{location}/liveSessions/{session_id}/liveAdTagDetails/" + assert ad_tag_details_name_prefix in out + + str_slice = list_live_ad_tag_details_response.live_ad_tag_details[0].name.split("/") + ad_tag_details_id = str_slice[len(str_slice) - 1].rstrip("\n") + ad_tag_details_name = f"projects/{project_number}/locations/{location}/liveSessions/{session_id}/liveAdTagDetails/{ad_tag_details_id}" + assert ad_tag_details_name in out + + # b/231626944 for projectNumber below + get_live_ad_tag_detail.get_live_ad_tag_detail( + project_number, location, session_id, ad_tag_details_id + ) + out, _ = capsys.readouterr() + assert ad_tag_details_name in out + + # Clean up live config and slate + delete_live_config.delete_live_config(project_id, location, live_config_id) + out, _ = capsys.readouterr() + assert "Deleted live config" in out + + delete_slate.delete_slate(project_id, location, slate_id) + out, _ = capsys.readouterr() + assert "Deleted slate" in out diff --git a/video/stitcher/noxfile_config.py b/video/stitcher/noxfile_config.py new file mode 100644 index 00000000000..c8377ecb974 --- /dev/null +++ b/video/stitcher/noxfile_config.py @@ -0,0 +1,38 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Default TEST_CONFIG_OVERRIDE for python repos. + +# You can copy this file into your directory, then it will be inported from +# the noxfile.py. + +# The source of truth: +# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/main/noxfile_config.py + +TEST_CONFIG_OVERRIDE = { + # You can opt out from the test for specific Python versions. + "ignored_versions": ["2.7", "3.6"], + # Old samples are opted out of enforcing Python type hints + # All new samples should feature them + "enforce_type_hints": True, + # An envvar key for determining the project id to use. Change it + # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a + # build specific Cloud project. You can also use your own string + # to use your own Cloud project. + # "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", + "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", + # A dictionary you want to inject into your test. Don't put any + # secrets here. These values will override predefined values. + "envs": {}, +} diff --git a/video/stitcher/requirements-test.txt b/video/stitcher/requirements-test.txt new file mode 100644 index 00000000000..c953c750e0b --- /dev/null +++ b/video/stitcher/requirements-test.txt @@ -0,0 +1,2 @@ +pytest==7.3.1 +requests==2.31.0 \ No newline at end of file diff --git a/video/stitcher/requirements.txt b/video/stitcher/requirements.txt new file mode 100644 index 00000000000..cc6ed3dfdfb --- /dev/null +++ b/video/stitcher/requirements.txt @@ -0,0 +1,3 @@ +google-api-python-client==2.88.0 +grpcio==1.54.2 +google-cloud-video-stitcher==0.7.2 \ No newline at end of file diff --git a/video/stitcher/slate_test.py b/video/stitcher/slate_test.py new file mode 100644 index 00000000000..27b3861114b --- /dev/null +++ b/video/stitcher/slate_test.py @@ -0,0 +1,72 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import uuid + +from google.protobuf import timestamp_pb2 +import pytest + +import create_slate +import delete_slate +import get_slate +import list_slates +import update_slate +import utils + +project_id = os.environ["GOOGLE_CLOUD_PROJECT"] +location = "us-central1" +now = timestamp_pb2.Timestamp() +now.GetCurrentTime() + +input_bucket_name = "cloud-samples-data/media/" +slate_video_file_name = "ForBiggerEscapes.mp4" +updated_slate_video_file_name = "ForBiggerJoyrides.mp4" +slate_id = f"python-test-slate-{uuid.uuid4().hex[:5]}-{now.seconds}" +slate_uri = f"https://storage.googleapis.com/{input_bucket_name}{slate_video_file_name}" +updated_slate_uri = ( + f"https://storage.googleapis.com/{input_bucket_name}{updated_slate_video_file_name}" +) + + +def test_slate_operations(capsys: pytest.fixture) -> None: + + utils.delete_stale_slates(project_id, location) + + slate_name_project_id = ( + f"projects/{project_id}/locations/{location}/slates/{slate_id}" + ) + + create_slate.create_slate(project_id, location, slate_id, slate_uri) + out, _ = capsys.readouterr() + assert slate_name_project_id in out + + list_slates.list_slates(project_id, location) + out, _ = capsys.readouterr() + assert slate_name_project_id in out + + response = update_slate.update_slate( + project_id, location, slate_id, updated_slate_uri + ) + out, _ = capsys.readouterr() + assert slate_name_project_id in out + assert updated_slate_uri in response.uri + + get_slate.get_slate(project_id, location, slate_id) + out, _ = capsys.readouterr() + assert slate_name_project_id in out + + delete_slate.delete_slate(project_id, location, slate_id) + out, _ = capsys.readouterr() + assert "Deleted slate" in out diff --git a/video/stitcher/update_cdn_key.py b/video/stitcher/update_cdn_key.py new file mode 100644 index 00000000000..e14861242e7 --- /dev/null +++ b/video/stitcher/update_cdn_key.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for updating a Media CDN or +Cloud CDN key. +Example usage: + python update_cdn_key.py --project_id --location \ + --cdn_key_id --hostname \ + --key_name --private_key [--is_cloud_cdn] +""" + +# [START videostitcher_update_cdn_key] + +import argparse + +from google.cloud.video import stitcher_v1 +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) +from google.protobuf import field_mask_pb2 as field_mask + + +def update_cdn_key( + project_id: str, + location: str, + cdn_key_id: str, + hostname: str, + key_name: str, + private_key: str, + is_cloud_cdn: bool, +) -> str: + """Updates a Media CDN or Cloud CDN key. + Args: + project_id: The GCP project ID. + location: The location of the CDN key. + cdn_key_id: The user-defined CDN key ID. + hostname: The hostname to which this CDN key applies. + key_name: For a Media CDN key, this is the keyset name. + For a Cloud CDN key, this is the public name of the CDN key. + private_key: For a Media CDN key, this is a 64-byte Ed25519 private + key encoded as a base64-encoded string. + See https://cloud.google.com/video-stitcher/docs/how-to/managing-cdn-keys#create-private-key-media-cdn + for more information. For a Cloud CDN key, this is a base64-encoded string secret. + is_cloud_cdn: If true, update a Cloud CDN key. If false, update a Media CDN key.""" + + client = VideoStitcherServiceClient() + + name = f"projects/{project_id}/locations/{location}/cdnKeys/{cdn_key_id}" + + cdn_key = stitcher_v1.types.CdnKey( + name=name, + hostname=hostname, + ) + + if is_cloud_cdn: + cdn_key.google_cdn_key = stitcher_v1.types.GoogleCdnKey( + key_name=key_name, + private_key=private_key, + ) + update_mask = field_mask.FieldMask(paths=["hostname", "google_cdn_key"]) + else: + cdn_key.media_cdn_key = stitcher_v1.types.MediaCdnKey( + key_name=key_name, + private_key=private_key, + ) + update_mask = field_mask.FieldMask(paths=["hostname", "media_cdn_key"]) + + operation = client.update_cdn_key(cdn_key=cdn_key, update_mask=update_mask) + response = operation.result() + print(f"Updated CDN key: {response.name}") + return response + + +# [END videostitcher_update_cdn_key] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location of the CDN key.", + required=True, + ) + parser.add_argument( + "--cdn_key_id", + help="The user-defined CDN key ID.", + required=True, + ) + parser.add_argument( + "--hostname", + help="The hostname to which this CDN key applies.", + required=True, + ) + parser.add_argument( + "--key_name", + help="For a Media CDN key, this is the keyset name. For a Cloud CDN" + + " key, this is the public name of the CDN key.", + required=True, + ) + parser.add_argument( + "--private_key", + help="For a Media CDN key, this is a 64-byte Ed25519 private key" + + "encoded as a base64-encoded string. See" + + " https://cloud.google.com/video-stitcher/docs/how-to/managing-cdn-keys#create-private-key-media-cdn" + + " for more information. For a Cloud CDN key, this is a" + + " base64-encoded string secret.", + required=True, + ) + parser.add_argument( + "--is_cloud_cdn", + action="store_true", + help="If included, create a Cloud CDN key. If absent, create a Media CDN key.", + ) + + args = parser.parse_args() + update_cdn_key( + args.project_id, + args.location, + args.cdn_key_id, + args.hostname, + args.key_name, + args.private_key, + args.is_cloud_cdn, + ) diff --git a/video/stitcher/update_cdn_key_akamai.py b/video/stitcher/update_cdn_key_akamai.py new file mode 100644 index 00000000000..d91c8786629 --- /dev/null +++ b/video/stitcher/update_cdn_key_akamai.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for updating an Akamai CDN key. +Example usage: + python update_cdn_key_akamai.py --project_id --location \ + --cdn_key_id --hostname \ + --akamai_token_key +""" + +# [START videostitcher_update_cdn_key_akamai] + +import argparse + +from google.cloud.video import stitcher_v1 +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) +from google.protobuf import field_mask_pb2 as field_mask + + +def update_cdn_key_akamai( + project_id: str, + location: str, + cdn_key_id: str, + hostname: str, + akamai_token_key: str, +) -> str: + """Updates an Akamai CDN key. + Args: + project_id: The GCP project ID. + location: The location of the CDN key. + cdn_key_id: The user-defined CDN key ID. + hostname: The hostname to which this CDN key applies. + akamai_token_key: A base64-encoded string token key.""" + + client = VideoStitcherServiceClient() + + name = f"projects/{project_id}/locations/{location}/cdnKeys/{cdn_key_id}" + + cdn_key = stitcher_v1.types.CdnKey( + name=name, + hostname=hostname, + akamai_cdn_key=stitcher_v1.types.AkamaiCdnKey( + token_key=akamai_token_key, + ), + ) + update_mask = field_mask.FieldMask(paths=["hostname", "akamai_cdn_key"]) + + operation = client.update_cdn_key(cdn_key=cdn_key, update_mask=update_mask) + response = operation.result() + print(f"Updated CDN key: {response.name}") + return response + + +# [END videostitcher_update_cdn_key_akamai] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location of the CDN key.", + required=True, + ) + parser.add_argument( + "--cdn_key_id", + help="The user-defined CDN key ID.", + required=True, + ) + parser.add_argument( + "--hostname", + help="The hostname to which this CDN key applies.", + required=True, + ) + parser.add_argument( + "--akamai_token_key", + help="The base64-encoded string token key.", + required=True, + ) + args = parser.parse_args() + update_cdn_key_akamai( + args.project_id, + args.location, + args.cdn_key_id, + args.hostname, + args.akamai_token_key, + ) diff --git a/video/stitcher/update_slate.py b/video/stitcher/update_slate.py new file mode 100644 index 00000000000..282c89ee716 --- /dev/null +++ b/video/stitcher/update_slate.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Video Stitcher sample for updating a slate. +Example usage: + python update_slate.py --project_id --location \ + --slate_id --slate_uri +""" + +# [START videostitcher_update_slate] + +import argparse + +from google.cloud.video import stitcher_v1 +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) +from google.protobuf import field_mask_pb2 as field_mask + + +def update_slate(project_id: str, location: str, slate_id: str, slate_uri: str) -> str: + """Updates a slate. + Args: + project_id: The GCP project ID. + location: The location of the slate. + slate_id: The existing slate's ID. + slate_uri: Updated uri of the video slate; must be an MP4 video with at least one audio track.""" + + client = VideoStitcherServiceClient() + + name = f"projects/{project_id}/locations/{location}/slates/{slate_id}" + slate = stitcher_v1.types.Slate( + name=name, + uri=slate_uri, + ) + update_mask = field_mask.FieldMask(paths=["uri"]) + + operation = client.update_slate(slate=slate, update_mask=update_mask) + response = operation.result() + print(f"Updated slate: {response.name}") + return response + + +# [END videostitcher_update_slate] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project_id", help="Your Cloud project ID.", required=True) + parser.add_argument( + "--location", + help="The location of the slate.", + required=True, + ) + parser.add_argument( + "--slate_id", + help="The existing slate's ID.", + required=True, + ) + parser.add_argument( + "--slate_uri", + help="Updated uri of the video slate; must be an MP4 video with at least one audio track.", + required=True, + ) + args = parser.parse_args() + update_slate( + args.project_id, + args.location, + args.slate_id, + args.slate_uri, + ) diff --git a/video/stitcher/utils.py b/video/stitcher/utils.py new file mode 100644 index 00000000000..28537306262 --- /dev/null +++ b/video/stitcher/utils.py @@ -0,0 +1,92 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from google.cloud.video.stitcher_v1.services.video_stitcher_service import ( + VideoStitcherServiceClient, +) +from google.protobuf import timestamp_pb2 + +seconds_per_hour = 3600 + + +def delete_stale_slates(project_id: str, location: str) -> None: + """Lists all outdated slates in a location. + Args: + project_id: The GCP project ID. + location: The location of the slates.""" + + client = VideoStitcherServiceClient() + + parent = f"projects/{project_id}/locations/{location}" + response = client.list_slates(parent=parent) + + now = timestamp_pb2.Timestamp() + now.GetCurrentTime() + + for slate in response.slates: + tmp = slate.name.split("-") + try: + creation_time_sec = int(tmp.pop()) + except ValueError: + continue + if (now.seconds - creation_time_sec) > (3 * seconds_per_hour): + response = client.delete_slate(name=slate.name) + + +def delete_stale_cdn_keys(project_id: str, location: str) -> None: + """Lists all outdated CDN keys in a location. + Args: + project_id: The GCP project ID. + location: The location of the CDN keys.""" + + client = VideoStitcherServiceClient() + + parent = f"projects/{project_id}/locations/{location}" + response = client.list_cdn_keys(parent=parent) + + now = timestamp_pb2.Timestamp() + now.GetCurrentTime() + + for cdn_key in response.cdn_keys: + tmp = cdn_key.name.split("-") + try: + creation_time_sec = int(tmp.pop()) + except ValueError: + continue + if (now.seconds - creation_time_sec) > (3 * seconds_per_hour): + response = client.delete_cdn_key(name=cdn_key.name) + + +def delete_stale_live_configs(project_id: str, location: str) -> None: + """Lists all outdated live configs in a location. + Args: + project_id: The GCP project ID. + location: The location of the live configs.""" + + client = VideoStitcherServiceClient() + + parent = f"projects/{project_id}/locations/{location}" + response = client.list_live_configs(parent=parent) + + now = timestamp_pb2.Timestamp() + now.GetCurrentTime() + + for live_config in response.live_configs: + tmp = live_config.name.split("-") + try: + creation_time_sec = int(tmp.pop()) + except ValueError: + continue + if (now.seconds - creation_time_sec) > (3 * seconds_per_hour): + response = client.delete_live_config(name=live_config.name) diff --git a/video/stitcher/vod_session_test.py b/video/stitcher/vod_session_test.py new file mode 100644 index 00000000000..92ba36053d4 --- /dev/null +++ b/video/stitcher/vod_session_test.py @@ -0,0 +1,94 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import pytest + +import create_vod_session +import get_vod_ad_tag_detail +import get_vod_session +import get_vod_stitch_detail +import list_vod_ad_tag_details +import list_vod_stitch_details + +project_id = os.environ["GOOGLE_CLOUD_PROJECT"] +project_number = os.environ["GOOGLE_CLOUD_PROJECT_NUMBER"] +location = "us-central1" +input_bucket_name = "cloud-samples-data/media/" +input_video_file_name = "hls-vod/manifest.m3u8" +vod_uri = f"https://storage.googleapis.com/{input_bucket_name}{input_video_file_name}" +# VMAP Pre-roll (https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags) +ad_tag_uri = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpreonly&ciu_szs=300x250%2C728x90&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&correlator=" + + +def test_vod_session_operations(capsys: pytest.fixture) -> None: + + create_vod_session.create_vod_session(project_id, location, vod_uri, ad_tag_uri) + out, _ = capsys.readouterr() + session_name_prefix = f"projects/{project_number}/locations/{location}/vodSessions/" + assert session_name_prefix in out + + str_slice = out.split("/") + session_id = str_slice[len(str_slice) - 1].rstrip("\n") + session_name = ( + f"projects/{project_number}/locations/{location}/vodSessions/{session_id}" + ) + assert session_name in out + + get_vod_session.get_vod_session(project_id, location, session_id) + out, _ = capsys.readouterr() + assert session_name in out + + # No list or delete methods for VOD sessions + + # Ad tag details + + response = list_vod_ad_tag_details.list_vod_ad_tag_details( + project_id, location, session_id + ) + out, _ = capsys.readouterr() + ad_tag_details_name_prefix = f"projects/{project_number}/locations/{location}/vodSessions/{session_id}/vodAdTagDetails/" + assert ad_tag_details_name_prefix in out + + str_slice = response.name.split("/") + ad_tag_details_id = str_slice[len(str_slice) - 1].rstrip("\n") + ad_tag_details_name = f"projects/{project_number}/locations/{location}/vodSessions/{session_id}/vodAdTagDetails/{ad_tag_details_id}" + assert ad_tag_details_name in out + + get_vod_ad_tag_detail.get_vod_ad_tag_detail( + project_id, location, session_id, ad_tag_details_id + ) + out, _ = capsys.readouterr() + assert ad_tag_details_name in out + + # Stitch details + + response = list_vod_stitch_details.list_vod_stitch_details( + project_id, location, session_id + ) + out, _ = capsys.readouterr() + stitch_details_name_prefix = f"projects/{project_number}/locations/{location}/vodSessions/{session_id}/vodStitchDetails/" + assert stitch_details_name_prefix in out + + str_slice = response.name.split("/") + stitch_details_id = str_slice[len(str_slice) - 1].rstrip("\n") + stitch_details_name = f"projects/{project_number}/locations/{location}/vodSessions/{session_id}/vodStitchDetails/{stitch_details_id}" + assert stitch_details_name in out + + get_vod_stitch_detail.get_vod_stitch_detail( + project_id, location, session_id, stitch_details_id + ) + out, _ = capsys.readouterr() + assert stitch_details_name in out