110 lines
3.2 KiB
JavaScript
110 lines
3.2 KiB
JavaScript
'use strict';
|
||
|
||
const util = require('util');
|
||
const request = require('request');
|
||
const cheerio = require('cheerio');
|
||
|
||
const YOUTUBE_BASE = 'https://www.youtube.com/%s';
|
||
const VIDEO_ID_REGEX = /watch\?v=([^&]*)/i;
|
||
const END_SCREEN_BASE = util.format(YOUTUBE_BASE, 'get_endscreen?v=%s');
|
||
const CARD_BASE = util.format(YOUTUBE_BASE, 'annotations_invideo?video_id=%s');
|
||
|
||
/**
|
||
* Récupère une liste des vidéos liées à la fin d’une autre vidéo.
|
||
*
|
||
* @param videoId Identifiant de la vidéo source.
|
||
* @return Liste des vidéos liées. Chaque vidéo est un objet contenant
|
||
* son identifiant (videoId) et son titre (title).
|
||
*/
|
||
const getEndScreenVideos = videoId =>
|
||
{
|
||
const url = util.format(END_SCREEN_BASE, videoId);
|
||
|
||
return new Promise((resolve, reject) =>
|
||
{
|
||
request(url, (err, res, body) =>
|
||
{
|
||
if (err)
|
||
{
|
||
reject(err);
|
||
return;
|
||
}
|
||
|
||
// Suppression des caractères initiaux inutiles si applicable
|
||
if (body.substr(0, 3) === ')]}')
|
||
{
|
||
body = body.substr(3);
|
||
}
|
||
|
||
// Interprétation du JSON
|
||
const data = JSON.parse(body);
|
||
|
||
// Aucun écran de fin
|
||
if (
|
||
typeof data !== 'object' || data === null ||
|
||
data.elements === undefined
|
||
)
|
||
{
|
||
resolve([]);
|
||
return;
|
||
}
|
||
|
||
// Filtrage des données pour extraire le titre et l’ID des vidéos
|
||
resolve(data.elements.map(elt => ({
|
||
videoId: elt.endscreenElementRenderer.endpoint
|
||
.watchEndpoint.videoId,
|
||
title: elt.endscreenElementRenderer.title.simpleText,
|
||
})));
|
||
});
|
||
});
|
||
};
|
||
|
||
exports.getEndScreenVideos = getEndScreenVideos;
|
||
|
||
/**
|
||
* Récupère une liste des vidéos liées en tant que carte d’une autre vidéo.
|
||
*
|
||
* @param videoId Identifiant de la vidéo source.
|
||
* @return Liste des vidéos liées. Chaque vidéo est un objet contenant
|
||
* son identifiant (videoId) et son titre (title).
|
||
*/
|
||
const getCardVideos = videoId =>
|
||
{
|
||
const url = util.format(CARD_BASE, videoId);
|
||
|
||
return new Promise((resolve, reject) =>
|
||
{
|
||
request(url, (err, res, body) =>
|
||
{
|
||
if (err)
|
||
{
|
||
reject(err);
|
||
return;
|
||
}
|
||
|
||
// Interprétation du XML externe et recherche des annotations
|
||
// de type carte
|
||
const nav = cheerio.load(body);
|
||
const cards = nav('annotation[type="card"][style="video"]');
|
||
const list = [];
|
||
|
||
cards.each((i, el) =>
|
||
{
|
||
// Interprétation du JSON de chaque carte, extraction
|
||
// du titre et de l’identifiant de la vidéo
|
||
const data = JSON.parse(nav(el).children('data').text());
|
||
const videoIdResults = VIDEO_ID_REGEX.exec(data.url);
|
||
|
||
list.push({
|
||
title: data.title,
|
||
videoId: videoIdResults ? videoIdResults[1] : null
|
||
});
|
||
});
|
||
|
||
resolve(list);
|
||
});
|
||
});
|
||
};
|
||
|
||
exports.getCardVideos = getCardVideos;
|