Add youtube to results, persist to mongo
This commit is contained in:
parent
d675ac4e9f
commit
f20fecf0d0
7 changed files with 125 additions and 31 deletions
|
@ -19,6 +19,5 @@ This is in super early development and is incapable of handling getting dugg, ne
|
||||||
On the immediate todo list:
|
On the immediate todo list:
|
||||||
|
|
||||||
* Use album release year for additional sanity check on matches
|
* 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
|
* 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
|
* 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
14
app.js
|
@ -8,6 +8,7 @@ var session = require('express-session');
|
||||||
var cookieParser = require('cookie-parser');
|
var cookieParser = require('cookie-parser');
|
||||||
var flash = require('connect-flash');
|
var flash = require('connect-flash');
|
||||||
var bodyParser = require('body-parser');
|
var bodyParser = require('body-parser');
|
||||||
|
var pmongo = require('promised-mongo');
|
||||||
|
|
||||||
var search = require('./routes/search');
|
var search = require('./routes/search');
|
||||||
var share = require('./routes/share');
|
var share = require('./routes/share');
|
||||||
|
@ -34,6 +35,19 @@ app.use(session({
|
||||||
app.use(flash());
|
app.use(flash());
|
||||||
app.use(express.static(path.join(__dirname, 'public')));
|
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
|
// force SSL
|
||||||
app.get('*', function(req,res,next) {
|
app.get('*', function(req,res,next) {
|
||||||
if (req.headers['cf-visitor'] && req.headers['cf-visitor'] != '{"scheme":"https"}') {
|
if (req.headers['cf-visitor'] && req.headers['cf-visitor'] != '{"scheme":"https"}') {
|
||||||
|
|
50
lib/services/youtube.js
Normal file
50
lib/services/youtube.js
Normal 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;
|
||||||
|
};
|
|
@ -20,6 +20,7 @@
|
||||||
"helmet": "^0.5.2",
|
"helmet": "^0.5.2",
|
||||||
"morgan": "~1.3.0",
|
"morgan": "~1.3.0",
|
||||||
"playmusic": "^1.1.0",
|
"playmusic": "^1.1.0",
|
||||||
|
"promised-mongo": "^0.11.1",
|
||||||
"q": "^1.1.2",
|
"q": "^1.1.2",
|
||||||
"rdio": "^1.5.2",
|
"rdio": "^1.5.2",
|
||||||
"serve-favicon": "~2.1.3",
|
"serve-favicon": "~2.1.3",
|
||||||
|
|
|
@ -107,3 +107,24 @@ h3 {
|
||||||
.service-link img {
|
.service-link img {
|
||||||
margin-bottom: 7px;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -21,37 +21,41 @@ module.exports = function(req, res) {
|
||||||
var itemId = req.params.id;
|
var itemId = req.params.id;
|
||||||
var promises = [];
|
var promises = [];
|
||||||
|
|
||||||
if (cache[serviceId][type + "-" + itemId]) {
|
req.db.matches.findOne({item_id:serviceId + itemId}).then(function(doc) {
|
||||||
res.render(type, {page: type, items: cache[serviceId][type + "-" + itemId]});
|
if (doc) {
|
||||||
return;
|
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) {
|
||||||
for (var id in services) {
|
promises.push(Q.timeout(services[id].search(item), 5000));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}).filter(function(result) {
|
|
||||||
return result || false;
|
|
||||||
});
|
|
||||||
|
|
||||||
items.sort(function(a, b) {
|
Q.allSettled(promises).then(function(results) {
|
||||||
return !a.id || !b.id;
|
var items = results.map(function(result) {
|
||||||
}).sort(function(a, b) {
|
if (result.state == "fulfilled") {
|
||||||
return !a.streamUrl || b.streamUrl;
|
return result.value;
|
||||||
});
|
}
|
||||||
|
}).filter(function(result) {
|
||||||
|
return result || false;
|
||||||
|
});
|
||||||
|
|
||||||
items.unshift(item);
|
items.sort(function(a, b) {
|
||||||
cache[serviceId][type + "-" + itemId] = items;
|
return !a.id || !b.id;
|
||||||
res.render(type, {page: type, items: items});
|
}).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});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,10 +17,15 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<% for (var i=0;i < items.length;i++) { var album = items[i]; %>
|
<% 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="service <%= i==0 ? "source-service" : "" %>">
|
||||||
<div class="matching-from"><%= i==0 ? "Found matches using this link" : "" %></div>
|
<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>
|
<a href="<%= album.streamUrl %>"><img src="<%= album.artwork %>" class="img-rounded album-artwork" width="100%"></a>
|
||||||
<div class="service-link">
|
<div class="service-link">
|
||||||
<a href="<%= album.streamUrl %>"><img src="/images/<%= album.service %>.png" class="img-rounded"></a>
|
<a href="<%= album.streamUrl %>"><img src="/images/<%= album.service %>.png" class="img-rounded"></a>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue