Add youtube to results, persist to mongo

This commit is contained in:
Jonathan Cremin 2014-12-05 16:26:01 +00:00
parent d675ac4e9f
commit f20fecf0d0
7 changed files with 125 additions and 31 deletions

View file

@ -19,6 +19,5 @@ This is in super early development and is incapable of handling getting dugg, ne
On the immediate todo list:
* Use album release year for additional sanity check on matches
* Maybe drop everything from the first left-hand bracket in album names to improve matches **after** failing to get a good match
* Handle expected and unexpected errors better than the current crash-fest
* Add some kind of persistence or caching so it could take a pummeling and not get me banned from the various services

14
app.js
View file

@ -8,6 +8,7 @@ var session = require('express-session');
var cookieParser = require('cookie-parser');
var flash = require('connect-flash');
var bodyParser = require('body-parser');
var pmongo = require('promised-mongo');
var search = require('./routes/search');
var share = require('./routes/share');
@ -34,6 +35,19 @@ app.use(session({
app.use(flash());
app.use(express.static(path.join(__dirname, 'public')));
var db;
if (process.env.MONGOHQ_URL) {
console.log("Connecting to MongoHQ")
db = pmongo(process.env.MONGOHQ_URL, ['matches']);
} else {
db = pmongo('match-audio', ['matches']);
}
app.use(function(req, res, next) {
req.db = res.db = db;
next();
})
// force SSL
app.get('*', function(req,res,next) {
if (req.headers['cf-visitor'] && req.headers['cf-visitor'] != '{"scheme":"https"}') {

50
lib/services/youtube.js Normal file
View file

@ -0,0 +1,50 @@
"use strict";
var parse = require('url').parse;
var request = require('superagent');
var Q = require('q');
module.exports.id = "youtube";
if (!process.env.YOUTUBE_KEY) {
console.warn("YOUTUBE_KEY environment variable not found, deactivating Youtube.");
return;
}
var credentials = {
key: process.env.YOUTUBE_KEY,
};
var apiRoot = "https://www.googleapis.com/youtube/v3";
module.exports.match = function(url, type) {
return false;
};
module.exports.search = function(data) {
var deferred = Q.defer();
var query, album;
var type = data.type;
if (type == "album") {
query = data.artist.name + " " + data.name;
album = data.name;
} else if (type == "track") {
query = data.artist.name + " " + data.album.name + " " + data.name;
album = data.album.name
}
var path = "/search?part=snippet&q=" + encodeURIComponent(query) + "&type=video&videoCaption=any&key=" + credentials.key;
request.get(apiRoot + path, function(res) {
var result = res.body.items[0];
deferred.resolve({
service: "youtube",
type: "video",
id: result.id.videoId,
name: result.snippet.title,
streamUrl: "https://www.youtube.com/watch?v=" + result.id.videoId,
purchaseUrl: null,
artwork: result.snippet.thumbnails.medium.url,
});
});
return deferred.promise;
};

View file

@ -20,6 +20,7 @@
"helmet": "^0.5.2",
"morgan": "~1.3.0",
"playmusic": "^1.1.0",
"promised-mongo": "^0.11.1",
"q": "^1.1.2",
"rdio": "^1.5.2",
"serve-favicon": "~2.1.3",

View file

@ -107,3 +107,24 @@ h3 {
.service-link img {
margin-bottom: 7px;
}
.js-video {
height: 0;
padding-top: 25px;
padding-bottom: 67.5%;
margin-bottom: 10px;
position: relative;
overflow: hidden;
}
.js-video.widescreen {
padding-bottom: 57.25%;
}
.js-video embed, .js-video iframe, .js-video object, .js-video video {
top: 0;
left: 0;
width: 100%;
height: 100%;
position: absolute;
}

View file

@ -21,37 +21,41 @@ module.exports = function(req, res) {
var itemId = req.params.id;
var promises = [];
if (cache[serviceId][type + "-" + itemId]) {
res.render(type, {page: type, items: cache[serviceId][type + "-" + itemId]});
return;
}
req.db.matches.findOne({item_id:serviceId + itemId}).then(function(doc) {
if (doc) {
res.render(type, {page: type, items: doc.items});
} else {
services[serviceId].lookupId(itemId, type).then(function(item) {
services[serviceId].lookupId(itemId, type).then(function(item) {
for (var id in services) {
if (id != serviceId) {
promises.push(Q.timeout(services[id].search(item), 5000));
}
}
Q.allSettled(promises).then(function(results) {
var items = results.map(function(result) {
if (result.state == "fulfilled") {
return result.value;
for (var id in services) {
if (id != serviceId) {
promises.push(Q.timeout(services[id].search(item), 5000));
}
}
}).filter(function(result) {
return result || false;
});
items.sort(function(a, b) {
return !a.id || !b.id;
}).sort(function(a, b) {
return !a.streamUrl || b.streamUrl;
});
Q.allSettled(promises).then(function(results) {
var items = results.map(function(result) {
if (result.state == "fulfilled") {
return result.value;
}
}).filter(function(result) {
return result || false;
});
items.unshift(item);
cache[serviceId][type + "-" + itemId] = items;
res.render(type, {page: type, items: items});
});
items.sort(function(a, b) {
return !a.id || !b.id;
}).sort(function(a, b) {
return !a.streamUrl || b.streamUrl;
}).sort(function(a, b) {
return a.type == "video" && b.type != "video";
});
items.unshift(item);
req.db.matches.save({item_id:serviceId + itemId, items:items});
cache[serviceId][type + "-" + itemId] = items;
res.render(type, {page: type, items: items});
});
});
}
});
};

View file

@ -17,10 +17,15 @@
</div>
<div class="row">
<% for (var i=0;i < items.length;i++) { var album = items[i]; %>
<div class="col-md-3 col-xs-6">
<% if (album.type != "video") { %><div class="col-md-3 col-xs-6"><% } else { %><div class="col-md-6 col-xs-12"><% } %>
<div class="service <%= i==0 ? "source-service" : "" %>">
<div class="matching-from"><%= i==0 ? "Found matches using this link" : "" %></div>
<% if (album.streamUrl) { %>
<% if (album.type == "video") { %>
<div class="js-video widescreen">
<iframe width="100%" src="//www.youtube.com/embed/<%= album.id %>" frameborder="0" allowfullscreen></iframe>
</div>
<a href="https://www.youtube.com/results?search_query=<%= items[0].name %> <%= items[0].artist.name %>">More Youtube matches</a>
<% } else if (album.streamUrl) { %>
<a href="<%= album.streamUrl %>"><img src="<%= album.artwork %>" class="img-rounded album-artwork" width="100%"></a>
<div class="service-link">
<a href="<%= album.streamUrl %>"><img src="/images/<%= album.service %>.png" class="img-rounded"></a>