Gestion des clips

Dans cette rubrique, vous apprendrez comment gérer des clips vidéo à l'aide de l'API CMS.

Introduction

Les clips sont des vidéos créées à partir de segments d'autres vidéos générés par Réseau social de Brightcove et d'autres outils. Si les clips sont créés pour être partagés via Brightcove Social, vous souhaiterez peut-être supprimer leurs rendus pour réduire votre stockage géré et/ou les désactiver pour les empêcher d'apparaître dans vos workflows vidéo.

Recherche d'extraits

Il existe des termes de recherche spéciaux pour vous aider CMS API à localiser des clips dans votre compte :

  • q=%2Bis_clip:true- ne renvoie que des clips
  • q=%2Dis_clip:true- renvoie uniquement les non-clips
  • q=%2Bis_clip:false- renvoie uniquement les non-clips (fonctionnellement identique à l'élément précédent)
  • q=%2Bclip_source_video_id: video_id - renvoie les clips générés à partir de la vidéo spécifiée

échantillon

Requête

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

Réponse

  [
    {
      "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": "https://brightcove.vo.llnwd.net/v1/unsecured/media/57838016001/201612/2025/57838016001_5235341448001_5235328819001-th.jpg?pubId=57838016001&videoId=5235328819001",
          "sources": [
            {
              "src": "https://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": "https://brightcove.vo.llnwd.net/v1/unsecured/media/57838016001/201612/2025/57838016001_5235339121001_5235328819001-vs.jpg?pubId=57838016001&videoId=5235328819001",
          "sources": [
            {
              "src": "https://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": "https://brightcove.vo.llnwd.net/v1/unsecured/media/57838016001/201612/1897/57838016001_5235339124001_5235312567001-th.jpg?pubId=57838016001&videoId=5235312567001",
          "sources": [
            {
              "src": "https://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": "https://brightcove.vo.llnwd.net/v1/unsecured/media/57838016001/201612/1897/57838016001_5235341824001_5235312567001-vs.jpg?pubId=57838016001&videoId=5235312567001",
          "sources": [
            {
              "src": "https://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"
    }
  ]

Supprimer des éléments

Si vous n'envisagez pas d'utiliser vos clips à d'autres fins que de les partager sur des sites de médias sociaux, vous souhaiterez peut-être réduire votre stockage géré en en supprimant les actifs. En termes de stockage, les rendus font la plus grande différence, mais vous pouvez également supprimer les affiches et les vignettes, si vous le souhaitez (cela aiderait également à identifier les clips dans Studio comme n'étant pas des vidéos à usage général).

Pour supprimer des éléments, vous utiliserez les points de terminaison des actifs de l'API CMS. La logique est simple : OBTENIR d'abord les ressources pour récupérer leurs identifiants dans le système Video Cloud, puis SUPPRIMER :

Logique de suppression des rendus
Logique de suppression des rendus

Habituellement, il n'y aura qu'une seule affiche et une seule vignette à supprimer, mais il y aura généralement plusieurs rendus, donc si vous voulez le faire par programme, vous devrez parcourir le tableau d'objets renvoyé par la demande de rendus GET et supprimer le rendus un par un. Vous trouverez ci-dessous les points de terminaison API pertinents et quelques exemples de code (JavaScript + un proxy écrit en PHP pour effectuer les requêtes API) pour effectuer les tâches de suppression des actifs.

Points de terminaison d'actifs

Voici les points de terminaison d'actifs pertinents dont vous aurez besoin pour supprimer des actifs. Pour tous ces points de terminaison, l'URL de base est :

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

Formats associés

OBTENIR des rendus

  /account_id/videos/video_id/assets/renditions

SUPPRIMER un rendu

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

Affiches

OBTENIR des affiches

  /account_id/videos/video_id/assets/poster

SUPPRIMER une affiche

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

Vignettes

OBTENIR des miniatures

  /account_id/videos/video_id/assets/thumbnail

SUPPRIMER une vignette

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

Exemple d'application

Vous trouverez ci-dessous un exemple de code pour une application qui trouve tous les clips d'un compte, puis supprime tous les rendus, ainsi que l'affiche et la vignette de chaque 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));
  }

Procuration