Merge pull request #487 from calzoneman/remove-yt2

Remove YouTube v2 API fallback since v2 is dead
This commit is contained in:
Erik Little 2015-06-07 13:11:09 -04:00
commit 3f79e9f858
3 changed files with 16 additions and 258 deletions

View file

@ -120,10 +120,14 @@ mail:
# YouTube v3 API key
# See https://developers.google.com/youtube/registering_an_application
# Google is closing the v2 API (which allowed anonymous requests) on
# April 20, 2015 so you must register a v3 API key now.
# NOTE: You must generate a Server key under Public API access, NOT a
# browser key.
# YouTube links will not work without this!
# Instructions:
# 1. Go to https://console.developers.google.com/project
# 2. Create a new API project
# 3. On the left sidebar, click "Credentials" under "APIs & auth"
# 4. Click "Create new Key" under "Public API access"
# 5. Click "Server key"
# 6. Under "APIs & auth" click "YouTube Data API" and then click "Enable API"
youtube-v3-key: ''
# Minutes between saving channel state to disk
channel-save-interval: 5

View file

@ -352,9 +352,8 @@ function preprocessConfig(cfg) {
require("cytube-mediaquery/lib/provider/youtube").setApiKey(
cfg["youtube-v3-key"]);
} else {
Logger.errlog.log("Warning: No YouTube v3 API key set. YouTube lookups will " +
"fall back to the v2 API, which is scheduled for closure soon after " +
"April 20, 2015. See " +
Logger.errlog.log("Warning: No YouTube v3 API key set. YouTube links will " +
"not work. See youtube-v3-key in config.template.yaml and " +
"https://developers.google.com/youtube/registering_an_application for " +
"information on registering an API key.");
}

View file

@ -66,7 +66,8 @@ var Getters = {
/* youtube.com */
yt: function (id, callback) {
if (!Config.get("youtube-v3-key")) {
return Getters.yt2(id, callback);
return callback("The YouTube API now requires an API key. Please see the " +
"documentation for youtube-v3-key in config.template.yaml");
}
@ -86,7 +87,8 @@ var Getters = {
/* youtube.com playlists */
yp: function (id, callback) {
if (!Config.get("youtube-v3-key")) {
return Getters.yp2(id, callback);
return callback("The YouTube API now requires an API key. Please see the " +
"documentation for youtube-v3-key in config.template.yaml");
}
YouTube.lookupPlaylist(id).then(function (videos) {
@ -108,7 +110,8 @@ var Getters = {
/* youtube.com search */
ytSearch: function (query, callback) {
if (!Config.get("youtube-v3-key")) {
return Getters.ytSearch2(query.split(" "), callback);
return callback("The YouTube API now requires an API key. Please see the " +
"documentation for youtube-v3-key in config.template.yaml");
}
YouTube.search(query).then(function (res) {
@ -730,254 +733,6 @@ var Getters = {
var media = new Media(id, title, "--:--", "hb");
callback(false, media);
},
/* youtube.com - old v2 API */
yt2: function (id, callback) {
var sv = Server.getServer();
var m = id.match(/([\w-]{11})/);
if (m) {
id = m[1];
} else {
callback("Invalid ID", null);
return;
}
var options = {
host: "gdata.youtube.com",
port: 443,
path: "/feeds/api/videos/" + id + "?v=2&alt=json",
method: "GET",
dataType: "jsonp",
timeout: 1000
};
if (Config.get("youtube-v2-key")) {
options.headers = {
"X-Gdata-Key": "key=" + Config.get("youtube-v2-key")
};
}
urlRetrieve(https, options, function (status, data) {
switch (status) {
case 200:
break; /* Request is OK, skip to handling data */
case 400:
return callback("Invalid request", null);
case 403:
return callback("Private video", null);
case 404:
return callback("Video not found", null);
case 500:
case 503:
return callback("Service unavailable", null);
default:
return callback("HTTP " + status, null);
}
var buffer = data;
try {
data = JSON.parse(data);
/* Check for embedding restrictions */
if (data.entry.yt$accessControl) {
var ac = data.entry.yt$accessControl;
for (var i = 0; i < ac.length; i++) {
if (ac[i].action === "embed") {
if (ac[i].permission === "denied") {
callback("Embedding disabled", null);
return;
}
break;
}
}
}
var seconds = data.entry.media$group.yt$duration.seconds;
var title = data.entry.title.$t;
var meta = {};
/* Check for country restrictions */
if (data.entry.media$group.media$restriction) {
var rest = data.entry.media$group.media$restriction;
if (rest.length > 0) {
if (rest[0].relationship === "deny") {
meta.restricted = rest[0].$t;
}
}
}
var media = new Media(id, title, seconds, "yt", meta);
callback(false, media);
} catch (e) {
// Gdata version 2 has the rather silly habit of
// returning error codes in XML when I explicitly asked
// for JSON
var m = buffer.match(/<internalReason>([^<]+)<\/internalReason>/);
if (m === null)
m = buffer.match(/<code>([^<]+)<\/code>/);
var err = e;
if (m) {
if(m[1] === "too_many_recent_calls") {
err = "YouTube is throttling the server right "+
"now for making too many requests. "+
"Please try again in a moment.";
} else {
err = m[1];
}
}
callback(err, null);
}
});
},
/* youtube.com playlists - old v2 api */
yp2: function (id, callback, url) {
/**
* NOTE: callback may be called multiple times, once for each <= 25 video
* batch of videos in the list. It will be called in order.
*/
var m = id.match(/([\w-]+)/);
if (m) {
id = m[1];
} else {
callback("Invalid ID", null);
return;
}
var path = "/feeds/api/playlists/" + id + "?v=2&alt=json";
/**
* NOTE: the third parameter, url, is used to chain this retriever
* multiple times to get all the videos from a playlist, as each
* request only returns 25 videos.
*/
if (url !== undefined) {
path = "/" + url.split("gdata.youtube.com")[1];
}
var options = {
host: "gdata.youtube.com",
port: 443,
path: path,
method: "GET",
dataType: "jsonp",
timeout: 1000
};
if (Config.get("youtube-v2-key")) {
options.headers = {
"X-Gdata-Key": "key=" + Config.get("youtube-v2-key")
};
}
urlRetrieve(https, options, function (status, data) {
switch (status) {
case 200:
break; /* Request is OK, skip to handling data */
case 400:
return callback("Invalid request", null);
case 403:
return callback("Private playlist", null);
case 404:
return callback("Playlist not found", null);
case 500:
case 503:
return callback("Service unavailable", null);
default:
return callback("HTTP " + status, null);
}
try {
data = JSON.parse(data);
var vids = [];
for(var i in data.feed.entry) {
try {
/**
* FIXME: This should probably check for embed restrictions
* and country restrictions on each video in the list
*/
var item = data.feed.entry[i];
var id = item.media$group.yt$videoid.$t;
var title = item.title.$t;
var seconds = item.media$group.yt$duration.seconds;
var media = new Media(id, title, seconds, "yt");
vids.push(media);
} catch(e) {
}
}
callback(false, vids);
var links = data.feed.link;
for (var i in links) {
if (links[i].rel === "next") {
/* Look up the next batch of videos from the list */
Getters["yp2"](id, callback, links[i].href);
}
}
} catch (e) {
callback(e, null);
}
});
},
/* youtube.com search - old v2 api */
ytSearch2: function (terms, callback) {
/**
* terms is a list of words from the search query. Each word must be
* encoded properly for use in the request URI
*/
for (var i in terms) {
terms[i] = encodeURIComponent(terms[i]);
}
var query = terms.join("+");
var options = {
host: "gdata.youtube.com",
port: 443,
path: "/feeds/api/videos/?q=" + query + "&v=2&alt=json",
method: "GET",
dataType: "jsonp",
timeout: 1000
};
if (Config.get("youtube-v2-key")) {
options.headers = {
"X-Gdata-Key": "key=" + Config.get("youtube-v2-key")
};
}
urlRetrieve(https, options, function (status, data) {
if (status !== 200) {
callback("YouTube search: HTTP " + status, null);
return;
}
try {
data = JSON.parse(data);
var vids = [];
for(var i in data.feed.entry) {
try {
/**
* FIXME: This should probably check for embed restrictions
* and country restrictions on each video in the list
*/
var item = data.feed.entry[i];
var id = item.media$group.yt$videoid.$t;
var title = item.title.$t;
var seconds = item.media$group.yt$duration.seconds;
var media = new Media(id, title, seconds, "yt");
media.thumb = item.media$group.media$thumbnail[0];
vids.push(media);
} catch(e) {
}
}
callback(false, vids);
} catch(e) {
callback(e, null);
}
});
},
};
/**