rinukkusu / spotify-dart

A dart library for interfacing with the Spotify API.
BSD 3-Clause "New" or "Revised" License
207 stars 93 forks source link

User's Following Artists api not working #83

Closed stefanoromanello closed 3 years ago

stefanoromanello commented 4 years ago

The method .me.following(FollowingType.artist) is not working because when _parseBundledPage tries to create a new Page it cant calculate isLast because the APIs are not returning the offset.

stefanoromanello commented 4 years ago

This is how I solved this while they release a new fixed version, edit the following files of spotify-dart:

_models.g.dart

Paging<T> _$PagingFromJson<T>(Map<String, dynamic> json) {
  return Paging<T>()
    ..href = json['href'] as String
    ..itemsNative = itemsNativeFromJson(json['items'] as List)
    ..limit = json['limit'] as int
    ..next = json['next'] as String
    ..offset = json['offset'] as int
    ..previous = json['previous'] as String
    ..cursorsAfter = json['cursors'] != null ? json['cursors']['after'] as String : null
    ..total = json['total'] as int;
}

paging.dart

@JsonSerializable(createToJson: false)
class Paging<T> extends Object {
  Paging();

  factory Paging.fromJson(Map<String, dynamic> json) => _$PagingFromJson(json);

  /// A link to the Web API endpoint returning the full result of the request.
  String href;

  /// The requested data
  ///
  /// Note this is the raw JSON value. Use a [Page]'s [Page.items] to get the
  /// requested data as a deserialized list.
  @JsonKey(
      name: 'items', fromJson: itemsNativeFromJson, toJson: itemsNativeToJson)
  Iterable<dynamic> itemsNative;

  /// The maximum number of items in the response (as set in the query or by
  /// default).
  int limit;

  /// URL to the next page of items. ([null] if none)
  String next;

  /// The offset of the items returned (as set in the query or by default).
  int offset;

  /// URL to the previous page of items. (null if none)
  String previous;

  /// The total number of items available to return.
  int total;

  //Cursor used for followers endpoint
  String cursorsAfter;
}

endpoint_paging.dart

class Page<T> {
  final Paging<T> _paging;
  Iterable<T> _items;
  Object _container;

  Page(this._paging, ParserFunction<T> pageItemParser, [Object pageContainer]) {
    _items = _paging.itemsNative.map(pageItemParser);
    _container = pageContainer;
  }

  /// The offset-based paging object is a container for a set of objects. It
  /// contains a key called items (whose value is an array of the requested
  /// objects) along with other keys like previous, next and limit that can be
  /// useful in future calls.
  Paging<T> get metadata => _paging;

  /// The requested data
  Iterable<T> get items => _items;

  /// The object containing this page, if applicable
  Object get container => _container;

  bool get isLast {
    if (_paging.offset != null)
      return _paging.offset + _paging.limit >= _paging.total;
    else
      return _paging.next==null;
  }

  int get nextOffset {
    if (_paging.offset != null)
      return _paging.offset + _paging.limit;
    else
      return null;  
  }

  int get totalItems => _paging.total; 

  String get cursorsAfter => _paging.cursorsAfter;

}

And to obtain the follower here a simple method to use the API:

void getUserFollowing() async {
    BundledPages bundeled = await _spotifyApi.me.following(FollowingType.artist);

    int limit = 5;
    bool readData = true;
    List<Page<Object>> pages;
    Page<dynamic> currentPage;

    while (readData) {
      currentPage != null
          ? pages = await bundeled.getPageAfter(limit, currentPage.cursorsAfter)
          : pages = await bundeled.first(limit);
      currentPage = pages.first;
      readData = !currentPage.isLast;

      List<Artist> artists = currentPage.items.toList().cast<Artist>();
      for (var artist in artists) {
        print(artist.name);
      }
    }
  }
hayribakici commented 4 years ago

This is a good idea, however I suggest, that the cursorAfter attribute shouldn't be in the Page-object, rather in its own CursorPage-object. This would reflect more the spotify object specification. @rinukkusu @chances , what do you think about having a new object CursorPage that extends the Page-object?

rinukkusu commented 3 years ago

@hayribakici sounds cleaner to me, yes!