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