Skip to content
This repository has been archived by the owner on Jun 26, 2024. It is now read-only.

Commit

Permalink
fix dead link, #37 #26 #3
Browse files Browse the repository at this point in the history
QQ music, Kugou music, need more…
  • Loading branch information
trazyn committed Oct 14, 2017
1 parent 60e610e commit dbefc46
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
dist/*
__tests__/*
src/assets/*
server/*
server/api/*
NeteaseCloudMusicApi/*

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@
},
"linux": {
"target": [
"deb", "rpm", "AppImage"
"deb",
"rpm",
"AppImage"
],
"icon": "../resource",
"category": "Music"
Expand Down Expand Up @@ -132,6 +134,7 @@
"electron-window-state": "^4.1.1",
"han": "0.0.7",
"ionicons201": "^1.0.0",
"md5": "^2.2.1",
"mobx": "^3.2.2",
"mobx-react": "^4.2.2",
"moment": "^2.18.1",
Expand Down
4 changes: 2 additions & 2 deletions server/router/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ async function getPersonalized() {
}

async function getSongs(id) {

var songs = [];

try {
let response = await axios.get(`/playlist/detail?id=${id}`);

if (response.data.code === 200) {
songs = response.data.playlist.tracks.map(e => {
var { al /* Album */, ar /* Artist */ } = e;
// eslint-disable-next-line
var {al /* Album */, ar /* Artist */} = e;

return {
id: e.id.toString(),
Expand Down
11 changes: 10 additions & 1 deletion server/router/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import express from 'express';
import apicache from 'apicache'
import axios from 'axios';
import _debug from 'debug';
import search from '../search';
/* eslint-enable */

const debug = _debug('dev:api');
Expand Down Expand Up @@ -228,7 +229,12 @@ router.get('/song/:id/:name/:artists/:flac?', cache('5 minutes', onlyStatus200),
let data = response.data;

if (data.code !== 200) {
throw data;
// Search from other source
song = await search(name, artists);

if (!song.src) {
throw data;
}
}

song = data.data[0];
Expand All @@ -242,6 +248,9 @@ router.get('/song/:id/:name/:artists/:flac?', cache('5 minutes', onlyStatus200),
error('Failed to get song URL: %O', ex);
}

var other = await search(name, artists);
debug('%O', other);

res.send({
song,
});
Expand Down
46 changes: 46 additions & 0 deletions server/search/Kugou.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

import axios from 'axios';
import md5 from 'md5';
import _debug from 'debug';

const debug = _debug('dev:plugin:Kugou');
const error = _debug('dev:plugin:Kugou:error');

async function getURL(hash) {
var key = md5(`${hash}kgcloud`);

var response = await axios.get(`http://trackercdn.kugou.com/i/?acceptMp3=1&cmd=4&pid=6&hash=${hash}&key=${key}`);
var data = response.data;

if (data.error
|| data.status !== 1) {
error('Failed to get song URL: %O', data);
return null;
} else {
return data.url;
}
}

export default async(keyword, artists) => {
debug(`Search '${keyword} - ${artists}' use Kugou plugin.`);

var response = await axios.get(`http://mobilecdn.kugou.com/api/v3/search/song?format=json&keyword=${encodeURIComponent(keyword)}&page=1&pagesize=1&showtype=1`);
var data = response.data;

if (data.status !== 1
|| data.data.info.length === 0) {
return;
}

for (let e of data.data.info) {
if (artists.split(',').findIndex(artist => e.singername.indexOf(artist)) === -1) {
continue;
}

debug('Find %O', e);

return {
src: await getURL(e['320hash'] || e['hash'])
};
}
};
80 changes: 80 additions & 0 deletions server/search/QQ.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@

import axios from 'axios';
import _debug from 'debug';

const debug = _debug('dev:plugin:QQ');
const error = _debug('dev:plugin:QQ:error');
const baseUrl = 'dl.stream.qqmusic.qq.com';
const baseApi = 'http://101.96.10.58/c.y.qq.com';

let updateTime = null;
let vkey = null;
let guid = null;

async function updateVkey() {
var currentMs = (new Date()).getUTCMilliseconds();
guid = Math.round(2147483647 * Math.random()) * currentMs % 1e10;

if (!updateTime
|| updateTime + 3600 * 1000 < +new Date()) {
try {
var response = await axios.get(`${baseApi}/base/fcgi-bin/fcg_musicexpress.fcg?json=3&guid=${guid}&g_tk=5381&jsonpCallback=jsonCallback&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf8&notice=0&platform=yqq&needNewCode=0`);
vkey = response.data.key;
updateTime = +new Date();
} catch (ex) {
error('Failed to update vkey: %O', ex);
}
}
return vkey;
}

function getURL(data) {
return `http://${baseUrl}/${data.prefix}${data.mid}.${data.type}?vkey=${vkey}&guid=${guid}&uin=0&fromtag=30`;
}

export default async(keyword, artists) => {
debug(`Search '${keyword} - ${artists}' use QQ plugin.`);

try {
await updateVkey();
} catch (ex) {
error('Failed to initialize QQ plugin: %O', ex);
throw ex;
}

var response = await axios.get(`${baseApi}/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&t=0&aggr=1&cr=1&catZhida=1&lossless=1&flag_qc=0&p=1&n=1&w=${encodeURIComponent(keyword)}&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0`);
var data = response.data;

if (data.code !== 0
|| data.data.song.list.length === 0) {
return;
}

for (let e of data.data.song.list) {
let list = e.file;
let song = {};

// Match the artists
if (e.singer.findIndex(e => artists.indexOf(e.name) === -1)) {
continue;
}

if (list.size_128 > 0) {
song.src = getURL({
mid: list.media_mid,
prefix: 'M500',
type: 'mp3',
});
}

if (list.size_320 > 0) {
song.src = getURL({
mid: list.media_mid,
prefix: 'M800',
type: 'mp3',
});
}

return song;
}
};
26 changes: 26 additions & 0 deletions server/search/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

import QQ from './QQ';
import Kugou from './Kugou';
import _debug from 'debug';

const debug = _debug('plugin:');

export default (keyword, artists) => {
var plugins = [QQ, Kugou];

debug('Plugin has loaded, search: \'%s\', \'%s\'', keyword, artists);

return Promise.all(
plugins.map(e => {
// If a request failed will keep waiting for other possible successes, if a request successed,
// treat it as a rejection so Promise.all immediate break.
return e(keyword, artists).then(
val => Promise.reject(val),
err => Promise.resolve(err)
);
})
).then(
errs => Promise.reject(errs),
val => Promise.resolve(val),
);
};

0 comments on commit dbefc46

Please sign in to comment.