Comment télécharger les vidéos de noovo.ca simplement à l’aide d’un fureteur




Ils existent plusieurs raisons pour vouloir télécharger les fichiers vidéo plutôt que d’utiliser l’interface Web fournit par les diffuseurs de contenus. Dans mon cas bien précis, la raison est simple: la qualité de ma connexion internet à la maison est souvent fluctuante dûe à la météo. Eh oui, je suis souvent en campagne profonde et alors limité à une connexion satellitaire.

Le but: télécharger les fichiers vidéo de noovo.ca sur votre disque dur afin de pouvoir les regarder ultérieurement

Je vais expliquer ma démarche (méthode essai-erreur) utilisée pour découvrir comment télécharger les fichiers vidéo de la plateforme Web de V Télé et Musique Plus afin de pouvoir les trimbaler à sa guise. Cette démarche se fera à l’aide de Chrome uniquement, aucun autre outil nécessaire. Pourquoi Chrome? Simplement car c’est le fureteur le plus populaire en ce moment. Personnellement, j’aime mieux FireFox pour ce genre de recherche, mais bon, on s'en sacre un peu.

Notez bien que le but caché est aussi d'automatiser ce processus plus tard. Par conséquent, on va fouiller un peu plus que nécessaire afin de comprendre comment les programmeurs ont standardisé leur application.

OK, débutons!

Trouvons notre vidéo de choix et préparons-nous

  1. Choisissons une émission que j’aime bien : http://noovo.ca/emissions/ca-va-brasser/episodes.
  2. Choisissons maintenant un épisode de courte durée pour faciliter nos tests et cliquons à l’aide du bouton droit de la souris (menu contextuel) sur Ouvrir le lien dans une fenêtre en navigation privée. Nous avons donc un onglet privée avec ce lien chargé: http://noovo.ca/videos/ca-va-brasser/mousse-chocolat-et-the-kruhnen-dtpa_82975.
  3. Assurons-nous de n’avoir aucune extension qui fonctionne (comme AdBlock par exemple).
  4. Ensuite, désactivons Flash afin de limiter les protocoles utilisés pour livrer le contenu en HTTP seulement.
    1. Rendons-nous sur chrome://plugins/ dans un autre onglet.
    2. Cliquons sur Désactiver.

    Flash permet d’utiliser plusieurs autres protocoles comme par exemple RTMP qui est un peu plus complexe à télécharger.

Analysons les requêtes pour comprendre comment noovo.ca livre son contenu vidéo

Rechargeons avec la console :

  1. Revenons à notre onglet où se trouve notre épisode de choix.
  2. Ouvrons la console avec F12.
  3. Rafraichissons la page et attendons que la vidéo joue.
  4. Nous voyons maintenant toutes les requêtes effectuées par la page dans notre console.

Fouillons les requêtes pour trouver le comment du pourquoi:

  1. Nous cherchons des vidéos donc il serait judicieux de regarder si ça télécharge un format bien connu en HTTP directement. Entrons .mp4 dans le champ Filter pour isoler une requête HTTP avec un fichier MP4. Ah bon, rien du tout. Essayons avec .flv, .mpeg, .mpg. Encore rien.
  2. Nous comprenons maintenant que le site ne charge pas de fichiers vidéo entiers directement mais utilise probablement un protocole comme HLS ou Dash.
  3. Commençons par HLS et cherchons pour une playlist en filtrant cette fois-ci avec m3u8. Oh! On voit des requêtes cette fois alors ça utilise HLS par défaut. Enfin on peut avancer!
  4. Regardons maintenant le contenu et URL complet en cliquant avec le bouton droit et Open link in new tab sur le premier fichier et analysons:
    1. L’URL http://c.brightcove.com/services/mobile/streaming/index/master.m3u8?videoId=4293298759001&pubId=618566855001 nous montre que noovo.ca utilise le service de streaming vidéo de Brightcove, un service très répandu chez les diffuseurs télévisuels qui ne veulent pas gérer ça eux même.
    2. Cet URL contient aussi un videoId 4293298759001. Aucune idée pour le moment d’où ça vient.
    3. Le contenu du fichier nous dévoile le même videoId 4293298759001, quelques assetId et surtout que le vidéo nous est offert en 4 résolutions et bitrate différents:
      #EXTM3U
      #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=264000,RESOLUTION=416x232
      http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=4293365253001&pubId=618566855001&videoId=4293298759001
      #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=40000
      http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=4293364503001&pubId=618566855001&videoId=4293298759001
      #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=464000,RESOLUTION=416x232
      http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=4293365786001&pubId=618566855001&videoId=4293298759001
      #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=664000,RESOLUTION=640x360
      http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=4293388608001&pubId=618566855001&videoId=4293298759001
      #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1064000,RESOLUTION=960x540
      http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=4293379212001&pubId=618566855001&videoId=4293298759001
      #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1664000,RESOLUTION=1280x720
      http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=4293375897001&pubId=618566855001&videoId=4293298759001

Fouillons un peu plus pour localiser le contenu voulu:

  1. Regardons comment le site fait pour obtenir le videoId de Brightcove car c’est avec cet ID que nous pourrons surement obtenir de l’information sur les fichiers complets disponibles.

    On peut toujours télécharger des fragments HLS et les recombiner avec FFmpeg mais c’est toujours plus simple de trouver les fichiers mp4 complets directement. La paresse, c'est excellent pour l'automatisation.
  2. Regardons donc le contenu de la page (source HTML) en utilisant CTRL-U, et cherchons pour 4293298759001. Rien.

    Si la page n’a aucun videoId dans sa source c’est probablement que Javascript l’obtient grâce à un API. Les programmeurs vont souvent essayer de simplifier leur vie en créant ces API fournissant de l’information à plusieurs sources mais provenant d’un seul système standardisé.
  3. Cherchons donc pour une requête dans la console qui contient api, filtrons pour ce texte et regardons les requêtes de type xhr (XMLHttpRequest). Oh, nous voyons un URL intéressant: http://api.noovo.ca/api/v1/pages/single-episode/ca-va-brasser/mousse-chocolat-et-the-kruhnen-dtpa_82975.
  4. Premièrement, ce qui saute aux yeux est la structure finale de l’URL qui est la même que la page sur laquelle on est présentement. Excellent ça! Ça va bien s’automatiser si on en a besoin.
  5. Deuxièmement, en regardant son contenu de format JSON, on s’aperçoit que le videoID 4293298759001 ici appelé brightcoveId s’y retrouve:
    {
       "status":"success",
       "data":{
          "createdAt":"2016-09-09T20:07:39.338Z",
          "slug":"mousse-chocolat-et-the-kruhnen-dtpa_82975",
          "show":{
             "slug":"ca-va-brasser",
             "title":"Ça va brasser!",
             "productionType":"produite",
             "url":"",
             "webtv":false,
             "id":"57c0a8c45f26ffcc4312653b"
          },
          "publishDate":"2015-06-15T19:51:00.000Z",
          "contentType":2,
          "title":"Mousse chocolat et thé | Kruhnen (DTPA)",
          "brightcoveId":"4293298759001",
          "description":"",
          "duration":147,
          "source":"vtele",
          "image":{
             "width":680,
             "height":382,
             "mediaType":"image",
             "trackingPixel":"",
             "credits":"",
             "caption":"",
             "url-home-slideshow":"http://api.noovo.ca/api/v1/medias/57d3168b898c0d9d322e259e.jpg/home-slideshow",
             "url-web-avatar":"http://api.noovo.ca/api/v1/medias/57d3168b898c0d9d322e259e.jpg/web-avatar",
             "url-page-header":"http://api.noovo.ca/api/v1/medias/57d3168b898c0d9d322e259e.jpg/page-header",
             "url-list-thumbnail":"http://api.noovo.ca/api/v1/medias/57d3168b898c0d9d322e259e.jpg/list-thumbnail",
             "url-list":"http://api.noovo.ca/api/v1/medias/57d3168b898c0d9d322e259e.jpg/list",
             "url":"http://api.noovo.ca/api/v1/medias/57d3168b898c0d9d322e259e.jpg",
             "id":"57d3168b898c0d9d322e259e"
          },
          "themes":[
             {
                "title":"Cuisine",
                "slug":"cuisine",
                "subthemes":[
    
                ],
                "color":"#01665e",
                "id":"56defbc7ee05300c05caddd4"
             }
          ],
          "viewsCount":148,
          "featuredDate":null,
          "featured":false,
          "popularity":-1,
          "popularity_monthly":-1,
          "moods":[
             "571e73efc2a8524e30b93481",
             "56def5664b4804c660c6bd80",
             "56def5664b4804c660c6bd7c"
          ],
          "tags":[
    
          ],
          "publishState":"prod",
          "expireSoon":false,
          "deletedFromBrightcove":false,
          "id":"57d3168bc9a67a8d32428d0c"
       }
    }

On a désormais l’information sur comment le vidéo est diffusé, par quel service, et comment trouver son identifiant unique. C'est probablement suffisant pour obtenir l'information voulue chez Brightcove.

Découvrons comment obtenir les fichiers disponibles

Brightcove fournit un API à ses clients comme à peu près tout le monde offrant un service de type SaaS. En cherchant sur google  brightcove api , on peut facilement trouver sa documentation. Un des liens intéressants est celui-ci: Accessing Video Content with the Media API.

Dans cette section de la documentation, on lit que pour obtenir l’information voulue sur le contenu vidéo, nous pouvons utiliser un URL ayant une structure comme celle-ci:

http://api.brightcove.com/services/library?command=find_video_by_id&video_id=1520880903001&video_fields=name,length,FLVURL&media_delivery=http&token=jskS1rEtQHy9exQKoc14IcMq8v5x2gCP6yaB7d0hraRtO__6HUuxMg..

Super, on a déjà le videoId. Le token lui, pas encore. Essayons donc de le trouver gràce à google, on peut toujours être chanceux :

  1. Cherchons pour  noovo api.brightcove.com find_video_by_id media_delivery token . Rien.
  2. Ah, peut-être on peut essayer avec le vieux nom  vtélé . Cherchons alors pour  vtele api.brightcove.com find_video_by_id media_delivery token . Encore rien.
  3. Allons voir sur GitHub. Peut-être quelqu’un a déjà créé un addon pour une platforme comme Kodi d'où on pourra extirper de l’information : https://github.com/search?utf8=%E2%9C%93&q=noovo+brightcove. Humm, non.

    Kodi, anciennement appelé XBMC, est bien connu pour avoir une panoplie de addons non-officiels permettant de visualiser des vidéos de plusieurs platformes de diffusion sans quitter son interface. Tout est open-source et utilise python donc c'est facile d'y trouver de l'information.
  4. Ah, essayons encore avec vtele cette fois: https://github.com/search?utf8=%E2%9C%93&q=vtele+brightcove. Oh! Il n’y a pas de code disponible mais un Issue a été créé : https://github.com/spmjc/plugin.video.freplay/issues/52.
  5. En regardant cet Issue en question, on peut voir ce magnifique token: 2sgr1KCsKKJXcqUFQdti_mXZAhdNB-wCFwCbGW6lz5atwI1QTrElxQ.. BINGO!

    Comment cette personne a trouvé le token en question n’est pas crucial pour le moment mais pour ceux qui se le demande... Il est possible de l’obtenir en utilisant un appareil mobile (tel qu’un iPad par exemple) et de monitorer les requêtes effectuées à l’aide d’un proxy. Le développement d’applications mobiles contraint souvent les développeurs à oublier les requêtes serveur-à-serveur cachant habituellement ce genre d’information afin d’être plus efficace à l’exécution.

Obtenons les fichiers vidéos

Maintenant que nous avons le token et le videoId, en théorie, nous pouvons obtenir l’information de Brightcove sur les vidéos disponibles.

Essayons donc avec cet URL:

http://api.brightcove.com/services/library?command=find_video_by_id&video_id=4293298759001&video_fields=name,length,FLVURL&media_delivery=http&token=2sgr1KCsKKJXcqUFQdti_mXZAhdNB-wCFwCbGW6lz5atwI1QTrElxQ..

Oh yeah! On obtient quelque chose de bien intéressant:

{
   "name":"Mousse chocolat et thé | Kruhnen (DTPA)",
   "length":146588,
   "FLVURL":"http:\/\/uds.ak.o.brightcove.com\/618566855001\/618566855001_4293368125001_4293298759001.mp4"
}

On a donc un appel API permettant d’obtenir un URL nous laissant télécharger un video en HTTP. Ceci dit, nous n’avons qu’un seul choix et non pas les 4 qualités (bitrate+résolution) précédemment détectées. Il nous faut donc comprendre quel appel exact faire à l’API de Brightcove pour obtenir ceux-ci.

En regardant d'un peu plus près la documentation (http://docs.brightcove.com/en/video-cloud/media/references/reference.html#Video_Read), on nous dit qu’on peut choisir les champs utilisés, et un de ceux-ci est renditions.

C’est exactement ce que l’on a besoin, alors essayons cet URL:

https://api.brightcove.com/services/library?video_fields=renditions&media_delivery=HTTP&command=find_video_by_id&video_id=4293298759001&token=2sgr1KCsKKJXcqUFQdti_mXZAhdNB-wCFwCbGW6lz5atwI1QTrElxQ..

Ataboy!! Finalement on a nos 4 choix au format MP4 dans cette réponse JSON:

{
   "renditions":[
      {
         "audioOnly":false,
         "controllerType":"DEFAULT",
         "displayName":"CVB150615_11h00_s04e03.mov",
         "encodingRate":1148856,
         "frameHeight":404,
         "frameWidth":720,
         "id":4293368136001,
         "referenceId":null,
         "remoteStreamName":null,
         "remoteUrl":null,
         "size":21214406,
         "uploadTimestampMillis":1434138086274,
         "url":"http:\/\/uds.ak.o.brightcove.com\/618566855001\/618566855001_4293368136001_4293298759001.mp4",
         "videoCodec":"H264",
         "videoContainer":"MP4",
         "videoDuration":146588
      },
      {
         "audioOnly":false,
         "controllerType":"DEFAULT",
         "displayName":"CVB150615_11h00_s04e03.mov",
         "encodingRate":780856,
         "frameHeight":360,
         "frameWidth":640,
         "id":4293368125001,
         "referenceId":null,
         "remoteStreamName":null,
         "remoteUrl":null,
         "size":14468970,
         "uploadTimestampMillis":1434138082765,
         "url":"http:\/\/uds.ak.o.brightcove.com\/618566855001\/618566855001_4293368125001_4293298759001.mp4",
         "videoCodec":"H264",
         "videoContainer":"MP4",
         "videoDuration":146588
      },
      {
         "audioOnly":false,
         "controllerType":"DEFAULT",
         "displayName":"CVB150615_11h00_s04e03.mov",
         "encodingRate":1748856,
         "frameHeight":720,
         "frameWidth":1280,
         "id":4293368099001,
         "referenceId":null,
         "remoteStreamName":null,
         "remoteUrl":null,
         "size":32161904,
         "uploadTimestampMillis":1434138079650,
         "url":"http:\/\/uds.ak.o.brightcove.com\/618566855001\/618566855001_4293368099001_4293298759001.mp4",
         "videoCodec":"H264",
         "videoContainer":"MP4",
         "videoDuration":146588
      },
      {
         "audioOnly":false,
         "controllerType":"DEFAULT",
         "displayName":"CVB150615_11h00_s04e03.mov",
         "encodingRate":512856,
         "frameHeight":268,
         "frameWidth":480,
         "id":4293368106001,
         "referenceId":null,
         "remoteStreamName":null,
         "remoteUrl":null,
         "size":9565066,
         "uploadTimestampMillis":1434138079982,
         "url":"http:\/\/uds.ak.o.brightcove.com\/618566855001\/618566855001_4293368106001_4293298759001.mp4",
         "videoCodec":"H264",
         "videoContainer":"MP4",
         "videoDuration":146588
      }
   ]
}

Téléchargons

On a pas mal fini là, on peut simplement télécharger n'importe quel de ces liens HTTP. Par exemple, si nous allons sur cet URL:

http://uds.ak.o.brightcove.com/618566855001/618566855001_4293368106001_4293298759001.mp4
Nous pouvons télécharger en utilisant CTRL-S et fermer l'onglet une fois le téléchargement entâmé.