From 3d0996819bbcf57d50c4c4a0d6f67ceaabba8fe9 Mon Sep 17 00:00:00 2001 From: Fergus Longley Date: Tue, 6 Jul 2021 22:09:21 +0100 Subject: [PATCH 1/4] Updated to null safety --- example/.gitignore | 1 + .../album_methods_example.dart | 2 +- .../artist_methods_example.dart | 2 +- .../track_methods_example.dart | 4 +- .../user_methods_example.dart | 4 +- .../album_methods_example.dart | 4 +- .../artist_methods_example.dart | 2 +- .../methods_example/geo_methods_example.dart | 2 +- .../library_methods_example.dart | 7 +- example/methods_example/scrobble_example.dart | 12 +- .../track_methods_example.dart | 6 +- .../methods_example/user_methods_example.dart | 10 +- example/scrobblenaut_example.dart | 6 +- lib/src/core/lastfm.dart | 61 +- lib/src/core/request.dart | 22 +- lib/src/core/session_key_generator.dart | 3 +- lib/src/exceptions/lastfm_exception.dart | 11 +- .../exceptions/scrobblenaut_exception.dart | 6 +- lib/src/extensions/album_extension.dart | 34 +- lib/src/extensions/artist_extension.dart | 29 +- lib/src/extensions/tag_extension.dart | 10 +- lib/src/extensions/track_extension.dart | 75 +- lib/src/extensions/user_extension.dart | 51 +- lib/src/helpers/lastfm_value_normalizer.dart | 58 +- lib/src/helpers/now_played_track.dart | 33 +- lib/src/helpers/scrobble_response.dart | 12 +- lib/src/helpers/scrobbled_track.dart | 39 +- lib/src/helpers/utils.dart | 5 +- lib/src/lastfm.dart | 5 +- lib/src/lastfm.g.dart | 766 ++++++++++++++++++ lib/src/lastfm/album.dart | 21 +- lib/src/lastfm/album_results.dart | 8 +- lib/src/lastfm/artist.dart | 30 +- lib/src/lastfm/artist_results.dart | 8 +- lib/src/lastfm/bio.dart | 8 +- lib/src/lastfm/chart.dart | 7 +- lib/src/lastfm/core/attr.dart | 25 + lib/src/lastfm/core/now_playing_object.dart | 35 +- lib/src/lastfm/core/scrobble_object.dart | 50 +- lib/src/lastfm/core/session.dart | 6 +- lib/src/lastfm/date.dart | 4 +- lib/src/lastfm/enums/periods.dart | 2 +- lib/src/lastfm/enums/tagging_type.dart | 2 +- lib/src/lastfm/image.dart | 5 +- lib/src/lastfm/link.dart | 6 +- lib/src/lastfm/registered.dart | 4 +- lib/src/lastfm/responses/library.dart | 17 + lib/src/lastfm/stats.dart | 6 +- lib/src/lastfm/streamable.dart | 4 +- lib/src/lastfm/tag.dart | 16 +- lib/src/lastfm/taggings.dart | 6 +- lib/src/lastfm/track.dart | 28 +- lib/src/lastfm/track_results.dart | 8 +- lib/src/lastfm/user.dart | 26 +- lib/src/lastfm/wiki.dart | 6 +- lib/src/methods/album_methods.dart | 47 +- lib/src/methods/artist_methods.dart | 69 +- lib/src/methods/chart_methods.dart | 6 +- lib/src/methods/geo_methods.dart | 11 +- lib/src/methods/library_methods.dart | 16 +- lib/src/methods/tag_methods.dart | 27 +- lib/src/methods/track_methods.dart | 168 ++-- lib/src/methods/user_methods.dart | 91 +-- lib/src/scrobblenaut.dart | 24 +- lib/src/tools/spaceship.dart | 46 +- pubspec.yaml | 20 +- test/scrobblenaut_test.dart | 2 +- 67 files changed, 1474 insertions(+), 673 deletions(-) create mode 100644 example/.gitignore create mode 100644 lib/src/lastfm.g.dart create mode 100644 lib/src/lastfm/core/attr.dart create mode 100644 lib/src/lastfm/responses/library.dart diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 0000000..5fe24d1 --- /dev/null +++ b/example/.gitignore @@ -0,0 +1 @@ +api_values.dart diff --git a/example/applied_methods_example/album_methods_example.dart b/example/applied_methods_example/album_methods_example.dart index 638649f..14b3de5 100644 --- a/example/applied_methods_example/album_methods_example.dart +++ b/example/applied_methods_example/album_methods_example.dart @@ -43,7 +43,7 @@ void main() async { )); print('Album Name: ${albumGetInfo.name} |' - ' Album Artist: ${albumGetInfo.artist.name}'); + ' Album Artist: ${albumGetInfo.artist?.name}'); albumGetInfo.tracks?.forEach((Track track) { print('Track Title: ${track.name} | Track Duration: ${track.duration}'); diff --git a/example/applied_methods_example/artist_methods_example.dart b/example/applied_methods_example/artist_methods_example.dart index 784640d..86b5655 100644 --- a/example/applied_methods_example/artist_methods_example.dart +++ b/example/applied_methods_example/artist_methods_example.dart @@ -37,7 +37,7 @@ void main() async { print('#######################artist.getCorrection#########################'); // artist.getCorrection - (await artistInstance.getCorrection())?.forEach((Artist artist) { + (await artistInstance.getCorrection()).forEach((Artist artist) { print('Artist correction: ${artist.name}'); }); diff --git a/example/applied_methods_example/track_methods_example.dart b/example/applied_methods_example/track_methods_example.dart index 67b4600..e86b32f 100644 --- a/example/applied_methods_example/track_methods_example.dart +++ b/example/applied_methods_example/track_methods_example.dart @@ -38,7 +38,7 @@ void main() async { print('######################track.getCorrection###########################'); // track.getCorrection - (await trackInstance.getCorrection())?.forEach((Track track) { + (await trackInstance.getCorrection()).forEach((Track track) { print('Track Correction Name: ${track.name} |' ' Track Correction URL: ${track.url}'); }); @@ -94,7 +94,7 @@ void main() async { await trackInstance.scrobble(timestamp: DateTime.now()); // YAY. IT WORKS! - scrobbleResponse.scrobbleResponses?.forEach((ScrobbledTrack scrobbledTrack) { + scrobbleResponse.scrobbleResponses.forEach((ScrobbledTrack scrobbledTrack) { print('Scrobbled Title: ${scrobbledTrack.track}'); }); diff --git a/example/applied_methods_example/user_methods_example.dart b/example/applied_methods_example/user_methods_example.dart index 5a42362..3e379fd 100644 --- a/example/applied_methods_example/user_methods_example.dart +++ b/example/applied_methods_example/user_methods_example.dart @@ -86,7 +86,7 @@ void main() async { print('#####################user.getWeeklyAlbumChart#######################'); // user.getTopTracks - (await userInstance.getTopTracks())?.forEach((Track track) { + (await userInstance.getTopTracks()).forEach((Track track) { print('Top Tracks Name: ${track.name} | Top Tracks URL: ${track.url} |' ' Duration: ${track.duration}'); }); @@ -94,7 +94,7 @@ void main() async { print('#####################user.getWeeklyArtistChart######################'); // user.getWeeklyAlbumChart - (await userInstance.getTopTracks())?.forEach((Track track) { + (await userInstance.getTopTracks()).forEach((Track track) { print('Top Tracks Name: ${track.name} | Top Tracks URL: ${track.url} |' ' Duration: ${track.duration}'); }); diff --git a/example/methods_example/album_methods_example.dart b/example/methods_example/album_methods_example.dart index 8f4aa00..7f09f56 100644 --- a/example/methods_example/album_methods_example.dart +++ b/example/methods_example/album_methods_example.dart @@ -41,7 +41,7 @@ void main() async { )); print('Album Name: ${albumGetInfo.name} |' - ' Album Artist: ${albumGetInfo.artist.name}'); + ' Album Artist: ${albumGetInfo.artist?.name}'); albumGetInfo.tracks?.forEach((Track track) { print('Track Title: ${track.name} | Track Duration: ${track.duration}'); @@ -60,7 +60,7 @@ void main() async { // album.getTopTags (await scrobblenaut.album.getTopTags(album: 'Your Name.', artist: 'RADWIMPS')) ?.forEach((Tag tag) { - print('Tag Name: ${tag.name} | Tag URL: ${tag.url}'); + print('Tag Name: ${tag.name} | Tag URL: ${tag.url}'); }); print('#########################album.removeTag############################'); diff --git a/example/methods_example/artist_methods_example.dart b/example/methods_example/artist_methods_example.dart index 6af41d8..61dcadf 100644 --- a/example/methods_example/artist_methods_example.dart +++ b/example/methods_example/artist_methods_example.dart @@ -33,7 +33,7 @@ void main() async { // artist.getCorrection (await scrobblenaut.artist.getCorrection(artist: 'RADWIMPS')) - ?.forEach((Artist artist) { + .forEach((Artist artist) { print('Artist correction: ${artist.name}'); }); diff --git a/example/methods_example/geo_methods_example.dart b/example/methods_example/geo_methods_example.dart index daf6fed..0ee3911 100644 --- a/example/methods_example/geo_methods_example.dart +++ b/example/methods_example/geo_methods_example.dart @@ -34,7 +34,7 @@ void main() async { // geo.getTopTracks (await scrobblenaut.geo.getTopTracks(country: 'canada')) - ?.forEach((Track track) { + .forEach((Track track) { print('Top Track Name: ${track.name} | Top Track URL : ${track.url} | ' 'Top Track Duration: ${track.duration}'); // Check if the duration is correct. diff --git a/example/methods_example/library_methods_example.dart b/example/methods_example/library_methods_example.dart index fea0335..94937d3 100644 --- a/example/methods_example/library_methods_example.dart +++ b/example/methods_example/library_methods_example.dart @@ -12,12 +12,8 @@ import '../api_values.dart'; void main() async { print('####################################################################'); - final lastFMAuth = await LastFM.authenticate( + final lastFMAuth = LastFM.noAuth( apiKey: APIValues.API, - apiSecret: APIValues.secret, - username: APIValues.username, - password: APIValues.password, - sessionKey: APIValues.sessionKey, ); final scrobblenaut = Scrobblenaut(lastFM: lastFMAuth); @@ -26,6 +22,7 @@ void main() async { // library.getArtist (await scrobblenaut.library.getArtists(user: 'nebulino')) + ?.artist ?.forEach((Artist artist) { print('Top Artist Name: ${artist.name} | Top Artist URL : ${artist.url}'); }); diff --git a/example/methods_example/scrobble_example.dart b/example/methods_example/scrobble_example.dart index a42a31d..b8dc600 100644 --- a/example/methods_example/scrobble_example.dart +++ b/example/methods_example/scrobble_example.dart @@ -16,7 +16,7 @@ void main() async { apiSecret: APIValues.secret, username: APIValues.username, password: APIValues.password, - sessionKey: APIValues.sessionKey, + // sessionKey: APIValues.sessionKey, ); // final lastFMnoAuth = await LastFM.noAuth(apiKey: APIValues.API); @@ -32,7 +32,7 @@ void main() async { timestamp: DateTime.now()); // YAY. IT WORKS! - response.scrobbleResponses?.forEach((ScrobbledTrack scrobbledTrack) { + response.scrobbleResponses.forEach((ScrobbledTrack scrobbledTrack) { print('Scrobbled Title: ${scrobbledTrack.track}'); }); @@ -43,17 +43,17 @@ void main() async { final anotherResponse = await scrobblenaut.track.scrobbleFromObject(scrobble: scrobble); - anotherResponse.scrobbleResponses?.forEach((ScrobbledTrack scrobbledTrack) { + anotherResponse.scrobbleResponses.forEach((ScrobbledTrack scrobbledTrack) { print('Scrobbled Title: ${scrobbledTrack.track}'); }); print('Multiple scrobble.'); final scrobble2 = Scrobble(track: 'Missing', artist: 'HoneyComeBear'); - final lastResponse = - await scrobblenaut.track.multiScrobble(scrobbleList: [scrobble, scrobble2]); + final lastResponse = await scrobblenaut.track + .multiScrobble(scrobbleList: [scrobble, scrobble2]); - lastResponse.scrobbleResponses?.forEach((ScrobbledTrack scrobbledTrack) { + lastResponse.scrobbleResponses.forEach((ScrobbledTrack scrobbledTrack) { print('Scrobbled Title: ${scrobbledTrack.track}'); }); diff --git a/example/methods_example/track_methods_example.dart b/example/methods_example/track_methods_example.dart index 140d2e6..2371195 100644 --- a/example/methods_example/track_methods_example.dart +++ b/example/methods_example/track_methods_example.dart @@ -18,7 +18,7 @@ void main() async { apiSecret: APIValues.secret, username: APIValues.username, password: APIValues.password, - sessionKey: APIValues.sessionKey, + // sessionKey: APIValues.sessionKey, ); final scrobblenaut = Scrobblenaut(lastFM: lastFMAuth); @@ -35,7 +35,7 @@ void main() async { // track.getCorrection (await scrobblenaut.track.getCorrection(track: 'TOMOYO', artist: 'Zekk')) - ?.forEach((Track track) { + .forEach((Track track) { print('Track Correction Name: ${track.name} |' ' Track Correction URL: ${track.url}'); }); @@ -103,7 +103,7 @@ void main() async { timestamp: DateTime.now()); // YAY. IT WORKS! - scrobbleResponse.scrobbleResponses?.forEach((ScrobbledTrack scrobbledTrack) { + scrobbleResponse.scrobbleResponses.forEach((ScrobbledTrack scrobbledTrack) { print('Scrobbled Title: ${scrobbledTrack.track}'); }); diff --git a/example/methods_example/user_methods_example.dart b/example/methods_example/user_methods_example.dart index 0fcf94e..30342e4 100644 --- a/example/methods_example/user_methods_example.dart +++ b/example/methods_example/user_methods_example.dart @@ -12,12 +12,8 @@ import '../api_values.dart'; void main() async { print('####################################################################'); - final lastFMAuth = await LastFM.authenticate( + final lastFMAuth = LastFM.noAuth( apiKey: APIValues.API, - apiSecret: APIValues.secret, - username: APIValues.username, - password: APIValues.password, - sessionKey: APIValues.sessionKey, ); final scrobblenaut = Scrobblenaut(lastFM: lastFMAuth); @@ -89,7 +85,7 @@ void main() async { // user.getTopTracks (await scrobblenaut.user.getTopTracks(user: 'nebulino')) - ?.forEach((Track track) { + .forEach((Track track) { print('Top Tracks Name: ${track.name} | Top Tracks URL: ${track.url} |' ' Duration: ${track.duration}'); }); @@ -98,7 +94,7 @@ void main() async { // user.getWeeklyAlbumChart (await scrobblenaut.user.getTopTracks(user: 'nebulino')) - ?.forEach((Track track) { + .forEach((Track track) { print('Top Tracks Name: ${track.name} | Top Tracks URL: ${track.url} |' ' Duration: ${track.duration}'); }); diff --git a/example/scrobblenaut_example.dart b/example/scrobblenaut_example.dart index f9dc010..5e4204b 100644 --- a/example/scrobblenaut_example.dart +++ b/example/scrobblenaut_example.dart @@ -11,7 +11,7 @@ import 'api_values.dart'; // Just an example of use. void main() async { - var lastFM = await LastFM.noAuth( + var lastFM = LastFM.noAuth( apiKey: APIValues.API, ); @@ -25,7 +25,7 @@ void main() async { )); print('Album Name: ${albumGetInfo.name} |' - ' Album Artist: ${albumGetInfo.artist.name}'); + ' Album Artist: ${albumGetInfo.artist?.name}'); albumGetInfo.tracks?.forEach((Track track) { print('Track Title: ${track.name} | Track Duration: ${track.duration}'); @@ -35,7 +35,7 @@ void main() async { apiKey: APIValues.API, apiSecret: APIValues.secret, username: APIValues.username, - password: APIValues.password + password: APIValues.password, ); scrobblenaut = Scrobblenaut(lastFM: lastFM); diff --git a/lib/src/core/lastfm.dart b/lib/src/core/lastfm.dart index ac82054..932d809 100644 --- a/lib/src/core/lastfm.dart +++ b/lib/src/core/lastfm.dart @@ -3,7 +3,6 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/src/core/session_key_generator.dart'; import 'package:scrobblenaut/src/helpers/utils.dart'; import 'package:scrobblenaut/src/tools/spaceship.dart'; @@ -13,41 +12,38 @@ class LastFM { SpaceShip _client; final String _apiKey; - final String _apiSecret; - final String _sessionKey; - final String _username; - final String _passwordHash; + final String? _apiSecret; + final String? _sessionKey; + final String? _username; + final String? _passwordHash; final bool _isAuth; /// Default constructor. LastFM._(this._apiKey, this._apiSecret, this._sessionKey, this._username, - this._passwordHash, this._isAuth) { - _client = SpaceShip( - base_url: 'https://ws.audioscrobbler.com/2.0/', - ); - } + this._passwordHash, this._isAuth) + : _client = SpaceShip( + base_url: 'https://ws.audioscrobbler.com/2.0/', + ); /// Default kind of API usage. /// You can use methods that does not required authentication. LastFM.noAuth({ - @required String apiKey, - String proxy, + required String apiKey, + String? proxy, }) : this._(apiKey, null, null, null, null, false); /// It creates a LastFM object with auth mode. static Future authenticate({ - @required String apiKey, - @required String apiSecret, - @required String username, - @required String password, - String sessionKey, - String proxy, + required String apiKey, + required String apiSecret, + required String username, + required String password, + String? sessionKey, + String? proxy, }) async { final passwordHash = generateMD5(password); - if ((apiKey != null && apiSecret != null) && - sessionKey == null && - (username != null && password != null)) { + if (sessionKey == null) { final session = await SessionKeyGenerator( LastFM._( apiKey, @@ -83,15 +79,14 @@ class LastFM { } static Future authenticateWithPasswordHash({ - @required String apiKey, - @required String apiSecret, - @required String username, - @required String passwordHash, - String sessionKey, + required String apiKey, + required String apiSecret, + required String username, + required String passwordHash, + String? sessionKey, + String? proxy, }) async { - if ((apiKey != null && apiSecret != null) && - sessionKey == null && - (username != null && passwordHash != null)) { + if (sessionKey == null) { final session = await SessionKeyGenerator( LastFM._( apiKey, @@ -133,16 +128,16 @@ class LastFM { String get apiKey => _apiKey; /// It returns the apiSecret used. - String get apiSecret => _apiSecret; + String? get apiSecret => _apiSecret; /// It returns, if authenticated, the session key. - String get sessionKey => _sessionKey; + String? get sessionKey => _sessionKey; /// It returns, if authenticated, the username. - String get username => _username; + String? get username => _username; /// It returns, if authenticated, the passwordHash. - String get passwordHash => _passwordHash; + String? get passwordHash => _passwordHash; /// True if authenticated. bool get isAuth => _isAuth; diff --git a/lib/src/core/request.dart b/lib/src/core/request.dart index 8d1190f..e8c98fc 100644 --- a/lib/src/core/request.dart +++ b/lib/src/core/request.dart @@ -3,27 +3,23 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/src/core/lastfm.dart'; import 'package:scrobblenaut/src/core/request_mode.dart'; import 'package:scrobblenaut/src/helpers/utils.dart'; /// It's creates a request object for the method. class Request { - LastFM _api; - Map _parameters; + final LastFM _api; + final Map _parameters; Request({ - @required LastFM api, - @required String method, - Map parameters, - }) { + required LastFM api, + required String method, + Map? parameters, + }) : _api = api, + _parameters = {} { parameters ?? {}; - _api = api; - - _parameters = {}; - parameters?.forEach((key, value) { if (value != null) { _parameters[key] = formatUnicode(text: value); @@ -56,13 +52,13 @@ class Request { signature += _parameters[key]; } - signature += _api.apiSecret; + signature += _api.apiSecret ?? ''; return generateMD5(signature); } /// It sends the request to the API. - Future send({@required RequestMode mode}) async { + Future send({required RequestMode mode}) async { switch (mode) { case RequestMode.GET: return await _api.client.get(parameters: _parameters); diff --git a/lib/src/core/session_key_generator.dart b/lib/src/core/session_key_generator.dart index d72ca3a..9d065da 100644 --- a/lib/src/core/session_key_generator.dart +++ b/lib/src/core/session_key_generator.dart @@ -3,7 +3,6 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/lastfm.dart'; import 'package:scrobblenaut/src/core/lastfm.dart'; import 'package:scrobblenaut/src/core/request.dart'; @@ -24,7 +23,7 @@ class SessionKeyGenerator { /// /// [auth.getMobileSession]: https://www.last.fm/api/show/auth.getMobileSession Future getSessionKey( - {@required String username, String passwordHash}) async { + {required String username, required String passwordHash}) async { final parameters = { 'username': username, 'authToken': generateMD5(username + passwordHash) diff --git a/lib/src/exceptions/lastfm_exception.dart b/lib/src/exceptions/lastfm_exception.dart index 095acba..a50e515 100644 --- a/lib/src/exceptions/lastfm_exception.dart +++ b/lib/src/exceptions/lastfm_exception.dart @@ -4,7 +4,6 @@ // // import 'package:dio/dio.dart'; -import 'package:meta/meta.dart'; import 'package:scrobblenaut/src/helpers/utils.dart'; import 'package:xml/xml.dart' as xml; @@ -14,9 +13,10 @@ class LastFMException extends DioError { final int _errorCode; final String _description; - LastFMException._(this._errorCode, this._description); + LastFMException._(this._errorCode, this._description) + : super(requestOptions: RequestOptions(path: '')); - LastFMException({@required String errorCode, @required String description}) + LastFMException({required String errorCode, required String description}) : this._(int.parse(errorCode), description); factory LastFMException.generate(dynamic errorObject) { @@ -32,7 +32,7 @@ class LastFMException extends DioError { .firstWhere((xmlNode) => xmlNode.getAttribute('code') != null); return LastFMException( - errorCode: errorNode.getAttribute('code'), + errorCode: errorNode.getAttribute('code') ?? '', description: errorNode.text); } else { // Else is a Json... @@ -43,6 +43,5 @@ class LastFMException extends DioError { } @override - String toString() => - '[LastFMException] => [Code ${_errorCode}]: ${_description}'; + String toString() => '[LastFMException] => [Code $_errorCode]: $_description'; } diff --git a/lib/src/exceptions/scrobblenaut_exception.dart b/lib/src/exceptions/scrobblenaut_exception.dart index d9e7e54..9e85432 100644 --- a/lib/src/exceptions/scrobblenaut_exception.dart +++ b/lib/src/exceptions/scrobblenaut_exception.dart @@ -6,14 +6,14 @@ /// It implements [Exception] class. /// You can find [description] that gives a brief information of what happened. class ScrobblenautException implements Exception { - final String _description; + final String? _description; ScrobblenautException._(this._description); - ScrobblenautException({String description}) : this._(description); + ScrobblenautException({String? description}) : this._(description); @override String toString() => '[ScrobblenautException]' + - (_description != null ? ': ${_description}' : ''); + (_description != null ? ': $_description' : ''); } diff --git a/lib/src/extensions/album_extension.dart b/lib/src/extensions/album_extension.dart index 757bd2c..6d1232f 100644 --- a/lib/src/extensions/album_extension.dart +++ b/lib/src/extensions/album_extension.dart @@ -3,7 +3,6 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/lastfm.dart'; import 'package:scrobblenaut/lastfm_methods.dart'; import 'package:scrobblenaut/scrobblenaut.dart'; @@ -14,35 +13,37 @@ extension AlbumExtension on Album { /// [AlbumMethods.addTags] Future addTags({ - @required List tags, + required List tags, }) async { return await _albumMethods.addTags( - album: name, artist: artist.name, tags: tags); + album: name ?? '', artist: artist?.name ?? '', tags: tags); } /// [AlbumMethods.getInfo] Future getInfo({ bool autoCorrect = false, - String username, + String? username, Language language = Language.en, }) async { + if (username == null && Scrobblenaut.instance.api.isAuth) { + username = Scrobblenaut.instance.api.username; + } return await _albumMethods.getInfo( - artist: artist.name, + artist: artist?.name, album: name, autoCorrect: autoCorrect, - // TODO: make it took from user if authenticated? username: username, language: language, ); } /// [AlbumMethods.getTags] - Future> getTags({ + Future?> getTags({ bool autoCorrect = false, - String user, + String? user, }) async { return await _albumMethods.getTags( - artist: artist.name, + artist: artist?.name, album: name, mbid: mbid, autoCorrect: autoCorrect, @@ -51,20 +52,23 @@ extension AlbumExtension on Album { } /// [AlbumMethods.getTopTags] - Future> getTopTags({ + Future?> getTopTags({ bool autoCorrect = false, }) async { return await _albumMethods.getTopTags( - artist: artist.name, album: name, mbid: mbid, autoCorrect: autoCorrect); + artist: artist?.name, + album: name, + mbid: mbid, + autoCorrect: autoCorrect); } /// [AlbumMethods.removeTag] Future removeTag({ - @required String tag, + required String tag, }) async { return await _albumMethods.removeTag( - artist: artist.name, - album: name, + artist: artist?.name ?? '', + album: name ?? '', tag: tag, ); } @@ -75,7 +79,7 @@ extension AlbumExtension on Album { int limit = 30, }) async { return await _albumMethods.search( - album: name, + album: name ?? '', page: page, limit: limit, ); diff --git a/lib/src/extensions/artist_extension.dart b/lib/src/extensions/artist_extension.dart index f616bea..5bcfcac 100644 --- a/lib/src/extensions/artist_extension.dart +++ b/lib/src/extensions/artist_extension.dart @@ -3,7 +3,6 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/lastfm.dart'; import 'package:scrobblenaut/lastfm_methods.dart'; import 'package:scrobblenaut/scrobblenaut.dart'; @@ -14,10 +13,10 @@ extension ArtistExtension on Artist { /// [ArtistMethods.addTags] Future addTags({ - @required List tags, + required List tags, }) async { return await _artistMethods.addTags( - artist: name, + artist: name ?? '', tags: tags, ); } @@ -25,13 +24,13 @@ extension ArtistExtension on Artist { /// [ArtistMethods.getCorrection] Future> getCorrection() async { return await _artistMethods.getCorrection( - artist: name, + artist: name ?? '', ); } /// [ArtistMethods.getInfo] Future getInfo({ - String username, + String? username, Language language = Language.en, bool autoCorrect = false, }) async { @@ -45,8 +44,8 @@ extension ArtistExtension on Artist { } /// [ArtistMethods.getSimilar] - Future> getSimilar({ - int limit, + Future?> getSimilar({ + int? limit, bool autoCorrect = false, }) async { return await _artistMethods.getSimilar( @@ -58,8 +57,8 @@ extension ArtistExtension on Artist { } /// [ArtistMethods.getTags] - Future> getTags({ - String user, + Future?> getTags({ + String? user, bool autoCorrect = false, }) async { return await _artistMethods.getTags( @@ -71,7 +70,7 @@ extension ArtistExtension on Artist { } /// [ArtistMethods.getTopAlbums] - Future> getTopAlbums({ + Future?> getTopAlbums({ int page = 1, int limit = 50, }) async { @@ -84,7 +83,7 @@ extension ArtistExtension on Artist { } /// [ArtistMethods.getTopTags] - Future> getTopTags({ + Future?> getTopTags({ bool autoCorrect = false, }) async { return await _artistMethods.getTopTags( @@ -95,7 +94,7 @@ extension ArtistExtension on Artist { } /// [ArtistMethods.getTopTracks] - Future> getTopTracks({ + Future?> getTopTracks({ int page = 1, int limit = 50, bool autoCorrect = false, @@ -111,10 +110,10 @@ extension ArtistExtension on Artist { /// [ArtistMethods.removeTag] Future removeTag({ - @required String tag, + required String tag, }) async { return await _artistMethods.removeTag( - artist: name, + artist: name ?? '', tag: tag, ); } @@ -125,7 +124,7 @@ extension ArtistExtension on Artist { int limit = 30, }) async { return await _artistMethods.search( - artist: name, + artist: name ?? '', page: page, limit: limit, ); diff --git a/lib/src/extensions/tag_extension.dart b/lib/src/extensions/tag_extension.dart index 08da8c2..9d46b76 100644 --- a/lib/src/extensions/tag_extension.dart +++ b/lib/src/extensions/tag_extension.dart @@ -22,14 +22,14 @@ extension TagExtension on Tag { } /// [TagMethods.getSimilar] - Future> getSimilar() async { + Future?> getSimilar() async { return await _tagMethods.getSimilar( tag: name, ); } /// [TagMethods.getTopAlbums] - Future> getTopAlbums({ + Future?> getTopAlbums({ int page = 1, int limit = 50, }) async { @@ -41,7 +41,7 @@ extension TagExtension on Tag { } /// [TagMethods.getTopArtists] - Future> getTopArtists({ + Future?> getTopArtists({ int page = 1, int limit = 50, }) async { @@ -53,7 +53,7 @@ extension TagExtension on Tag { } /// [TagMethods.getTopTracks] - Future> getTopTracks({ + Future?> getTopTracks({ int page = 1, int limit = 50, }) async { @@ -65,7 +65,7 @@ extension TagExtension on Tag { } /// [TagMethods.getWeeklyChartList] - Future> getWeeklyChartList() async { + Future?> getWeeklyChartList() async { return await _tagMethods.getWeeklyChartList( tag: name, ); diff --git a/lib/src/extensions/track_extension.dart b/lib/src/extensions/track_extension.dart index 1ef40d7..05b5987 100644 --- a/lib/src/extensions/track_extension.dart +++ b/lib/src/extensions/track_extension.dart @@ -3,7 +3,6 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/lastfm.dart'; import 'package:scrobblenaut/lastfm_methods.dart'; import 'package:scrobblenaut/scrobblenaut.dart'; @@ -15,10 +14,10 @@ extension TrackExtension on Track { TrackMethods get _trackMethods => Scrobblenaut.instance.track; /// [TrackMethods.addTags] - Future addTags({@required List tags}) async { + Future addTags({required List tags}) async { return await _trackMethods.addTags( track: name, - artist: artist.name, + artist: artist?.name ?? '', tags: tags, ); } @@ -27,18 +26,18 @@ extension TrackExtension on Track { Future> getCorrection() async { return await _trackMethods.getCorrection( track: name, - artist: artist.name, + artist: artist?.name ?? '', ); } /// [TrackMethods.getInfo] Future getInfo({ - String username, + String? username, bool autoCorrect = false, }) async { return await _trackMethods.getInfo( track: name, - artist: artist.name, + artist: artist?.name, mbid: mbid, username: username, autoCorrect: autoCorrect, @@ -46,13 +45,13 @@ extension TrackExtension on Track { } /// [TrackMethods.getSimilar] - Future> getSimilar({ - int limit, + Future?> getSimilar({ + int? limit, bool autoCorrect = false, }) async { return await _trackMethods.getSimilar( track: name, - artist: artist.name, + artist: artist?.name, mbid: mbid, limit: limit, autoCorrect: autoCorrect, @@ -60,13 +59,13 @@ extension TrackExtension on Track { } /// [TrackMethods.getTags] - Future> getTags({ - String user, + Future?> getTags({ + String? user, bool autoCorrect = false, }) async { return await _trackMethods.getTags( track: name, - artist: artist.name, + artist: artist?.name, mbid: mbid, user: user, autoCorrect: autoCorrect, @@ -74,12 +73,12 @@ extension TrackExtension on Track { } /// [TrackMethods.getTopTags] - Future> getTopTags({ + Future?> getTopTags({ bool autoCorrect = false, }) async { return await _trackMethods.getTopTags( track: name, - artist: artist.name, + artist: artist?.name, mbid: mbid, autoCorrect: autoCorrect, ); @@ -89,38 +88,38 @@ extension TrackExtension on Track { Future love() async { return await _trackMethods.love( track: name, - artist: artist.name, + artist: artist?.name ?? '', ); } /// [TrackMethods.removeTag] Future removeTag({ - @required String tag, + required String tag, }) async { return await _trackMethods.removeTag( track: name, - artist: artist.name, + artist: artist?.name ?? '', tag: tag, ); } /// [TrackMethods.scrobble] Future scrobble({ - String album, - int trackNumber, - Duration duration, - DateTime timestamp, - String context, - String streamId, + String? album, + int? trackNumber, + Duration? duration, + DateTime? timestamp, + String? context, + String? streamId, bool chosenByUser = false, - String mbid, + String? mbid, }) async { timestamp ??= DateTime.now(); return await _trackMethods.scrobble( track: name, - album: album ?? this.album.name, - artist: artist.name, + album: album ?? this.album?.name, + artist: artist?.name ?? '', trackNumber: trackNumber, duration: duration ?? this.duration, timestamp: timestamp, @@ -133,13 +132,13 @@ extension TrackExtension on Track { /// [TrackMethods.search] Future search({ - String artist, + String? artist, int page = 1, int limit = 30, }) async { return await _trackMethods.search( track: name, - artist: artist ?? this.artist.name, + artist: artist ?? this.artist?.name, page: page, limit: limit, ); @@ -149,25 +148,25 @@ extension TrackExtension on Track { Future unLove() async { return await _trackMethods.unLove( track: name, - artist: artist.name, + artist: artist?.name ?? '', ); } /// [TrackMethods.updateNowPlaying] Future updateNowPlaying({ - String album, - int trackNumber, - Duration duration, - DateTime timestamp, - String context, - String streamId, + String? album, + int? trackNumber, + Duration? duration, + DateTime? timestamp, + String? context, + String? streamId, bool chosenByUser = false, - String mbid, + String? mbid, }) async { return await _trackMethods.updateNowPlaying( track: name, - album: album ?? this.album.name, - artist: artist.name, + album: album ?? this.album?.name, + artist: artist?.name ?? '', trackNumber: trackNumber, duration: duration ?? this.duration, timestamp: timestamp, diff --git a/lib/src/extensions/user_extension.dart b/lib/src/extensions/user_extension.dart index 5be0a25..02a3de3 100644 --- a/lib/src/extensions/user_extension.dart +++ b/lib/src/extensions/user_extension.dart @@ -3,7 +3,6 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/lastfm.dart'; import 'package:scrobblenaut/lastfm_methods.dart'; import 'package:scrobblenaut/scrobblenaut.dart'; @@ -13,7 +12,7 @@ extension UserExtension on User { UserMethods get _userMethods => Scrobblenaut.instance.user; /// [UserMethods.getFriends] - Future> getFriends({ + Future?> getFriends({ bool enableRecentTracks = false, int page = 1, int limit = 50, @@ -34,7 +33,7 @@ extension UserExtension on User { } /// [UserMethods.getLovedTracks] - Future> getLovedTracks({ + Future?> getLovedTracks({ int page = 1, int limit = 50, }) async { @@ -47,8 +46,8 @@ extension UserExtension on User { /// [UserMethods.getPersonalTags] Future getPersonalTags({ - @required String tag, - @required TaggingType taggingType, + required String tag, + required TaggingType taggingType, int page = 1, int limit = 50, }) async { @@ -60,13 +59,12 @@ extension UserExtension on User { } /// [UserMethods.getRecentTracks] - Future> getRecentTracks({ + Future?> getRecentTracks({ int page = 1, int limit = 50, // MAX 200 - DateTime fromDate, - DateTime toDate, + DateTime? fromDate, + DateTime? toDate, bool extended = false, - bool nowPlaying = false, }) async { return await _userMethods.getRecentTracks( user: name, @@ -75,13 +73,12 @@ extension UserExtension on User { fromDate: fromDate, toDate: toDate, extended: extended, - nowPlaying: nowPlaying, ); } /// [UserMethods.getTopAlbums] - Future> getTopAlbums({ - Period period, + Future?> getTopAlbums({ + Period? period, int page = 1, int limit = 50, }) async { @@ -94,8 +91,8 @@ extension UserExtension on User { } /// [UserMethods.getTopArtists] - Future> getTopArtists({ - Period period, + Future?> getTopArtists({ + Period? period, int page = 1, int limit = 50, }) async { @@ -108,8 +105,8 @@ extension UserExtension on User { } /// [UserMethods.getTopTags] - Future> getTopTags({ - int limit, + Future?> getTopTags({ + int? limit, }) async { return await _userMethods.getTopTags( user: name, @@ -119,7 +116,7 @@ extension UserExtension on User { /// [UserMethods.getTopTracks] Future> getTopTracks({ - Period period, + Period? period, int page = 1, int limit = 50, }) async { @@ -132,9 +129,9 @@ extension UserExtension on User { } /// [UserMethods.getWeeklyAlbumChart] - Future> getWeeklyAlbumChart({ - DateTime fromDate, - DateTime toDate, + Future?> getWeeklyAlbumChart({ + DateTime? fromDate, + DateTime? toDate, }) async { return await _userMethods.getWeeklyAlbumChart( user: name, @@ -144,9 +141,9 @@ extension UserExtension on User { } /// [UserMethods.] - Future> getWeeklyArtistChart({ - DateTime fromDate, - DateTime toDate, + Future?> getWeeklyArtistChart({ + DateTime? fromDate, + DateTime? toDate, }) async { return await _userMethods.getWeeklyArtistChart( user: name, @@ -156,16 +153,16 @@ extension UserExtension on User { } /// [UserMethods.] - Future> getWeeklyChartList() async { + Future?> getWeeklyChartList() async { return await _userMethods.getWeeklyChartList( user: name, ); } /// [UserMethods.] - Future> getWeeklyTrackChart({ - DateTime fromDate, - DateTime toDate, + Future?> getWeeklyTrackChart({ + DateTime? fromDate, + DateTime? toDate, }) async { return await _userMethods.getWeeklyTrackChart( user: name, diff --git a/lib/src/helpers/lastfm_value_normalizer.dart b/lib/src/helpers/lastfm_value_normalizer.dart index 54ef0a2..08b0426 100644 --- a/lib/src/helpers/lastfm_value_normalizer.dart +++ b/lib/src/helpers/lastfm_value_normalizer.dart @@ -14,7 +14,7 @@ class LastFMValueNormalizer { /// It transforms a supposed number into a Dart int. /// This because LastFM sometimes sends a String, sometimes a int. /// How knows... - static int NumberToInt(dynamic supposedNumber) { + static int? NumberToInt(dynamic supposedNumber) { if (supposedNumber != null) { if (supposedNumber is String) { return int.parse(supposedNumber); @@ -31,8 +31,8 @@ class LastFMValueNormalizer { /// It transforms a supposed number into a Dart bool. /// This because LastFM sends int (0, 1) instead of a bool. - static bool NumberToBool(dynamic supposedBool) { - bool _intParser(int number) => + static bool? NumberToBool(dynamic supposedBool) { + bool? _intParser(int? number) => number == null ? null : (number == 1 ? true : false); if (supposedBool != null) { @@ -50,7 +50,7 @@ class LastFMValueNormalizer { } /// It transforms a bool into a LastFM 'bool' [0,1]. - static int BoolToIntBool(bool booleanToTransform) => + static int? BoolToIntBool(bool? booleanToTransform) => booleanToTransform == null ? null : booleanToTransform @@ -60,12 +60,12 @@ class LastFMValueNormalizer { /// It transforms a supposed artist into a real [Artist] object. /// This because sometimes LastFM returns an artist as Map, /// sometimes as String, which is the Artist name. - static Artist ArtistParser(dynamic supposedArtist) { + static Artist? ArtistParser(dynamic supposedArtist) { if (supposedArtist != null) { if (supposedArtist is String) { return Artist(name: supposedArtist); } else if (supposedArtist is Map) { - return Artist.fromJson(supposedArtist); + return Artist.fromJson(supposedArtist as Map); } else { throw ScrobblenautException( description: 'The supposed Artist is not recognized.'); @@ -80,7 +80,7 @@ class LastFMValueNormalizer { /// This is useful for [track.getInfo] for example because in other /// circumstances the received duration is in seconds since epoch (unix time). /// Thanks LastFM, really appreciated. - static Duration MillisecondsDurationParser(dynamic supposedMilliseconds) { + static Duration? MillisecondsDurationParser(dynamic supposedMilliseconds) { // Thanks LastFM: sometimes can contain 'FIX ME'. if (supposedMilliseconds.toString() == 'FIXME') return null; @@ -104,7 +104,7 @@ class LastFMValueNormalizer { /// This is useful for [album.getInfo] for example because in other /// circumstances the received duration is in milliseconds since epoch. /// Thanks LastFM, really appreciated. - static Duration SecondsDurationParser(dynamic supposedSeconds) { + static Duration? SecondsDurationParser(dynamic supposedSeconds) { if (supposedSeconds != null) { if (supposedSeconds is String) { return Duration(seconds: int.parse(supposedSeconds)); @@ -120,16 +120,16 @@ class LastFMValueNormalizer { } /// It transforms a Duration into Milliseconds. - static int DurationToMilliseconds(Duration duration) => + static int? DurationToMilliseconds(Duration? duration) => duration == null ? null : duration.inMilliseconds; /// It transforms a Duration into Seconds. - static int DurationToSeconds(Duration duration) => + static int? DurationToSeconds(Duration? duration) => duration == null ? null : duration.inSeconds; /// It transforms a LastFM number received from [Artist][streamable] /// into a bool. - static bool isArtistStreamable(dynamic supposedBool) { + static bool? isArtistStreamable(dynamic supposedBool) { if (supposedBool != null) { switch (supposedBool.toString()) { case '0': @@ -146,12 +146,12 @@ class LastFMValueNormalizer { } /// It helps managing a Streamable string or a object. - static Streamable StreamableParser(dynamic streamable) { + static Streamable? StreamableParser(dynamic streamable) { if (streamable != null) { if (streamable is String) { return Streamable(text: streamable); } else if (streamable is Map) { - return Streamable.fromJson(streamable); + return Streamable.fromJson(streamable as Map); } else { throw ScrobblenautException( description: 'The supposed streamable is not recognized.'); @@ -162,7 +162,7 @@ class LastFMValueNormalizer { } /// It transforms a LastFM supposed unixTime into a DateTime. - static DateTime DateTimeFromUnixTime(dynamic unixTime) { + static DateTime? DateTimeFromUnixTime(dynamic unixTime) { // I've found a nil. if (unixTime.toString() == 'nil') { return null; @@ -183,51 +183,57 @@ class LastFMValueNormalizer { } /// It transforms a LastFM supposed unixTime from a DateTime. - static int DateTimeToUnixTime(DateTime dateTime) => dateTime == null + static int? DateTimeToUnixTime(DateTime? dateTime) => dateTime == null ? null : (dateTime.millisecondsSinceEpoch / 1000).round(); /// Makes a meaning-less number into a string. - static String MeaninglessNumber(dynamic supposedText) => + static String? MeaninglessNumber(dynamic supposedText) => supposedText == null ? null : (supposedText.toString()); /// Tracks extractor. - static List tracksExtractor(Map tracks) => + static List? tracksExtractor(Map? tracks) => tracks == null ? null : List.generate((tracks['track'] as List).length, (i) => Track.fromJson(tracks['track'][i])); /// Tags extractor. - static List tagsExtractor(Map tags) => tags == null - ? null - : List.generate( + static List? tagsExtractor(Map? tags) { + if (tags == null) { + return null; + } else if (tags['tag'] is List) { + return List.generate( (tags['tag'] as List).length, (i) => Tag.fromJson(tags['tag'][i])); + } else if (tags['tag'] is Map) { + return [Tag.fromJson(tags['tag'])]; + } + } /// Albums extractor. - static List albumsExtractor(Map albums) => + static List? albumsExtractor(Map? albums) => albums == null ? null : List.generate((albums['album'] as List).length, (i) => Album.fromJson(albums['album'][i])); /// Artists extractor. - static List artistsExtractor(Map artists) => + static List? artistsExtractor(Map? artists) => artists == null ? null : List.generate((artists['artist'] as List).length, (i) => Artist.fromJson(artists['artist'][i])); /// SimilarArtists extractor. - static List similarArtistsExtractor( - Map similarArtists) => + static List? similarArtistsExtractor( + Map? similarArtists) => similarArtists == null ? null : List.generate((similarArtists['artist'] as List).length, (i) => Artist.fromJson(similarArtists['artist'][i])); /// Links extractor. - static List linksExtractor(Map links) { + static List? linksExtractor(Map? links) { final supposedLinksList = links; if (links != null) { if (supposedLinksList is List) { @@ -242,7 +248,7 @@ class LastFMValueNormalizer { } /// TimeStamp normalizer for POST methods. - static int timestampToSecondsSinceEpoch(DateTime timestamp) => + static int? timestampToSecondsSinceEpoch(DateTime? timestamp) => timestamp == null ? null : (timestamp.millisecondsSinceEpoch / 1000).round(); diff --git a/lib/src/helpers/now_played_track.dart b/lib/src/helpers/now_played_track.dart index 8ca467e..5a57279 100644 --- a/lib/src/helpers/now_played_track.dart +++ b/lib/src/helpers/now_played_track.dart @@ -26,19 +26,19 @@ class NowPlayedTrack { final String _albumArtist; /// True if is a corrected track. - final bool _tracksCorrected; + final bool? _tracksCorrected; /// True if is a corrected artist. - final bool _artistsCorrected; + final bool? _artistsCorrected; /// True if is a corrected album. - final bool _albumsCorrected; + final bool? _albumsCorrected; /// True if is a corrected album artist. - final bool _albumArtistsCorrected; + final bool? _albumArtistsCorrected; /// The received ignoreMessage code. - final bool _ignoredMessageCode; + final bool? _ignoredMessageCode; NowPlayedTrack._( this._status, @@ -62,11 +62,11 @@ class NowPlayedTrack { String album; String artist; String albumArtist; - bool tracksCorrected; - bool artistsCorrected; - bool albumsCorrected; - bool albumArtistsCorrected; - bool ignoredMessageCode; + bool? tracksCorrected; + bool? artistsCorrected; + bool? albumsCorrected; + bool? albumArtistsCorrected; + bool? ignoredMessageCode; // Status node. final statusNode = responseXML.findElements('lfm').first; @@ -79,7 +79,8 @@ class NowPlayedTrack { throw ScrobblenautException(description: 'Response unrecognized.'); } - bool _s2b(supposedBool) => LastFMValueNormalizer.NumberToBool(supposedBool); + bool? _s2b(supposedBool) => + LastFMValueNormalizer.NumberToBool(supposedBool); track = responseXML.findAllElements('track').first.text; @@ -138,17 +139,17 @@ class NowPlayedTrack { String get albumArtist => _albumArtist; /// True if is a corrected track. - bool get tracksCorrected => _tracksCorrected; + bool? get tracksCorrected => _tracksCorrected; /// True if is a corrected artist. - bool get artistsCorrected => _artistsCorrected; + bool? get artistsCorrected => _artistsCorrected; /// True if is a corrected album. - bool get albumsCorrected => _albumsCorrected; + bool? get albumsCorrected => _albumsCorrected; /// True if is a corrected album artist. - bool get albumArtistsCorrected => _albumArtistsCorrected; + bool? get albumArtistsCorrected => _albumArtistsCorrected; /// The received ignoreMessage code. - bool get ignoredMessageCode => _ignoredMessageCode; + bool? get ignoredMessageCode => _ignoredMessageCode; } diff --git a/lib/src/helpers/scrobble_response.dart b/lib/src/helpers/scrobble_response.dart index 19292cc..13fd8f5 100644 --- a/lib/src/helpers/scrobble_response.dart +++ b/lib/src/helpers/scrobble_response.dart @@ -19,10 +19,10 @@ class ScrobbleResponse { final List _scrobbledTracks; /// Number of accepted scrobble. - final int _scrobbleAccepted; + final int? _scrobbleAccepted; /// Number of ignored scrobble. - final int _scrobbleIgnored; + final int? _scrobbleIgnored; ScrobbleResponse._( this._status, @@ -38,8 +38,8 @@ class ScrobbleResponse { bool status; var scrobbledTracks = []; - int scrobbleAccepted; - int scrobbleIgnored; + int? scrobbleAccepted; + int? scrobbleIgnored; // Status node. final statusNode = responseXML.findElements('lfm').first; @@ -80,8 +80,8 @@ class ScrobbleResponse { List get scrobbleResponses => _scrobbledTracks; /// Returns the number of accepted scrobbles. - int get scrobbleAccepted => _scrobbleAccepted; + int? get scrobbleAccepted => _scrobbleAccepted; /// Returns the number of ignored scrobbles. - int get scrobbleIgnored => _scrobbleIgnored; + int? get scrobbleIgnored => _scrobbleIgnored; } diff --git a/lib/src/helpers/scrobbled_track.dart b/lib/src/helpers/scrobbled_track.dart index 14a7710..3cd22f1 100644 --- a/lib/src/helpers/scrobbled_track.dart +++ b/lib/src/helpers/scrobbled_track.dart @@ -22,22 +22,22 @@ class ScrobbledTrack { final String _albumArtist; /// True if is a corrected track. - final bool _tracksCorrected; + final bool? _tracksCorrected; /// True if is a corrected artist. - final bool _artistsCorrected; + final bool? _artistsCorrected; /// True if is a corrected album. - final bool _albumsCorrected; + final bool? _albumsCorrected; /// True if is a corrected album artist. - final bool _albumArtistsCorrected; + final bool? _albumArtistsCorrected; /// The timestamp of the scrobble. - final DateTime _timestamp; + final DateTime? _timestamp; /// The received ignoreMessage code. - final bool _ignoredMessageCode; + final bool? _ignoredMessageCode; ScrobbledTrack._( this._track, @@ -57,14 +57,15 @@ class ScrobbledTrack { String album; String artist; String albumArtist; - bool tracksCorrected; - bool artistsCorrected; - bool albumsCorrected; - bool albumArtistsCorrected; - DateTime timestamp; - bool ignoredMessageCode; + bool? tracksCorrected; + bool? artistsCorrected; + bool? albumsCorrected; + bool? albumArtistsCorrected; + DateTime? timestamp; + bool? ignoredMessageCode; - bool _s2b(supposedBool) => LastFMValueNormalizer.NumberToBool(supposedBool); + bool? _s2b(supposedBool) => + LastFMValueNormalizer.NumberToBool(supposedBool); track = scrobbleElement.findAllElements('track').first.text; @@ -129,20 +130,20 @@ class ScrobbledTrack { String get albumArtist => _albumArtist; /// True if is a corrected track. - bool get tracksCorrected => _tracksCorrected; + bool? get tracksCorrected => _tracksCorrected; /// True if is a corrected artist. - bool get artistsCorrected => _artistsCorrected; + bool? get artistsCorrected => _artistsCorrected; /// True if is a corrected album. - bool get albumsCorrected => _albumsCorrected; + bool? get albumsCorrected => _albumsCorrected; /// True if is a corrected album artist. - bool get albumArtistsCorrected => _albumArtistsCorrected; + bool? get albumArtistsCorrected => _albumArtistsCorrected; /// The timestamp of the scrobble. - DateTime get timestamp => _timestamp; + DateTime? get timestamp => _timestamp; /// The received ignoreMessage code. - bool get ignoredMessageCode => _ignoredMessageCode; + bool? get ignoredMessageCode => _ignoredMessageCode; } diff --git a/lib/src/helpers/utils.dart b/lib/src/helpers/utils.dart index 561f643..66639df 100644 --- a/lib/src/helpers/utils.dart +++ b/lib/src/helpers/utils.dart @@ -6,9 +6,10 @@ import 'dart:convert'; import 'dart:typed_data'; +// ignore: import_of_legacy_library_into_null_safe import 'package:convert/convert.dart'; +// ignore: import_of_legacy_library_into_null_safe import 'package:crypto/crypto.dart' show md5; -import 'package:meta/meta.dart'; /// Generate a MD5 string by a given value. String generateMD5(String value) { @@ -24,7 +25,7 @@ String generateStringFromList(List list) { } /// Format the text in unicode -String formatUnicode({@required dynamic text}) { +String formatUnicode({required dynamic text}) { if (text is Uint8List) { return utf8.decode(text); } else if (text is String) { diff --git a/lib/src/lastfm.dart b/lib/src/lastfm.dart index 8982f76..d533d0e 100644 --- a/lib/src/lastfm.dart +++ b/lib/src/lastfm.dart @@ -7,7 +7,6 @@ library lastfm_objects; import 'package:json_annotation/json_annotation.dart'; -import 'package:meta/meta.dart'; import 'package:scrobblenaut/src/helpers/lastfm_value_normalizer.dart'; part 'lastfm.g.dart'; @@ -16,6 +15,7 @@ part 'lastfm.g.dart'; part 'package:scrobblenaut/src/lastfm/core/now_playing_object.dart'; part 'package:scrobblenaut/src/lastfm/core/scrobble_object.dart'; part 'package:scrobblenaut/src/lastfm/core/session.dart'; +part 'package:scrobblenaut/src/lastfm/core/attr.dart'; // Enums. part 'package:scrobblenaut/src/lastfm/enums/languages.dart'; @@ -42,3 +42,6 @@ part 'package:scrobblenaut/src/lastfm/track.dart'; part 'package:scrobblenaut/src/lastfm/track_results.dart'; part 'package:scrobblenaut/src/lastfm/user.dart'; part 'package:scrobblenaut/src/lastfm/wiki.dart'; + +// LastFM Responses +part 'package:scrobblenaut/src/lastfm/responses/library.dart'; diff --git a/lib/src/lastfm.g.dart b/lib/src/lastfm.g.dart new file mode 100644 index 0000000..5349480 --- /dev/null +++ b/lib/src/lastfm.g.dart @@ -0,0 +1,766 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of lastfm_objects; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +NowPlaying _$NowPlayingFromJson(Map json) { + return NowPlaying( + track: json['track'] as String, + album: json['album'] as String?, + artist: json['artist'] as String, + trackNumber: json['trackNumber'] as int?, + duration: json['duration'] == null + ? null + : Duration(microseconds: json['duration'] as int), + context: json['context'] as String?, + mbid: json['mbid'] as String?, + albumArtist: json['albumArtist'] as String?, + ); +} + +Map _$NowPlayingToJson(NowPlaying instance) { + final val = { + 'artist': instance.artist, + 'track': instance.track, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('album', instance.album); + writeNotNull('trackNumber', instance.trackNumber); + writeNotNull('context', instance.context); + writeNotNull('mbid', instance.mbid); + writeNotNull('duration', + LastFMValueNormalizer.DurationToMilliseconds(instance.duration)); + writeNotNull('albumArtist', instance.albumArtist); + return val; +} + +Scrobble _$ScrobbleFromJson(Map json) { + $checkKeys(json, requiredKeys: const ['artist', 'track']); + return Scrobble( + track: json['track'] as String, + album: json['album'] as String?, + artist: json['artist'] as String, + trackNumber: json['trackNumber'] as int?, + duration: json['duration'] == null + ? null + : Duration(microseconds: json['duration'] as int), + timestamp: json['timestamp'] == null + ? null + : DateTime.parse(json['timestamp'] as String), + context: json['context'] as String?, + streamId: json['streamId'] as String?, + chosenByUser: json['chosenByUser'] as bool?, + mbid: json['mbid'] as String?, + ); +} + +Map _$ScrobbleToJson(Scrobble instance) { + final val = { + 'artist': instance.artist, + 'track': instance.track, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('timestamp', + LastFMValueNormalizer.DateTimeToUnixTime(instance.timestamp)); + writeNotNull('album', instance.album); + writeNotNull('context', instance.context); + writeNotNull('streamId', instance.streamId); + writeNotNull('chosenByUser', + LastFMValueNormalizer.BoolToIntBool(instance.chosenByUser)); + writeNotNull('trackNumber', instance.trackNumber); + writeNotNull('mbid', instance.mbid); + writeNotNull('duration', + LastFMValueNormalizer.DurationToMilliseconds(instance.duration)); + return val; +} + +Session _$SessionFromJson(Map json) { + return Session( + name: json['name'] as String?, + sessionKey: json['key'] as String?, + subscriber: json['subscriber'] as int?, + ); +} + +Map _$SessionToJson(Session instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('name', instance.name); + writeNotNull('key', instance.sessionKey); + writeNotNull('subscriber', instance.subscriber); + return val; +} + +Attr _$AttrFromJson(Map json) { + return Attr( + page: LastFMValueNormalizer.NumberToInt(json['page']), + perPage: LastFMValueNormalizer.NumberToInt(json['perPage']), + user: json['user'] as String?, + total: LastFMValueNormalizer.NumberToInt(json['total']), + totalPages: LastFMValueNormalizer.NumberToInt(json['totalPages']), + ); +} + +Map _$AttrToJson(Attr instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('page', instance.page); + writeNotNull('perPage', instance.perPage); + writeNotNull('user', instance.user); + writeNotNull('total', instance.total); + writeNotNull('totalPages', instance.totalPages); + return val; +} + +Album _$AlbumFromJson(Map json) { + return Album( + title: json['title'] as String?, + name: json['name'] as String?, + artist: LastFMValueNormalizer.ArtistParser(json['artist']), + url: json['url'] as String?, + images: (json['image'] as List?) + ?.map((e) => Image.fromJson(e as Map)) + .toList(), + tracks: LastFMValueNormalizer.tracksExtractor( + json['tracks'] as Map?), + tags: LastFMValueNormalizer.tagsExtractor( + json['tags'] as Map?), + listeners: LastFMValueNormalizer.NumberToInt(json['listeners']), + playCount: LastFMValueNormalizer.NumberToInt(json['playcount']), + mbid: json['mbid'] as String?, + ); +} + +Map _$AlbumToJson(Album instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('title', instance.title); + writeNotNull('name', instance.name); + writeNotNull('artist', instance.artist); + writeNotNull('url', instance.url); + writeNotNull('image', instance.images); + writeNotNull('tracks', instance.tracks); + writeNotNull('tags', instance.tags); + writeNotNull('listeners', instance.listeners); + writeNotNull('playcount', instance.playCount); + writeNotNull('mbid', instance.mbid); + return val; +} + +AlbumSearchResults _$AlbumSearchResultsFromJson(Map json) { + return AlbumSearchResults( + albums: LastFMValueNormalizer.albumsExtractor( + json['albummatches'] as Map?), + totalResults: + LastFMValueNormalizer.NumberToInt(json['opensearch:TotalResults']), + statingIndex: + LastFMValueNormalizer.NumberToInt(json['opensearch:StartIndex']), + itemsPerPage: + LastFMValueNormalizer.NumberToInt(json['opensearch:ItemsPerPage']), + ); +} + +Map _$AlbumSearchResultsToJson(AlbumSearchResults instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('albummatches', instance.albums); + writeNotNull('opensearch:TotalResults', instance.totalResults); + writeNotNull('opensearch:StartIndex', instance.statingIndex); + writeNotNull('opensearch:ItemsPerPage', instance.itemsPerPage); + return val; +} + +Artist _$ArtistFromJson(Map json) { + return Artist( + name: json['name'] as String?, + url: json['url'] as String?, + images: (json['image'] as List?) + ?.map((e) => Image.fromJson(e as Map)) + .toList(), + tags: LastFMValueNormalizer.tagsExtractor( + json['tags'] as Map?), + tagCount: LastFMValueNormalizer.NumberToInt(json['tagcount']), + stats: json['stats'] == null + ? null + : Stats.fromJson(json['stats'] as Map), + bio: json['bio'] == null + ? null + : Bio.fromJson(json['bio'] as Map), + similarArtists: LastFMValueNormalizer.similarArtistsExtractor( + json['similar'] as Map?), + match: json['match'] as String?, + isStreamable: LastFMValueNormalizer.isArtistStreamable(json['streamable']), + listeners: LastFMValueNormalizer.NumberToInt(json['listeners']), + playCount: LastFMValueNormalizer.NumberToInt(json['playcount']), + onTour: LastFMValueNormalizer.NumberToBool(json['ontour']), + mbid: json['mbid'] as String?, + ); +} + +Map _$ArtistToJson(Artist instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('name', instance.name); + writeNotNull('url', instance.url); + writeNotNull('image', instance.images); + writeNotNull('tags', instance.tags); + writeNotNull('tagcount', instance.tagCount); + writeNotNull('stats', instance.stats); + writeNotNull('bio', instance.bio); + writeNotNull('similar', instance.similarArtists); + writeNotNull('match', instance.match); + writeNotNull('streamable', instance.isStreamable); + writeNotNull('listeners', instance.listeners); + writeNotNull('playcount', instance.playCount); + writeNotNull('ontour', instance.onTour); + writeNotNull('mbid', instance.mbid); + return val; +} + +ArtistSearchResults _$ArtistSearchResultsFromJson(Map json) { + return ArtistSearchResults( + artists: LastFMValueNormalizer.artistsExtractor( + json['artistmatches'] as Map?), + totalResults: + LastFMValueNormalizer.NumberToInt(json['opensearch:TotalResults']), + statingIndex: + LastFMValueNormalizer.NumberToInt(json['opensearch:StartIndex']), + itemsPerPage: + LastFMValueNormalizer.NumberToInt(json['opensearch:ItemsPerPage']), + ); +} + +Map _$ArtistSearchResultsToJson(ArtistSearchResults instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('artistmatches', instance.artists); + writeNotNull('opensearch:TotalResults', instance.totalResults); + writeNotNull('opensearch:StartIndex', instance.statingIndex); + writeNotNull('opensearch:ItemsPerPage', instance.itemsPerPage); + return val; +} + +Bio _$BioFromJson(Map json) { + return Bio( + links: LastFMValueNormalizer.linksExtractor( + json['links'] as Map?), + published: json['published'] as String?, + summary: json['summary'] as String?, + content: json['content'] as String?, + ); +} + +Map _$BioToJson(Bio instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('links', instance.links); + writeNotNull('published', instance.published); + writeNotNull('summary', instance.summary); + writeNotNull('content', instance.content); + return val; +} + +Chart _$ChartFromJson(Map json) { + return Chart( + text: json['#text'] as String?, + fromDate: LastFMValueNormalizer.DateTimeFromUnixTime(json['from']), + toDate: LastFMValueNormalizer.DateTimeFromUnixTime(json['to']), + ); +} + +Map _$ChartToJson(Chart instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('#text', instance.text); + writeNotNull( + 'from', LastFMValueNormalizer.DateTimeToUnixTime(instance.fromDate)); + writeNotNull('to', LastFMValueNormalizer.DateTimeToUnixTime(instance.toDate)); + return val; +} + +Date _$DateFromJson(Map json) { + return Date( + unixDate: json['uts'] as String?, + text: json['#text'] as String?, + ); +} + +Map _$DateToJson(Date instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('uts', instance.unixDate); + writeNotNull('#text', instance.text); + return val; +} + +Image _$ImageFromJson(Map json) { + return Image( + size: _$enumDecodeNullable(_$SizeEnumMap, json['size'], + unknownValue: Size.None), + text: json['#text'] as String?, + ); +} + +Map _$ImageToJson(Image instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('size', _$SizeEnumMap[instance.size]); + writeNotNull('#text', instance.text); + return val; +} + +K _$enumDecode( + Map enumValues, + Object? source, { + K? unknownValue, +}) { + if (source == null) { + throw ArgumentError( + 'A value must be provided. Supported values: ' + '${enumValues.values.join(', ')}', + ); + } + + return enumValues.entries.singleWhere( + (e) => e.value == source, + orElse: () { + if (unknownValue == null) { + throw ArgumentError( + '`$source` is not one of the supported values: ' + '${enumValues.values.join(', ')}', + ); + } + return MapEntry(unknownValue, enumValues.values.first); + }, + ).key; +} + +K? _$enumDecodeNullable( + Map enumValues, + dynamic source, { + K? unknownValue, +}) { + if (source == null) { + return null; + } + return _$enumDecode(enumValues, source, unknownValue: unknownValue); +} + +const _$SizeEnumMap = { + Size.small: 'small', + Size.medium: 'medium', + Size.large: 'large', + Size.extralarge: 'extralarge', + Size.mega: 'mega', + Size.empty: 'empty', + Size.None: 'None', +}; + +Link _$LinkFromJson(Map json) { + return Link( + text: json['#text'] as String?, + rel: json['rel'] as String?, + webLink: json['href'] as String?, + ); +} + +Map _$LinkToJson(Link instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('#text', instance.text); + writeNotNull('rel', instance.rel); + writeNotNull('href', instance.webLink); + return val; +} + +Registered _$RegisteredFromJson(Map json) { + return Registered( + unixTime: LastFMValueNormalizer.DateTimeFromUnixTime(json['unixtime']), + text: LastFMValueNormalizer.MeaninglessNumber(json['#text']), + ); +} + +Map _$RegisteredToJson(Registered instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull( + 'unixtime', LastFMValueNormalizer.DateTimeToUnixTime(instance.unixTime)); + writeNotNull('#text', instance.text); + return val; +} + +Stats _$StatsFromJson(Map json) { + return Stats( + listeners: LastFMValueNormalizer.NumberToInt(json['listeners']), + playCount: LastFMValueNormalizer.NumberToInt(json['playcount']), + userPlayCount: LastFMValueNormalizer.NumberToInt(json['userplaycount']), + ); +} + +Map _$StatsToJson(Stats instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('listeners', instance.listeners); + writeNotNull('playcount', instance.playCount); + writeNotNull('userplaycount', instance.userPlayCount); + return val; +} + +Streamable _$StreamableFromJson(Map json) { + return Streamable( + text: json['#text'] as String?, + fullTrack: json['fulltrack'] as String?, + ); +} + +Map _$StreamableToJson(Streamable instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('#text', instance.text); + writeNotNull('fulltrack', instance.fullTrack); + return val; +} + +Tag _$TagFromJson(Map json) { + return Tag( + name: json['name'] as String, + url: json['url'] as String?, + count: LastFMValueNormalizer.NumberToInt(json['count']), + total: LastFMValueNormalizer.NumberToInt(json['total']), + reach: LastFMValueNormalizer.NumberToInt(json['reach']), + taggings: LastFMValueNormalizer.NumberToInt(json['taggings']), + streamable: LastFMValueNormalizer.NumberToBool(json['streamable']), + wiki: json['wiki'] == null + ? null + : Wiki.fromJson(json['wiki'] as Map), + ); +} + +Map _$TagToJson(Tag instance) { + final val = { + 'name': instance.name, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('url', instance.url); + writeNotNull('count', instance.count); + writeNotNull('total', instance.total); + writeNotNull('reach', instance.reach); + writeNotNull('taggings', instance.taggings); + writeNotNull('streamable', instance.streamable); + writeNotNull('wiki', instance.wiki); + return val; +} + +Taggings _$TaggingsFromJson(Map json) { + return Taggings( + albums: LastFMValueNormalizer.albumsExtractor( + json['albums'] as Map?), + artists: LastFMValueNormalizer.artistsExtractor( + json['artists'] as Map?), + tracks: LastFMValueNormalizer.tracksExtractor( + json['tracks'] as Map?), + ); +} + +Map _$TaggingsToJson(Taggings instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('albums', instance.albums); + writeNotNull('artists', instance.artists); + writeNotNull('tracks', instance.tracks); + return val; +} + +Track _$TrackFromJson(Map json) { + return Track( + name: json['name'] as String, + album: json['album'] == null + ? null + : Album.fromJson(json['album'] as Map), + artist: LastFMValueNormalizer.ArtistParser(json['artist']), + url: json['url'] as String?, + duration: + LastFMValueNormalizer.MillisecondsDurationParser(json['duration']), + images: (json['image'] as List?) + ?.map((e) => Image.fromJson(e as Map)) + .toList(), + topTags: LastFMValueNormalizer.tagsExtractor( + json['toptags'] as Map?), + date: json['date'] == null + ? null + : Date.fromJson(json['date'] as Map), + streamable: LastFMValueNormalizer.StreamableParser(json['streamable']), + listeners: LastFMValueNormalizer.NumberToInt(json['listeners']), + playCount: LastFMValueNormalizer.NumberToInt(json['playcount']), + wiki: json['wiki'] == null + ? null + : Wiki.fromJson(json['wiki'] as Map), + mbid: json['mbid'] as String?, + loved: LastFMValueNormalizer.NumberToBool(json['loved']), + ); +} + +Map _$TrackToJson(Track instance) { + final val = { + 'name': instance.name, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('album', instance.album); + writeNotNull('artist', instance.artist); + writeNotNull('url', instance.url); + writeNotNull('duration', instance.duration?.inMicroseconds); + writeNotNull('image', instance.images); + writeNotNull('toptags', instance.topTags); + writeNotNull('date', instance.date); + writeNotNull('streamable', instance.streamable); + writeNotNull('listeners', instance.listeners); + writeNotNull('playcount', instance.playCount); + writeNotNull('wiki', instance.wiki); + writeNotNull('mbid', instance.mbid); + writeNotNull('loved', instance.loved); + return val; +} + +TrackSearchResults _$TrackSearchResultsFromJson(Map json) { + return TrackSearchResults( + tracks: LastFMValueNormalizer.tracksExtractor( + json['trackmatches'] as Map?), + totalResults: + LastFMValueNormalizer.NumberToInt(json['opensearch:TotalResults']), + statingIndex: + LastFMValueNormalizer.NumberToInt(json['opensearch:StartIndex']), + itemsPerPage: + LastFMValueNormalizer.NumberToInt(json['opensearch:ItemsPerPage']), + ); +} + +Map _$TrackSearchResultsToJson(TrackSearchResults instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('trackmatches', instance.tracks); + writeNotNull('opensearch:TotalResults', instance.totalResults); + writeNotNull('opensearch:StartIndex', instance.statingIndex); + writeNotNull('opensearch:ItemsPerPage', instance.itemsPerPage); + return val; +} + +User _$UserFromJson(Map json) { + return User( + name: json['name'] as String, + realName: json['realname'] as String?, + gender: json['gender'] as String?, + age: json['age'] as String?, + country: json['country'] as String?, + url: json['url'] as String?, + image: (json['image'] as List?) + ?.map((e) => Image.fromJson(e as Map)) + .toList(), + subscriber: LastFMValueNormalizer.NumberToBool(json['subscriber']), + playlists: LastFMValueNormalizer.NumberToInt(json['playlists']), + playCount: LastFMValueNormalizer.NumberToInt(json['playcount']), + registered: json['registered'] == null + ? null + : Registered.fromJson(json['registered'] as Map), + bootstrap: json['bootstrap'] as String?, + type: json['type'] as String?, + ); +} + +Map _$UserToJson(User instance) { + final val = { + 'name': instance.name, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('realname', instance.realName); + writeNotNull('gender', instance.gender); + writeNotNull('age', instance.age); + writeNotNull('country', instance.country); + writeNotNull('url', instance.url); + writeNotNull('image', instance.image); + writeNotNull('subscriber', instance.subscriber); + writeNotNull('playlists', instance.playlists); + writeNotNull('playcount', instance.playCount); + writeNotNull('registered', instance.registered); + writeNotNull('bootstrap', instance.bootstrap); + writeNotNull('type', instance.type); + return val; +} + +Wiki _$WikiFromJson(Map json) { + return Wiki( + published: json['published'] as String?, + summary: json['summary'] as String?, + content: json['content'] as String?, + ); +} + +Map _$WikiToJson(Wiki instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('published', instance.published); + writeNotNull('summary', instance.summary); + writeNotNull('content', instance.content); + return val; +} + +LibraryGetArtistsResponse _$LibraryGetArtistsResponseFromJson( + Map json) { + return LibraryGetArtistsResponse( + artist: (json['artist'] as List?) + ?.map((e) => Artist.fromJson(e as Map)) + .toList(), + attr: json['@attr'] == null + ? null + : Attr.fromJson(json['@attr'] as Map), + ); +} + +Map _$LibraryGetArtistsResponseToJson( + LibraryGetArtistsResponse instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('artist', instance.artist); + writeNotNull('@attr', instance.attr); + return val; +} diff --git a/lib/src/lastfm/album.dart b/lib/src/lastfm/album.dart index 326933e..b88ef28 100644 --- a/lib/src/lastfm/album.dart +++ b/lib/src/lastfm/album.dart @@ -8,46 +8,45 @@ part of lastfm_objects; /// This object represents an album. @JsonSerializable(includeIfNull: false) class Album { - // TODO: what's this? /// Title of the album. @JsonKey(name: 'title') - String title; + String? title; /// Name of the album. @JsonKey(name: 'name') - String name; + String? name; /// Artist of the album. @JsonKey(name: 'artist', fromJson: LastFMValueNormalizer.ArtistParser) - Artist artist; + Artist? artist; /// LastFM url of the album. @JsonKey(name: 'url') - String url; + String? url; /// A list of different size of the album cover. @JsonKey(name: 'image') - List images; + List? images; /// A list of tracks of the album. @JsonKey(name: 'tracks', fromJson: LastFMValueNormalizer.tracksExtractor) - List tracks; + List? tracks; /// A list of tags assigned to the album. @JsonKey(name: 'tags', fromJson: LastFMValueNormalizer.tagsExtractor) - List tags; + List? tags; /// The number of listeners of the album. @JsonKey(name: 'listeners', fromJson: LastFMValueNormalizer.NumberToInt) - int listeners; // Last.FM treats this as String + int? listeners; // Last.FM treats this as String /// The number of plays of the album. @JsonKey(name: 'playcount', fromJson: LastFMValueNormalizer.NumberToInt) - int playCount; // Last.FM treats this as String + int? playCount; // Last.FM treats this as String /// MusicBrainz ID. @JsonKey(name: 'mbid') - String mbid; + String? mbid; Album({ this.title, diff --git a/lib/src/lastfm/album_results.dart b/lib/src/lastfm/album_results.dart index 9ef318e..ee1ab89 100644 --- a/lib/src/lastfm/album_results.dart +++ b/lib/src/lastfm/album_results.dart @@ -11,25 +11,25 @@ class AlbumSearchResults { /// A list of matched albums from the search. @JsonKey( name: 'albummatches', fromJson: LastFMValueNormalizer.albumsExtractor) - List albums; + List? albums; /// The number of generated matches from the search. @JsonKey( name: 'opensearch:TotalResults', fromJson: LastFMValueNormalizer.NumberToInt) - int totalResults; + int? totalResults; /// A value that sign the starting index of the search. @JsonKey( name: 'opensearch:StartIndex', fromJson: LastFMValueNormalizer.NumberToInt) - int statingIndex; + int? statingIndex; /// Number of matches per page. @JsonKey( name: 'opensearch:ItemsPerPage', fromJson: LastFMValueNormalizer.NumberToInt) - int itemsPerPage; + int? itemsPerPage; AlbumSearchResults({ this.albums, diff --git a/lib/src/lastfm/artist.dart b/lib/src/lastfm/artist.dart index a8fecd1..299f1e7 100644 --- a/lib/src/lastfm/artist.dart +++ b/lib/src/lastfm/artist.dart @@ -10,64 +10,64 @@ part of lastfm_objects; class Artist { /// Name of the artist. @JsonKey(name: 'name') - String name; + String? name; /// LastFM url of the artist. @JsonKey(name: 'url') - String url; + String? url; /// A list of different size of the artist cover. @JsonKey(name: 'image') - List images; + List? images; /// A list of tags assigned to the artist.. @JsonKey(name: 'tags', fromJson: LastFMValueNormalizer.tagsExtractor) - List tags; + List? tags; /// Number of tags onto the artist. @JsonKey(name: 'tagcount', fromJson: LastFMValueNormalizer.NumberToInt) - int tagCount; + int? tagCount; /// The artist stats if a user is given. @JsonKey(name: 'stats') - Stats stats; + Stats? stats; /// The artist bio. @JsonKey(name: 'bio') - Bio bio; + Bio? bio; /// A list of similar artists. @JsonKey( name: 'similar', fromJson: LastFMValueNormalizer.similarArtistsExtractor) - List similarArtists; + List? similarArtists; // TODO: Match meaning. @JsonKey(name: 'match') - String match; + String? match; /// True if the Artist is streamable. @JsonKey( name: 'streamable', fromJson: LastFMValueNormalizer.isArtistStreamable) - bool isStreamable; + bool? isStreamable; /// The number of listeners. @JsonKey(name: 'listeners', fromJson: LastFMValueNormalizer.NumberToInt) - int listeners; + int? listeners; /// The number of plays of the artist. @JsonKey(name: 'playcount', fromJson: LastFMValueNormalizer.NumberToInt) - int playCount; + int? playCount; /// Information about ongoing Tours. @JsonKey(name: 'ontour', fromJson: LastFMValueNormalizer.NumberToBool) - bool onTour; + bool? onTour; /// MusicBrainz ID. @JsonKey(name: 'mbid') - String mbid; + String? mbid; Artist({ - this.name, + required this.name, this.url, this.images, this.tags, diff --git a/lib/src/lastfm/artist_results.dart b/lib/src/lastfm/artist_results.dart index e484980..e380d89 100644 --- a/lib/src/lastfm/artist_results.dart +++ b/lib/src/lastfm/artist_results.dart @@ -11,25 +11,25 @@ class ArtistSearchResults { /// A list of matched artists from the search. @JsonKey( name: 'artistmatches', fromJson: LastFMValueNormalizer.artistsExtractor) - List artists; + List? artists; /// The number of generated matches from the search. @JsonKey( name: 'opensearch:TotalResults', fromJson: LastFMValueNormalizer.NumberToInt) - int totalResults; + int? totalResults; /// A value that sign the starting index of the search. @JsonKey( name: 'opensearch:StartIndex', fromJson: LastFMValueNormalizer.NumberToInt) - int statingIndex; + int? statingIndex; /// Number of matches per page. @JsonKey( name: 'opensearch:ItemsPerPage', fromJson: LastFMValueNormalizer.NumberToInt) - int itemsPerPage; + int? itemsPerPage; ArtistSearchResults({ this.artists, diff --git a/lib/src/lastfm/bio.dart b/lib/src/lastfm/bio.dart index c8df5bd..64991ff 100644 --- a/lib/src/lastfm/bio.dart +++ b/lib/src/lastfm/bio.dart @@ -10,21 +10,21 @@ part of lastfm_objects; class Bio { /// A list of links. @JsonKey(name: 'links', fromJson: LastFMValueNormalizer.linksExtractor) - List links; + List? links; /// A string that indicates the date of publishing. /// **NOTE:** it's a string and it can't be transformed into a Dart DateTime. /// Because it's different between different bio. @JsonKey(name: 'published') - String published; + String? published; /// A brief summary of the bio. @JsonKey(name: 'summary') - String summary; + String? summary; /// The real content of the bio. @JsonKey(name: 'content') - String content; + String? content; Bio({ this.links, diff --git a/lib/src/lastfm/chart.dart b/lib/src/lastfm/chart.dart index fcdc955..782a9f9 100644 --- a/lib/src/lastfm/chart.dart +++ b/lib/src/lastfm/chart.dart @@ -8,23 +8,22 @@ part of lastfm_objects; /// This object represents a chart. @JsonSerializable(includeIfNull: false) class Chart { - // TODO: What is this? @JsonKey(name: '#text') - String text; + String? text; /// The starting date of the chart. @JsonKey( name: 'from', fromJson: LastFMValueNormalizer.DateTimeFromUnixTime, toJson: LastFMValueNormalizer.DateTimeToUnixTime) - DateTime fromDate; + DateTime? fromDate; /// The ending date of the chart. @JsonKey( name: 'to', fromJson: LastFMValueNormalizer.DateTimeFromUnixTime, toJson: LastFMValueNormalizer.DateTimeToUnixTime) - DateTime toDate; + DateTime? toDate; Chart({ this.text, diff --git a/lib/src/lastfm/core/attr.dart b/lib/src/lastfm/core/attr.dart new file mode 100644 index 0000000..7724a4c --- /dev/null +++ b/lib/src/lastfm/core/attr.dart @@ -0,0 +1,25 @@ +part of lastfm_objects; + +/// This is a object that helps scrobbling multiple tracks. +@JsonSerializable(includeIfNull: false) +class Attr { + @JsonKey(name: 'page', fromJson: LastFMValueNormalizer.NumberToInt) + int? page; + + @JsonKey(name: 'perPage', fromJson: LastFMValueNormalizer.NumberToInt) + int? perPage; + + String? user; + + @JsonKey(name: 'total', fromJson: LastFMValueNormalizer.NumberToInt) + int? total; + + @JsonKey(name: 'totalPages', fromJson: LastFMValueNormalizer.NumberToInt) + int? totalPages; + + Attr({this.page, this.perPage, this.user, this.total, this.totalPages}); + + factory Attr.fromJson(Map json) => _$AttrFromJson(json); + + Map toJson() => _$AttrToJson(this); +} diff --git a/lib/src/lastfm/core/now_playing_object.dart b/lib/src/lastfm/core/now_playing_object.dart index 67c0416..15fc0b7 100644 --- a/lib/src/lastfm/core/now_playing_object.dart +++ b/lib/src/lastfm/core/now_playing_object.dart @@ -8,43 +8,48 @@ part of lastfm_objects; /// This is a object that helps scrobbling multiple tracks. @JsonSerializable(includeIfNull: false) class NowPlaying { + /// The [Artist] name to scrobble. + @JsonKey(name: 'artist') + String artist; + /// The [Track] title to scrobble. @JsonKey(name: 'track') String track; /// The [Album] name to scrobble. @JsonKey(name: 'album') - String album; - - /// The [Artist] name to scrobble. - @JsonKey(name: 'artist') - String artist; + String? album; /// The track number of the [Track] to scrobble. @JsonKey(name: 'trackNumber') - int trackNumber; - - /// The duration of the [Track] to scrobble. - @JsonKey( - name: 'duration', toJson: LastFMValueNormalizer.DurationToMilliseconds) - Duration duration; + int? trackNumber; /// Sub-client version (not public, only enabled for certain API keys). @JsonKey(name: 'context') - String context; + String? context; /// MusicBrainz ID. @JsonKey(name: 'mbid') - String mbid; + String? mbid; + + /// The duration of the [Track] to scrobble. + @JsonKey( + name: 'duration', toJson: LastFMValueNormalizer.DurationToMilliseconds) + Duration? duration; + + /// The album artist - if this differs from the track artist. + @JsonKey(name: 'albumArtist') + String? albumArtist; NowPlaying({ - @required this.track, + required this.track, this.album, - @required this.artist, + required this.artist, this.trackNumber, this.duration, this.context, this.mbid, + this.albumArtist, }); factory NowPlaying.fromJson(Map json) => diff --git a/lib/src/lastfm/core/scrobble_object.dart b/lib/src/lastfm/core/scrobble_object.dart index 68effeb..3e12774 100644 --- a/lib/src/lastfm/core/scrobble_object.dart +++ b/lib/src/lastfm/core/scrobble_object.dart @@ -8,63 +8,63 @@ part of lastfm_objects; /// This is a object that helps scrobbling multiple tracks. @JsonSerializable(includeIfNull: false) class Scrobble { - /// The [Track] title to scrobble. - @JsonKey(name: 'track', required: true) - String track; - - /// The [Album] name to scrobble. - @JsonKey(name: 'album') - String album; - /// The [Artist] name to scrobble. @JsonKey(name: 'artist', required: true) String artist; - /// The track number of the [Track] to scrobble. - @JsonKey(name: 'trackNumber') - int trackNumber; - - /// The duration of the [Track] to scrobble. - @JsonKey( - name: 'duration', toJson: LastFMValueNormalizer.DurationToMilliseconds) - Duration duration; + /// The [Track] title to scrobble. + @JsonKey(name: 'track', required: true) + String track; /// The TimeStamp of the scrobble. /// If You're not doing strange stuff, you can use DateTime.now(). @JsonKey(name: 'timestamp', toJson: LastFMValueNormalizer.DateTimeToUnixTime) - DateTime timestamp = DateTime.now(); + DateTime timestamp; + + /// The [Album] name to scrobble. + @JsonKey(name: 'album') + String? album; /// Sub-client version (not public, only enabled for certain API keys). @JsonKey(name: 'context') - String context; + String? context; /// The stream id for this track received from the radio.getPlaylist service, /// if scrobbling Last.fm radio. @JsonKey(name: 'streamId') - String streamId; + String? streamId; /// If the user chose this song, set on True, /// else (if the song was chosen by someone else, such as a radio station /// or recommendation service) set it to False. @JsonKey(name: 'chosenByUser', toJson: LastFMValueNormalizer.BoolToIntBool) - bool chosenByUser; + bool? chosenByUser; + + /// The track number of the [Track] to scrobble. + @JsonKey(name: 'trackNumber') + int? trackNumber; /// MusicBrainz ID. @JsonKey(name: 'mbid') - String mbid; + String? mbid; + + /// The duration of the [Track] to scrobble. + @JsonKey( + name: 'duration', toJson: LastFMValueNormalizer.DurationToMilliseconds) + Duration? duration; Scrobble({ - this.track, + required this.track, this.album, - this.artist, + required this.artist, this.trackNumber, this.duration, - this.timestamp, + DateTime? timestamp, this.context, this.streamId, this.chosenByUser, this.mbid, - }); + }) : timestamp = timestamp ?? DateTime.now(); factory Scrobble.fromJson(Map json) => _$ScrobbleFromJson(json); diff --git a/lib/src/lastfm/core/session.dart b/lib/src/lastfm/core/session.dart index 2196b12..ae8cefb 100644 --- a/lib/src/lastfm/core/session.dart +++ b/lib/src/lastfm/core/session.dart @@ -10,15 +10,15 @@ part of lastfm_objects; class Session { /// Name of the session. It contains the user name most of the time. @JsonKey(name: 'name') - String name; + String? name; /// This is the key of a LastFM session. @JsonKey(name: 'key') - String sessionKey; + String? sessionKey; /// This gives the subscriber number. @JsonKey(name: 'subscriber') - int subscriber; + int? subscriber; Session({ this.name, diff --git a/lib/src/lastfm/date.dart b/lib/src/lastfm/date.dart index 094d173..a547850 100644 --- a/lib/src/lastfm/date.dart +++ b/lib/src/lastfm/date.dart @@ -12,11 +12,11 @@ class Date { // TODO: needs to be transformed? or just delete and make Date a DateTime? /// Unix date in string. @JsonKey(name: 'uts') - String unixDate; + String? unixDate; // TODO: What's this? it's necessary? @JsonKey(name: '#text') - String text; + String? text; Date({ this.unixDate, diff --git a/lib/src/lastfm/enums/periods.dart b/lib/src/lastfm/enums/periods.dart index 480c9a4..3d64c23 100644 --- a/lib/src/lastfm/enums/periods.dart +++ b/lib/src/lastfm/enums/periods.dart @@ -16,7 +16,7 @@ enum Period { } extension PeriodExtension on Period { - String get value { + String? get value { switch (this) { case Period.WEEK: return '7day'; diff --git a/lib/src/lastfm/enums/tagging_type.dart b/lib/src/lastfm/enums/tagging_type.dart index b234d95..afc43cd 100644 --- a/lib/src/lastfm/enums/tagging_type.dart +++ b/lib/src/lastfm/enums/tagging_type.dart @@ -13,7 +13,7 @@ enum TaggingType { } extension TaggingTypeExtension on TaggingType { - String get type { + String? get type { switch (this) { case TaggingType.artist: return 'artist'; diff --git a/lib/src/lastfm/image.dart b/lib/src/lastfm/image.dart index f58fd70..d03efe6 100644 --- a/lib/src/lastfm/image.dart +++ b/lib/src/lastfm/image.dart @@ -14,14 +14,13 @@ class Image { name: 'size', defaultValue: null, disallowNullValue: false, - nullable: true, unknownEnumValue: Size.None) - Size size; + Size? size; // TODO: change the name? /// The link of the image. @JsonKey(name: '#text') - String text; + String? text; Image({ this.size, diff --git a/lib/src/lastfm/link.dart b/lib/src/lastfm/link.dart index bcba963..39d6ffc 100644 --- a/lib/src/lastfm/link.dart +++ b/lib/src/lastfm/link.dart @@ -11,15 +11,15 @@ class Link { // TODO: change the name? /// The link of the image. @JsonKey(name: '#text') - String text; + String? text; // TODO: What's this? Original? @JsonKey(name: 'rel') - String rel; + String? rel; /// This is the web link of the LastFM url. @JsonKey(name: 'href') - String webLink; + String? webLink; Link({ this.text, diff --git a/lib/src/lastfm/registered.dart b/lib/src/lastfm/registered.dart index 7718d8c..f9349af 100644 --- a/lib/src/lastfm/registered.dart +++ b/lib/src/lastfm/registered.dart @@ -14,11 +14,11 @@ class Registered { name: 'unixtime', fromJson: LastFMValueNormalizer.DateTimeFromUnixTime, toJson: LastFMValueNormalizer.DateTimeToUnixTime) - DateTime unixTime; + DateTime? unixTime; // TODO: what's this? is this necessary? @JsonKey(name: '#text', fromJson: LastFMValueNormalizer.MeaninglessNumber) - String text; + String? text; Registered({ this.unixTime, diff --git a/lib/src/lastfm/responses/library.dart b/lib/src/lastfm/responses/library.dart new file mode 100644 index 0000000..37ea66e --- /dev/null +++ b/lib/src/lastfm/responses/library.dart @@ -0,0 +1,17 @@ +part of lastfm_objects; + +@JsonSerializable(includeIfNull: false) +class LibraryGetArtistsResponse { + @JsonKey(name: 'artist') + List? artist; + + @JsonKey(name: '@attr') + Attr? attr; + + LibraryGetArtistsResponse({this.artist, this.attr}); + + factory LibraryGetArtistsResponse.fromJson(Map json) => + _$LibraryGetArtistsResponseFromJson(json); + + Map toJson() => _$LibraryGetArtistsResponseToJson(this); +} diff --git a/lib/src/lastfm/stats.dart b/lib/src/lastfm/stats.dart index b83506b..b9f3e66 100644 --- a/lib/src/lastfm/stats.dart +++ b/lib/src/lastfm/stats.dart @@ -10,15 +10,15 @@ part of lastfm_objects; class Stats { /// The number of listeners of a user. @JsonKey(name: 'listeners', fromJson: LastFMValueNormalizer.NumberToInt) - int listeners; // Last.FM treats this as String + int? listeners; // Last.FM treats this as String /// The number of plays of a user. @JsonKey(name: 'playcount', fromJson: LastFMValueNormalizer.NumberToInt) - int playCount; // Last.FM treats this as String + int? playCount; // Last.FM treats this as String /// The number of plays from a user. @JsonKey(name: 'userplaycount', fromJson: LastFMValueNormalizer.NumberToInt) - int userPlayCount; // Last.FM treats this as String + int? userPlayCount; // Last.FM treats this as String Stats({ this.listeners, diff --git a/lib/src/lastfm/streamable.dart b/lib/src/lastfm/streamable.dart index 3a11539..67700b2 100644 --- a/lib/src/lastfm/streamable.dart +++ b/lib/src/lastfm/streamable.dart @@ -10,11 +10,11 @@ part of lastfm_objects; class Streamable { // TODO: what's this? @JsonKey(name: '#text') - String text; + String? text; // TODO: what's this? @JsonKey(name: 'fulltrack') - String fullTrack; + String? fullTrack; Streamable({ this.text, diff --git a/lib/src/lastfm/tag.dart b/lib/src/lastfm/tag.dart index d114d27..affeaeb 100644 --- a/lib/src/lastfm/tag.dart +++ b/lib/src/lastfm/tag.dart @@ -14,34 +14,34 @@ class Tag { // LastFM url of the tag. @JsonKey(name: 'url') - String url; + String? url; /// The usage number of the tag. @JsonKey(name: 'count', fromJson: LastFMValueNormalizer.NumberToInt) - int count; + int? count; /// The total number of usage of this tag from a user. @JsonKey(name: 'total', fromJson: LastFMValueNormalizer.NumberToInt) - int total; + int? total; /// The total number of usage of this tag. @JsonKey(name: 'reach', fromJson: LastFMValueNormalizer.NumberToInt) - int reach; + int? reach; /// The number of usage applied from a user. @JsonKey(name: 'taggings', fromJson: LastFMValueNormalizer.NumberToInt) - int taggings; + int? taggings; /// If True, this tag can be used as a Radio Station. @JsonKey(name: 'streamable', fromJson: LastFMValueNormalizer.NumberToBool) - bool streamable; + bool? streamable; /// The wiki of the tag. @JsonKey(name: 'wiki') - Wiki wiki; + Wiki? wiki; Tag({ - this.name, + required this.name, this.url, this.count, this.total, diff --git a/lib/src/lastfm/taggings.dart b/lib/src/lastfm/taggings.dart index d7122aa..5ca1985 100644 --- a/lib/src/lastfm/taggings.dart +++ b/lib/src/lastfm/taggings.dart @@ -10,15 +10,15 @@ part of lastfm_objects; class Taggings { /// A list of tagged albums. @JsonKey(name: 'albums', fromJson: LastFMValueNormalizer.albumsExtractor) - List albums; + List? albums; /// A list of tagged artists. @JsonKey(name: 'artists', fromJson: LastFMValueNormalizer.artistsExtractor) - List artists; + List? artists; /// A list of tagged tracks. @JsonKey(name: 'tracks', fromJson: LastFMValueNormalizer.tracksExtractor) - List tracks; + List? tracks; Taggings({ this.albums, diff --git a/lib/src/lastfm/track.dart b/lib/src/lastfm/track.dart index b6f3ad4..4833c3a 100644 --- a/lib/src/lastfm/track.dart +++ b/lib/src/lastfm/track.dart @@ -14,65 +14,65 @@ class Track { /// The album that contains the track. @JsonKey(name: 'album') - Album album; + Album? album; /// The artist that has created the track. @JsonKey(name: 'artist', fromJson: LastFMValueNormalizer.ArtistParser) - Artist artist; + Artist? artist; // LastFM url of the track. @JsonKey(name: 'url') - String url; + String? url; /// The duration of the track. @JsonKey( name: 'duration', fromJson: LastFMValueNormalizer.MillisecondsDurationParser) - Duration duration; + Duration? duration; /// A list of different size of the track cover. @JsonKey(name: 'image') - List images; + List? images; /// A list of Top Tags of the track. @JsonKey(name: 'toptags', fromJson: LastFMValueNormalizer.tagsExtractor) - List topTags; + List? topTags; // TODO: make it directly a Dart object? /// The date of publishing of the track. @JsonKey(name: 'date') - Date date; + Date? date; // TODO: what's this for real? /// Streamable object of the track. @JsonKey(name: 'streamable', fromJson: LastFMValueNormalizer.StreamableParser) - Streamable streamable; + Streamable? streamable; /// The number of listeners of the track. @JsonKey( name: 'listeners', fromJson: LastFMValueNormalizer.NumberToInt, ) - int listeners; + int? listeners; /// The number of plays of the track. @JsonKey(name: 'playcount', fromJson: LastFMValueNormalizer.NumberToInt) - int playCount; + int? playCount; /// The wiki of the track. @JsonKey(name: 'wiki') - Wiki wiki; + Wiki? wiki; /// MusicBrainz ID. @JsonKey(name: 'mbid') - String mbid; + String? mbid; /// If called from a [User] data, True if the user loved the track. @JsonKey(name: 'loved', fromJson: LastFMValueNormalizer.NumberToBool) - bool loved; + bool? loved; Track({ - this.name, + required this.name, this.album, this.artist, this.url, diff --git a/lib/src/lastfm/track_results.dart b/lib/src/lastfm/track_results.dart index 6685e5a..17da969 100644 --- a/lib/src/lastfm/track_results.dart +++ b/lib/src/lastfm/track_results.dart @@ -11,25 +11,25 @@ class TrackSearchResults { /// A list of matched tracks from the search. @JsonKey( name: 'trackmatches', fromJson: LastFMValueNormalizer.tracksExtractor) - List tracks; + List? tracks; /// The number of generated matches from the search. @JsonKey( name: 'opensearch:TotalResults', fromJson: LastFMValueNormalizer.NumberToInt) - int totalResults; + int? totalResults; /// A value that sign the starting index of the search. @JsonKey( name: 'opensearch:StartIndex', fromJson: LastFMValueNormalizer.NumberToInt) - int statingIndex; + int? statingIndex; /// Number of matches per page. @JsonKey( name: 'opensearch:ItemsPerPage', fromJson: LastFMValueNormalizer.NumberToInt) - int itemsPerPage; + int? itemsPerPage; TrackSearchResults({ this.tracks, diff --git a/lib/src/lastfm/user.dart b/lib/src/lastfm/user.dart index e700d51..bbec543 100644 --- a/lib/src/lastfm/user.dart +++ b/lib/src/lastfm/user.dart @@ -14,54 +14,54 @@ class User { /// The real name of the user. @JsonKey(name: 'realname') - String realName; + String? realName; /// THe user's gender. @JsonKey(name: 'gender') - String gender; + String? gender; /// The age of the user. @JsonKey(name: 'age') - String age; + String? age; /// The user's country. @JsonKey(name: 'country') - String country; + String? country; // LastFM url of the user. @JsonKey(name: 'url') - String url; + String? url; /// A list of different size of the user profile picture. @JsonKey(name: 'image') - List image; + List? image; // If it's a subscriber. @JsonKey(name: 'subscriber', fromJson: LastFMValueNormalizer.NumberToBool) - bool subscriber; + bool? subscriber; // The number of playlist of the user. @JsonKey(name: 'playlists', fromJson: LastFMValueNormalizer.NumberToInt) - int playlists; + int? playlists; /// The play count of the user. @JsonKey(name: 'playcount', fromJson: LastFMValueNormalizer.NumberToInt) - int playCount; + int? playCount; /// The registration information of the user. @JsonKey(name: 'registered') - Registered registered; + Registered? registered; // TODO: what's this? @JsonKey(name: 'bootstrap') - String bootstrap; + String? bootstrap; /// The type of the user. @JsonKey(name: 'type') - String type; + String? type; User({ - this.name, + required this.name, this.realName, this.gender, this.age, diff --git a/lib/src/lastfm/wiki.dart b/lib/src/lastfm/wiki.dart index 975d925..9384689 100644 --- a/lib/src/lastfm/wiki.dart +++ b/lib/src/lastfm/wiki.dart @@ -10,15 +10,15 @@ class Wiki { // TODO: is this a date? /// The publication information of the wiki. @JsonKey(name: 'published') - String published; + String? published; /// A brief summary of the wiki. @JsonKey(name: 'summary') - String summary; + String? summary; /// The real content of the wiki. @JsonKey(name: 'content') - String content; + String? content; Wiki({ this.published, diff --git a/lib/src/methods/album_methods.dart b/lib/src/methods/album_methods.dart index 0cb6ea8..aade316 100644 --- a/lib/src/methods/album_methods.dart +++ b/lib/src/methods/album_methods.dart @@ -3,7 +3,6 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/lastfm.dart'; import 'package:scrobblenaut/src/core/lastfm.dart'; import 'package:scrobblenaut/src/core/request.dart'; @@ -22,9 +21,9 @@ class AlbumMethods { /// /// https://www.last.fm/api/show/album.addTags Future addTags({ - @required String artist, - @required String album, - @required List tags, + required String artist, + required String album, + required List tags, }) async { if (!_api.isAuth) { return Future.error(ScrobblenautException( @@ -61,11 +60,11 @@ class AlbumMethods { /// /// https://www.last.fm/api/show/album.getInfo Future getInfo({ - String artist, - String album, - String mbid, + String? artist, + String? album, + String? mbid, bool autoCorrect = false, - String username, + String? username, Language language = Language.en, }) async { if ((album == null || artist == null) && mbid == null) { @@ -80,7 +79,7 @@ class AlbumMethods { 'mbid': mbid, 'autocorrect': (autoCorrect ? 1 : 0), 'username': username, - 'lang': language?.code, + 'lang': language.code, }; final request = @@ -92,7 +91,7 @@ class AlbumMethods { // from [track.getInfo]. var albumInfo = Album.fromJson(response['album']); albumInfo.tracks?.forEach((Track track) { - track.duration = track.duration * 1000; + track.duration = track.duration != null ? track.duration! * 1000 : null; }); return albumInfo; @@ -103,12 +102,12 @@ class AlbumMethods { /// album.getTopTags. /// /// https://www.last.fm/api/show/album.getTags - Future> getTags({ - String artist, - String album, - String mbid, + Future?> getTags({ + String? artist, + String? album, + String? mbid, bool autoCorrect = false, - String user, + String? user, }) async { if ((album == null || artist == null) && mbid == null) { return Future.error(ScrobblenautException( @@ -125,7 +124,7 @@ class AlbumMethods { 'artist': artist, 'album': album, 'mbid': mbid, - 'user': user, + 'user': user ?? _api.username, 'autocorrect': (autoCorrect ? 1 : 0), }; @@ -144,10 +143,10 @@ class AlbumMethods { /// Get the top tags for an album on Last.fm, ordered by popularity. /// /// https://www.last.fm/api/show/album.getTopTags - Future> getTopTags({ - String artist, - String album, - String mbid, + Future?> getTopTags({ + String? artist, + String? album, + String? mbid, bool autoCorrect = false, }) async { if ((album == null || artist == null) && mbid == null) { @@ -179,9 +178,9 @@ class AlbumMethods { /// /// https://www.last.fm/api/show/album.removeTag Future removeTag({ - @required String artist, - @required String album, - @required String tag, + required String artist, + required String album, + required String tag, }) async { if (!_api.isAuth) { return Future.error(ScrobblenautException( @@ -212,7 +211,7 @@ class AlbumMethods { /// /// https://www.last.fm/api/show/album.search Future search({ - @required String album, + required String album, int page = 1, int limit = 30, }) async { diff --git a/lib/src/methods/artist_methods.dart b/lib/src/methods/artist_methods.dart index 6e453e8..bd218b9 100644 --- a/lib/src/methods/artist_methods.dart +++ b/lib/src/methods/artist_methods.dart @@ -3,7 +3,6 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/lastfm.dart'; import 'package:scrobblenaut/scrobblenaut_exceptions.dart'; import 'package:scrobblenaut/src/core/lastfm.dart'; @@ -22,8 +21,8 @@ class ArtistMethods { /// /// https://www.last.fm/api/show/artist.addTags Future addTags({ - @required String artist, - @required List tags, + required String artist, + required List tags, }) async { if (!_api.isAuth) { return Future.error(ScrobblenautException( @@ -59,7 +58,7 @@ class ArtistMethods { /// /// https://www.last.fm/api/show/artist.getCorrection Future> getCorrection({ - @required String artist, + required String artist, }) async { final parameters = { 'artist': artist, @@ -87,9 +86,9 @@ class ArtistMethods { /// /// https://www.last.fm/api/show/artist.getInfo Future getInfo({ - String artist, - String mbid, - String username, + String? artist, + String? mbid, + String? username, Language language = Language.en, bool autoCorrect = false, }) async { @@ -102,7 +101,7 @@ class ArtistMethods { 'artist': artist, 'mbid': mbid, 'username': username, - 'lang': language?.code, + 'lang': language.code, 'autocorrect': (autoCorrect ? 1 : 0), }; @@ -116,10 +115,10 @@ class ArtistMethods { /// Get all the artists similar to this artist. /// /// https://www.last.fm/api/show/artist.getSimilar - Future> getSimilar({ - String artist, - String mbid, - int limit, + Future?> getSimilar({ + String? artist, + String? mbid, + int? limit, bool autoCorrect = false, }) async { if (artist == null && mbid == null) { @@ -155,26 +154,30 @@ class ArtistMethods { /// by all users use artist.getTopTags. /// /// https://www.last.fm/api/show/artist.getTags - Future> getTags({ - String artist, - String mbid, - String user, + Future?> getTags({ + String? artist, + String? mbid, + String? user, bool autoCorrect = false, }) async { if (artist == null && mbid == null) { - return Future.error(ScrobblenautException( - description: 'This method requires at least artist or mbid.')); + return Future.error( + ScrobblenautException( + description: 'This method requires at least artist or mbid.'), + ); } if (!_api.isAuth && user == null) { - return Future.error(ScrobblenautException( - description: "You're not authenticated, you must use user.")); + return Future.error( + ScrobblenautException( + description: "You're not authenticated, you must use user."), + ); } final parameters = { 'artist': artist, 'mbid': mbid, - 'user': user, + 'user': user ?? _api.username, 'autocorrect': (autoCorrect ? 1 : 0), }; @@ -193,9 +196,9 @@ class ArtistMethods { /// Get the top albums for an artist on Last.fm, ordered by popularity. /// /// https://www.last.fm/api/show/artist.getTopAlbums - Future> getTopAlbums({ - String artist, - String mbid, + Future?> getTopAlbums({ + String? artist, + String? mbid, int page = 1, int limit = 50, }) async { @@ -227,9 +230,9 @@ class ArtistMethods { /// Get the top tags for an artist on Last.fm, ordered by popularity. /// /// https://www.last.fm/api/show/artist.getTopTags - Future> getTopTags({ - String artist, - String mbid, + Future?> getTopTags({ + String? artist, + String? mbid, bool autoCorrect = false, }) async { if (artist == null && mbid == null) { @@ -258,9 +261,9 @@ class ArtistMethods { /// Get the top tracks by an artist on Last.fm, ordered by popularity. /// /// https://www.last.fm/api/show/artist.getTopTracks - Future> getTopTracks({ - String artist, - String mbid, + Future?> getTopTracks({ + String? artist, + String? mbid, int page = 1, int limit = 50, bool autoCorrect = false, @@ -295,8 +298,8 @@ class ArtistMethods { /// /// https://www.last.fm/api/show/artist.removeTag Future removeTag({ - @required String artist, - @required String tag, + required String artist, + required String tag, }) async { if (!_api.isAuth) { return Future.error(ScrobblenautException( @@ -326,7 +329,7 @@ class ArtistMethods { /// /// https://www.last.fm/api/show/artist.search. Future search({ - @required String artist, + required String artist, int page = 1, int limit = 30, }) async { diff --git a/lib/src/methods/chart_methods.dart b/lib/src/methods/chart_methods.dart index 6ac3651..6852a43 100644 --- a/lib/src/methods/chart_methods.dart +++ b/lib/src/methods/chart_methods.dart @@ -17,7 +17,7 @@ class ChartMethods { /// Get the top artists chart. /// /// https://www.last.fm/api/show/chart.getTopArtists - Future> getTopArtists({ + Future?> getTopArtists({ int page = 1, int limit = 50, }) async { @@ -42,7 +42,7 @@ class ChartMethods { /// Get the top tags chart. /// /// https://www.last.fm/api/show/chart.getTopTags - Future> getTopTags({ + Future?> getTopTags({ int page = 1, int limit = 50, }) async { @@ -67,7 +67,7 @@ class ChartMethods { /// Get the top tracks chart. /// /// https://www.last.fm/api/show/chart.getTopTracks - Future> getTopTracks({ + Future?> getTopTracks({ int page = 1, int limit = 50, }) async { diff --git a/lib/src/methods/geo_methods.dart b/lib/src/methods/geo_methods.dart index 4109e3b..3c2a8a6 100644 --- a/lib/src/methods/geo_methods.dart +++ b/lib/src/methods/geo_methods.dart @@ -3,7 +3,6 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/lastfm.dart'; import 'package:scrobblenaut/src/core/lastfm.dart'; import 'package:scrobblenaut/src/core/request.dart'; @@ -18,8 +17,8 @@ class GeoMethods { /// Get the most popular artists on Last.fm by country. /// /// https://www.last.fm/api/show/geo.getTopArtists - Future> getTopArtists({ - @required String country, + Future?> getTopArtists({ + required String country, int page = 1, int limit = 50, }) async { @@ -46,8 +45,8 @@ class GeoMethods { /// /// https://www.last.fm/api/show/geo.getTopTracks Future> getTopTracks({ - @required String country, - String location, + required String country, + String? location, int page = 1, int limit = 50, }) async { @@ -73,7 +72,7 @@ class GeoMethods { (topTracks as List).length, (i) => Track.fromJson(topTracks[i])); fixTopTracks.forEach((Track track) { - track.duration = track.duration * 1000; + track.duration = track.duration != null ? track.duration! * 1000 : null; }); return fixTopTracks; } diff --git a/lib/src/methods/library_methods.dart b/lib/src/methods/library_methods.dart index bcae1d9..5c65957 100644 --- a/lib/src/methods/library_methods.dart +++ b/lib/src/methods/library_methods.dart @@ -3,12 +3,13 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/lastfm.dart'; import 'package:scrobblenaut/src/core/lastfm.dart'; import 'package:scrobblenaut/src/core/request.dart'; import 'package:scrobblenaut/src/core/request_mode.dart'; +import '../../lastfm.dart'; + /// This contains all the methods about a [Library]. class LibraryMethods { final LastFM _api; @@ -19,10 +20,10 @@ class LibraryMethods { /// and tag counts. /// /// https://www.last.fm/api/show/library.getArtists - Future> getArtists({ - @required String user, + Future getArtists({ + required String user, int limit = 50, - int page, + int? page, }) async { final parameters = { 'user': user, @@ -35,11 +36,8 @@ class LibraryMethods { final response = await request.send(mode: RequestMode.GET); - final artists = response['artists']['artist']; + final artists = response['artists']; - return artists == null - ? null - : List.generate( - (artists as List).length, (i) => Artist.fromJson(artists[i])); + return artists == null ? null : LibraryGetArtistsResponse.fromJson(artists); } } diff --git a/lib/src/methods/tag_methods.dart b/lib/src/methods/tag_methods.dart index 8fe0487..e9b0c95 100644 --- a/lib/src/methods/tag_methods.dart +++ b/lib/src/methods/tag_methods.dart @@ -3,7 +3,6 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/lastfm.dart'; import 'package:scrobblenaut/src/core/lastfm.dart'; import 'package:scrobblenaut/src/core/request.dart'; @@ -19,12 +18,12 @@ class TagMethods { /// /// https://www.last.fm/api/show/tag.getInfo Future getInfo({ - @required String tag, + required String tag, Language language = Language.en, }) async { final parameters = { 'tag': tag, - 'lang': language?.code, + 'lang': language.code, }; final request = @@ -37,8 +36,8 @@ class TagMethods { /// Returns tags ranked by similarity, based on listening data. /// /// https://www.last.fm/api/show/tag.getSimilar - Future> getSimilar({ - @required String tag, + Future?> getSimilar({ + required String tag, }) async { final parameters = { 'tag': tag, @@ -60,8 +59,8 @@ class TagMethods { /// Get the top albums tagged by this tag, ordered by tag count. /// /// https://www.last.fm/api/show/tag.getTopAlbums - Future> getTopAlbums({ - @required String tag, + Future?> getTopAlbums({ + required String tag, int page = 1, int limit = 50, }) async { @@ -87,8 +86,8 @@ class TagMethods { /// Get the top artists tagged by this tag, ordered by tag count. /// /// https://www.last.fm/api/show/tag.getTopArtists - Future> getTopArtists({ - @required String tag, + Future?> getTopArtists({ + required String tag, int page = 1, int limit = 50, }) async { @@ -115,7 +114,7 @@ class TagMethods { /// sorted by popularity (number of times used). /// /// https://www.last.fm/api/show/tag.getTopTags - Future> getTopTags() async { + Future?> getTopTags() async { final request = Request(api: _api, method: 'tag.getTopTags'); final response = await request.send(mode: RequestMode.GET); @@ -131,8 +130,8 @@ class TagMethods { /// Get the top tracks tagged by this tag, ordered by tag count. /// /// https://www.last.fm/api/show/tag.getTopTracks - Future> getTopTracks({ - @required String tag, + Future?> getTopTracks({ + required String tag, int page = 1, int limit = 50, }) async { @@ -159,8 +158,8 @@ class TagMethods { /// expressed as date ranges which can be sent to the chart services. /// /// https://www.last.fm/api/show/tag.getWeeklyChartList. - Future> getWeeklyChartList({ - @required String tag, + Future?> getWeeklyChartList({ + required String tag, }) async { final parameters = { 'tag': tag, diff --git a/lib/src/methods/track_methods.dart b/lib/src/methods/track_methods.dart index 9df30bf..d1bada5 100644 --- a/lib/src/methods/track_methods.dart +++ b/lib/src/methods/track_methods.dart @@ -3,7 +3,6 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/lastfm.dart'; import 'package:scrobblenaut/scrobblenaut_exceptions.dart'; import 'package:scrobblenaut/src/core/lastfm.dart'; @@ -25,9 +24,9 @@ class TrackMethods { /// /// https://www.last.fm/api/show/track.addTags Future addTags({ - @required String track, - @required String artist, - @required List tags, + required String track, + required String artist, + required List tags, }) async { if (!_api.isAuth) { return Future.error(ScrobblenautException( @@ -64,8 +63,8 @@ class TrackMethods { /// /// https://www.last.fm/api/show/artist.getCorrection Future> getCorrection({ - @required String track, - @required String artist, + required String track, + required String artist, }) async { final parameters = { 'track': track, @@ -95,16 +94,18 @@ class TrackMethods { /// /// https://www.last.fm/api/show/track.getInfo Future getInfo({ - String track, - String artist, - String mbid, - String username, + String? track, + String? artist, + String? mbid, + String? username, bool autoCorrect = false, }) async { if ((track == null || artist == null) && mbid == null) { - return Future.error(ScrobblenautException( - description: 'At least mbid is required. ' - 'Can be used also track and artist.')); + return Future.error( + ScrobblenautException( + description: 'At least mbid is required. ' + 'Can be used also track and artist.'), + ); } final parameters = { @@ -118,24 +119,25 @@ class TrackMethods { final request = Request(api: _api, method: 'track.getInfo', parameters: parameters); - return (Track.fromJson( - (await request.send(mode: RequestMode.GET))['track'])); + return Track.fromJson((await request.send(mode: RequestMode.GET))['track']); } /// Get the similar tracks for this track on Last.fm, based on listening data. /// /// https://www.last.fm/api/show/track.getSimilar - Future> getSimilar({ - String track, - String artist, - String mbid, - int limit, + Future?> getSimilar({ + String? track, + String? artist, + String? mbid, + int? limit, bool autoCorrect = false, }) async { if ((track == null || artist == null) && mbid == null) { - return Future.error(ScrobblenautException( - description: 'At least mbid is required. ' - 'Can be used also track and artist.')); + return Future.error( + ScrobblenautException( + description: 'At least mbid is required. ' + 'Can be used also track and artist.'), + ); } final parameters = { @@ -164,11 +166,11 @@ class TrackMethods { /// all users use track.getTopTags. /// /// https://www.last.fm/api/show/track.getTags - Future> getTags({ - String track, - String artist, - String mbid, - String user, + Future?> getTags({ + String? track, + String? artist, + String? mbid, + String? user, bool autoCorrect = false, }) async { if ((track == null || artist == null) && mbid == null) { @@ -213,10 +215,10 @@ class TrackMethods { /// Supply either track & artist name or mbid. /// /// https://www.last.fm/api/show/track.getTopTags - Future> getTopTags({ - String track, - String artist, - String mbid, + Future?> getTopTags({ + String? track, + String? artist, + String? mbid, bool autoCorrect = false, }) async { if ((track == null || artist == null) && mbid == null) { @@ -248,8 +250,8 @@ class TrackMethods { /// /// https://www.last.fm/api/show/track.love Future love({ - @required String track, - @required String artist, + required String track, + required String artist, }) async { if (!_api.isAuth) { return Future.error(ScrobblenautException( @@ -279,9 +281,9 @@ class TrackMethods { /// /// https://www.last.fm/api/show/track.removeTag Future removeTag({ - @required String track, - @required String artist, - @required String tag, + required String track, + required String artist, + required String tag, }) async { if (!_api.isAuth) { return Future.error(ScrobblenautException( @@ -325,16 +327,16 @@ class TrackMethods { /// unless they have been explicitly approved by the user. /// Parameter names are case sensitive. Future scrobble({ - @required String track, - String album, - @required String artist, - int trackNumber, - Duration duration, - DateTime timestamp, - String context, - String streamId, + required String track, + String? album, + required String artist, + int? trackNumber, + Duration? duration, + DateTime? timestamp, + String? context, + String? streamId, bool chosenByUser = false, - String mbid, + String? mbid, }) async { if (!_api.isAuth) { return Future.error(ScrobblenautException( @@ -368,7 +370,7 @@ class TrackMethods { /// See [TrackMethods.scrobble]. Future scrobbleFromObject( - {@required Scrobble scrobble}) async { + {required Scrobble scrobble}) async { if (!_api.isAuth) { return Future.error(ScrobblenautException( description: "You can't use this method unless you Authenticate.")); @@ -380,15 +382,13 @@ class TrackMethods { 'artist': scrobble.artist, 'trackNumber': scrobble.trackNumber, 'duration': scrobble.duration?.inSeconds, - 'timestamp': scrobble.timestamp == null - ? LastFMValueNormalizer.timestampToSecondsSinceEpoch(DateTime.now()) - : LastFMValueNormalizer.timestampToSecondsSinceEpoch( - scrobble.timestamp), + 'timestamp': LastFMValueNormalizer.timestampToSecondsSinceEpoch( + scrobble.timestamp), 'context': scrobble.context, 'streamId': scrobble.streamId, 'chosenByUser': (scrobble.chosenByUser == null ? null - : scrobble.chosenByUser + : scrobble.chosenByUser! ? 1 : 0), 'mbid': scrobble.mbid, @@ -405,12 +405,14 @@ class TrackMethods { /// See [TrackMethods.scrobble] and [Scrobble] for more information. Future multiScrobble( - {@required List scrobbleList}) async { + {required List scrobbleList}) async { // TODO: make a queue for scrobbleList longer than 50? if (scrobbleList.length > 50) { - return Future.error(ScrobblenautException( - description: "You've supplied more than 50 scrobbles.")); + return Future.error( + ScrobblenautException( + description: "You've supplied more than 50 scrobbles."), + ); } var parameters = {}; @@ -418,16 +420,18 @@ class TrackMethods { var i = 1; scrobbleList.forEach((Scrobble scrobble) { - parameters['track[${i}]'] = scrobble.track; - parameters['album[${i}]'] = scrobble.album; - parameters['artist[${i}]'] = scrobble.artist; - parameters['trackNumber[${i}]'] = scrobble.trackNumber; - parameters['duration[${i}]'] = scrobble.duration; - parameters['timestamp[${i}]'] = scrobble.timestamp; - parameters['context[${i}]'] = scrobble.context; - parameters['streamId[${i}]'] = scrobble.streamId; - parameters['chosenByUser[${i}]'] = scrobble.chosenByUser; - parameters['mbid[${i}]'] = scrobble.mbid; + parameters['track[$i]'] = scrobble.track; + parameters['album[$i]'] = scrobble.album; + parameters['artist[$i]'] = scrobble.artist; + parameters['trackNumber[$i]'] = scrobble.trackNumber; + parameters['duration[$i]'] = scrobble.duration; + parameters['timestamp[$i]'] = + LastFMValueNormalizer.timestampToSecondsSinceEpoch( + scrobble.timestamp); + parameters['context[$i]'] = scrobble.context; + parameters['streamId[$i]'] = scrobble.streamId; + parameters['chosenByUser[$i]'] = scrobble.chosenByUser; + parameters['mbid[$i]'] = scrobble.mbid; i++; }); @@ -446,8 +450,8 @@ class TrackMethods { /// /// https://www.last.fm/api/show/track.search Future search({ - @required String track, - String artist, + required String track, + String? artist, int page = 1, int limit = 30, }) async { @@ -470,8 +474,8 @@ class TrackMethods { /// /// https://www.last.fm/api/show/track.unlove Future unLove({ - @required String track, - @required String artist, + required String track, + required String artist, }) async { if (!_api.isAuth) { return Future.error(ScrobblenautException( @@ -502,16 +506,16 @@ class TrackMethods { /// /// https://www.last.fm/api/show/track.updateNowPlaying Future updateNowPlaying({ - @required String track, - String album, - @required String artist, - int trackNumber, - Duration duration, - DateTime timestamp, - String context, - String streamId, + required String track, + String? album, + required String artist, + int? trackNumber, + Duration? duration, + DateTime? timestamp, + String? context, + String? streamId, bool chosenByUser = false, - String mbid, + String? mbid, }) async { if (!_api.isAuth) { return Future.error(ScrobblenautException( @@ -543,10 +547,12 @@ class TrackMethods { /// See [TrackMethods.updateNowPlaying]. Future updateNowPlayingFromObject( - {@required NowPlaying track}) async { + {required NowPlaying track}) async { if (!_api.isAuth) { - return Future.error(ScrobblenautException( - description: "You can't use this method unless you Authenticate.")); + return Future.error( + ScrobblenautException( + description: "You can't use this method unless you Authenticate."), + ); } final parameters = { diff --git a/lib/src/methods/user_methods.dart b/lib/src/methods/user_methods.dart index 84a2ced..f5192ca 100644 --- a/lib/src/methods/user_methods.dart +++ b/lib/src/methods/user_methods.dart @@ -3,7 +3,6 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/lastfm.dart'; import 'package:scrobblenaut/scrobblenaut.dart'; import 'package:scrobblenaut/scrobblenaut_exceptions.dart'; @@ -22,8 +21,8 @@ class UserMethods { /// Get a list of the user's friends on Last.fm. /// /// https://www.last.fm/api/show/user.getFriends - Future> getFriends({ - @required String user, + Future?> getFriends({ + required String user, bool enableRecentTracks = false, int page = 1, int limit = 50, @@ -52,7 +51,7 @@ class UserMethods { /// /// https://www.last.fm/api/show/user.getInfo Future getInfo({ - String user, + required String user, }) async { final parameters = { 'user': user, @@ -69,8 +68,8 @@ class UserMethods { /// Get the last 50 tracks loved by a user. /// /// https://www.last.fm/api/show/user.getLovedTracks - Future> getLovedTracks({ - @required String user, + Future?> getLovedTracks({ + required String user, int page = 1, int limit = 50, }) async { @@ -97,16 +96,16 @@ class UserMethods { /// /// https://www.last.fm/api/show/user.getPersonalTags Future getPersonalTags({ - @required String user, - @required String tag, - @required TaggingType taggingType, + required String user, + required String tag, + required TaggingType taggingType, int page = 1, int limit = 50, }) async { final parameters = { 'user': user, 'tag': tag, - 'taggingtype': taggingType?.type, + 'taggingtype': taggingType.type, 'page': page, 'limit': limit, }; @@ -154,20 +153,17 @@ class UserMethods { } /// Get a list of the recent tracks listened to by this user. - /// Also includes the currently playing track with the nowPlaying="true" - /// attribute if the user is currently listening. /// /// **NOTE:** the output list is already ordered by last listened first. /// /// https://www.last.fm/api/show/user.getRecentTracks - Future> getRecentTracks({ - @required String user, + Future?> getRecentTracks({ + required String user, int page = 1, int limit = 50, // MAX 200 - DateTime fromDate, - DateTime toDate, + DateTime? fromDate, + DateTime? toDate, bool extended = false, - bool nowPlaying = false, }) async { if (limit > 200) { return Future.error( @@ -181,7 +177,6 @@ class UserMethods { 'from': LastFMValueNormalizer.DateTimeToUnixTime(fromDate), 'to': LastFMValueNormalizer.DateTimeToUnixTime(toDate), 'extended': (extended ? 1 : 0), - 'nowplaying': (nowPlaying ? 1 : 0), }; final request = Request( @@ -204,8 +199,8 @@ class UserMethods { : null; // If there's no #text field, don't touch the artist. }); - return List.generate((recentTracks as List).length, - (i) => Track.fromJson(recentTracks[i])); + return List.generate( + recentTracks.length, (i) => Track.fromJson(recentTracks[i])); } } @@ -215,9 +210,9 @@ class UserMethods { /// **NOTE:** the output list is already ordered by rank. /// /// https://www.last.fm/api/show/user.getTopAlbums - Future> getTopAlbums({ - @required String user, - Period period, + Future?> getTopAlbums({ + required String user, + Period? period, int page = 1, int limit = 50, }) async { @@ -248,9 +243,9 @@ class UserMethods { /// **NOTE:** the output list is already ordered by rank. /// /// https://www.last.fm/api/show/user.getTopArtists - Future> getTopArtists({ - @required String user, - Period period, + Future?> getTopArtists({ + required String user, + Period? period, int page = 1, int limit = 50, }) async { @@ -279,9 +274,9 @@ class UserMethods { /// **NOTE:** the output list is already ordered by rank. /// /// https://www.last.fm/api/show/user.getTopTags - Future> getTopTags({ - @required String user, - int limit, + Future?> getTopTags({ + required String user, + int? limit, }) async { final parameters = { 'user': user, @@ -309,8 +304,8 @@ class UserMethods { /// /// https://www.last.fm/api/show/user.getTopTracks Future> getTopTracks({ - @required String user, - Period period, + required String user, + Period? period, int page = 1, int limit = 50, }) async { @@ -338,7 +333,9 @@ class UserMethods { (topTracks as List).length, (i) => Track.fromJson(topTracks[i])); fixTopTracks.forEach((Track track) { - track.duration = track.duration * 1000; + if (track.duration != null) { + track.duration = track.duration! * 1000; + } }); return fixTopTracks; } @@ -351,10 +348,10 @@ class UserMethods { /// **NOTE:** the output list is already ordered by rank. /// /// https://www.last.fm/api/show/user.getWeeklyAlbumChart - Future> getWeeklyAlbumChart({ - @required String user, - DateTime fromDate, - DateTime toDate, + Future?> getWeeklyAlbumChart({ + required String user, + DateTime? fromDate, + DateTime? toDate, }) async { final parameters = { 'user': user, @@ -384,10 +381,10 @@ class UserMethods { /// **NOTE:** the output list is already ordered by rank. /// /// https://www.last.fm/api/show/user.getWeeklyArtistChart - Future> getWeeklyArtistChart({ - @required String user, - DateTime fromDate, - DateTime toDate, + Future?> getWeeklyArtistChart({ + required String user, + DateTime? fromDate, + DateTime? toDate, }) async { final parameters = { 'user': user, @@ -402,7 +399,7 @@ class UserMethods { final response = await request.send(mode: RequestMode.GET); - final weeklyArtistChart = response['weeklyartistchart']['track']; + final weeklyArtistChart = response['weeklyartistchart']['artist']; return weeklyArtistChart == null ? null @@ -414,8 +411,8 @@ class UserMethods { /// expressed as date ranges which can be sent to the chart services. /// /// https://www.last.fm/api/show/user.getWeeklyChartList - Future> getWeeklyChartList({ - @required String user, + Future?> getWeeklyChartList({ + required String user, }) async { final parameters = { 'user': user, @@ -441,10 +438,10 @@ class UserMethods { /// **NOTE:** the output list is already ordered by rank. /// /// https://www.last.fm/api/show/user.getWeeklyTrackChart - Future> getWeeklyTrackChart({ - @required String user, - DateTime fromDate, - DateTime toDate, + Future?> getWeeklyTrackChart({ + required String user, + DateTime? fromDate, + DateTime? toDate, }) async { final parameters = { 'user': user, diff --git a/lib/src/scrobblenaut.dart b/lib/src/scrobblenaut.dart index 61a39ad..4f3b46d 100644 --- a/lib/src/scrobblenaut.dart +++ b/lib/src/scrobblenaut.dart @@ -3,7 +3,6 @@ // Copyright (c) 2020 Nebulino // // // -import 'package:meta/meta.dart'; import 'package:scrobblenaut/lastfm_methods.dart'; import 'package:scrobblenaut/src/core/lastfm.dart'; @@ -12,7 +11,7 @@ import 'package:scrobblenaut/src/core/lastfm.dart'; /// [LastFM]: https://www.last.fm/api/ class Scrobblenaut { /// The Scrobblenaut instance. - static Scrobblenaut _instance; + static late Scrobblenaut _instance; /// The [LastFM] object. Helps creating each methods. final LastFM _api; @@ -26,23 +25,22 @@ class Scrobblenaut { TrackMethods _trackMethods; UserMethods _userMethods; - Scrobblenaut._(this._api) { - _albumMethods = AlbumMethods(_api); - _artistMethods = ArtistMethods(_api); - _chartMethods = ChartMethods(_api); - _geoMethods = GeoMethods(_api); - _libraryMethods = LibraryMethods(_api); - _tagMethods = TagMethods(_api); - _trackMethods = TrackMethods(_api); - _userMethods = UserMethods(_api); - + Scrobblenaut._(this._api) + : _albumMethods = AlbumMethods(_api), + _artistMethods = ArtistMethods(_api), + _chartMethods = ChartMethods(_api), + _geoMethods = GeoMethods(_api), + _libraryMethods = LibraryMethods(_api), + _tagMethods = TagMethods(_api), + _trackMethods = TrackMethods(_api), + _userMethods = UserMethods(_api) { _instance = this; } // TODO: create a [User] if _api.isAuth /// It creates a Scrobblenaut Session using a LastFM object. - Scrobblenaut({@required LastFM lastFM}) : this._(lastFM); + Scrobblenaut({required LastFM lastFM}) : this._(lastFM); /// It returns the created instance. static Scrobblenaut get instance => _instance; diff --git a/lib/src/tools/spaceship.dart b/lib/src/tools/spaceship.dart index 6849f42..a25c6dc 100644 --- a/lib/src/tools/spaceship.dart +++ b/lib/src/tools/spaceship.dart @@ -4,7 +4,6 @@ // // import 'package:dio/dio.dart'; -import 'package:meta/meta.dart'; import 'package:scrobblenaut/scrobblenaut_exceptions.dart'; import 'package:scrobblenaut/src/helpers/post_response_helper.dart'; import 'package:scrobblenaut/src/helpers/utils.dart'; @@ -14,33 +13,30 @@ import 'package:scrobblenaut/src/helpers/utils.dart'; /// /// [LastFM]: https://last.fm/api class SpaceShip { - Dio _dio; + late Dio _dio; - SpaceShip({@required String base_url}) { + SpaceShip({required String base_url, String? proxy}) { _dio = Dio( BaseOptions( - baseUrl: '${base_url}', - headers: { - 'Content-type': 'application/x-www-form-urlencoded', - 'Accept-Charset': 'utf-8', - 'User-Agent': 'DartyFM' - }, + baseUrl: '$base_url', + headers: {'Accept-Charset': 'utf-8', 'User-Agent': 'DartyFM'}, contentType: Headers.formUrlEncodedContentType, responseType: ResponseType.json), - )..interceptors - .add(InterceptorsWrapper(onRequest: (RequestOptions options) { - options.queryParameters?.removeWhere((key, value) => value == null); + )..interceptors.add(InterceptorsWrapper(onRequest: + (RequestOptions options, RequestInterceptorHandler handler) { + options.queryParameters.removeWhere((key, value) => value == null); if (options.data == null) { - return options; + handler.next(options); + return; } if (options.data is Map) { (options.data as Map).removeWhere((key, value) => value == null); } - return options; - }, onResponse: (response) { + handler.next(options); + }, onResponse: (response, handler) { // Sometimes it responds without giving a error... if (isXml(response.data)) { final postResponse = PostResponseHelper.parse(response.data); @@ -56,26 +52,28 @@ class SpaceShip { } } - return response.data; - }, onError: (error) { - if (error.type == DioErrorType.RESPONSE) { - return LastFMException.generate(error.response.data); + handler.next(response); + }, onError: (error, ErrorInterceptorHandler handler) { + if (error.type == DioErrorType.response) { + handler.next(LastFMException.generate(error.response?.data)); } else { - return error; + handler.next(error); } })); } - Future get({ - @required Map parameters, - }) async { + Future get( + {required Map parameters, retryLimit = 5}) async { parameters['format'] = 'json'; + // TODO: Catch errors from API and retry + // for (var i = 0; i < retryLimit; i++) { return (await _dio.get('', queryParameters: parameters)).data; + // } } // Post request with JSON response exists? Future post({ - @required Map parameters, + required Map parameters, }) async { return (await _dio.post('', data: parameters)).data; } diff --git a/pubspec.yaml b/pubspec.yaml index 69193fc..16989ca 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,18 +5,18 @@ homepage: https://github.com/Nebulino/Scrobblenaut issue_tracker: https://github.com/Nebulino/Scrobblenaut/issues environment: - sdk: '>=2.7.0 <3.0.0' + sdk: ">=2.12.0-0 <3.0.0" dependencies: - meta: ^1.1.8 - json_annotation: ^3.0.1 + meta: ^1.3.0 + json_annotation: ^4.0.1 convert: ^3.0.0 - dio: ^3.0.10 - crypto: ^3.0.0 - xml: ^5.0.2 + dio: ^4.0.0 + crypto: ^3.0.1 + xml: ^5.1.1 dev_dependencies: - pedantic: ^1.9.0 - test: ^1.14.6 - json_serializable: ^3.1.0 - build_runner: ^1.10.0 + pedantic: ^1.11.0 + test: ^1.17.5 + json_serializable: ^4.1.3 + build_runner: ^2.0.4 diff --git a/test/scrobblenaut_test.dart b/test/scrobblenaut_test.dart index f2b9b40..7d7e74c 100644 --- a/test/scrobblenaut_test.dart +++ b/test/scrobblenaut_test.dart @@ -10,7 +10,7 @@ import 'package:test/test.dart'; // Some Scrobblenaut tests. void main() { group('A group of tests', () { - Scrobblenaut scrobblenaut; + late Scrobblenaut scrobblenaut; String token; LastFM lastFM; From a138aa57796cd1c1b3359d461b49515e58948baa Mon Sep 17 00:00:00 2001 From: Fergus Longley Date: Tue, 6 Jul 2021 22:13:38 +0100 Subject: [PATCH 2/4] Bump package version for breaking changes --- lib/src/lastfm.g.dart | 766 ------------------------------------------ pubspec.yaml | 2 +- 2 files changed, 1 insertion(+), 767 deletions(-) delete mode 100644 lib/src/lastfm.g.dart diff --git a/lib/src/lastfm.g.dart b/lib/src/lastfm.g.dart deleted file mode 100644 index 5349480..0000000 --- a/lib/src/lastfm.g.dart +++ /dev/null @@ -1,766 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of lastfm_objects; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -NowPlaying _$NowPlayingFromJson(Map json) { - return NowPlaying( - track: json['track'] as String, - album: json['album'] as String?, - artist: json['artist'] as String, - trackNumber: json['trackNumber'] as int?, - duration: json['duration'] == null - ? null - : Duration(microseconds: json['duration'] as int), - context: json['context'] as String?, - mbid: json['mbid'] as String?, - albumArtist: json['albumArtist'] as String?, - ); -} - -Map _$NowPlayingToJson(NowPlaying instance) { - final val = { - 'artist': instance.artist, - 'track': instance.track, - }; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('album', instance.album); - writeNotNull('trackNumber', instance.trackNumber); - writeNotNull('context', instance.context); - writeNotNull('mbid', instance.mbid); - writeNotNull('duration', - LastFMValueNormalizer.DurationToMilliseconds(instance.duration)); - writeNotNull('albumArtist', instance.albumArtist); - return val; -} - -Scrobble _$ScrobbleFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['artist', 'track']); - return Scrobble( - track: json['track'] as String, - album: json['album'] as String?, - artist: json['artist'] as String, - trackNumber: json['trackNumber'] as int?, - duration: json['duration'] == null - ? null - : Duration(microseconds: json['duration'] as int), - timestamp: json['timestamp'] == null - ? null - : DateTime.parse(json['timestamp'] as String), - context: json['context'] as String?, - streamId: json['streamId'] as String?, - chosenByUser: json['chosenByUser'] as bool?, - mbid: json['mbid'] as String?, - ); -} - -Map _$ScrobbleToJson(Scrobble instance) { - final val = { - 'artist': instance.artist, - 'track': instance.track, - }; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('timestamp', - LastFMValueNormalizer.DateTimeToUnixTime(instance.timestamp)); - writeNotNull('album', instance.album); - writeNotNull('context', instance.context); - writeNotNull('streamId', instance.streamId); - writeNotNull('chosenByUser', - LastFMValueNormalizer.BoolToIntBool(instance.chosenByUser)); - writeNotNull('trackNumber', instance.trackNumber); - writeNotNull('mbid', instance.mbid); - writeNotNull('duration', - LastFMValueNormalizer.DurationToMilliseconds(instance.duration)); - return val; -} - -Session _$SessionFromJson(Map json) { - return Session( - name: json['name'] as String?, - sessionKey: json['key'] as String?, - subscriber: json['subscriber'] as int?, - ); -} - -Map _$SessionToJson(Session instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('name', instance.name); - writeNotNull('key', instance.sessionKey); - writeNotNull('subscriber', instance.subscriber); - return val; -} - -Attr _$AttrFromJson(Map json) { - return Attr( - page: LastFMValueNormalizer.NumberToInt(json['page']), - perPage: LastFMValueNormalizer.NumberToInt(json['perPage']), - user: json['user'] as String?, - total: LastFMValueNormalizer.NumberToInt(json['total']), - totalPages: LastFMValueNormalizer.NumberToInt(json['totalPages']), - ); -} - -Map _$AttrToJson(Attr instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('page', instance.page); - writeNotNull('perPage', instance.perPage); - writeNotNull('user', instance.user); - writeNotNull('total', instance.total); - writeNotNull('totalPages', instance.totalPages); - return val; -} - -Album _$AlbumFromJson(Map json) { - return Album( - title: json['title'] as String?, - name: json['name'] as String?, - artist: LastFMValueNormalizer.ArtistParser(json['artist']), - url: json['url'] as String?, - images: (json['image'] as List?) - ?.map((e) => Image.fromJson(e as Map)) - .toList(), - tracks: LastFMValueNormalizer.tracksExtractor( - json['tracks'] as Map?), - tags: LastFMValueNormalizer.tagsExtractor( - json['tags'] as Map?), - listeners: LastFMValueNormalizer.NumberToInt(json['listeners']), - playCount: LastFMValueNormalizer.NumberToInt(json['playcount']), - mbid: json['mbid'] as String?, - ); -} - -Map _$AlbumToJson(Album instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('title', instance.title); - writeNotNull('name', instance.name); - writeNotNull('artist', instance.artist); - writeNotNull('url', instance.url); - writeNotNull('image', instance.images); - writeNotNull('tracks', instance.tracks); - writeNotNull('tags', instance.tags); - writeNotNull('listeners', instance.listeners); - writeNotNull('playcount', instance.playCount); - writeNotNull('mbid', instance.mbid); - return val; -} - -AlbumSearchResults _$AlbumSearchResultsFromJson(Map json) { - return AlbumSearchResults( - albums: LastFMValueNormalizer.albumsExtractor( - json['albummatches'] as Map?), - totalResults: - LastFMValueNormalizer.NumberToInt(json['opensearch:TotalResults']), - statingIndex: - LastFMValueNormalizer.NumberToInt(json['opensearch:StartIndex']), - itemsPerPage: - LastFMValueNormalizer.NumberToInt(json['opensearch:ItemsPerPage']), - ); -} - -Map _$AlbumSearchResultsToJson(AlbumSearchResults instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('albummatches', instance.albums); - writeNotNull('opensearch:TotalResults', instance.totalResults); - writeNotNull('opensearch:StartIndex', instance.statingIndex); - writeNotNull('opensearch:ItemsPerPage', instance.itemsPerPage); - return val; -} - -Artist _$ArtistFromJson(Map json) { - return Artist( - name: json['name'] as String?, - url: json['url'] as String?, - images: (json['image'] as List?) - ?.map((e) => Image.fromJson(e as Map)) - .toList(), - tags: LastFMValueNormalizer.tagsExtractor( - json['tags'] as Map?), - tagCount: LastFMValueNormalizer.NumberToInt(json['tagcount']), - stats: json['stats'] == null - ? null - : Stats.fromJson(json['stats'] as Map), - bio: json['bio'] == null - ? null - : Bio.fromJson(json['bio'] as Map), - similarArtists: LastFMValueNormalizer.similarArtistsExtractor( - json['similar'] as Map?), - match: json['match'] as String?, - isStreamable: LastFMValueNormalizer.isArtistStreamable(json['streamable']), - listeners: LastFMValueNormalizer.NumberToInt(json['listeners']), - playCount: LastFMValueNormalizer.NumberToInt(json['playcount']), - onTour: LastFMValueNormalizer.NumberToBool(json['ontour']), - mbid: json['mbid'] as String?, - ); -} - -Map _$ArtistToJson(Artist instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('name', instance.name); - writeNotNull('url', instance.url); - writeNotNull('image', instance.images); - writeNotNull('tags', instance.tags); - writeNotNull('tagcount', instance.tagCount); - writeNotNull('stats', instance.stats); - writeNotNull('bio', instance.bio); - writeNotNull('similar', instance.similarArtists); - writeNotNull('match', instance.match); - writeNotNull('streamable', instance.isStreamable); - writeNotNull('listeners', instance.listeners); - writeNotNull('playcount', instance.playCount); - writeNotNull('ontour', instance.onTour); - writeNotNull('mbid', instance.mbid); - return val; -} - -ArtistSearchResults _$ArtistSearchResultsFromJson(Map json) { - return ArtistSearchResults( - artists: LastFMValueNormalizer.artistsExtractor( - json['artistmatches'] as Map?), - totalResults: - LastFMValueNormalizer.NumberToInt(json['opensearch:TotalResults']), - statingIndex: - LastFMValueNormalizer.NumberToInt(json['opensearch:StartIndex']), - itemsPerPage: - LastFMValueNormalizer.NumberToInt(json['opensearch:ItemsPerPage']), - ); -} - -Map _$ArtistSearchResultsToJson(ArtistSearchResults instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('artistmatches', instance.artists); - writeNotNull('opensearch:TotalResults', instance.totalResults); - writeNotNull('opensearch:StartIndex', instance.statingIndex); - writeNotNull('opensearch:ItemsPerPage', instance.itemsPerPage); - return val; -} - -Bio _$BioFromJson(Map json) { - return Bio( - links: LastFMValueNormalizer.linksExtractor( - json['links'] as Map?), - published: json['published'] as String?, - summary: json['summary'] as String?, - content: json['content'] as String?, - ); -} - -Map _$BioToJson(Bio instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('links', instance.links); - writeNotNull('published', instance.published); - writeNotNull('summary', instance.summary); - writeNotNull('content', instance.content); - return val; -} - -Chart _$ChartFromJson(Map json) { - return Chart( - text: json['#text'] as String?, - fromDate: LastFMValueNormalizer.DateTimeFromUnixTime(json['from']), - toDate: LastFMValueNormalizer.DateTimeFromUnixTime(json['to']), - ); -} - -Map _$ChartToJson(Chart instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('#text', instance.text); - writeNotNull( - 'from', LastFMValueNormalizer.DateTimeToUnixTime(instance.fromDate)); - writeNotNull('to', LastFMValueNormalizer.DateTimeToUnixTime(instance.toDate)); - return val; -} - -Date _$DateFromJson(Map json) { - return Date( - unixDate: json['uts'] as String?, - text: json['#text'] as String?, - ); -} - -Map _$DateToJson(Date instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('uts', instance.unixDate); - writeNotNull('#text', instance.text); - return val; -} - -Image _$ImageFromJson(Map json) { - return Image( - size: _$enumDecodeNullable(_$SizeEnumMap, json['size'], - unknownValue: Size.None), - text: json['#text'] as String?, - ); -} - -Map _$ImageToJson(Image instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('size', _$SizeEnumMap[instance.size]); - writeNotNull('#text', instance.text); - return val; -} - -K _$enumDecode( - Map enumValues, - Object? source, { - K? unknownValue, -}) { - if (source == null) { - throw ArgumentError( - 'A value must be provided. Supported values: ' - '${enumValues.values.join(', ')}', - ); - } - - return enumValues.entries.singleWhere( - (e) => e.value == source, - orElse: () { - if (unknownValue == null) { - throw ArgumentError( - '`$source` is not one of the supported values: ' - '${enumValues.values.join(', ')}', - ); - } - return MapEntry(unknownValue, enumValues.values.first); - }, - ).key; -} - -K? _$enumDecodeNullable( - Map enumValues, - dynamic source, { - K? unknownValue, -}) { - if (source == null) { - return null; - } - return _$enumDecode(enumValues, source, unknownValue: unknownValue); -} - -const _$SizeEnumMap = { - Size.small: 'small', - Size.medium: 'medium', - Size.large: 'large', - Size.extralarge: 'extralarge', - Size.mega: 'mega', - Size.empty: 'empty', - Size.None: 'None', -}; - -Link _$LinkFromJson(Map json) { - return Link( - text: json['#text'] as String?, - rel: json['rel'] as String?, - webLink: json['href'] as String?, - ); -} - -Map _$LinkToJson(Link instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('#text', instance.text); - writeNotNull('rel', instance.rel); - writeNotNull('href', instance.webLink); - return val; -} - -Registered _$RegisteredFromJson(Map json) { - return Registered( - unixTime: LastFMValueNormalizer.DateTimeFromUnixTime(json['unixtime']), - text: LastFMValueNormalizer.MeaninglessNumber(json['#text']), - ); -} - -Map _$RegisteredToJson(Registered instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull( - 'unixtime', LastFMValueNormalizer.DateTimeToUnixTime(instance.unixTime)); - writeNotNull('#text', instance.text); - return val; -} - -Stats _$StatsFromJson(Map json) { - return Stats( - listeners: LastFMValueNormalizer.NumberToInt(json['listeners']), - playCount: LastFMValueNormalizer.NumberToInt(json['playcount']), - userPlayCount: LastFMValueNormalizer.NumberToInt(json['userplaycount']), - ); -} - -Map _$StatsToJson(Stats instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('listeners', instance.listeners); - writeNotNull('playcount', instance.playCount); - writeNotNull('userplaycount', instance.userPlayCount); - return val; -} - -Streamable _$StreamableFromJson(Map json) { - return Streamable( - text: json['#text'] as String?, - fullTrack: json['fulltrack'] as String?, - ); -} - -Map _$StreamableToJson(Streamable instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('#text', instance.text); - writeNotNull('fulltrack', instance.fullTrack); - return val; -} - -Tag _$TagFromJson(Map json) { - return Tag( - name: json['name'] as String, - url: json['url'] as String?, - count: LastFMValueNormalizer.NumberToInt(json['count']), - total: LastFMValueNormalizer.NumberToInt(json['total']), - reach: LastFMValueNormalizer.NumberToInt(json['reach']), - taggings: LastFMValueNormalizer.NumberToInt(json['taggings']), - streamable: LastFMValueNormalizer.NumberToBool(json['streamable']), - wiki: json['wiki'] == null - ? null - : Wiki.fromJson(json['wiki'] as Map), - ); -} - -Map _$TagToJson(Tag instance) { - final val = { - 'name': instance.name, - }; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('url', instance.url); - writeNotNull('count', instance.count); - writeNotNull('total', instance.total); - writeNotNull('reach', instance.reach); - writeNotNull('taggings', instance.taggings); - writeNotNull('streamable', instance.streamable); - writeNotNull('wiki', instance.wiki); - return val; -} - -Taggings _$TaggingsFromJson(Map json) { - return Taggings( - albums: LastFMValueNormalizer.albumsExtractor( - json['albums'] as Map?), - artists: LastFMValueNormalizer.artistsExtractor( - json['artists'] as Map?), - tracks: LastFMValueNormalizer.tracksExtractor( - json['tracks'] as Map?), - ); -} - -Map _$TaggingsToJson(Taggings instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('albums', instance.albums); - writeNotNull('artists', instance.artists); - writeNotNull('tracks', instance.tracks); - return val; -} - -Track _$TrackFromJson(Map json) { - return Track( - name: json['name'] as String, - album: json['album'] == null - ? null - : Album.fromJson(json['album'] as Map), - artist: LastFMValueNormalizer.ArtistParser(json['artist']), - url: json['url'] as String?, - duration: - LastFMValueNormalizer.MillisecondsDurationParser(json['duration']), - images: (json['image'] as List?) - ?.map((e) => Image.fromJson(e as Map)) - .toList(), - topTags: LastFMValueNormalizer.tagsExtractor( - json['toptags'] as Map?), - date: json['date'] == null - ? null - : Date.fromJson(json['date'] as Map), - streamable: LastFMValueNormalizer.StreamableParser(json['streamable']), - listeners: LastFMValueNormalizer.NumberToInt(json['listeners']), - playCount: LastFMValueNormalizer.NumberToInt(json['playcount']), - wiki: json['wiki'] == null - ? null - : Wiki.fromJson(json['wiki'] as Map), - mbid: json['mbid'] as String?, - loved: LastFMValueNormalizer.NumberToBool(json['loved']), - ); -} - -Map _$TrackToJson(Track instance) { - final val = { - 'name': instance.name, - }; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('album', instance.album); - writeNotNull('artist', instance.artist); - writeNotNull('url', instance.url); - writeNotNull('duration', instance.duration?.inMicroseconds); - writeNotNull('image', instance.images); - writeNotNull('toptags', instance.topTags); - writeNotNull('date', instance.date); - writeNotNull('streamable', instance.streamable); - writeNotNull('listeners', instance.listeners); - writeNotNull('playcount', instance.playCount); - writeNotNull('wiki', instance.wiki); - writeNotNull('mbid', instance.mbid); - writeNotNull('loved', instance.loved); - return val; -} - -TrackSearchResults _$TrackSearchResultsFromJson(Map json) { - return TrackSearchResults( - tracks: LastFMValueNormalizer.tracksExtractor( - json['trackmatches'] as Map?), - totalResults: - LastFMValueNormalizer.NumberToInt(json['opensearch:TotalResults']), - statingIndex: - LastFMValueNormalizer.NumberToInt(json['opensearch:StartIndex']), - itemsPerPage: - LastFMValueNormalizer.NumberToInt(json['opensearch:ItemsPerPage']), - ); -} - -Map _$TrackSearchResultsToJson(TrackSearchResults instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('trackmatches', instance.tracks); - writeNotNull('opensearch:TotalResults', instance.totalResults); - writeNotNull('opensearch:StartIndex', instance.statingIndex); - writeNotNull('opensearch:ItemsPerPage', instance.itemsPerPage); - return val; -} - -User _$UserFromJson(Map json) { - return User( - name: json['name'] as String, - realName: json['realname'] as String?, - gender: json['gender'] as String?, - age: json['age'] as String?, - country: json['country'] as String?, - url: json['url'] as String?, - image: (json['image'] as List?) - ?.map((e) => Image.fromJson(e as Map)) - .toList(), - subscriber: LastFMValueNormalizer.NumberToBool(json['subscriber']), - playlists: LastFMValueNormalizer.NumberToInt(json['playlists']), - playCount: LastFMValueNormalizer.NumberToInt(json['playcount']), - registered: json['registered'] == null - ? null - : Registered.fromJson(json['registered'] as Map), - bootstrap: json['bootstrap'] as String?, - type: json['type'] as String?, - ); -} - -Map _$UserToJson(User instance) { - final val = { - 'name': instance.name, - }; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('realname', instance.realName); - writeNotNull('gender', instance.gender); - writeNotNull('age', instance.age); - writeNotNull('country', instance.country); - writeNotNull('url', instance.url); - writeNotNull('image', instance.image); - writeNotNull('subscriber', instance.subscriber); - writeNotNull('playlists', instance.playlists); - writeNotNull('playcount', instance.playCount); - writeNotNull('registered', instance.registered); - writeNotNull('bootstrap', instance.bootstrap); - writeNotNull('type', instance.type); - return val; -} - -Wiki _$WikiFromJson(Map json) { - return Wiki( - published: json['published'] as String?, - summary: json['summary'] as String?, - content: json['content'] as String?, - ); -} - -Map _$WikiToJson(Wiki instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('published', instance.published); - writeNotNull('summary', instance.summary); - writeNotNull('content', instance.content); - return val; -} - -LibraryGetArtistsResponse _$LibraryGetArtistsResponseFromJson( - Map json) { - return LibraryGetArtistsResponse( - artist: (json['artist'] as List?) - ?.map((e) => Artist.fromJson(e as Map)) - .toList(), - attr: json['@attr'] == null - ? null - : Attr.fromJson(json['@attr'] as Map), - ); -} - -Map _$LibraryGetArtistsResponseToJson( - LibraryGetArtistsResponse instance) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('artist', instance.artist); - writeNotNull('@attr', instance.attr); - return val; -} diff --git a/pubspec.yaml b/pubspec.yaml index 16989ca..e326e31 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: scrobblenaut description: A deadly simple LastFM API Wrapper for Dart. So deadly simple that it's gonna hit the mark. -version: 2.0.5+1 +version: 3.0.0 homepage: https://github.com/Nebulino/Scrobblenaut issue_tracker: https://github.com/Nebulino/Scrobblenaut/issues From 4011a6a7d1b0c4db77db8fe0fe0de7a74ebf2f86 Mon Sep 17 00:00:00 2001 From: Space Traveler Date: Sun, 11 Sep 2022 01:39:37 +0200 Subject: [PATCH 3/4] Updating packages and adding some docs. --- example/.gitignore | 1 + lib/src/lastfm/core/attr.dart | 12 +++++++++++- lib/src/lastfm/responses/library.dart | 3 +++ pubspec.yaml | 20 ++++++++++---------- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/example/.gitignore b/example/.gitignore index 5fe24d1..67be08d 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -1 +1,2 @@ +### Examples-Level ### api_values.dart diff --git a/lib/src/lastfm/core/attr.dart b/lib/src/lastfm/core/attr.dart index 7724a4c..a1e9921 100644 --- a/lib/src/lastfm/core/attr.dart +++ b/lib/src/lastfm/core/attr.dart @@ -1,19 +1,29 @@ +// // +// Scrobblenaut - A deadly simple Last.FM API Wrapper for Dart. // +// Copyright (c) 2020 Nebulino // +// // + part of lastfm_objects; -/// This is a object that helps scrobbling multiple tracks. +/// This is a object that contains information about the response. @JsonSerializable(includeIfNull: false) class Attr { + /// The page of the response. @JsonKey(name: 'page', fromJson: LastFMValueNormalizer.NumberToInt) int? page; + /// The number of items per page. @JsonKey(name: 'perPage', fromJson: LastFMValueNormalizer.NumberToInt) int? perPage; + /// The user that requested the response. String? user; + /// The total number of items. @JsonKey(name: 'total', fromJson: LastFMValueNormalizer.NumberToInt) int? total; + /// The number of pages. @JsonKey(name: 'totalPages', fromJson: LastFMValueNormalizer.NumberToInt) int? totalPages; diff --git a/lib/src/lastfm/responses/library.dart b/lib/src/lastfm/responses/library.dart index 37ea66e..9b1171f 100644 --- a/lib/src/lastfm/responses/library.dart +++ b/lib/src/lastfm/responses/library.dart @@ -1,10 +1,13 @@ part of lastfm_objects; +/// This object represents a response about an artist library from a search. @JsonSerializable(includeIfNull: false) class LibraryGetArtistsResponse { + /// A list of artists. @JsonKey(name: 'artist') List? artist; + /// The attributes related to the response. @JsonKey(name: '@attr') Attr? attr; diff --git a/pubspec.yaml b/pubspec.yaml index e326e31..8d8ec3e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,15 +8,15 @@ environment: sdk: ">=2.12.0-0 <3.0.0" dependencies: - meta: ^1.3.0 - json_annotation: ^4.0.1 - convert: ^3.0.0 - dio: ^4.0.0 - crypto: ^3.0.1 - xml: ^5.1.1 + meta: ^1.8.0 + json_annotation: ^4.6.0 + convert: ^3.0.2 + dio: ^4.0.6 + crypto: ^3.0.2 + xml: ^6.1.0 dev_dependencies: - pedantic: ^1.11.0 - test: ^1.17.5 - json_serializable: ^4.1.3 - build_runner: ^2.0.4 + lints: ^2.0.0 + test: ^1.21.5 + json_serializable: ^6.3.1 + build_runner: ^2.2.0 From 3f3ca04a0c76c12da6dba24df07ead72504d9023 Mon Sep 17 00:00:00 2001 From: Space Traveler Date: Sun, 11 Sep 2022 01:56:16 +0200 Subject: [PATCH 4/4] Updating some docs. --- lib/src/extensions/user_extension.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/extensions/user_extension.dart b/lib/src/extensions/user_extension.dart index 02a3de3..c4792ff 100644 --- a/lib/src/extensions/user_extension.dart +++ b/lib/src/extensions/user_extension.dart @@ -140,7 +140,7 @@ extension UserExtension on User { ); } - /// [UserMethods.] + /// [UserMethods.getWeeklyArtistChart] Future?> getWeeklyArtistChart({ DateTime? fromDate, DateTime? toDate, @@ -152,14 +152,14 @@ extension UserExtension on User { ); } - /// [UserMethods.] + /// [UserMethods.getWeeklyChartList] Future?> getWeeklyChartList() async { return await _userMethods.getWeeklyChartList( user: name, ); } - /// [UserMethods.] + /// [UserMethods.getWeeklyTrackChart] Future?> getWeeklyTrackChart({ DateTime? fromDate, DateTime? toDate,