Merge pull request #5 from forkbomb9/patch-1
getTrackDownloadUrl: return track data in json format
This commit is contained in:
commit
d54d9022d9
|
@ -1,7 +1,7 @@
|
|||
import test from 'ava';
|
||||
import axios from 'axios';
|
||||
import * as api from '../src';
|
||||
import {trackIsEncrypted, decryptDownload} from '../src/lib/decrypt';
|
||||
import {decryptDownload} from '../src/lib/decrypt';
|
||||
import {downloadAlbumCover} from '../src/metadata-writer/abumCover';
|
||||
import {getLyricsMusixmatch} from '../src/metadata-writer/musixmatchLyrics';
|
||||
import {getTrackDownloadUrl} from '../src/lib/get-url';
|
||||
|
@ -146,14 +146,15 @@ test('SEARCH TRACK, ALBUM & ARTIST', async (t) => {
|
|||
if (process.env.CI) {
|
||||
test('DOWNLOAD TRACK128 & ADD METADATA', async (t) => {
|
||||
const track = await api.getTrackInfo(SNG_ID);
|
||||
const url = await getTrackDownloadUrl(track, 1);
|
||||
const {data} = await axios.get(url, {responseType: 'arraybuffer'});
|
||||
const trackData = await getTrackDownloadUrl(track, 1);
|
||||
if (!trackData) throw new Error("Selected track+quality are unavailable");
|
||||
const {data} = await axios.get(trackData.trackUrl, {responseType: 'arraybuffer'});
|
||||
|
||||
t.truthy(data);
|
||||
t.true(Buffer.isBuffer(data));
|
||||
t.is(data.length, 3596119);
|
||||
|
||||
const decryptedTrack: Buffer = trackIsEncrypted(url) ? decryptDownload(data, track.SNG_ID) : data;
|
||||
const decryptedTrack: Buffer = trackData.isEncrypted ? decryptDownload(data, track.SNG_ID) : data;
|
||||
t.true(Buffer.isBuffer(decryptedTrack));
|
||||
t.is(decryptedTrack.length, 3596119);
|
||||
|
||||
|
@ -164,14 +165,15 @@ if (process.env.CI) {
|
|||
|
||||
// test('TRACK128 WITHOUT ALBUM INFO', async (t) => {
|
||||
// const track = await api.getTrackInfo('912254892');
|
||||
// const url = await getTrackDownloadUrl(track, 1);
|
||||
// const {data} = await axios.get(url, {responseType: 'arraybuffer'});
|
||||
// const trackData = await getTrackDownloadUrl(track, 1);
|
||||
// if (!trackData) throw new Error("Selected track+quality are unavailable");
|
||||
// const {data} = await axios.get(trackData.trackUrl, {responseType: 'arraybuffer'});
|
||||
|
||||
// t.truthy(data);
|
||||
// t.true(Buffer.isBuffer(data));
|
||||
// t.is(data.length, 3262170);
|
||||
|
||||
// const decryptedTrack: Buffer = trackIsEncrypted(url) ? decryptDownload(data, track.SNG_ID) : data;
|
||||
// const decryptedTrack: Buffer = trackData.isEncrypted ? decryptDownload(data, track.SNG_ID) : data;
|
||||
// t.true(Buffer.isBuffer(decryptedTrack));
|
||||
// t.is(decryptedTrack.length, 3262170);
|
||||
|
||||
|
@ -184,14 +186,15 @@ if (process.env.CI) {
|
|||
|
||||
test('DOWNLOAD TRACK320 & ADD METADATA', async (t) => {
|
||||
const track = await api.getTrackInfo(SNG_ID);
|
||||
const url = await getTrackDownloadUrl(track, 3);
|
||||
const {data} = await axios.get(url, {responseType: 'arraybuffer'});
|
||||
const trackData = await getTrackDownloadUrl(track, 3);
|
||||
if (!trackData) throw new Error("Selected track+quality are unavailable");
|
||||
const {data} = await axios.get(trackData.trackUrl, {responseType: 'arraybuffer'});
|
||||
|
||||
t.truthy(data);
|
||||
t.true(Buffer.isBuffer(data));
|
||||
t.is(data.length, 8990301);
|
||||
|
||||
const decryptedTrack: Buffer = trackIsEncrypted(url) ? decryptDownload(data, track.SNG_ID) : data;
|
||||
const decryptedTrack: Buffer = trackData.isEncrypted ? decryptDownload(data, track.SNG_ID) : data;
|
||||
t.true(Buffer.isBuffer(decryptedTrack));
|
||||
t.is(decryptedTrack.length, 8990301);
|
||||
|
||||
|
@ -202,14 +205,15 @@ if (process.env.CI) {
|
|||
|
||||
test('DOWNLOAD TRACK1411 & ADD METADATA', async (t) => {
|
||||
const track = await api.getTrackInfo(SNG_ID);
|
||||
const url = await getTrackDownloadUrl(track, 9);
|
||||
const {data} = await axios.get(url, {responseType: 'arraybuffer'});
|
||||
const trackData = await getTrackDownloadUrl(track, 9);
|
||||
if (!trackData) throw new Error("Selected track+quality are unavailable");
|
||||
const {data} = await axios.get(trackData.trackUrl, {responseType: 'arraybuffer'});
|
||||
|
||||
t.truthy(data);
|
||||
t.true(Buffer.isBuffer(data));
|
||||
t.is(data.length, 25418289);
|
||||
|
||||
const decryptedTrack: Buffer = trackIsEncrypted(url) ? decryptDownload(data, track.SNG_ID) : data;
|
||||
const decryptedTrack: Buffer = trackData.isEncrypted ? decryptDownload(data, track.SNG_ID) : data;
|
||||
t.true(Buffer.isBuffer(decryptedTrack));
|
||||
t.is(data.length, 25418289);
|
||||
|
||||
|
|
|
@ -67,7 +67,3 @@ export const decryptDownload = (source: Buffer, trackId: string) => {
|
|||
|
||||
return destBuffer;
|
||||
};
|
||||
|
||||
export const trackIsEncrypted = (url: string) => {
|
||||
return url.includes('/mobile/') || url.includes('/media/');
|
||||
};
|
||||
|
|
|
@ -65,7 +65,8 @@ const getTrackUrlFromServer = async (track_token: string, format: string): Promi
|
|||
* @param track Track info json returned from `getTrackInfo`
|
||||
* @param quality 1 = 128kbps, 3 = 320kbps and 9 = flac (around 1411kbps)
|
||||
*/
|
||||
export const getTrackDownloadUrl = async (track: trackType, quality: number): Promise<string> => {
|
||||
export const getTrackDownloadUrl = async (track: trackType, quality: number): Promise<{trackUrl: string, isEncrypted: boolean, fileSize: number} | null> => {
|
||||
let wrongLicense = false;
|
||||
let formatName: string;
|
||||
switch (quality) {
|
||||
case 9:
|
||||
|
@ -84,12 +85,19 @@ export const getTrackDownloadUrl = async (track: trackType, quality: number): Pr
|
|||
// Get URL with the official API
|
||||
try {
|
||||
const url = await getTrackUrlFromServer(track.TRACK_TOKEN, formatName);
|
||||
if (url && (await testUrl(url))) {
|
||||
return url;
|
||||
if (url) {
|
||||
const fileSize = await testUrl(url);
|
||||
if (fileSize > 0) {
|
||||
return {
|
||||
trackUrl: url,
|
||||
isEncrypted: url.includes('/mobile/') || url.includes('/media/'),
|
||||
fileSize: fileSize,
|
||||
};
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (err instanceof WrongLicense) {
|
||||
throw new Error(`Your account can't stream ${formatName} tracks`);
|
||||
wrongLicense = true;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
|
@ -98,17 +106,23 @@ export const getTrackDownloadUrl = async (track: trackType, quality: number): Pr
|
|||
// Fallback to the old method
|
||||
const filename = getSongFileName(track, quality); // encrypted file name
|
||||
const url = `https://e-cdns-proxy-${track.MD5_ORIGIN[0]}.dzcdn.net/mobile/1/${filename}`;
|
||||
if (await testUrl(url)) {
|
||||
return url;
|
||||
const fileSize = await testUrl(url);
|
||||
if (fileSize > 0) {
|
||||
return {
|
||||
trackUrl: url,
|
||||
isEncrypted: url.includes('/mobile/') || url.includes('/media/'),
|
||||
fileSize: fileSize,
|
||||
};
|
||||
}
|
||||
throw new Error(`Forbidden to access ${url}`);
|
||||
if (wrongLicense) throw new Error(`Your account can't stream ${formatName} tracks`);
|
||||
return null;
|
||||
};
|
||||
|
||||
const testUrl = async (url: string): Promise<boolean> => {
|
||||
const testUrl = async (url: string): Promise<number> => {
|
||||
try {
|
||||
let response = await axios.head(url);
|
||||
return Number(response.headers['content-length']) > 0 ? true : false;
|
||||
return Number(response.headers['content-length']);
|
||||
} catch (err) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue