Update service images for retina, remove rdio :(
|
@ -1,168 +0,0 @@
|
||||||
import { parse } from 'url';
|
|
||||||
import bluebird from 'bluebird';
|
|
||||||
import rdioInit from 'rdio';
|
|
||||||
import { match as urlMatch } from './url';
|
|
||||||
|
|
||||||
export let id = 'rdio';
|
|
||||||
|
|
||||||
if (!process.env.RDIO_CLIENT_ID || !process.env.RDIO_CLIENT_SECRET) {
|
|
||||||
console.warn('RDIO_CLIENT_ID or RDIO_CLIENT_SECRET environment constiables not found, deactivating Rdio.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const Rdio = rdioInit({
|
|
||||||
rdio: {
|
|
||||||
clientId: process.env.RDIO_CLIENT_ID,
|
|
||||||
clientSecret: process.env.RDIO_CLIENT_SECRET,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const rdio = bluebird.promisifyAll(new Rdio());
|
|
||||||
|
|
||||||
export const match = urlMatch;
|
|
||||||
|
|
||||||
export function* lookupId(id) {
|
|
||||||
yield rdio.getClientTokenAsync();
|
|
||||||
const response = yield rdio.requestAsync({method: 'getObjectFromShortCode', short_code: id}, false);
|
|
||||||
const result = response.result;
|
|
||||||
const parsedShortUrl = parse(result.shortUrl);
|
|
||||||
const rid = parsedShortUrl.path.replace('/x/', '').replace('/', '');
|
|
||||||
const type = result.album ? 'track' : 'album';
|
|
||||||
|
|
||||||
const item = {
|
|
||||||
service: 'rdio',
|
|
||||||
type: type,
|
|
||||||
id: rid,
|
|
||||||
name: result.name,
|
|
||||||
streamUrl: result.shortUrl,
|
|
||||||
purchaseUrl: null,
|
|
||||||
artwork: {
|
|
||||||
small: result.icon.replace('square-200', 'square-250').replace('http:', 'https:'),
|
|
||||||
large: result.icon.replace('square-200', 'square-600').replace('http:', 'https:')
|
|
||||||
},
|
|
||||||
artist: {
|
|
||||||
name: result.artist
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (type === 'track') {
|
|
||||||
item.album = {
|
|
||||||
name: result.album
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function* parseUrl(url) {
|
|
||||||
const parsedUrl = parse(url);
|
|
||||||
|
|
||||||
let query, args;
|
|
||||||
|
|
||||||
if (parsedUrl.host === 'rd.io') {
|
|
||||||
query = {
|
|
||||||
method: 'getObjectFromShortCode',
|
|
||||||
short_code: parsedUrl.path.replace('/x/', '').replace('/', '')
|
|
||||||
};
|
|
||||||
} else if (parsedUrl.host.match(/rdio\.com$/)) {
|
|
||||||
query = {
|
|
||||||
method: 'getObjectFromUrl',
|
|
||||||
url: parsedUrl.path
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
const error = new Error('Not Found');
|
|
||||||
error.status = 404;
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield rdio.getClientTokenAsync();
|
|
||||||
const response = yield rdio.requestAsync(query, false);
|
|
||||||
const result = response.result;
|
|
||||||
const parsedShortUrl = parse(result.shortUrl);
|
|
||||||
const id = parsedShortUrl.path.replace('/x/', '').replace('/', '');
|
|
||||||
const type = result.album ? 'track' : 'album';
|
|
||||||
const item = {
|
|
||||||
service: 'rdio',
|
|
||||||
type: type,
|
|
||||||
id: id,
|
|
||||||
name: result.name,
|
|
||||||
streamUrl: result.shortUrl,
|
|
||||||
purchaseUrl: null,
|
|
||||||
artwork: {
|
|
||||||
small: result.icon.replace('square-200', 'square-250').replace('http:', 'https:'),
|
|
||||||
large: result.icon.replace('square-200', 'square-600').replace('http:', 'https:')
|
|
||||||
},
|
|
||||||
artist: {
|
|
||||||
name: result.artist
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (type === 'track') {
|
|
||||||
item.album = {
|
|
||||||
name: result.album
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function* search(data) {
|
|
||||||
let query, albumClean;
|
|
||||||
const type = data.type;
|
|
||||||
|
|
||||||
if (type === 'album') {
|
|
||||||
query = data.artist.name + ' ' + data.name;
|
|
||||||
albumClean = data.name.match(/([^\(\[]+)/)[0];
|
|
||||||
} else if (type === 'track') {
|
|
||||||
query = data.artist.name + ' ' + data.album.name + ' ' + data.name;
|
|
||||||
try {
|
|
||||||
albumClean = data.album.name.match(/([^\(\[]+)/)[0];
|
|
||||||
} catch(e) {
|
|
||||||
albumClean = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
yield rdio.getClientTokenAsync();
|
|
||||||
const response = yield rdio.requestAsync({method: 'search', query: query, types: type}, false);
|
|
||||||
const result = response.result.results.filter(function(item) {
|
|
||||||
if (type === 'album' && item.name.match(/([^\(\[]+)/)[0] === albumClean) {
|
|
||||||
return item;
|
|
||||||
} else if (type === 'track' && (item.album.match(/([^\(\[]+)/)[0] === albumClean || !albumClean)) {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
}).shift();
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
const matches = albumClean.match(/^[^\(\[]+/);
|
|
||||||
if (matches && matches[0] && matches[0] !== albumClean) {
|
|
||||||
const cleanedData = JSON.parse(JSON.stringify(data));
|
|
||||||
if (type === 'album') {
|
|
||||||
cleanedData.name = matches[0].trim();
|
|
||||||
} else if (type === 'track') {
|
|
||||||
cleanedData.album.name = matches[0].trim();
|
|
||||||
}
|
|
||||||
return module.exports.search(cleanedData);
|
|
||||||
} else {
|
|
||||||
return {service: 'rdio'};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const parsedShortUrl = parse(result.shortUrl);
|
|
||||||
const id = parsedShortUrl.path.replace('/x/', '').replace('/', '');
|
|
||||||
const item = {
|
|
||||||
service: 'rdio',
|
|
||||||
type: type,
|
|
||||||
id: id,
|
|
||||||
name: result.name,
|
|
||||||
streamUrl: result.shortUrl,
|
|
||||||
purchaseUrl: null,
|
|
||||||
artwork: {
|
|
||||||
small: result.icon.replace('square-200', 'square-250').replace('http:', 'https:'),
|
|
||||||
large: result.icon.replace('square-200', 'square-600').replace('http:', 'https:')
|
|
||||||
},
|
|
||||||
artist: {
|
|
||||||
name: result.artist
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (type === 'track') {
|
|
||||||
item.album = {
|
|
||||||
name: result.album
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,11 +0,0 @@
|
||||||
import { parse } from 'url';
|
|
||||||
|
|
||||||
export function* match(url) {
|
|
||||||
const parsed = parse(url);
|
|
||||||
if (!parsed.host.match(/rd\.io$/) && !parsed.host.match(/rdio\.com$/)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const regular = parsed.path.match(/[\/]*artist[\/]*([^\/]*)[\/]*album[\/]*([^\/]*)[\/]*([track]*)?[\/]*([^\/]*)/);
|
|
||||||
const short = parsed.path.match(/[\/]*x[\/]*([^\/]*)/);
|
|
||||||
return (regular && !!regular[2]) || (short && !!short[1]);
|
|
||||||
};
|
|
11
package.json
|
@ -17,13 +17,12 @@
|
||||||
"npm": "^3.3.0"
|
"npm": "^3.3.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"babel": "~6.1.18",
|
"babel": "^6.1.18",
|
||||||
"babel-cli": "^6.2.0",
|
"babel-cli": "^6.3.13",
|
||||||
"babel-core": "^6.2.1",
|
"babel-core": "^6.3.13",
|
||||||
"babel-plugin-syntax-jsx": "^6.1.18",
|
"babel-plugin-syntax-jsx": "^6.3.13",
|
||||||
"babel-plugin-transform-es2015-arrow-functions": "^6.1.18",
|
"babel-plugin-transform-es2015-arrow-functions": "^6.3.13",
|
||||||
"babel-plugin-transform-es2015-block-scoped-functions": "^6.1.18",
|
"babel-plugin-transform-es2015-block-scoped-functions": "^6.1.18",
|
||||||
"babel-plugin-transform-es2015-block-scoping": "^6.1.18",
|
|
||||||
"babel-plugin-transform-es2015-classes": "^6.2.2",
|
"babel-plugin-transform-es2015-classes": "^6.2.2",
|
||||||
"babel-plugin-transform-es2015-computed-properties": "^6.1.18",
|
"babel-plugin-transform-es2015-computed-properties": "^6.1.18",
|
||||||
"babel-plugin-transform-es2015-constants": "^6.1.4",
|
"babel-plugin-transform-es2015-constants": "^6.1.4",
|
||||||
|
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 5 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 7.7 KiB |
|
@ -136,6 +136,7 @@ h3 {
|
||||||
|
|
||||||
.service {
|
.service {
|
||||||
padding: 40px 10px 10px 10px;
|
padding: 40px 10px 10px 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
.matching-from {
|
.matching-from {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -152,7 +153,6 @@ h3 {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 0;
|
height: 0;
|
||||||
padding-bottom: 100%;
|
padding-bottom: 100%;
|
||||||
margin-bottom: 10px;
|
|
||||||
background-repeat: none;
|
background-repeat: none;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
@ -211,7 +211,7 @@ h3 {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
.service-link img {
|
.service-link img {
|
||||||
margin-bottom: 7px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
.error {
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
import 'should';
|
|
||||||
import * as rdio from '../../lib/services/rdio';
|
|
||||||
|
|
||||||
describe('Rdio', function(){
|
|
||||||
describe('lookupId', function(){
|
|
||||||
it('should find album by ID', function* (){
|
|
||||||
const result = yield rdio.lookupId('Qj4NXr0');
|
|
||||||
result.name.should.equal('Listen (Deluxe)');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('search', function(){
|
|
||||||
it('should find album by search', function* (){
|
|
||||||
const result = yield rdio.search({type: 'album', artist: {name: 'David Guetta'}, name: 'Listen (Deluxe)'});
|
|
||||||
result.name.should.equal('Listen (Deluxe)');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('parseUrl', function(){
|
|
||||||
it('should parse regular url into album object', function* (){
|
|
||||||
const result = yield rdio.parseUrl('https://www.rdio.com/artist/David_Guetta/album/Listen_(Deluxe)/');
|
|
||||||
result.name.should.equal('Listen (Deluxe)');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should parse short url into album object', function* (){
|
|
||||||
const result = yield rdio.parseUrl('http://rd.io/x/Qj4NXr0/');
|
|
||||||
result.name.should.equal('Listen (Deluxe)');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -39,7 +39,7 @@ const MusicItem = React.createClass({
|
||||||
return (
|
return (
|
||||||
<div className='col-md-3 col-xs-6'>
|
<div className='col-md-3 col-xs-6'>
|
||||||
<div className={'service' + (this.props.inc === 0 ? ' source-service' : '')}>
|
<div className={'service' + (this.props.inc === 0 ? ' source-service' : '')}>
|
||||||
<div className='matching-from hidden-xs'>{this.props.inc === 0 ? 'Found matches using this link' : ''}</div>
|
<div className='matching-from'>{this.props.inc === 0 ? 'Found matches using' : ''}</div>
|
||||||
<a href={this.props.item.streamUrl || this.props.item.purchaseUrl}>
|
<a href={this.props.item.streamUrl || this.props.item.purchaseUrl}>
|
||||||
<div className={this.props.item.service === 'youtube' ? 'artwork-youtube artwork' : 'artwork'} style={{backgroundImage: 'url(' + this.props.item.artwork.small + ')'}}>
|
<div className={this.props.item.service === 'youtube' ? 'artwork-youtube artwork' : 'artwork'} style={{backgroundImage: 'url(' + this.props.item.artwork.small + ')'}}>
|
||||||
</div>
|
</div>
|
||||||
|
@ -47,13 +47,13 @@ const MusicItem = React.createClass({
|
||||||
{this.props.item.service === 'youtube' && this.props.inc > 0 ? this.props.item.name : ''}
|
{this.props.item.service === 'youtube' && this.props.inc > 0 ? this.props.item.name : ''}
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
<div className='service-link'>
|
<div className='service-link'>
|
||||||
<a href={this.props.item.streamUrl || this.props.item.purchaseUrl}>
|
<a href={this.props.item.streamUrl || this.props.item.purchaseUrl}>
|
||||||
<img src={'/images/' + this.props.item.service + '.png'} className='img-rounded' />
|
<img src={'/images/' + this.props.item.service + '.png'} />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|