1.1.24 - FLAC for HiFi users
This commit is contained in:
parent
6302f54fbd
commit
53f6b760fe
|
@ -148,12 +148,12 @@
|
||||||
"Save": "Zapisz",
|
"Save": "Zapisz",
|
||||||
"Edit": "Edytuj",
|
"Edit": "Edytuj",
|
||||||
"Importer": "Importer",
|
"Importer": "Importer",
|
||||||
"Enter URL": "Enter URL",
|
"Enter URL": "Wprowadź adres URL",
|
||||||
"Currently only Spotify is supported and limited to 100 tracks.": "Currently only Spotify is supported and limited to 100 tracks.",
|
"Currently only Spotify is supported and limited to 100 tracks.": "Obecnie obsługuje tylko Spotify i maksymalnie 100 utworów.",
|
||||||
"Import into playlist": "Import into playlist",
|
"Import into playlist": "Importuj na playlistę",
|
||||||
"Keep sidebar open": "Keep sidebar open",
|
"Keep sidebar open": "Panel boczny zawsze otwarty",
|
||||||
"WARNING: Might require reload to work properly!": "WARNING: Might require reload to work properly!",
|
"WARNING: Might require reload to work properly!": "UWAGA: Może wymagać ponownego uruchomienia, by działać poprawnie!",
|
||||||
"An error occured, URL might be invalid or unsupported.": "An error occured, URL might be invalid or unsupported.",
|
"An error occured, URL might be invalid or unsupported.": "Wystąpił błąd, adres URL może być nieprawidłowy lub nieobsługiwany.",
|
||||||
"Top tracks": "Najpopularniejsze utwory",
|
"Top tracks": "Najpopularniejsze utwory",
|
||||||
"Show all top tracks": "Pokaż wszystkie najpopularniejsze utwory",
|
"Show all top tracks": "Pokaż wszystkie najpopularniejsze utwory",
|
||||||
"Singles": "Single",
|
"Singles": "Single",
|
||||||
|
@ -163,9 +163,9 @@
|
||||||
"No": "Nie",
|
"No": "Nie",
|
||||||
"Download Filename": "Nazwa pobieranego pliku",
|
"Download Filename": "Nazwa pobieranego pliku",
|
||||||
"Language": "Język",
|
"Language": "Język",
|
||||||
"Background Image": "Background Image",
|
"Background Image": "Obraz w tle",
|
||||||
"Enter URL or absolute path. WARNING: Requires reload!": "Enter URL or absolute path. WARNING: Requires reload!",
|
"Enter URL or absolute path. WARNING: Requires reload!": "Wprowadź adres URL lub całą ścieżkę pliku. UWAGA: Wymaga ponownego uruchomienia!",
|
||||||
"LGBT Mode": "LGBT Mode",
|
"LGBT Mode": "Tryb LGBT",
|
||||||
"Native top bar": "Native top bar",
|
"Native top bar": "Natywny górny pasek",
|
||||||
"Requires restart of Freezer!": "Requires restart of Freezer!"
|
"Requires restart of Freezer!": "Wymaga ponownego uruchomiania Freezera!"
|
||||||
}
|
}
|
|
@ -236,7 +236,11 @@ new Vue({
|
||||||
this.playbackInfo = playbackInfo;
|
this.playbackInfo = playbackInfo;
|
||||||
|
|
||||||
//Stream URL
|
//Stream URL
|
||||||
let url = `${process.env.NODE_ENV === 'development' ? "http://localhost:10069" : window.location.origin}${this.playbackInfo.url}`;
|
let url;
|
||||||
|
if (this.playbackInfo.encrypted)
|
||||||
|
url = `${process.env.NODE_ENV === 'development' ? "http://localhost:10069" : window.location.origin}${this.playbackInfo.url}`;
|
||||||
|
else
|
||||||
|
url = this.playbackInfo.direct;
|
||||||
//Cancel loading
|
//Cancel loading
|
||||||
this.loaders--;
|
this.loaders--;
|
||||||
if (this.loaders > 0) {
|
if (this.loaders > 0) {
|
||||||
|
@ -424,7 +428,10 @@ new Vue({
|
||||||
if (this.gapless.promise) resolve();
|
if (this.gapless.promise) resolve();
|
||||||
}
|
}
|
||||||
this.gapless.info = info
|
this.gapless.info = info
|
||||||
|
if (info.encrypted)
|
||||||
this.gapless.audio = new Audio(`${process.env.NODE_ENV === 'development' ? "http://localhost:10069" : window.location.origin}${info.url}`);
|
this.gapless.audio = new Audio(`${process.env.NODE_ENV === 'development' ? "http://localhost:10069" : window.location.origin}${info.url}`);
|
||||||
|
else
|
||||||
|
this.gapless.audio = new Audio(info.direct);
|
||||||
this.gapless.audio.volume = 0.00;
|
this.gapless.audio.volume = 0.00;
|
||||||
this.gapless.audio.preload = 'auto';
|
this.gapless.audio.preload = 'auto';
|
||||||
this.gapless.crossfade = false;
|
this.gapless.crossfade = false;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "freezer",
|
"name": "freezer",
|
||||||
"version": "1.1.20",
|
"version": "1.1.23",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "freezer",
|
"name": "freezer",
|
||||||
"version": "1.1.20",
|
"version": "1.1.23",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"arg": "^5.0.0",
|
"arg": "^5.0.0",
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"discord-rpc": "^3.2.0",
|
"discord-rpc": "^3.2.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
|
"form-data": "^2.3.3",
|
||||||
"lastfmapi": "^0.1.1",
|
"lastfmapi": "^0.1.1",
|
||||||
"metaflac-js2": "^1.0.7",
|
"metaflac-js2": "^1.0.7",
|
||||||
"nedb": "^1.8.0",
|
"nedb": "^1.8.0",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "freezer",
|
"name": "freezer",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.1.23",
|
"version": "1.1.24",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "background.js",
|
"main": "background.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -140,11 +140,37 @@ class DeezerAPI {
|
||||||
this.token = data.results.checkForm;
|
this.token = data.results.checkForm;
|
||||||
this.userId = data.results.USER.USER_ID;
|
this.userId = data.results.USER.USER_ID;
|
||||||
this.favoritesPlaylist = data.results.USER.LOVEDTRACKS_ID.toString();
|
this.favoritesPlaylist = data.results.USER.LOVEDTRACKS_ID.toString();
|
||||||
|
try {
|
||||||
|
await this.authorizeAtv();
|
||||||
|
} catch (e) {
|
||||||
|
logger.warn(`Couldnt authorize ATV: ${e}`);
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.userId || this.userId == 0 || !this.token) return false;
|
if (!this.userId || this.userId == 0 || !this.token) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Authorize Android TV
|
||||||
|
async authorizeAtv() {
|
||||||
|
let res = await axios.post(
|
||||||
|
"https://distribution-api.deezer.com/device/token",
|
||||||
|
{"brand_name":"Hisense","device_id":"7239e4071d8992c955ad","model_name":"HE50A6109FUWTS","country_code":"FRA"}
|
||||||
|
);
|
||||||
|
let deviceToken = res.data.device_token;
|
||||||
|
// Get unauthorized token
|
||||||
|
res = await axios.get('https://connect.deezer.com/oauth/access_token.php?grant_type=client_credentials&client_id=447462&client_secret=a83bf7f38ad2f137e444727cfc3775cf&output=json');
|
||||||
|
let accessToken = res.data.access_token;
|
||||||
|
// Get smart login code
|
||||||
|
res = await axios.post(`https://connect.deezer.com/2.0/smartlogin/device?access_token=${accessToken}&device_token=${deviceToken}`);
|
||||||
|
let smartLoginCode = res.data.data.smartLoginCode;
|
||||||
|
// Associate
|
||||||
|
await this.callApi('deezer.associateSmartLoginCodeWithUser', {'SMARTLOGIN_CODE': smartLoginCode});
|
||||||
|
// Get authorized token
|
||||||
|
res = await axios.get(`https://connect.deezer.com/2.0/smartlogin/${smartLoginCode}?access_token=${accessToken}`);
|
||||||
|
accessToken = res.data.data.accessToken;
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
//Wrapper because electron is piece of shit
|
//Wrapper because electron is piece of shit
|
||||||
async callPublicApi(path, params) {
|
async callPublicApi(path, params) {
|
||||||
if (this.electron) return await this._callPublicApiElectron(path, params);
|
if (this.electron) return await this._callPublicApiElectron(path, params);
|
||||||
|
@ -223,6 +249,30 @@ class DeezerAPI {
|
||||||
return `https://e-cdns-proxy-${md5origin.substring(0, 1)}.dzcdn.net/mobile/1/${step3}`;
|
return `https://e-cdns-proxy-${md5origin.substring(0, 1)}.dzcdn.net/mobile/1/${step3}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Generate url with android tv support
|
||||||
|
async generateUrl(trackId, md5origin, mediaVersion, quality = 3) {
|
||||||
|
if (quality == 9 && this.accessToken) {
|
||||||
|
try {
|
||||||
|
let res = await axios({
|
||||||
|
method: 'GET',
|
||||||
|
url: `https://api.deezer.com/platform/gcast/track/${trackId}/streamUrls`,
|
||||||
|
headers: {
|
||||||
|
"Authorization": "Bearer " + this.accessToken
|
||||||
|
},
|
||||||
|
responseType: 'json'
|
||||||
|
});
|
||||||
|
if (res.data.data.attributes.url_flac)
|
||||||
|
return {encrypted: false, url: res.data.data.attributes.url_flac};
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(`Failed getting ATV URL! Using normal: ${e}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
encrypted: true,
|
||||||
|
url: DeezerAPI.getUrl(trackId, md5origin, mediaVersion, quality)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async fallback(info, quality = 3) {
|
async fallback(info, quality = 3) {
|
||||||
let qualityInfo = Track.getUrlInfo(info);
|
let qualityInfo = Track.getUrlInfo(info);
|
||||||
|
@ -266,11 +316,15 @@ class DeezerAPI {
|
||||||
//Fallback thru available qualities, -1 if none work
|
//Fallback thru available qualities, -1 if none work
|
||||||
async qualityFallback(info, quality = 3) {
|
async qualityFallback(info, quality = 3) {
|
||||||
try {
|
try {
|
||||||
let res = await axios.head(DeezerAPI.getUrl(info.trackId, info.md5origin, info.mediaVersion, quality));
|
let urlGen = await this.generateUrl(info.trackId, info.md5origin, info.mediaVersion, quality);
|
||||||
|
let res = await axios.head(urlGen.url);
|
||||||
if (res.status > 400) throw new Error(`Status code: ${res.status}`);
|
if (res.status > 400) throw new Error(`Status code: ${res.status}`);
|
||||||
//Make sure it's an int
|
//Make sure it's an int
|
||||||
info.quality = parseInt(quality.toString(), 10);
|
info.quality = parseInt(quality.toString(), 10);
|
||||||
info.size = parseInt(res.headers['content-length'], 10);
|
info.size = parseInt(res.headers['content-length'], 10);
|
||||||
|
info.encrypted = urlGen.encrypted;
|
||||||
|
if (!info.encrypted)
|
||||||
|
info.direct = urlGen.url;
|
||||||
return info;
|
return info;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.warn('Quality fallback: ' + e);
|
logger.warn('Quality fallback: ' + e);
|
||||||
|
|
|
@ -206,6 +206,7 @@ class DownloadThread {
|
||||||
this.stopped = true;
|
this.stopped = true;
|
||||||
this.isUserUploaded = download.track.id.toString().startsWith('-');
|
this.isUserUploaded = download.track.id.toString().startsWith('-');
|
||||||
this.coverPath = null;
|
this.coverPath = null;
|
||||||
|
this.encrypted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Callback wrapper
|
//Callback wrapper
|
||||||
|
@ -262,9 +263,11 @@ class DownloadThread {
|
||||||
this.download.downloaded = start;
|
this.download.downloaded = start;
|
||||||
|
|
||||||
//Download
|
//Download
|
||||||
let url = DeezerAPI.getUrl(this.qualityInfo.trackId, this.qualityInfo.md5origin, this.qualityInfo.mediaVersion, this.qualityInfo.quality);
|
let urlGen = await deezer.generateUrl(this.qualityInfo.trackId, this.qualityInfo.md5origin, this.qualityInfo.mediaVersion, this.qualityInfo.quality);
|
||||||
|
this.encrypted = urlGen.encrypted;
|
||||||
|
|
||||||
if (this.stopped) return;
|
if (this.stopped) return;
|
||||||
this._request = https.get(url, {headers: {'Range': `bytes=${start}-`}}, (r) => {
|
this._request = https.get(urlGen.url, {headers: {'Range': `bytes=${start}-`}}, (r) => {
|
||||||
this._response = r;
|
this._response = r;
|
||||||
let outFile = fs.createWriteStream(tmp, {flags: 'a'});
|
let outFile = fs.createWriteStream(tmp, {flags: 'a'});
|
||||||
|
|
||||||
|
@ -321,13 +324,18 @@ class DownloadThread {
|
||||||
this.download.state = 2;
|
this.download.state = 2;
|
||||||
|
|
||||||
//Decrypt
|
//Decrypt
|
||||||
decryptor.decryptFile(decryptor.getKey(this.qualityInfo.trackId), tmp, `${tmp}.DEC`);
|
|
||||||
let outPath = this.generatePath(this.qualityInfo.quality);
|
let outPath = this.generatePath(this.qualityInfo.quality);
|
||||||
await fs.promises.mkdir(path.dirname(outPath), {recursive: true});
|
await fs.promises.mkdir(path.dirname(outPath), {recursive: true});
|
||||||
|
if (this.encrypted) {
|
||||||
|
decryptor.decryptFile(decryptor.getKey(this.qualityInfo.trackId), tmp, `${tmp}.DEC`);
|
||||||
await fs.promises.copyFile(`${tmp}.DEC`, outPath);
|
await fs.promises.copyFile(`${tmp}.DEC`, outPath);
|
||||||
await fs.promises.unlink(`${tmp}.DEC`);
|
await fs.promises.unlink(`${tmp}.DEC`);
|
||||||
|
} else {
|
||||||
|
await fs.promises.copyFile(tmp, outPath);
|
||||||
|
}
|
||||||
await fs.promises.unlink(tmp);
|
await fs.promises.unlink(tmp);
|
||||||
|
|
||||||
|
|
||||||
let cover = null;
|
let cover = null;
|
||||||
|
|
||||||
if (!this.isUserUploaded) {
|
if (!this.isUserUploaded) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "freezer",
|
"name": "freezer",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.1.23",
|
"version": "1.1.24",
|
||||||
"description": "Freezer PC",
|
"description": "Freezer PC",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"pack": "electron-builder --dir",
|
"pack": "electron-builder --dir",
|
||||||
|
|
Loading…
Reference in New Issue