Skip to content

Commit

Permalink
Merge branch 'features/subscriptions' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Guillaume Roux committed Mar 26, 2021
2 parents 1ed41c9 + d85fafb commit 4126dc7
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 4 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

A wrapper in pure Dart to connect to Twitch.tv using OAuth implicit authentication.

All the endpoints are implemented as defined in the [Twitch API Reference](https://dev.twitch.tv/docs/api/reference)

## Getting started

**NOTE: This package is in its early stage, please be patient until more methods are implemented or do not hesitate to open a merge request if you added support for an endpoint.**
**NOTE: This package is in its early stage, please be patient until more methods are implemented or do not hesitate to open a merge request if you added support for an endpoint. Currently I do not have a roadmap of the endpoint I am going to add in priority so do not hesitate to make suggestions depending of your needs.**

To use this package you will need to register an application on the [Twitch developer console](https://dev.twitch.tv/console/apps) to get a **client ID**.

Expand Down Expand Up @@ -132,7 +134,7 @@ Now you are ready to use the methods implemented in [Supported Features](#suppor

### Subscriptions

* [ ] Get Broadcaster Subscriptions
* [x] Get Broadcaster Subscriptions

### Tags

Expand Down
10 changes: 9 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:twitch_api/twitch_api.dart';

const clientId = "n9dgfacl10ivdy8vlr493qjavykdkn";
const clientId = "YOUR CLIENT ID";
const redirectUri = "http://localhost:8080/static.html";

void main() {
Expand Down Expand Up @@ -73,6 +73,7 @@ class _MyHomePageState extends State<MyHomePage> {
TwitchApiScope.analyticsReadExtensions,
TwitchApiScope.analyticsReadGames,
TwitchApiScope.userReadEmail,
TwitchApiScope.channelReadSubscriptions,
]).then((value) => setState(() {}));
});
}
Expand Down Expand Up @@ -210,6 +211,13 @@ class _MyHomePageState extends State<MyHomePage> {
),
child: Text('Search "fort" Category'),
),
ElevatedButton(
onPressed: () => _twitchClient.getBroadcasterSubscriptions().then(
(value) => _displayDataAlert(
value.data.first.userName, value.data.first.tier),
),
child: Text('Get Broadcaster Subscriptions'),
),
],
),
);
Expand Down
39 changes: 38 additions & 1 deletion lib/src/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:async';

import 'package:dio/dio.dart';
import 'package:twitch_api/src/exceptions/twitch_api_exception.dart';
import 'package:twitch_api/src/models/twitch_broadcaster_subscription.dart';
import 'package:twitch_api/src/models/twitch_channel_info.dart';
import 'package:twitch_api/src/models/twitch_game.dart';
import 'package:twitch_api/src/models/twitch_game_analytic.dart';
Expand Down Expand Up @@ -290,7 +291,7 @@ class TwitchClient {
/// identified by optional user IDs and/or login name. If neither a user ID
/// nor a login name is specified, the user is looked up by Bearer token.
///
/// Required scrope: `TwitchApiScope.userReadEmail`
/// Required scrope: [TwitchApiScope.userReadEmail]
///
/// `ids`: User ID. Multiple user IDs can be specified. Limit: 100.
///
Expand Down Expand Up @@ -518,4 +519,40 @@ class TwitchClient {
final data = await getCall(['streams'], queryParameters: queryParameters);
return TwitchResponse.streamsInfo(data);
}

/// Get all of a broadcaster’s subscriptions.
///
/// Required scope: [TwitchApiScope.channelReadSubscriptions]
///
/// [userIds]: Filters results to only include potential subscriptions made by
/// the provided user IDs. Accepts up to 100 values.
///
/// [after]: tells the server where to start fetching the next set of results
/// in a multi-page response. This applies only to queries without [userIds].
/// If a [userIds] is specified, it supersedes any cursor/offset combinations.
/// The cursor value specified here is from the `pagination` response field of
/// a prior query.
///
/// [first]: Maximum number of objects to return. Maximum: 100. Default: 20.
Future<TwitchResponse<TwitchBroadcasterSubscription>>
getBroadcasterSubscriptions({
List<String> userIds = const [],
String after,
int first = 20,
}) async {
assert(first > 0 && first < 101);
assert(userIds.length < 101);

final Map<String, dynamic> queryParameters = {
'broadcaster_id': accessToken.userId,
'first': first.toString(),
};
if (userIds.isNotEmpty) queryParameters['user_id'] = userIds.join(',');
if (after != null) queryParameters['after'] = after;

final data =
await getCall(['subscriptions'], queryParameters: queryParameters);
return TwitchResponse<
TwitchBroadcasterSubscription>.broadcasterSubscriptions(data);
}
}
2 changes: 2 additions & 0 deletions lib/src/models/twitch_api_scopes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ enum TwitchApiScope {
analyticsReadGames,
bitsRead,
channelEditCommercial,
channelReadSubscriptions,
userReadEmail,
}

Expand All @@ -12,6 +13,7 @@ class TwitchApiScopes {
TwitchApiScope.analyticsReadGames: 'analytics:read:games',
TwitchApiScope.bitsRead: 'bits:read',
TwitchApiScope.channelEditCommercial: 'channel:edit:commercial',
TwitchApiScope.channelReadSubscriptions: 'channel:read:subscriptions',
TwitchApiScope.userReadEmail: 'user:read:email',
};

Expand Down
71 changes: 71 additions & 0 deletions lib/src/models/twitch_broadcaster_subscription.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
class TwitchBroadcasterSubscription {
/// User ID of the broadcaster.
final String broadcasterId;

/// Login of the broadcaster.
final String broadcasterLogin;

/// Display name of the broadcaster.
final String broadcasterName;

/// If the subscription was gifted, this is the user ID of the gifter. Empty
/// string otherwise.
final String gifterId;

/// If the subscription was gifted, this is the login of the gifter. Empty
/// string otherwise.
final String gifterLogin;

/// If the subscription was gifted, this is the display name of the gifter.
/// Empty string otherwise.
final String gifterName;

/// `true` if the subscription is a gift subscription.
final bool isGift;

/// Name of the subscription.
final String planName;

/// Type of subscription (Tier 1, Tier 2, Tier 3). 1000 = Tier 1, 2000 = Tier
/// 2, 3000 = Tier 3 subscriptions.
final String tier;

/// ID of the subscribed user.
final String userId;

/// Display name of the subscribed user.
final String userName;

/// Login of the subscribed user.
final String userLogin;

TwitchBroadcasterSubscription({
this.broadcasterId,
this.broadcasterLogin,
this.broadcasterName,
this.gifterId,
this.gifterLogin,
this.gifterName,
this.isGift,
this.planName,
this.tier,
this.userId,
this.userLogin,
this.userName,
});

factory TwitchBroadcasterSubscription.fromJson(Map<String, dynamic> json) =>
TwitchBroadcasterSubscription(
broadcasterId: json['broadcaster_id'],
broadcasterLogin: json['broadcaster_login'],
broadcasterName: json['broadcaster_name'],
gifterId: json['gifter_id'],
gifterLogin: json['gifter_login'],
gifterName: json['gifter_name'],
isGift: json['is_gift'],
planName: json['plan_name'],
tier: json['tier'],
userId: json['user_id'],
userName: json['user_name'],
);
}
10 changes: 10 additions & 0 deletions lib/src/models/twitch_response.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:twitch_api/src/models/twitch_broadcaster_subscription.dart';
import 'package:twitch_api/src/models/twitch_extension_analytic.dart';
import 'package:twitch_api/src/models/twitch_game_analytic.dart';
import 'package:twitch_api/src/models/twitch_search_category.dart';
Expand Down Expand Up @@ -68,4 +69,13 @@ class TwitchResponse<T> {
.toList(),
pagination: json['pagination'],
);

/// Constructor for request containing [TwitchBroadcasterSubscription].
factory TwitchResponse.broadcasterSubscriptions(Map<String, dynamic> json) =>
TwitchResponse(
data: (json['data'] as Iterable)
.map<T>((e) => TwitchBroadcasterSubscription.fromJson(e) as T)
.toList(),
pagination: json['pagination'],
);
}
2 changes: 2 additions & 0 deletions lib/twitch_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ export 'src/models/twitch_game.dart';
export 'src/models/twitch_stream_info.dart';
export 'src/models/twitch_search_channel.dart';
export 'src/models/twitch_response.dart';
export 'src/models/twitch_broadcaster_subscription.dart';
export 'src/models/twitch_search_category.dart';

0 comments on commit 4126dc7

Please sign in to comment.