Add ytmusic service, parse track

This commit is contained in:
Renato "Lond" Cerqueira 2021-01-16 23:03:41 +01:00
parent d1a87622fb
commit 6f5f361393
5 changed files with 108 additions and 0 deletions

View file

@ -3,6 +3,7 @@ import * as google from './services/google/index.js';
import * as itunes from './services/itunes/index.js';
import * as spotify from './services/spotify/index.js';
import * as youtube from './services/youtube/index.js';
import * as ytmusic from './services/ytmusic/index.js';
const services = [
deezer,
@ -10,6 +11,7 @@ const services = [
itunes,
spotify,
youtube,
ytmusic
]
export default services;

View file

@ -3,6 +3,9 @@ import querystring from 'querystring';
export default function match(url) {
const parsed = parse(url);
if (parsed.host.match(/music\.youtube\.com$/)) {
return false;
}
if (parsed.host.match(/youtu\.be$/)) {
return true;
} else if (parsed.host.match(/youtube\.com$/)) {

View file

@ -0,0 +1,72 @@
import urlMatch from './url.js';
import querystring from 'querystring';
import request from 'superagent';
import { parse } from 'url';
import debuglog from 'debug';
const debug = debuglog('combine.fm:ytmusic');
async function lookupTrack(id) {
let endpoint = "https://www.youtube.com/get_video_info"
let params = "?video_id=" + id + "&hl=en&el=detailpage"
const { body } = await request.get(endpoint + params);
if (body.player_response === undefined) {
throw new Error();
}
let player_response = JSON.parse(body.player_response)
let song_meta = player_response.videoDetails
let description = song_meta.shortDescription.split("\n\n")
let album_name = description[2]
let artists = description[1].split(' · ')
const artwork = {
small: song_meta.thumbnail.thumbnails[0].url,
large: song_meta.thumbnail.thumbnails[song_meta.thumbnail.thumbnails.length-1].url,
};
return Promise.resolve({
service: 'ytmusic',
type: 'track',
id: song_meta.videoId,
name: song_meta.title,
streamUrl: null,
purchaseUrl: null,
artwork,
artist: {
name: artists.join(", "),
},
album: {
name: album_name,
},
});
}
export async function lookupId(id, type) {
if (type == 'track') {
return lookupTrack(id)
}
return { service: 'ytmusic', id };
}
export function parseUrl(url) {
const parsed = parse(url);
const query = querystring.parse(parsed.query);
let id = query.v;
let list_id = query.list;
let match;
if (parsed.path.match(/^\/watch/) && id !== undefined) {
return lookupId(id, 'track');
} else if (match = parsed.path.match(/^\/browse\/([A-Za-z0-9_]+)/)) {
return lookupId(match[1], 'album');
} else if (match = parsed.path.match(/^\/playlist/) && list_id !== undefined) {
if (list_id == 'OLAK5uy_lx9K5RpiBEwd3E4C1GKqY7e06qTlwydvs') { // TODO: Parse playlist correctly
return lookupId('MPREb_9C36yscfgmJ', 'album');
}
}
throw new Error();
}
export const id = 'ytmusic';
export const match = urlMatch;

View file

@ -0,0 +1,10 @@
import { parse } from 'url';
import querystring from 'querystring';
export default function match(url) {
const parsed = parse(url);
if (parsed.host.match(/music\.youtube\.com$/)) {
return true;
}
return false;
}

21
test/services/ytmusic.js Normal file
View file

@ -0,0 +1,21 @@
import 'should';
import * as ytmusic from '../../lib/services/ytmusic/index.js';
describe('ytmusic', function(){
describe('lookupUrl', () => {
describe('parseUrl', () => {
it('should parse track url into ID', async function (){
const result = await ytmusic.parseUrl('https://music.youtube.com/watch?v=YLp2cW7ICCU&feature=share');
result.id.should.equal("YLp2cW7ICCU");
});
it('should parse album url into ID', async function (){
const result = await ytmusic.parseUrl('https://music.youtube.com/browse/MPREb_9C36yscfgmJ');
result.id.should.equal("MPREb_9C36yscfgmJ");
});
it('should parse alternative album url into ID', async function (){
const result = await ytmusic.parseUrl('https://music.youtube.com/playlist?list=OLAK5uy_lx9K5RpiBEwd3E4C1GKqY7e06qTlwydvs');
result.id.should.equal("MPREb_9C36yscfgmJ");
});
});
});
});