Fixing Adding to Queue for Tracks
[DeezloaderRemix.git] / app / lib / deezer-api / index.js
1 const request = require('request-promise-native')
2 const tough = require('tough-cookie');
3 const Track = require('./obj/Track.js')
4
5 module.exports = class Deezer {
6   constructor(){
7     this.apiUrl = `http://www.deezer.com/ajax/gw-light.php`
8     this.legacyApiUrl = `https://api.deezer.com/`
9     this.httpHeaders = {
10       "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
11       "Content-Language": "en-US",
12       "Cache-Control": "max-age=0",
13       "Accept": "*/*",
14       "Accept-Charset": "utf-8,ISO-8859-1;q=0.7,*;q=0.3",
15       "Accept-Language": "en-US,en;q=0.9,en-US;q=0.8,en;q=0.7"
16     }
17     this.albumPicturesHost = `https://e-cdns-images.dzcdn.net/images/cover/`
18     this.user = {}
19     this.jar = request.jar()
20   }
21
22   getCookies(){
23     return this.jar.getCookies("https://www.deezer.com")
24   }
25
26   setCookies(cookies){
27     JSON.parse("{\"a\": "+cookies+"}").a.forEach(x => {
28       this.jar.setCookie(tough.Cookie.fromJSON(x), "https://www.deezer.com")
29     })
30   }
31
32   async getToken(){
33     var tokenData = await this.apiCall('deezer.getUserData')
34     return tokenData.results.checkForm
35   }
36
37   // Simple function to request data from the hidden API (gw-light.php)
38   async apiCall(method, args = {}){
39     var result = await request({
40       uri: this.apiUrl,
41       method: 'POST',
42       qs: {
43         api_version: "1.0",
44         api_token: (method === "deezer.getUserData" ? "null" : await this.getToken()),
45         input: "3",
46         method: method
47       },
48       body: args,
49       jar: this.jar,
50       json: true,
51       headers: this.httpHeaders
52     })
53     return result
54   }
55
56   // Simple function to request data from the legacy API (api.deezer.com)
57   async legacyApiCall(method, args = {}){
58     var result = await request({
59       uri: `${this.legacyApiUrl}${method}`,
60       method: 'GET',
61       qs: args,
62       jar: this.jar,
63       json: true,
64       headers: this.httpHeaders
65     })
66     return result
67   }
68
69   // Login function
70   async login(mail, password){
71     try{
72       // The new login page requires a checkFormLogin field
73       // We can get that from the hidden API
74       var checkFormLogin = await this.apiCall("deezer.getUserData")
75       // Now we'll ask to login
76       var login = await request({
77         method: 'POST',
78         url: `https://www.deezer.com/ajax/action.php`,
79         form: {
80           type:'login',
81           mail: mail,
82           password: password,
83           checkFormLogin: checkFormLogin.results.checkFormLogin
84         },
85         headers: {
86           ...this.httpHeaders,
87           'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
88         },
89         jar: this.jar,
90         withCredentials: true
91       })
92       if (!login.includes('success'))
93         throw new Error(`Wrong e-mail or password`)
94       // Next we'll get the user data, so we can display playlists the name, images from the user
95       var userData = await this.apiCall(`deezer.getUserData`)
96       this.user = {
97         email: mail,
98         id: userData.results.USER.USER_ID,
99         name: userData.results.USER.BLOG_NAME,
100         picture: userData.results.USER.USER_PICTURE ? `https://e-cdns-images.dzcdn.net/images/user/${userData.results.USER.USER_PICTURE}/250x250-000000-80-0-0.jpg` : ""
101       }
102       return true
103     } catch(err){
104       throw new Error(`Can't connect to Deezer: ${err.message}`)
105     }
106   }
107
108   // Login via cookie function
109   async loginViaCookies(cookies, email){
110     try{
111       this.setCookies(cookies)
112       var userData = await this.apiCall(`deezer.getUserData`)
113       this.user = {
114         email: email,
115         id: userData.results.USER.USER_ID,
116         name: userData.results.USER.BLOG_NAME,
117         picture: userData.results.USER.USER_PICTURE ? `https://e-cdns-images.dzcdn.net/images/user/${userData.results.USER.USER_PICTURE}/250x250-000000-80-0-0.jpg` : ""
118       }
119       return true
120     } catch(err){
121       throw new Error(`Can't connect to Deezer: ${err.message}`)
122     }
123   }
124
125   async getTrack(id, settings = {}){
126     var body
127     if (id<0){
128       body = await this.apiCall(`song.getData`, {sng_id: id})
129       body.type = -1
130     }else{
131       body = await this.apiCall(`deezer.pageTrack`, {sng_id: id})
132       body.type = 0
133     }
134     return new Track(body)
135   }
136
137   async getAlbum(id){
138     var body = await this.apiCall(`album.getData`, {alb_id: id})
139     return body
140   }
141
142   async getAlbumTracks(id){
143     var body = await this.apiCall(`song.getListByAlbum`, {alb_id: id, nb: -1})
144     return body.results
145   }
146
147   async getArtist(id){
148     var body = await this.apiCall(`deezer.pageArtist`, {art_id: id})
149     return body
150   }
151
152   async getPlaylist(id){
153     var body = await this.apiCall(`deezer.pagePlaylist`, {playlist_id: id})
154     return body
155   }
156
157   async getPlaylistTracks(id){
158     var body = await this.apiCall(`playlist.getSongs`, {playlist_id: id, nb: -1})
159     return body.results
160   }
161
162   async legacyGetUserPlaylists(id){
163     var body = await this.legacyApiCall(`user/${id}/playlists`, {limit: -1})
164     return body
165   }
166
167   async legacyGetChartsTopCountry(){
168     return await this.legacyGetUserPlaylists('637006841')
169   }
170
171   async legacyGetPlaylistTracks(id){
172     var body = await this.legacyApiCall(`playlist/${id}/tracks`, {limit: -1})
173     return body
174   }
175
176   async legacyGetAlbum(id){
177     var body = await this.legacyApiCall(`album/${id}`)
178     return body
179   }
180
181   async legacyGetAlbumTracks(id){
182     var body = await this.legacyApiCall(`album/${id}/tracks`, {limit: -1})
183     return body
184   }
185
186   async legacySearch(term, type){
187     var body = await this.legacyApiCall(`search/${type}`, {q: term})
188     if(body.error) {
189       throw new Error("Wrong search type/text: " + text)
190     }
191     return body
192   }
193 }