|
|
|
|
|
|
|
const PROVIDERS = [ |
|
{ |
|
name: 'netease', |
|
instance: netease, |
|
searchable: true, |
|
support_login: true, |
|
id: 'ne', |
|
}, |
|
{ |
|
name: 'xiami', |
|
instance: xiami, |
|
searchable: false, |
|
hidden: true, |
|
support_login: false, |
|
id: 'xm', |
|
}, |
|
{ |
|
name: 'qq', |
|
instance: qq, |
|
searchable: true, |
|
support_login: true, |
|
id: 'qq', |
|
}, |
|
{ |
|
name: 'kugou', |
|
instance: kugou, |
|
searchable: true, |
|
support_login: false, |
|
id: 'kg', |
|
}, |
|
{ |
|
name: 'kuwo', |
|
instance: kuwo, |
|
searchable: true, |
|
support_login: false, |
|
id: 'kw', |
|
}, |
|
{ |
|
name: 'bilibili', |
|
instance: bilibili, |
|
searchable: false, |
|
support_login: false, |
|
id: 'bi', |
|
}, |
|
{ |
|
name: 'migu', |
|
instance: migu, |
|
searchable: true, |
|
support_login: true, |
|
id: 'mg', |
|
}, |
|
{ |
|
name: 'taihe', |
|
instance: taihe, |
|
searchable: true, |
|
support_login: false, |
|
id: 'th', |
|
}, |
|
{ |
|
name: 'localmusic', |
|
instance: localmusic, |
|
searchable: false, |
|
hidden: true, |
|
support_login: false, |
|
id: 'lm', |
|
}, |
|
{ |
|
name: 'myplaylist', |
|
instance: myplaylist, |
|
searchable: false, |
|
hidden: true, |
|
support_login: false, |
|
id: 'my', |
|
}, |
|
]; |
|
|
|
function getProviderByName(sourceName) { |
|
return (PROVIDERS.find((i) => i.name === sourceName) || {}).instance; |
|
} |
|
|
|
function getAllProviders() { |
|
return PROVIDERS.filter((i) => !i.hidden).map((i) => i.instance); |
|
} |
|
|
|
function getAllSearchProviders() { |
|
return PROVIDERS.filter((i) => i.searchable).map((i) => i.instance); |
|
} |
|
|
|
function getProviderNameByItemId(itemId) { |
|
const prefix = itemId.slice(0, 2); |
|
return (PROVIDERS.find((i) => i.id === prefix) || {}).name; |
|
} |
|
|
|
function getProviderByItemId(itemId) { |
|
const prefix = itemId.slice(0, 2); |
|
return (PROVIDERS.find((i) => i.id === prefix) || {}).instance; |
|
} |
|
|
|
|
|
const playlistCache = new LRUCache({ |
|
max: 100, |
|
maxAge: 60 * 60 * 1000, |
|
}); |
|
|
|
function queryStringify(options) { |
|
const query = JSON.parse(JSON.stringify(options)); |
|
return new URLSearchParams(query).toString(); |
|
} |
|
|
|
setPrototypeOfLocalStorage(); |
|
|
|
|
|
const MediaService = { |
|
getLoginProviders() { |
|
return PROVIDERS.filter((i) => !i.hidden && i.support_login); |
|
}, |
|
search(source, options) { |
|
const url = `/search?${queryStringify(options)}`; |
|
if (source === 'allmusic') { |
|
|
|
const callbackArray = getAllSearchProviders().map((p) => (fn) => { |
|
p.search(url).success((r) => { |
|
fn(null, r); |
|
}); |
|
}); |
|
return { |
|
success: (fn) => |
|
async.parallel(callbackArray, (err, platformResultArray) => { |
|
|
|
const result = { |
|
result: [], |
|
total: 1000, |
|
type: platformResultArray[0].type, |
|
}; |
|
const maxLength = Math.max( |
|
...platformResultArray.map((elem) => elem.result.length) |
|
); |
|
for (let i = 0; i < maxLength; i += 1) { |
|
platformResultArray.forEach((elem) => { |
|
if (i < elem.result.length) { |
|
result.result.push(elem.result[i]); |
|
} |
|
}); |
|
} |
|
return fn(result); |
|
}), |
|
}; |
|
} |
|
const provider = getProviderByName(source); |
|
return provider.search(url); |
|
}, |
|
|
|
showMyPlaylist() { |
|
return myplaylist.show_myplaylist('my'); |
|
}, |
|
|
|
showPlaylistArray(source, offset, filter_id) { |
|
const provider = getProviderByName(source); |
|
const url = `/show_playlist?${queryStringify({ offset, filter_id })}`; |
|
return provider.show_playlist(url); |
|
}, |
|
|
|
getPlaylistFilters(source) { |
|
const provider = getProviderByName(source); |
|
return provider.get_playlist_filters(); |
|
}, |
|
|
|
getLyric(track_id, album_id, lyric_url, tlyric_url) { |
|
const provider = getProviderByItemId(track_id); |
|
const url = `/lyric?${queryStringify({ |
|
track_id, |
|
album_id, |
|
lyric_url, |
|
tlyric_url, |
|
})}`; |
|
return provider.lyric(url); |
|
}, |
|
|
|
showFavPlaylist() { |
|
return myplaylist.show_myplaylist('favorite'); |
|
}, |
|
|
|
queryPlaylist(listId, type) { |
|
const result = myplaylist.myplaylist_containers(type, listId); |
|
return { |
|
success: (fn) => fn({ result }), |
|
}; |
|
}, |
|
|
|
getPlaylist(listId, useCache = true) { |
|
const provider = getProviderByItemId(listId); |
|
const url = `/playlist?list_id=${listId}`; |
|
let hit = null; |
|
if (useCache) { |
|
hit = playlistCache.get(listId); |
|
} |
|
|
|
if (hit) { |
|
return { |
|
success: (fn) => fn(hit), |
|
}; |
|
} |
|
return { |
|
success: (fn) => |
|
provider.get_playlist(url).success((playlist) => { |
|
if (provider !== myplaylist && provider !== localmusic) { |
|
playlistCache.set(listId, playlist); |
|
} |
|
fn(playlist); |
|
}), |
|
}; |
|
}, |
|
|
|
clonePlaylist(id, type) { |
|
const provider = getProviderByItemId(id); |
|
const url = `/playlist?list_id=${id}`; |
|
return { |
|
success: (fn) => { |
|
provider.get_playlist(url).success((data) => { |
|
myplaylist.save_myplaylist(type, data); |
|
fn(); |
|
}); |
|
}, |
|
}; |
|
}, |
|
|
|
removeMyPlaylist(id, type) { |
|
myplaylist.remove_myplaylist(type, id); |
|
return { |
|
success: (fn) => fn(), |
|
}; |
|
}, |
|
|
|
addMyPlaylist(id, track) { |
|
const newPlaylist = myplaylist.add_track_to_myplaylist(id, track); |
|
return { |
|
success: (fn) => fn(newPlaylist), |
|
}; |
|
}, |
|
insertTrackToMyPlaylist(id, track, to_track, direction) { |
|
const newPlaylist = myplaylist.insert_track_to_myplaylist( |
|
id, |
|
track, |
|
to_track, |
|
direction |
|
); |
|
return { |
|
success: (fn) => fn(newPlaylist), |
|
}; |
|
}, |
|
addPlaylist(id, tracks) { |
|
const provider = getProviderByItemId(id); |
|
return provider.add_playlist(id, tracks); |
|
}, |
|
|
|
removeTrackFromMyPlaylist(id, track) { |
|
myplaylist.remove_track_from_myplaylist(id, track); |
|
return { |
|
success: (fn) => fn(), |
|
}; |
|
}, |
|
|
|
removeTrackFromPlaylist(id, track) { |
|
const provider = getProviderByItemId(id); |
|
return provider.remove_from_playlist(id, track); |
|
}, |
|
|
|
createMyPlaylist(title, track) { |
|
myplaylist.create_myplaylist(title, track); |
|
return { |
|
success: (fn) => { |
|
fn(); |
|
}, |
|
}; |
|
}, |
|
insertMyplaylistToMyplaylists( |
|
playlistType, |
|
playlistId, |
|
toPlaylistId, |
|
direction |
|
) { |
|
const newPlaylists = myplaylist.insert_myplaylist_to_myplaylists( |
|
playlistType, |
|
playlistId, |
|
toPlaylistId, |
|
direction |
|
); |
|
return { |
|
success: (fn) => fn(newPlaylists), |
|
}; |
|
}, |
|
editMyPlaylist(id, title, coverImgUrl) { |
|
myplaylist.edit_myplaylist(id, title, coverImgUrl); |
|
return { |
|
success: (fn) => fn(), |
|
}; |
|
}, |
|
|
|
parseURL(url) { |
|
return { |
|
success: (fn) => { |
|
const providers = getAllProviders(); |
|
Promise.all( |
|
providers.map( |
|
(provider) => |
|
new Promise((res, rej) => |
|
provider.parse_url(url).success((r) => { |
|
if (r !== undefined) { |
|
return rej(r); |
|
} |
|
return res(r); |
|
}) |
|
) |
|
) |
|
) |
|
.then(() => fn({})) |
|
.catch((result) => fn({ result })); |
|
}, |
|
}; |
|
}, |
|
|
|
mergePlaylist(source, target) { |
|
const tarData = localStorage.getObject(target).tracks; |
|
const srcData = localStorage.getObject(source).tracks; |
|
tarData.forEach((tarTrack) => { |
|
if (!srcData.find((srcTrack) => srcTrack.id === tarTrack.id)) { |
|
myplaylist.add_track_to_myplaylist(source, tarTrack); |
|
} |
|
}); |
|
return { |
|
success: (fn) => fn(), |
|
}; |
|
}, |
|
|
|
bootstrapTrack(track, playerSuccessCallback, playerFailCallback) { |
|
const successCallback = playerSuccessCallback; |
|
const sound = {}; |
|
function failureCallback() { |
|
if (localStorage.getObject('enable_auto_choose_source') === false) { |
|
playerFailCallback(); |
|
return; |
|
} |
|
const trackPlatform = getProviderNameByItemId(track.id); |
|
const failover_source_list = getLocalStorageValue( |
|
'auto_choose_source_list', |
|
['kuwo', 'qq', 'migu'] |
|
).filter((i) => i !== trackPlatform); |
|
|
|
const getUrlPromises = failover_source_list.map( |
|
(source) => |
|
new Promise((resolve, reject) => { |
|
if (track.source === source) { |
|
|
|
resolve(); |
|
return; |
|
} |
|
|
|
const keyword = `${track.title} ${track.artist}`; |
|
const curpage = 1; |
|
const url = `/search?keywords=${keyword}&curpage=${curpage}&type=0`; |
|
const provider = getProviderByName(source); |
|
provider.search(url).success((data) => { |
|
for (let i = 0; i < data.result.length; i += 1) { |
|
const searchTrack = data.result[i]; |
|
|
|
|
|
if ( |
|
!searchTrack.disable && |
|
searchTrack.title === track.title && |
|
searchTrack.artist === track.artist |
|
) { |
|
provider.bootstrap_track( |
|
searchTrack, |
|
(response) => { |
|
sound.url = response.url; |
|
sound.bitrate = response.bitrate; |
|
sound.platform = response.platform; |
|
reject(sound); |
|
}, |
|
resolve |
|
); |
|
return; |
|
} |
|
} |
|
resolve(sound); |
|
}); |
|
}) |
|
); |
|
|
|
Promise.all(getUrlPromises) |
|
.then(playerFailCallback) |
|
.catch((response) => { |
|
playerSuccessCallback(response); |
|
}); |
|
} |
|
|
|
const provider = getProviderByName(track.source); |
|
|
|
provider.bootstrap_track(track, successCallback, failureCallback); |
|
}, |
|
|
|
login(source, options) { |
|
const url = `/login?${queryStringify(options)}`; |
|
const provider = getProviderByName(source); |
|
|
|
return provider.login(url); |
|
}, |
|
getUser(source) { |
|
const provider = getProviderByName(source); |
|
return provider.get_user(); |
|
}, |
|
getLoginUrl(source) { |
|
const provider = getProviderByName(source); |
|
return provider.get_login_url(); |
|
}, |
|
getUserCreatedPlaylist(source, options) { |
|
const provider = getProviderByName(source); |
|
const url = `/get_user_create_playlist?${queryStringify(options)}`; |
|
|
|
return provider.get_user_created_playlist(url); |
|
}, |
|
getUserFavoritePlaylist(source, options) { |
|
const provider = getProviderByName(source); |
|
const url = `/get_user_favorite_playlist?${queryStringify(options)}`; |
|
|
|
return provider.get_user_favorite_playlist(url); |
|
}, |
|
getRecommendPlaylist(source) { |
|
const provider = getProviderByName(source); |
|
|
|
return provider.get_recommend_playlist(); |
|
}, |
|
logout(source) { |
|
const provider = getProviderByName(source); |
|
|
|
return provider.logout(); |
|
}, |
|
}; |
|
|
|
|
|
const loWeb = MediaService; |
|
|