support Contact Support | system status System Status
Page Contents

    Managing Clips

    In this topic, you will learn how to manage video clips using the CMS API.

    Introduction

    Clips are videos created from segments of other videos generated by Brightcove Social and other tools. If the clips are created for sharing via Brightcove Social, you may wish to remove their renditions to reduce your managed storage and/or disable them to prevent them from showing up in your video workflows.

    Finding clips

    There are special search terms for the CMS API to help you locate clips in your account:

    • q=%2Bis_clip:true - returns only clips
    • q=%2Dis_clip:true - returns only non-clips
    • q=%2Bis_clip:false - returns only non-clips (functionally identical to the previous item)
    • q=%2Bclip_source_video_id: video_id - returns clips generated from the specified video

    Sample

    Request

      https://cms.api.brightcove.com/v1/accounts/57838016001/videos?q=%2Bis_clip:true

    Response

      [
        {
          "id": "5235328819001",
          "account_id": "57838016001",
          "ad_keys": null,
          "clip_source_video_id": "4752143002001",
          "complete": true,
          "created_at": "2016-12-04T17:06:20.562Z",
          "cue_points": [],
          "custom_fields": {
            "subject": "Birds"
          },
          "delivery_type": "static_origin",
          "description": null,
          "digital_master_id": "5235339325001",
          "duration": 24042,
          "economics": "AD_SUPPORTED",
          "folder_id": null,
          "geo": null,
          "has_digital_master": true,
          "images": {
            "thumbnail": {
              "asset_id": "5235341448001",
              "remote": false,
              "src": "http://brightcove.vo.llnwd.net/v1/unsecured/media/57838016001/201612/2025/57838016001_5235341448001_5235328819001-th.jpg?pubId=57838016001&videoId=5235328819001",
              "sources": [
                {
                  "src": "http://brightcove.vo.llnwd.net/v1/unsecured/media/57838016001/201612/2025/57838016001_5235341448001_5235328819001-th.jpg?pubId=57838016001&videoId=5235328819001",
                  "height": 90,
                  "width": 160
                },
                {
                  "src": "https://brightcove.hs.llnwd.net/v2/unsecured/media/57838016001/201612/2025/57838016001_5235341448001_5235328819001-th.jpg?pubId=57838016001&videoId=5235328819001",
                  "height": 90,
                  "width": 160
                }
              ]
            },
            "poster": {
              "asset_id": "5235339121001",
              "remote": false,
              "src": "http://brightcove.vo.llnwd.net/v1/unsecured/media/57838016001/201612/2025/57838016001_5235339121001_5235328819001-vs.jpg?pubId=57838016001&videoId=5235328819001",
              "sources": [
                {
                  "src": "http://brightcove.vo.llnwd.net/v1/unsecured/media/57838016001/201612/2025/57838016001_5235339121001_5235328819001-vs.jpg?pubId=57838016001&videoId=5235328819001",
                  "height": 360,
                  "width": 640
                },
                {
                  "src": "https://brightcove.hs.llnwd.net/v2/unsecured/media/57838016001/201612/2025/57838016001_5235339121001_5235328819001-vs.jpg?pubId=57838016001&videoId=5235328819001",
                  "height": 360,
                  "width": 640
                }
              ]
            }
          },
          "link": null,
          "long_description": null,
          "name": "greatblueheron.mp4 - Clip-2016-12-04",
          "original_filename": "2efadac9-8e36-423c-b988-afcf2cd23c49.mov",
          "projection": null,
          "published_at": "2016-12-04T17:06:20.562Z",
          "reference_id": null,
          "schedule": null,
          "sharing": null,
          "state": "ACTIVE",
          "tags": [
            "newtag"
          ],
          "text_tracks": [],
          "updated_at": "2016-12-04T17:08:41.944Z"
        },
        {
          "id": "5235312567001",
          "account_id": "57838016001",
          "ad_keys": null,
          "clip_source_video_id": "5220368996001",
          "complete": true,
          "created_at": "2016-12-04T17:07:58.450Z",
          "cue_points": [],
          "custom_fields": {
            "subject": "Birds"
          },
          "delivery_type": "static_origin",
          "description": "Mother and child owls...",
          "digital_master_id": "5235341452001",
          "duration": 39253,
          "economics": "AD_SUPPORTED",
          "folder_id": null,
          "geo": null,
          "has_digital_master": true,
          "images": {
            "thumbnail": {
              "asset_id": "5235339124001",
              "remote": false,
              "src": "http://brightcove.vo.llnwd.net/v1/unsecured/media/57838016001/201612/1897/57838016001_5235339124001_5235312567001-th.jpg?pubId=57838016001&videoId=5235312567001",
              "sources": [
                {
                  "src": "http://brightcove.vo.llnwd.net/v1/unsecured/media/57838016001/201612/1897/57838016001_5235339124001_5235312567001-th.jpg?pubId=57838016001&videoId=5235312567001",
                  "height": 90,
                  "width": 160
                },
                {
                  "src": "https://brightcove.hs.llnwd.net/v2/unsecured/media/57838016001/201612/1897/57838016001_5235339124001_5235312567001-th.jpg?pubId=57838016001&videoId=5235312567001",
                  "height": 90,
                  "width": 160
                }
              ]
            },
            "poster": {
              "asset_id": "5235341824001",
              "remote": false,
              "src": "http://brightcove.vo.llnwd.net/v1/unsecured/media/57838016001/201612/1897/57838016001_5235341824001_5235312567001-vs.jpg?pubId=57838016001&videoId=5235312567001",
              "sources": [
                {
                  "src": "http://brightcove.vo.llnwd.net/v1/unsecured/media/57838016001/201612/1897/57838016001_5235341824001_5235312567001-vs.jpg?pubId=57838016001&videoId=5235312567001",
                  "height": 540,
                  "width": 960
                },
                {
                  "src": "https://brightcove.hs.llnwd.net/v2/unsecured/media/57838016001/201612/1897/57838016001_5235341824001_5235312567001-vs.jpg?pubId=57838016001&videoId=5235312567001",
                  "height": 540,
                  "width": 960
                }
              ]
            }
          },
          "link": null,
          "long_description": null,
          "name": "Great Horned Owl - Clip-2016-12-04",
          "original_filename": "c0640095-e696-41ea-8e7e-2ebf4d090d69.mov",
          "projection": null,
          "published_at": "2016-12-04T17:07:58.450Z",
          "reference_id": null,
          "schedule": null,
          "sharing": null,
          "state": "ACTIVE",
          "tags": [
            "bird",
            "nature",
            "air"
          ],
          "text_tracks": [],
          "updated_at": "2016-12-04T17:09:16.967Z"
        }
      ]

    Removing Assets

    If you are not going to use your clips for any other purpose than sharing the to social media sites, you may wish to reduce your managed storage by removing assets from them. In terms of storage, the renditions make the most difference, but you can remove posters and thumbnails as well, if you wish (this would also help to identify the clips in Studio as not being videos for general use).

    To remove assets, you will use the asset endpoints of the CMS API. The logic is simple: first GET the assets to retrieve their ids in the Video Cloud system, and then DELETE them:

    Logic for Removing Rendtions
    Logic for Removing Renditions

    Usually there will be only a single poster and thumbnail to delete, but there will generally be multiple renditions, so if you are going to do this programmatically, you will need to loop over the array of objects returned by the GET renditions request and delete the renditions one by one. Below are the relevant API endpoints and some sample code (JavaScript + a proxy written in PHP to make the API requests) to perform the tasks of removing the assets.

    Asset endpoints

    Here are the relevant asset endpoints you will need to remove assets. For all these endpoints, the base URL is:

      https://cms.api.brightcove.com/v1/accounts

    Renditions

    GET renditions

      /account_id/videos/video_id/assets/renditions

    DELETE a rendition

      /account_id/videos/video_id/assets/renditions/rendition_id

    Posters

    GET posters

      /account_id/videos/video_id/assets/poster

    DELETE a poster

      /account_id/videos/video_id/assets/poster/poster_id

    Thumbnails

    GET thumbnails

      /account_id/videos/video_id/assets/thumbnail

    DELETE a thumbnail

      /account_id/videos/video_id/assets/thumbnail/thumbnail_id

    Sample app

    Below is sample code for an app that finds all the clips in an account and then removes all renditions, as well as the poster and thumbnail for each clip.

    HTML

      <fieldset>
          <legend>Inputs</legend>
          <p>Account id: <input type="text" name="account_id" id="account_id" value=""></p>
          <p>Client id: <input type="text" name="client_id" id="client_id" value=""></p>
          <p>Client secret: <input type="text" name="client_secret" id="client_secret" value=""></p>
          <p><button id="goBtn">Remove all clip assets</button></p>
      </fieldset>
      <h2>Results</h2>
      <pre id="status"></pre>

    JavaScript

      var BCLS = (function (window, document) {
        /**
         * this scripts assumes that HTML elements with ids shown
         * in the following assignments exist in the page that
         * calls this script.
         * Alternatively, store the client_id and client_secret
         * in the proxy (NOT in a client-side script!)
         * and the account_id value here
         */
        var account_id      = document.getElementById('account_id'),
            client_id       = document.getElementById('client_id'),
            client_secret   = document.getElementById('client_secret'),
            status          = document.getElementById('status'),
            goBtn           = document.getElementById('goBtn'),
            videoCount      = 0,
            videoNumber     = 0,
            totalCalls      = 0,
            callNumber      = 0,
            renditionNumber = 0,
            videoData       = [],
            renditionData   = [],
            posterData      = {},
            thumbnailData   = {};
      
        /**
         * sets up all API requests and handles the responses
         * @param {String} type the request type
         */
        function setUpRequest(type) {
            var baseURL = 'https://cms.api.brightcove.com/v1/accounts',
                endpoint,
                responseDecoded,
                // recommended limit value for best performance with CMS API
                limit   = 25,
                options = {};
            options.client_id = (client_id.value) ? client_id.value : null;
            options.client_secret = (client_secret.value) ? client_secret.value : null;
      
            switch (type) {
                // get a count of clips
                case 'getCount':
                    endpoint = '/' + account_id.value + '/counts/videos?q=%2Bis_clip:true';
                    options.url = baseURL + endpoint;
                    options.requestType = 'GET';
                    makeRequest(options, function(response) {
                        if (response) {
                            responseDecoded = JSON.parse(response);
                            videoCount = parseInt(responseDecoded.count);
                            // calculate total calls needed to get the video clips
                            totalCalls = Math.ceil(videoCount / limit);
                            setUpRequest('getVideoClips');
                        }
                    });
                    break;
                // retrieve the clips
                case 'getVideoClips':
                    endpoint = '/' + account_id.value + '/videos?q=%2Bis_clip:true&limit=' + limit + '&offset=' + (limit * callNumber);
                    options.url = baseURL + endpoint;
                    options.requestType = 'GET';
                    makeRequest(options, function(response) {
                        if (response) {
                            responseDecoded = JSON.parse(response);
                            // add new clips to videoData array
                            videoData.push.apply(videoData, responseDecoded);
                        }
                        // increment the call number
                        callNumber++;
                        // are we done?
                        if (callNumber < totalCalls) {
                            // get the next batch
                            setUpRequest('getVideoClips');
                        } else {
                            // got all the clips
                            // update status
                            status.textContent =+ videoData.length + ' video clips found \n';
                            // reset the callNumber
                            callNumber = 0;
                            setUpRequest('getRenditions');
                        }
                    });
                    break;
                case 'getRenditions':
                    endpoint = '/' + account_id.value + '/videos/' + videoData[videoNumber].id + '/assets/renditions';
                    options.url = baseURL + endpoint;
                    options.requestType = 'GET';
                    // update status
                    status.textContent =+ 'fetching renditions for clip ' + videoData[callNumber].name + ' \n';
                    makeRequest(options, function(response) {
                      if (response) {
                          responseDecoded = JSON.parse(response);
                          renditionData = responseDecoded;
                          // update status
                          status.textContent =+ renditionData.length + ' renditions found for clip ' + videoData[callNumber].name + ' \n';
                          if (renditionData.length > 0) {
                              setUpRequest('deleteRendition');
                          } else {
                              setUpRequest('getPoster');
                          }
                      } else {
                          // no renditions
                          status.textContent =+ 'no renditions found for clip number ' + videoData[callNumber].name + ' \n';
                          setUpRequest('getPoster');
                      }
                    });
                    break;
                case 'deleteRendition':
                    endpoint = '/' + account_id.value + '/videos/' + videoData[videoNumber].id + '/assets/renditions/' + renditionData[renditionNumber].id;
                    options.url = baseURL + endpoint;
                    options.requestType = 'DELETE';
                    makeRequest(options, function(response) {
                      // there should be no response unless there was an error
                      if (response) {
                          status.textContent += 'Delete rendition response: ' + response + ' \n';
                          // keep going anyway
                          renditionNumber++;
                          if (renditionNumber < renditionData.length) {
                              setUpRequest('deleteRendition');
                          } else {
                              // done with renditions, do poster
                              setUpRequest('getPoster');
                          }
                      } else {
                          status.textContent += 'Rendition deleted for ' + videoData[callNumber].name + '\n';
                          renditionNumber++;
                          // check to see if there are more renditions
                          if (renditionNumber < renditionData.length) {
                              setUpRequest('deleteRendition');
                          } else {
                              // do the poster
                              setUpRequest('getPoster');
                          }
                      }
                    });
                    break;
                case 'getPoster':
                    endpoint = '/' + account_id.value + '/videos/' + videoData[videoNumber].id + '/assets/poster';
                    options.url = baseURL + endpoint;
                    options.requestType = 'GET';
                    makeRequest(options, function(response) {
                      if (response) {
                          posterData = JSON.parse(response);
                          setUpRequest('deletePoster');
                      } else {
                          // no poster, do the thumbail
                          setUpRequest('getThumbnail');
                      }
                    });
                    break;
                case 'deletePoster':
                    endpoint = '/' + account_id.value + '/videos/' + videoData[videoNumber].id + '/assets/poster/' + posterData.id;
                    options.url = baseURL + endpoint;
                    options.requestType = 'DELETE';
                    makeRequest(options, function(response) {
                      // no response unless something went wront
                      if (response) {
                          status.textContent += 'Delete poster response: ' + response + ' \n';
                          // try thumbnail anyway
                          setUpRequest('getThumbnail');
                      } else {
                          // success; do thumbnail
                          status.textContent += 'Poster deleted for ' + videoData[callNumber].name + ' \n';
                          setUpRequest('getThumbnail');
                      }
                     });
                    break;
                case 'getThumbnail':
                    endpoint = '/' + account_id.value + '/videos/' + videoData[callNumber].id + '/assets/thumbnail';
                    options.url = baseURL + endpoint;
                    options.requestType = 'GET';
                    makeRequest('options', function(response) {
                      if (response) {
                          thumbnailData = JSON.parse(response);
                          setUpRequest('deleteThumbnail');
                      } else {
                          // if no thumbnail, go on
                          videoNumber++;
                          if (videoNumber < videoCount) {
                              setUpRequest('getRenditions');
                          } else {
                              // done
                              status.textContent += 'Finished!';
                          }
                      }
                    });
                    break;
                case 'deleteThumbnail':
                    endpoint = '/' + account_id.value + '/videos/' + videoData[videoNumber].id + '/assets/thumbnail/' + thumbnailData.id;
                    options.url = baseURL + endpoint;
                    options.requestType = 'DELETE';
                    makeRequest(options, function(response) {
                      // no response unless something went wrong
                      if (response) {
                          status.textContent += 'Delete thumbnail response: ' + response + ' \n';
                          // do next video anyway if any
                          videoNumber++;
                          if (videoNumber < videoCount) {
                              setUpRequest('getRenditions');
                          } else {
                              // done
                              status.textContent += 'Finished!';
                          }
                      } else {
                          // success
                          status.textContent += 'Thumbnail deleted for ' + videoData[callNumber].name + ' \n';
                          // do next video if any
                          videoNumber++;
                          if (videoNumber < videoCount) {
                              setUpRequest('getRenditions');
                          } else {
                              // done
                              status.textContent += 'Finished!';
                          }
                      }
                    });
                    break;
                default:
                  if (console) {
                      console.log('default case: we should not be here');
                  }
            }
        }
      
        /**
         * send API request to the proxy
         * @param  {Object} requestData options for the request
         * @param  {Function} [callback] callback function
         */
        function makeRequest(options, callback) {
          var httpRequest = new XMLHttpRequest(),
            response,
            requestParams,
            dataString,
            proxyURL = 'https://solutions.brightcove.com/bcls/bcls-proxy/clips-proxy.php',
            // response handler
            getResponse = function() {
              try {
                if (httpRequest.readyState === 4) {
                    if (httpRequest.status >= 200 && httpRequest.status < 300) {
                      response = httpRequest.responseText;
                      console.log('raw response', response);
                      // some API requests return '{null}' for empty responses - breaks JSON.parse
                      if (response === '{null}') {
                        response = null;
                      }
                      // return the response
                      callback(response);
                    } else {
                      alert('There was a problem with the request. Request returned ' + httpRequest.status);
                    }
                  }
                } catch (e) {
                  alert('Caught Exception: ' + e);
                }
              };
        /**
         * set up request data
         * the proxy used here takes the following request body:
         * JSON.stringify(options)
         */
        // set response handler
        httpRequest.onreadystatechange = getResponse;
        // open the request
        httpRequest.open('POST', proxyURL);
        // set headers if there is a set header line, remove it
        // open and send request
        httpRequest.send(JSON.stringify(options));
      }

    Proxy


    Page last updated on 28 Sep 2020