Downloads fix, Spanish translation
This commit is contained in:
parent
2858859abd
commit
17df300a18
18 changed files with 548 additions and 103 deletions
|
@ -123,7 +123,7 @@ class DeezerAPI {
|
|||
Map<dynamic, dynamic> data = await callApi('deezer.pageAlbum', params: {
|
||||
'alb_id': id,
|
||||
'header': true,
|
||||
'lang': 'us'
|
||||
'lang': settings.deezerLanguage??'en'
|
||||
});
|
||||
return Album.fromPrivateJson(data['results']['DATA'], songsJson: data['results']['SONGS']);
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ class DeezerAPI {
|
|||
Future<Artist> artist(String id) async {
|
||||
Map<dynamic, dynamic> data = await callApi('deezer.pageArtist', params: {
|
||||
'art_id': id,
|
||||
'lang': 'us',
|
||||
'lang': settings.deezerLanguage??'en',
|
||||
});
|
||||
return Artist.fromPrivateJson(
|
||||
data['results']['DATA'],
|
||||
|
@ -145,7 +145,7 @@ class DeezerAPI {
|
|||
Future<List<Track>> playlistTracksPage(String id, int start, {int nb = 50}) async {
|
||||
Map data = await callApi('deezer.pagePlaylist', params: {
|
||||
'playlist_id': id,
|
||||
'lang': 'us',
|
||||
'lang': settings.deezerLanguage??'en',
|
||||
'nb': nb,
|
||||
'tags': true,
|
||||
'start': start
|
||||
|
@ -157,7 +157,7 @@ class DeezerAPI {
|
|||
Future<Playlist> playlist(String id, {int nb = 100}) async {
|
||||
Map<dynamic, dynamic> data = await callApi('deezer.pagePlaylist', params: {
|
||||
'playlist_id': id,
|
||||
'lang': 'us',
|
||||
'lang': settings.deezerLanguage??'en',
|
||||
'nb': nb,
|
||||
'tags': true,
|
||||
'start': 0
|
||||
|
@ -167,6 +167,10 @@ class DeezerAPI {
|
|||
|
||||
//Get playlist with all tracks
|
||||
Future<Playlist> fullPlaylist(String id) async {
|
||||
return await playlist(id, nb: 100000);
|
||||
|
||||
//OLD WORKAROUND
|
||||
/*
|
||||
Playlist p = await playlist(id, nb: 200);
|
||||
for (int i=200; i<p.trackCount; i++) {
|
||||
//Get another page of tracks
|
||||
|
@ -176,6 +180,7 @@ class DeezerAPI {
|
|||
continue;
|
||||
}
|
||||
return p;
|
||||
*/
|
||||
}
|
||||
|
||||
//Add track to favorites
|
||||
|
@ -305,7 +310,7 @@ class DeezerAPI {
|
|||
"large-card": ["album", "playlist", "show", "video-link"],
|
||||
"ads": [] //Nope
|
||||
},
|
||||
"LANG": "us",
|
||||
"LANG": settings.deezerLanguage??'en',
|
||||
"OPTIONS": []
|
||||
}));
|
||||
return HomePage.fromPrivateJson(data['results']);
|
||||
|
@ -336,7 +341,7 @@ class DeezerAPI {
|
|||
"large-card": ["album", "playlist", "show", "video-link"],
|
||||
"ads": [] //Nope
|
||||
},
|
||||
"LANG": "us",
|
||||
"LANG": settings.deezerLanguage??'en',
|
||||
"OPTIONS": []
|
||||
}));
|
||||
return HomePage.fromPrivateJson(data['results']);
|
||||
|
|
|
@ -186,10 +186,12 @@ class Album {
|
|||
int fans;
|
||||
bool offline; //If the album is offline, or just saved in db as metadata
|
||||
bool library;
|
||||
|
||||
//TODO: Not in DB
|
||||
AlbumType type;
|
||||
String releaseDate;
|
||||
|
||||
Album({this.id, this.title, this.art, this.artists, this.tracks, this.fans, this.offline, this.library, this.type});
|
||||
Album({this.id, this.title, this.art, this.artists, this.tracks, this.fans, this.offline, this.library, this.type, this.releaseDate});
|
||||
|
||||
String get artistString => artists.map<String>((art) => art.name).join(', ');
|
||||
Duration get duration => Duration(seconds: tracks.fold(0, (v, t) => v += t.duration.inSeconds));
|
||||
|
@ -210,7 +212,8 @@ class Album {
|
|||
tracks: (songsJson['data']??[]).map<Track>((dynamic track) => Track.fromPrivateJson(track)).toList(),
|
||||
fans: json['NB_FAN'],
|
||||
library: library,
|
||||
type: type
|
||||
type: type,
|
||||
releaseDate: json['DIGITAL_RELEASE_DATE']??json['PHYSICAL_RELEASE_DATE']
|
||||
);
|
||||
}
|
||||
Map<String, dynamic> toSQL({off = false}) => {
|
||||
|
@ -281,7 +284,7 @@ class Artist {
|
|||
albums: (albumsJson['data']??[]).map<Album>((dynamic data) => Album.fromPrivateJson(data)).toList(),
|
||||
topTracks: (topJson['data']??[]).map<Track>((dynamic data) => Track.fromPrivateJson(data)).toList(),
|
||||
library: library,
|
||||
radio: _radio
|
||||
radio: _radio,
|
||||
);
|
||||
}
|
||||
Map<String, dynamic> toSQL({off = false}) => {
|
||||
|
|
|
@ -70,6 +70,7 @@ Album _$AlbumFromJson(Map<String, dynamic> json) {
|
|||
offline: json['offline'] as bool,
|
||||
library: json['library'] as bool,
|
||||
type: _$enumDecodeNullable(_$AlbumTypeEnumMap, json['type']),
|
||||
releaseDate: json['releaseDate'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -83,6 +84,7 @@ Map<String, dynamic> _$AlbumToJson(Album instance) => <String, dynamic>{
|
|||
'offline': instance.offline,
|
||||
'library': instance.library,
|
||||
'type': _$AlbumTypeEnumMap[instance.type],
|
||||
'releaseDate': instance.releaseDate,
|
||||
};
|
||||
|
||||
T _$enumDecode<T>(
|
||||
|
|
|
@ -132,10 +132,23 @@ class DownloadManager {
|
|||
}
|
||||
).catchError((e, st) async {
|
||||
if (stopped) return;
|
||||
print('Download error: $e\n$st');
|
||||
//Catch download errors
|
||||
_download = null;
|
||||
_cancelNotifications = true;
|
||||
|
||||
//Deezer error - track is unavailable
|
||||
if (queue[0].state == DownloadState.DEEZER_ERROR) {
|
||||
await db.rawUpdate('UPDATE downloads SET state = 4 WHERE trackId = ?', [queue[0].track.id]);
|
||||
queue.removeAt(0);
|
||||
_cancelNotifications = false;
|
||||
_download = null;
|
||||
updateQueue();
|
||||
return;
|
||||
}
|
||||
|
||||
//Clean
|
||||
_download = null;
|
||||
stopped = true;
|
||||
print('Download error: $e\n$st');
|
||||
|
||||
queue[0].state = DownloadState.NONE;
|
||||
//Shift to end
|
||||
queue.add(queue[0]);
|
||||
|
@ -442,7 +455,7 @@ class DownloadManager {
|
|||
|
||||
Future<List<Download>> getFinishedDownloads() async {
|
||||
//Fetch from db
|
||||
List<Map> data = await db.rawQuery("SELECT * FROM downloads INNER JOIN tracks ON tracks.id = downloads.trackId WHERE downloads.state = 1");
|
||||
List<Map> data = await db.rawQuery("SELECT * FROM downloads INNER JOIN tracks ON tracks.id = downloads.trackId WHERE downloads.state = 1 OR downloads.state > 3");
|
||||
List<Download> downloads = data.map<Download>((d) => Download.fromSQL(d, parseTrack: true)).toList();
|
||||
return downloads;
|
||||
}
|
||||
|
@ -545,6 +558,12 @@ class Download {
|
|||
try {rawTrackPublic = await deezerAPI.callPublicApi('track/${this.track.id}');} catch (e) {rawTrackPublic = {};}
|
||||
try {rawAlbumPublic = await deezerAPI.callPublicApi('album/${this.track.album.id}');} catch (e) {rawAlbumPublic = {};}
|
||||
|
||||
//Global block check
|
||||
if (rawTrackPublic['available_countries'] != null && rawTrackPublic['available_countries'].length == 0) {
|
||||
this.state = DownloadState.DEEZER_ERROR;
|
||||
throw Exception('Download error - not on Deezer');
|
||||
}
|
||||
|
||||
//Get path if public
|
||||
RegExp sanitize = RegExp(r'[\/\\\?\%\*\:\|\"\<\>]');
|
||||
//Download path
|
||||
|
@ -608,6 +627,10 @@ class Download {
|
|||
//Download
|
||||
this.state = DownloadState.DOWNLOADING;
|
||||
|
||||
//Quality fallback
|
||||
if (this.url == null)
|
||||
await _fallback();
|
||||
|
||||
//Create download file
|
||||
File downloadFile = File(this.path + '.ENC');
|
||||
//Get start position
|
||||
|
@ -616,26 +639,32 @@ class Download {
|
|||
FileStat stat = await downloadFile.stat();
|
||||
start = stat.size;
|
||||
} else {
|
||||
//Create file if doesnt exist
|
||||
//Create file if doesn't exist
|
||||
await downloadFile.create(recursive: true);
|
||||
}
|
||||
|
||||
//Quality fallback
|
||||
if (this.url == null)
|
||||
await _fallback();
|
||||
|
||||
//Download
|
||||
_cancel = CancelToken();
|
||||
Response response = await dio.get(
|
||||
this.url,
|
||||
options: Options(
|
||||
responseType: ResponseType.stream,
|
||||
headers: {
|
||||
'Range': 'bytes=$start-'
|
||||
},
|
||||
),
|
||||
cancelToken: _cancel
|
||||
);
|
||||
Response response;
|
||||
try {
|
||||
response = await dio.get(
|
||||
this.url,
|
||||
options: Options(
|
||||
responseType: ResponseType.stream,
|
||||
headers: {
|
||||
'Range': 'bytes=$start-'
|
||||
},
|
||||
),
|
||||
cancelToken: _cancel
|
||||
);
|
||||
} on DioError catch (e) {
|
||||
//Deezer fetch error
|
||||
if (e.response.statusCode == 403 || e.response.statusCode == 404) {
|
||||
this.state = DownloadState.DEEZER_ERROR;
|
||||
}
|
||||
throw Exception('Download error - Deezer blocked.');
|
||||
}
|
||||
|
||||
//Size
|
||||
this.total = int.parse(response.headers['Content-Length'][0]) + start;
|
||||
this.received = start;
|
||||
|
@ -655,7 +684,6 @@ class Download {
|
|||
await _outSink.close();
|
||||
_cancel = null;
|
||||
|
||||
|
||||
this.state = DownloadState.POST;
|
||||
//Decrypt
|
||||
await platformChannel.invokeMethod('decryptTrack', {'id': track.id, 'path': path});
|
||||
|
@ -754,21 +782,23 @@ class Download {
|
|||
'trackId': track.id,
|
||||
'path': path,
|
||||
'url': url,
|
||||
'state': state == DownloadState.DONE ? 1:0,
|
||||
'state': state.index,
|
||||
'private': private?1:0
|
||||
};
|
||||
factory Download.fromSQL(Map<String, dynamic> data, {parseTrack = false}) => Download(
|
||||
track: parseTrack?Track.fromSQL(data):Track(id: data['trackId']),
|
||||
path: data['path'],
|
||||
url: data['url'],
|
||||
state: data['state'] == 1 ? DownloadState.DONE:DownloadState.NONE,
|
||||
state: DownloadState.values[data['state']],
|
||||
private: data['private'] == 1
|
||||
);
|
||||
}
|
||||
|
||||
enum DownloadState {
|
||||
NONE,
|
||||
DONE,
|
||||
DOWNLOADING,
|
||||
POST,
|
||||
DONE
|
||||
DEEZER_ERROR,
|
||||
ERROR
|
||||
}
|
|
@ -485,7 +485,9 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
|||
//Load queue after some initialization in frontend
|
||||
if (name == 'load') await this._loadQueueFile();
|
||||
//Shuffle
|
||||
if (name == 'shuffle') await _player.setShuffleModeEnabled(args);
|
||||
if (name == 'shuffle') {
|
||||
await _player.setShuffleModeEnabled(args);
|
||||
}
|
||||
//Android auto callback
|
||||
if (name == 'screenAndroidAuto' && _androidAutoCallback != null) {
|
||||
_androidAutoCallback.complete(jsonDecode(args).map<MediaItem>((m) => MediaItem.fromJson(m)).toList());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue