diff --git a/.github/workflows/media-video-stitcher.yaml b/.github/workflows/media-video-stitcher.yaml new file mode 100644 index 0000000000..26a384f684 --- /dev/null +++ b/.github/workflows/media-video-stitcher.yaml @@ -0,0 +1,71 @@ +name: media-video-stitcher +on: + push: + branches: + - main + paths: + - 'media/video-stitcher/**' + - '.github/workflows/media-video-stitcher.yaml' + pull_request: + paths: + - 'media/video-stitcher/**' + - '.github/workflows/media-video-stitcher.yaml' + pull_request_target: + types: [labeled] + paths: + - 'media/video-stitcher/**' + - '.github/workflows/media-video-stitcher.yaml' + schedule: + - cron: '0 0 * * 0' +jobs: + test: + if: ${{ github.event.action != 'labeled' || github.event.label.name == 'actions:force-run' }} + runs-on: ubuntu-latest + timeout-minutes: 60 + permissions: + contents: 'write' + pull-requests: 'write' + id-token: 'write' + steps: + - uses: actions/checkout@v3.1.0 + with: + ref: ${{github.event.pull_request.head.sha}} + - uses: 'google-github-actions/auth@v1.0.0' + with: + workload_identity_provider: 'projects/1046198160504/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider' + service_account: 'kokoro-system-test@long-door-651.iam.gserviceaccount.com' + create_credentials_file: 'true' + access_token_lifetime: 600s + - uses: actions/setup-node@v3.5.1 + with: + node-version: 16 + - run: npm install + working-directory: media/video-stitcher + - run: npm test + working-directory: media/video-stitcher + env: + MOCHA_REPORTER_SUITENAME: media_video_stitcher + MOCHA_REPORTER_OUTPUT: media_video_stitcher_sponge_log.xml + MOCHA_REPORTER: xunit + - if: ${{ github.event.action == 'labeled' && github.event.label.name == 'actions:force-run' }} + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + try { + await github.rest.issues.removeLabel({ + name: 'actions:force-run', + owner: 'GoogleCloudPlatform', + repo: 'nodejs-docs-samples', + issue_number: context.payload.pull_request.number + }); + } catch (e) { + if (!e.message.includes('Label does not exist')) { + throw e; + } + } + - if: ${{ github.event_name == 'schedule' && always() }} + run: | + curl https://github.com/googleapis/repo-automation-bots/releases/download/flakybot-1.1.0/flakybot -o flakybot -s -L + chmod +x ./flakybot + ./flakybot --repo GoogleCloudPlatform/nodejs-docs-samples --commit_hash ${{github.sha}} --build_url https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} diff --git a/.github/workflows/workflows.json b/.github/workflows/workflows.json index a920b52213..6f5ca40618 100644 --- a/.github/workflows/workflows.json +++ b/.github/workflows/workflows.json @@ -69,6 +69,7 @@ "healthcare/hl7v2", "iam", "kms", + "media/video-stitcher", "mediatranslation", "monitoring/opencensus", "monitoring/prometheus", diff --git a/CODEOWNERS b/CODEOWNERS index 638ba27838..750ba5cc87 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -76,3 +76,4 @@ vision @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/nodejs-samples-revi # Self-service retail @GoogleCloudPlatform/cloud-retail-team @GoogleCloudPlatform/nodejs-samples-reviewers +media @GoogleCloudPlatform/cloud-media-team @GoogleCloudPlatform/nodejs-samples-reviewers diff --git a/media/video-stitcher/createCdnKey.js b/media/video-stitcher/createCdnKey.js new file mode 100644 index 0000000000..debcf573ec --- /dev/null +++ b/media/video-stitcher/createCdnKey.js @@ -0,0 +1,79 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main( + projectId, + location, + cdnKeyId, + hostname, + gCdnKeyname, + gCdnPrivateKey, + akamaiTokenKey = '' +) { + // [START videostitcher_create_cdn_key] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // cdnKeyId = 'my-cdn-key'; + // hostname = 'cdn.example.com'; + // gCdnKeyname = 'gcdn-key'; + // gCdnPrivateKey = 'VGhpcyBpcyBhIHRlc3Qgc3RyaW5nLg=='; + // akamaiTokenKey = 'VGhpcyBpcyBhIHRlc3Qgc3RyaW5nLg=='; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function createCdnKey() { + // Construct request + const request = { + parent: stitcherClient.locationPath(projectId, location), + cdnKey: { + hostname: hostname, + }, + cdnKeyId: cdnKeyId, + }; + + if (akamaiTokenKey !== '') { + request.cdnKey.akamaiCdnKey = { + tokenKey: akamaiTokenKey, + }; + } else { + request.cdnKey.googleCdnKey = { + keyName: gCdnKeyname, + privateKey: gCdnPrivateKey, + }; + } + + const [cdnKey] = await stitcherClient.createCdnKey(request); + console.log(`CDN key: ${cdnKey.name}`); + } + + createCdnKey(); + // [END videostitcher_create_cdn_key] +} + +// node createCdnKey.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/createLiveSession.js b/media/video-stitcher/createLiveSession.js new file mode 100644 index 0000000000..2f9dc62e7a --- /dev/null +++ b/media/video-stitcher/createLiveSession.js @@ -0,0 +1,66 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, sourceUri, adTagUri, slateId) { + // [START videostitcher_create_live_session] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // sourceUri = 'https://storage.googleapis.com/my-bucket/main.mpd'; + // Single Inline Linear (https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags) + // (https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags) + // adTagUri = 'https://pubads.g.doubleclick.net/gampad/ads...'; + // slateId = 'my-slate'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function createLiveSession() { + // Construct request + const request = { + parent: stitcherClient.locationPath(projectId, location), + liveSession: { + sourceUri: sourceUri, + adTagMap: { + default: { + uri: adTagUri, + }, + }, + defaultSlateId: slateId, + }, + }; + + const [session] = await stitcherClient.createLiveSession(request); + console.log(`Live session: ${session.name}`); + console.log(`Play URI: ${session.playUri}`); + } + + createLiveSession(); + // [END videostitcher_create_live_session] +} + +// node createLiveSession.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/createSlate.js b/media/video-stitcher/createSlate.js new file mode 100644 index 0000000000..d273e33e3e --- /dev/null +++ b/media/video-stitcher/createSlate.js @@ -0,0 +1,56 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, slateId, slateUri) { + // [START videostitcher_create_slate] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // slateId = 'my-slate'; + // slateUri = 'https://my-slate-uri/test.mp4'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function createSlate() { + // Construct request + const request = { + parent: stitcherClient.locationPath(projectId, location), + slate: { + uri: slateUri, + }, + slateId: slateId, + }; + const [slate] = await stitcherClient.createSlate(request); + console.log(`Slate: ${slate.name}`); + } + + createSlate(); + // [END videostitcher_create_slate] +} + +// node createSlate.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/createVodSession.js b/media/video-stitcher/createVodSession.js new file mode 100644 index 0000000000..acc9d29de4 --- /dev/null +++ b/media/video-stitcher/createVodSession.js @@ -0,0 +1,58 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, sourceUri, adTagUri) { + // [START videostitcher_create_vod_session] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // sourceUri = 'https://storage.googleapis.com/my-bucket/main.mpd'; + // See VMAP Pre-roll + // (https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags) + // adTagUri = 'https://pubads.g.doubleclick.net/gampad/ads...'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function createVodSession() { + // Construct request + const request = { + parent: stitcherClient.locationPath(projectId, location), + vodSession: { + sourceUri: sourceUri, + adTagUri: adTagUri, + }, + }; + const [session] = await stitcherClient.createVodSession(request); + console.log(`VOD session: ${session.name}`); + } + + createVodSession(); + // [END videostitcher_create_vod_session] +} + +// node createVodSession.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/deleteCdnKey.js b/media/video-stitcher/deleteCdnKey.js new file mode 100644 index 0000000000..6c179ffe76 --- /dev/null +++ b/media/video-stitcher/deleteCdnKey.js @@ -0,0 +1,51 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, cdnKeyId) { + // [START videostitcher_delete_cdn_key] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // cdnKeyId = 'my-cdn-key'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function deleteCdnKey() { + // Construct request + const request = { + name: stitcherClient.cdnKeyPath(projectId, location, cdnKeyId), + }; + await stitcherClient.deleteCdnKey(request); + console.log('Deleted CDN key'); + } + + deleteCdnKey(); + // [END videostitcher_delete_cdn_key] +} + +// node deleteCdnKey.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/deleteSlate.js b/media/video-stitcher/deleteSlate.js new file mode 100644 index 0000000000..f295653b3f --- /dev/null +++ b/media/video-stitcher/deleteSlate.js @@ -0,0 +1,51 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, slateId) { + // [START videostitcher_delete_slate] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // slateId = 'my-slate'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function deleteSlate() { + // Construct request + const request = { + name: stitcherClient.slatePath(projectId, location, slateId), + }; + await stitcherClient.deleteSlate(request); + console.log('Deleted slate'); + } + + deleteSlate(); + // [END videostitcher_delete_slate] +} + +// node deleteSlate.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/getCdnKey.js b/media/video-stitcher/getCdnKey.js new file mode 100644 index 0000000000..9666b944ff --- /dev/null +++ b/media/video-stitcher/getCdnKey.js @@ -0,0 +1,51 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, cdnKeyId) { + // [START videostitcher_get_cdn_key] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // cdnKeyId = 'my-cdn-key'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function getCdnKey() { + // Construct request + const request = { + name: stitcherClient.cdnKeyPath(projectId, location, cdnKeyId), + }; + const [cdnKey] = await stitcherClient.getCdnKey(request); + console.log(`CDN key: ${cdnKey.name}`); + } + + getCdnKey(); + // [END videostitcher_get_cdn_key] +} + +// node getCdnKey.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/getLiveAdTagDetail.js b/media/video-stitcher/getLiveAdTagDetail.js new file mode 100644 index 0000000000..00b3913307 --- /dev/null +++ b/media/video-stitcher/getLiveAdTagDetail.js @@ -0,0 +1,57 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, sessionId, adTagDetailId) { + // [START videostitcher_get_live_ad_tag_detail] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // sessionId = 'my-session-id'; + // adTagDetailId = 'my-ad-tag-detail-id'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function getLiveAdTagDetail() { + // Construct request + const request = { + name: stitcherClient.liveAdTagDetailPath( + projectId, + location, + sessionId, + adTagDetailId + ), + }; + const [adTagDetail] = await stitcherClient.getLiveAdTagDetail(request); + console.log(`Live ad tag detail: ${adTagDetail.name}`); + } + + getLiveAdTagDetail(); + // [END videostitcher_get_live_ad_tag_detail] +} + +// node getLiveAdTagDetail.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/getLiveSession.js b/media/video-stitcher/getLiveSession.js new file mode 100644 index 0000000000..b933b63e4a --- /dev/null +++ b/media/video-stitcher/getLiveSession.js @@ -0,0 +1,51 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, sessionId) { + // [START videostitcher_get_live_session] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // sessionId = 'my-session-id'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function getLiveSession() { + // Construct request + const request = { + name: stitcherClient.liveSessionPath(projectId, location, sessionId), + }; + const [session] = await stitcherClient.getLiveSession(request); + console.log(`Live session: ${session.name}`); + } + + getLiveSession(); + // [END videostitcher_get_live_session] +} + +// node getLiveSession.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/getSlate.js b/media/video-stitcher/getSlate.js new file mode 100644 index 0000000000..5cc2161001 --- /dev/null +++ b/media/video-stitcher/getSlate.js @@ -0,0 +1,51 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, slateId) { + // [START videostitcher_get_slate] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // slateId = 'my-slate'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function getSlate() { + // Construct request + const request = { + name: stitcherClient.slatePath(projectId, location, slateId), + }; + const [slate] = await stitcherClient.getSlate(request); + console.log(`Slate: ${slate.name}`); + } + + getSlate(); + // [END videostitcher_get_slate] +} + +// node getSlate.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/getVodAdTagDetail.js b/media/video-stitcher/getVodAdTagDetail.js new file mode 100644 index 0000000000..2004c6609b --- /dev/null +++ b/media/video-stitcher/getVodAdTagDetail.js @@ -0,0 +1,57 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, sessionId, adTagDetailId) { + // [START videostitcher_get_vod_ad_tag_detail] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // sessionId = 'my-session-id'; + // adTagDetailId = 'my-ad-tag-detail-id'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function getVodAdTagDetail() { + // Construct request + const request = { + name: stitcherClient.vodAdTagDetailPath( + projectId, + location, + sessionId, + adTagDetailId + ), + }; + const [adTagDetail] = await stitcherClient.getVodAdTagDetail(request); + console.log(`VOD ad tag detail: ${adTagDetail.name}`); + } + + getVodAdTagDetail(); + // [END videostitcher_get_vod_ad_tag_detail] +} + +// node getVodAdTagDetail.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/getVodSession.js b/media/video-stitcher/getVodSession.js new file mode 100644 index 0000000000..17e2bb7f12 --- /dev/null +++ b/media/video-stitcher/getVodSession.js @@ -0,0 +1,51 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, sessionId) { + // [START videostitcher_get_vod_session] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // sessionId = 'my-session-id'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function getVodSession() { + // Construct request + const request = { + name: stitcherClient.vodSessionPath(projectId, location, sessionId), + }; + const [session] = await stitcherClient.getVodSession(request); + console.log(`VOD session: ${session.name}`); + } + + getVodSession(); + // [END videostitcher_get_vod_session] +} + +// node getVodSession.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/getVodStitchDetail.js b/media/video-stitcher/getVodStitchDetail.js new file mode 100644 index 0000000000..e31f5bbba3 --- /dev/null +++ b/media/video-stitcher/getVodStitchDetail.js @@ -0,0 +1,57 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, sessionId, stitchDetailId) { + // [START videostitcher_get_vod_stitch_detail] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // sessionId = 'my-session-id'; + // stitchDetailId = 'my-stitch-detail-id'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function getVodStitchDetail() { + // Construct request + const request = { + name: stitcherClient.vodStitchDetailPath( + projectId, + location, + sessionId, + stitchDetailId + ), + }; + const [stitchDetail] = await stitcherClient.getVodStitchDetail(request); + console.log(`VOD stitch detail: ${stitchDetail.name}`); + } + + getVodStitchDetail(); + // [END videostitcher_get_vod_stitch_detail] +} + +// node getVodStitchDetail.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/listCdnKeys.js b/media/video-stitcher/listCdnKeys.js new file mode 100644 index 0000000000..9ec5f97f9f --- /dev/null +++ b/media/video-stitcher/listCdnKeys.js @@ -0,0 +1,51 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location) { + // [START videostitcher_list_cdn_keys] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function listCdnKeys() { + const iterable = await stitcherClient.listCdnKeysAsync({ + parent: stitcherClient.locationPath(projectId, location), + }); + console.info('CDN keys:'); + for await (const response of iterable) { + console.log(response.name); + } + } + + listCdnKeys(); + // [END videostitcher_list_cdn_keys] +} + +// node listCdnKeys.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/listLiveAdTagDetails.js b/media/video-stitcher/listLiveAdTagDetails.js new file mode 100644 index 0000000000..1fe9d06c70 --- /dev/null +++ b/media/video-stitcher/listLiveAdTagDetails.js @@ -0,0 +1,54 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, sessionId) { + // [START videostitcher_list_live_ad_tag_details] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // sessionId = 'my-session-id'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function listLiveAdTagDetails() { + // Construct request + const request = { + parent: stitcherClient.liveSessionPath(projectId, location, sessionId), + }; + const iterable = await stitcherClient.listLiveAdTagDetailsAsync(request); + console.log('Live ad tag details:'); + for await (const response of iterable) { + console.log(response.name); + } + } + + listLiveAdTagDetails(); + // [END videostitcher_list_live_ad_tag_details] +} + +// node listLiveAdTagDetails.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/listSlates.js b/media/video-stitcher/listSlates.js new file mode 100644 index 0000000000..3a49b6bd89 --- /dev/null +++ b/media/video-stitcher/listSlates.js @@ -0,0 +1,51 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location) { + // [START videostitcher_list_slates] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function listSlates() { + const iterable = await stitcherClient.listSlatesAsync({ + parent: stitcherClient.locationPath(projectId, location), + }); + console.info('Slates:'); + for await (const response of iterable) { + console.log(response.name); + } + } + + listSlates(); + // [END videostitcher_list_slates] +} + +// node listSlates.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/listVodAdTagDetails.js b/media/video-stitcher/listVodAdTagDetails.js new file mode 100644 index 0000000000..3b80e1d2bd --- /dev/null +++ b/media/video-stitcher/listVodAdTagDetails.js @@ -0,0 +1,54 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, sessionId) { + // [START videostitcher_list_vod_ad_tag_details] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // sessionId = 'my-session-id'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function listVodAdTagDetails() { + // Construct request + const request = { + parent: stitcherClient.vodSessionPath(projectId, location, sessionId), + }; + const iterable = await stitcherClient.listVodAdTagDetailsAsync(request); + console.log('VOD ad tag details:'); + for await (const response of iterable) { + console.log(response.name); + } + } + + listVodAdTagDetails(); + // [END videostitcher_list_vod_ad_tag_details] +} + +// node listVodAdTagDetails.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/listVodStitchDetails.js b/media/video-stitcher/listVodStitchDetails.js new file mode 100644 index 0000000000..842d63fe7a --- /dev/null +++ b/media/video-stitcher/listVodStitchDetails.js @@ -0,0 +1,54 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, sessionId) { + // [START videostitcher_list_vod_stitch_details] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // sessionId = 'my-session-id'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function listVodStitchDetails() { + // Construct request + const request = { + parent: stitcherClient.vodSessionPath(projectId, location, sessionId), + }; + const iterable = await stitcherClient.listVodStitchDetailsAsync(request); + console.log('VOD stitch details:'); + for await (const response of iterable) { + console.log(response.name); + } + } + + listVodStitchDetails(); + // [END videostitcher_list_vod_stitch_details] +} + +// node listVodStitchDetails.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/package.json b/media/video-stitcher/package.json new file mode 100644 index 0000000000..cbb4283721 --- /dev/null +++ b/media/video-stitcher/package.json @@ -0,0 +1,23 @@ +{ + "name": "nodejs-video-stitcher", + "private": true, + "license": "Apache-2.0", + "author": "Google LLC", + "engines": { + "node": ">=10" + }, + "files": [ + "*.js" + ], + "scripts": { + "test": "c8 mocha --timeout 600000 test/*.js" + }, + "dependencies": { + "@google-cloud/video-stitcher": "^0.3.0" + }, + "devDependencies": { + "c8": "^7.1.0", + "chai": "^4.2.0", + "mocha": "^8.0.0" + } +} diff --git a/media/video-stitcher/test/stitcher.test.js b/media/video-stitcher/test/stitcher.test.js new file mode 100644 index 0000000000..0b63d90083 --- /dev/null +++ b/media/video-stitcher/test/stitcher.test.js @@ -0,0 +1,439 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +const path = require('path'); +const assert = require('assert'); +const {execSync} = require('child_process'); +const {describe, it, before, after} = require('mocha'); + +const bucketName = 'cloud-samples-data/media'; +const vodFileName = 'hls-vod/manifest.m3u8'; +const liveFileName = 'hls-live/manifest.m3u8'; + +const projectId = process.env.GCLOUD_PROJECT; +const location = 'us-central1'; +const slateIdPrefix = 'nodejs-test-stitcher-slate-'; +const slateUri = `https://storage.googleapis.com/${bucketName}/ForBiggerEscapes.mp4`; + +const akamaiCdnKeyIdPrefix = 'nodejs-test-stitcher-akamai-key-'; +const googleCdnKeyIdPrefix = 'nodejs-test-stitcher-google-key-'; + +const hostname = 'cdn.example.com'; +const gCdnKeyname = 'gcdn-test-key'; +const gCdnPrivateKey = 'VGhpcyBpcyBhIHRlc3Qgc3RyaW5nLg=='; +const akamaiTokenKey = 'VGhpcyBpcyBhIHRlc3Qgc3RyaW5nLg=='; + +const vodUri = `https://storage.googleapis.com/${bucketName}/${vodFileName}`; +// VMAP Pre-roll (https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags) +const vodAdTagUri = + "'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='"; +const vodSessionPrefix = `/locations/${location}/vodSessions/`; + +const liveUri = `https://storage.googleapis.com/${bucketName}/${liveFileName}`; +// Single Inline Linear (https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags) +const liveAdTagUri = + "'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='"; +const liveSessionPrefix = `/locations/${location}/liveSessions/`; + +const https = require('https'); +const cwd = path.join(__dirname, '..'); + +async function getPage(url) { + let data = ''; + return new Promise(resolve => { + https.get(url, res => { + res.on('data', chunk => { + data += chunk; + }); + res.on('end', () => { + resolve(data); + }); + }); + }); +} + +before(() => { + // Delete existing test slates more than an hour old. + + const DATE_NOW_SEC = Math.floor(Date.now() / 1000); + const ONE_HOUR_IN_SEC = 60 * 60 * 1; + + const slates = execSync(`node listSlates.js ${projectId} ${location}`, {cwd}); + + slates + .toString() + .split(/\r?\n/) + .forEach(line => { + if (line.includes(`locations/${location}/slates/${slateIdPrefix}`)) { + this.nextId = line.split('/').pop(); + let createTime = this.nextId.split('-').pop(); + createTime = parseInt(createTime); + if ( + isNaN(createTime) === false && + createTime < DATE_NOW_SEC - ONE_HOUR_IN_SEC + ) { + try { + execSync( + `node deleteSlate.js ${projectId} ${location} ${this.nextId}`, + { + cwd, + } + ); + } catch (err) { + if (err.message.includes('NOT_FOUND')) { + // Ignore not found error + } else { + throw err; // re-throw the error unchanged + } + } + } + } + }); + + // Delete existing test CDN keys + const keys = execSync(`node listCdnKeys.js ${projectId} ${location}`, {cwd}); + + keys + .toString() + .split(/\r?\n/) + .forEach(line => { + if ( + line.includes( + `locations/${location}/cdnKeys/${googleCdnKeyIdPrefix}` + ) || + line.includes(`locations/${location}/cdnKeys/${akamaiCdnKeyIdPrefix}`) + ) { + this.nextId = line.split('/').pop(); + let createTime = this.nextId.split('-').pop(); + createTime = parseInt(createTime); + if ( + isNaN(createTime) === false && + createTime < DATE_NOW_SEC - ONE_HOUR_IN_SEC + ) { + try { + execSync( + `node deleteCdnKey.js ${projectId} ${location} ${this.nextId}`, + { + cwd, + } + ); + } catch (err) { + if (err.message.includes('NOT_FOUND')) { + // Ignore not found error + } else { + throw err; // re-throw the error unchanged + } + } + } + } + }); +}); + +describe('Slate functions', () => { + before(() => { + const DATE_NOW_SEC = Math.floor(Date.now() / 1000); + this.slateId = `${slateIdPrefix}${DATE_NOW_SEC}`; + this.slateName = `/locations/${location}/slates/${this.slateId}`; + + const output = execSync( + `node createSlate.js ${projectId} ${location} ${this.slateId} ${slateUri}`, + {cwd} + ); + assert.ok(output.includes(this.slateName)); + }); + + after(() => { + const output = execSync( + `node deleteSlate.js ${projectId} ${location} ${this.slateId}`, + {cwd} + ); + assert.ok(output.includes('Deleted slate')); + }); + + it('should show a list of slates', () => { + const output = execSync(`node listSlates.js ${projectId} ${location}`, { + cwd, + }); + assert.ok(output.includes(this.slateName)); + }); + + it('should update a slate', () => { + const output = execSync( + `node updateSlate.js ${projectId} ${location} ${this.slateId} ${slateUri}`, + {cwd} + ); + assert.ok(output.includes(this.slateName)); + }); + + it('should get a slate', () => { + const output = execSync( + `node getSlate.js ${projectId} ${location} ${this.slateId}`, + {cwd} + ); + assert.ok(output.includes(this.slateName)); + }); +}); + +describe('Google CDN key functions', () => { + before(() => { + const DATE_NOW_SEC = Math.floor(Date.now() / 1000); + this.googleCdnKeyId = `${googleCdnKeyIdPrefix}${DATE_NOW_SEC}`; + this.googleCdnKeyName = `/locations/${location}/cdnKeys/${this.googleCdnKeyId}`; + + const output = execSync( + `node createCdnKey.js ${projectId} ${location} ${this.googleCdnKeyId} ${hostname} ${gCdnKeyname} ${gCdnPrivateKey} ''`, + {cwd} + ); + assert.ok(output.includes(this.googleCdnKeyName)); + }); + + after(() => { + const output = execSync( + `node deleteCdnKey.js ${projectId} ${location} ${this.googleCdnKeyId}`, + {cwd} + ); + assert.ok(output.includes('Deleted CDN key')); + }); + + it('should show a list of Google CDN keys', () => { + const output = execSync(`node listCdnKeys.js ${projectId} ${location}`, { + cwd, + }); + assert.ok(output.includes(this.googleCdnKeyName)); + }); + + it('should update a Google CDN key', () => { + const output = execSync( + `node updateCdnKey.js ${projectId} ${location} ${this.googleCdnKeyId} ${hostname} ${gCdnKeyname} ${gCdnPrivateKey} ''`, + {cwd} + ); + assert.ok(output.includes(this.googleCdnKeyName)); + }); + + it('should get a Google CDN key', () => { + const output = execSync( + `node getCdnKey.js ${projectId} ${location} ${this.googleCdnKeyId}`, + {cwd} + ); + assert.ok(output.includes(this.googleCdnKeyName)); + }); +}); + +describe('Akamai CDN key functions', () => { + before(() => { + const DATE_NOW_SEC = Math.floor(Date.now() / 1000); + this.akamaiCdnKeyId = `${akamaiCdnKeyIdPrefix}${DATE_NOW_SEC}`; + this.akamaiCdnKeyName = `/locations/${location}/cdnKeys/${this.akamaiCdnKeyId}`; + + const output = execSync( + `node createCdnKey.js ${projectId} ${location} ${this.akamaiCdnKeyId} ${hostname} '' '' ${akamaiTokenKey}`, + {cwd} + ); + assert.ok(output.includes(this.akamaiCdnKeyName)); + }); + + after(() => { + const output = execSync( + `node deleteCdnKey.js ${projectId} ${location} ${this.akamaiCdnKeyId}`, + {cwd} + ); + assert.ok(output.includes('Deleted CDN key')); + }); + + it('should show a list of Akamai CDN keys', () => { + const output = execSync(`node listCdnKeys.js ${projectId} ${location}`, { + cwd, + }); + assert.ok(output.includes(this.akamaiCdnKeyName)); + }); + + it('should update an Akamai CDN key', () => { + const output = execSync( + `node updateCdnKey.js ${projectId} ${location} ${this.akamaiCdnKeyId} ${hostname} '' '' ${akamaiTokenKey}`, + {cwd} + ); + assert.ok(output.includes(this.akamaiCdnKeyName)); + }); + + it('should get an Akamai CDN key', () => { + const output = execSync( + `node getCdnKey.js ${projectId} ${location} ${this.akamaiCdnKeyId}`, + {cwd} + ); + assert.ok(output.includes(this.akamaiCdnKeyName)); + }); +}); + +describe('VOD session functions', () => { + it('should create a VOD session', () => { + const output = execSync( + `node createVodSession.js ${projectId} ${location} ${vodUri} ${vodAdTagUri}`, + {cwd} + ); + assert.ok(output.includes(vodSessionPrefix)); + this.vodSessionId = output.toString().split('/').pop(); + this.vodSessionId = this.vodSessionId.replace(/\r?\n|\r/g, ''); + }); + + it('should get a VOD session', () => { + const output = execSync( + `node getVodSession.js ${projectId} ${location} ${this.vodSessionId}`, + {cwd} + ); + assert.ok(output.includes(`${vodSessionPrefix}${this.vodSessionId}`)); + }); + + // No list or delete methods for VOD sessions + + // Ad tag details + + it('should show a list of ad tag details for a VOD session', () => { + const output = execSync( + `node listVodAdTagDetails.js ${projectId} ${location} ${this.vodSessionId}`, + { + cwd, + } + ); + this.adTagDetailsNamePrefix = `${vodSessionPrefix}${this.vodSessionId}/vodAdTagDetails/`; + assert.ok(output.includes(this.adTagDetailsNamePrefix)); + this.vodAdTagDetailsId = output.toString().split('/').pop(); + this.vodAdTagDetailsId = this.vodAdTagDetailsId.replace(/\r?\n|\r/g, ''); + }); + + it('should get an ad tag detail', () => { + const output = execSync( + `node getVodAdTagDetail.js ${projectId} ${location} ${this.vodSessionId} ${this.vodAdTagDetailsId}`, + {cwd} + ); + assert.ok( + output.includes(`${this.adTagDetailsNamePrefix}${this.vodAdTagDetailsId}`) + ); + }); + + // Stitch details + + it('should show a list of stitch details for a VOD session', () => { + const output = execSync( + `node listVodStitchDetails.js ${projectId} ${location} ${this.vodSessionId}`, + { + cwd, + } + ); + this.stitchDetailsNamePrefix = `${vodSessionPrefix}${this.vodSessionId}/vodStitchDetails/`; + assert.ok(output.includes(this.stitchDetailsNamePrefix)); + this.stitchDetailsId = output.toString().split('/').pop(); + this.stitchDetailsId = this.stitchDetailsId.replace(/\r?\n|\r/g, ''); + }); + + it('should get a stitch detail', () => { + const output = execSync( + `node getVodStitchDetail.js ${projectId} ${location} ${this.vodSessionId} ${this.stitchDetailsId}`, + {cwd} + ); + assert.ok( + output.includes(`${this.stitchDetailsNamePrefix}${this.stitchDetailsId}`) + ); + }); +}); + +describe('Live session functions', () => { + before(() => { + const DATE_NOW_SEC = Math.floor(Date.now() / 1000); + this.slateId = `${slateIdPrefix}${DATE_NOW_SEC}`; + this.slateName = `/locations/${location}/slates/${this.slateId}`; + + const output = execSync( + `node createSlate.js ${projectId} ${location} ${this.slateId} ${slateUri}`, + {cwd} + ); + assert.ok(output.includes(this.slateName)); + }); + + after(() => { + const output = execSync( + `node deleteSlate.js ${projectId} ${location} ${this.slateId}`, + {cwd} + ); + assert.ok(output.includes('Deleted slate')); + }); + + it('should create and get a live session and list and get ad tag details', async function () { + let output = execSync( + `node createLiveSession.js ${projectId} ${location} ${liveUri} ${liveAdTagUri} ${this.slateId}`, + {cwd} + ); + assert.ok(output.includes(liveSessionPrefix)); + + let match = new RegExp('Live session:.(.*)', 'g').exec(output); + this.liveSessionId = match[1].toString().split('/').pop(); + this.liveSessionId = this.liveSessionId.replace(/\r?\n|\r/g, ''); + match = new RegExp('Play URI:.(.*)', 'g').exec(output); + this.playUri = match[1].replace(/\r?\n|\r/g, ''); + + output = execSync( + `node getLiveSession.js ${projectId} ${location} ${this.liveSessionId}`, + {cwd} + ); + assert.ok(output.includes(`${liveSessionPrefix}${this.liveSessionId}`)); + + // 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 playUri first. The last line of the response will contain a + // renditions location. Curl the live session name with the rendition + // location appended. + + let data = await getPage(this.playUri); + assert.ok(data.includes('renditions/')); + + match = new RegExp('renditions/.*', 'g').exec(data); + this.renditions = match[0].replace(/\r?\n|\r/g, ''); + + // playUri will be in the following format: + // .../projects/{project}/locations/{location}/liveSessions/{session-id}/manifest.m3u8?signature=... + // Replace manifest.m3u8?signature=... with the /renditions location. + + const arr = this.playUri.split('/'); + arr.pop(); + const str = arr.join('/'); + this.renditionsUrl = `${str}/${this.renditions}`; + data = await getPage(this.renditionsUrl); + + output = execSync( + `node listLiveAdTagDetails.js ${projectId} ${location} ${this.liveSessionId}`, + {cwd} + ); + this.liveAdTagDetailsNamePrefix = `${liveSessionPrefix}${this.liveSessionId}/liveAdTagDetails/`; + assert.ok(output.includes(this.liveAdTagDetailsNamePrefix)); + this.liveAdTagDetailsId = output.toString().split('/').pop(); + this.liveAdTagDetailsId = this.liveAdTagDetailsId.replace(/\r?\n|\r/g, ''); + + output = execSync( + `node getLiveAdTagDetail.js ${projectId} ${location} ${this.liveSessionId} ${this.liveAdTagDetailsId}`, + {cwd} + ); + assert.ok( + output.includes( + `${this.liveAdTagDetailsNamePrefix}${this.liveAdTagDetailsId}` + ) + ); + }); +}); diff --git a/media/video-stitcher/updateCdnKey.js b/media/video-stitcher/updateCdnKey.js new file mode 100644 index 0000000000..2ae161be71 --- /dev/null +++ b/media/video-stitcher/updateCdnKey.js @@ -0,0 +1,84 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main( + projectId, + location, + cdnKeyId, + hostname, + gCdnKeyname, + gCdnPrivateKey, + akamaiTokenKey = '' +) { + // [START videostitcher_update_cdn_key] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // cdnKeyId = 'my-cdn-key'; + // hostname = 'cdn.example.com'; + // gCdnKeyname = 'gcdn-key'; + // gCdnPrivateKey = 'VGhpcyBpcyBhIHRlc3Qgc3RyaW5nLg=='; + // akamaiTokenKey = 'VGhpcyBpcyBhIHRlc3Qgc3RyaW5nLg=='; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function updateCdnKey() { + // Construct request + const request = { + cdnKey: { + name: stitcherClient.cdnKeyPath(projectId, location, cdnKeyId), + hostname: hostname, + }, + }; + + if (akamaiTokenKey !== '') { + request.cdnKey.akamaiCdnKey = { + tokenKey: akamaiTokenKey, + }; + request.updateMask = { + paths: ['hostname', 'akamai_cdn_key'], + }; + } else { + request.cdnKey.googleCdnKey = { + keyName: gCdnKeyname, + privateKey: gCdnPrivateKey, + }; + request.updateMask = { + paths: ['hostname', 'google_cdn_key'], + }; + } + + const [cdnKey] = await stitcherClient.updateCdnKey(request); + console.log(`Updated CDN key: ${cdnKey.name}`); + } + + updateCdnKey(); + // [END videostitcher_update_cdn_key] +} + +// node updateCdnKey.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/video-stitcher/updateSlate.js b/media/video-stitcher/updateSlate.js new file mode 100644 index 0000000000..9b6b0aa92d --- /dev/null +++ b/media/video-stitcher/updateSlate.js @@ -0,0 +1,59 @@ +/** + * Copyright 2022, Google, Inc. + * 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. + */ + +'use strict'; + +function main(projectId, location, slateId, slateUri) { + // [START videostitcher_update_slate] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // slateId = 'my-slate'; + // slateUri = 'https://my-slate-uri/test.mp4'; + + // Imports the Video Stitcher library + const {VideoStitcherServiceClient} = + require('@google-cloud/video-stitcher').v1; + // Instantiates a client + const stitcherClient = new VideoStitcherServiceClient(); + + async function updateSlate() { + // Construct request + const request = { + slate: { + name: stitcherClient.slatePath(projectId, location, slateId), + uri: slateUri, + }, + updateMask: { + paths: ['uri'], + }, + }; + + const [slate] = await stitcherClient.updateSlate(request); + console.log(`Updated slate: ${slate.name}`); + } + + updateSlate(); + // [END videostitcher_update_slate] +} + +// node updateSlate.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2));