Twitch API tweaks & additions (#41)

- Added request for streams under a desired category
- Tweaked models
This commit is contained in:
tommyxchow 2021-11-26 01:14:47 -05:00
parent 41b5fefa32
commit 57c5d1f4a9
8 changed files with 80 additions and 19 deletions

View file

@ -97,6 +97,7 @@ class Twitch {
/// Returns the user's info given their token (headers)
static Future<UserTwitch?> getUserInfo({required Map<String, String>? headers}) async {
final response = await http.get(Uri.parse('https://api.twitch.tv/helix/users'), headers: headers);
if (response.statusCode == 200) {
final userData = jsonDecode(response.body)['data'] as List;
@ -133,7 +134,11 @@ class Twitch {
/// Returns the validity of the given token
static Future<bool> validateToken({required String token}) async {
debugPrint('Validating token...');
final response = await http.get(Uri.parse('https://id.twitch.tv/oauth2/validate'), headers: {'Authorization': 'Bearer $token'});
final response = await http.get(
Uri.parse('https://id.twitch.tv/oauth2/validate'),
headers: {'Authorization': 'Bearer $token'},
);
if (response.statusCode == 200) {
debugPrint('Token validated!');
return true;
@ -144,7 +149,7 @@ class Twitch {
}
/// Returns a map containing top 20 streams and a cursor for further requests.
static Future<Map<String, dynamic>?> getTopStreams({required Map<String, String>? headers, required String? cursor}) async {
static Future<StreamsTwitch?> getTopStreams({required Map<String, String>? headers, required String? cursor}) async {
final Uri uri;
if (cursor == null) {
@ -157,16 +162,19 @@ class Twitch {
if (response.statusCode == 200) {
final decoded = jsonDecode(response.body);
final data = decoded['data'] as List;
return {'streams': data.map((stream) => StreamTwitch.fromJson(stream)).toList(), 'cursor': decoded['pagination']['cursor']};
return StreamsTwitch.fromJson(decoded);
} else {
debugPrint('Failed to update top streams');
}
}
/// Returns a map with the given user's top 20 followed streams and a cursor for further requests.
static Future<Map<String, dynamic>?> getFollowedStreams({required String id, required Map<String, String>? headers, required String? cursor}) async {
static Future<StreamsTwitch?> getFollowedStreams({
required String id,
required Map<String, String>? headers,
required String? cursor,
}) async {
final Uri uri;
if (cursor == null) {
@ -179,14 +187,38 @@ class Twitch {
if (response.statusCode == 200) {
final decoded = jsonDecode(response.body);
final data = decoded['data'] as List;
return {'streams': data.map((stream) => StreamTwitch.fromJson(stream)).toList(), 'cursor': decoded['pagination']['cursor']};
return StreamsTwitch.fromJson(decoded);
} else {
debugPrint('Failed to update followed streams');
}
}
/// Returns the list of streams under the given game/category ID.
static Future<StreamsTwitch?> getStreamsUnderGame({
required String gameId,
required Map<String, String>? headers,
required String? cursor,
}) async {
final Uri uri;
if (cursor == null) {
uri = Uri.parse('https://api.twitch.tv/helix/streams?game_id=$gameId');
} else {
uri = Uri.parse('https://api.twitch.tv/helix/streams?game_id=$gameId&after=$cursor');
}
final response = await http.get(uri, headers: headers);
if (response.statusCode == 200) {
final decoded = jsonDecode(response.body);
return StreamsTwitch.fromJson(decoded);
} else {
debugPrint('Failed to update game streams');
}
}
/// Returns the stream info given the user login.
static Future<StreamTwitch?> getStream({required String userLogin, required Map<String, String>? headers}) async {
final uri = Uri.parse('https://api.twitch.tv/helix/streams?user_login=$userLogin');
@ -263,9 +295,8 @@ class Twitch {
if (response.statusCode == 200) {
final decoded = jsonDecode(response.body);
final data = decoded['data'] as List;
return CategoriesTwitch(data.map((category) => CategoryTwitch.fromJson(category)).toList(), decoded['pagination']['cursor']);
return CategoriesTwitch.fromJson(decoded);
} else {
debugPrint('Failed to update top games');
}

View file

@ -17,12 +17,15 @@ class CategoryTwitch {
factory CategoryTwitch.fromJson(Map<String, dynamic> json) => _$CategoryTwitchFromJson(json);
}
@JsonSerializable(createToJson: false, fieldRename: FieldRename.snake)
class CategoriesTwitch {
final List<CategoryTwitch> data;
final String cursor;
final Map<String, String> pagination;
const CategoriesTwitch(
this.data,
this.cursor,
this.pagination,
);
factory CategoriesTwitch.fromJson(Map<String, dynamic> json) => _$CategoriesTwitchFromJson(json);
}

View file

@ -12,3 +12,11 @@ CategoryTwitch _$CategoryTwitchFromJson(Map<String, dynamic> json) =>
json['id'] as String,
json['name'] as String,
);
CategoriesTwitch _$CategoriesTwitchFromJson(Map<String, dynamic> json) =>
CategoriesTwitch(
(json['data'] as List<dynamic>)
.map((e) => CategoryTwitch.fromJson(e as Map<String, dynamic>))
.toList(),
Map<String, String>.from(json['pagination'] as Map),
);

View file

@ -39,3 +39,16 @@ class StreamTwitch {
factory StreamTwitch.fromJson(Map<String, dynamic> json) => _$StreamTwitchFromJson(json);
}
@JsonSerializable(createToJson: false, fieldRename: FieldRename.snake)
class StreamsTwitch {
final List<StreamTwitch> data;
final Map<String, String> pagination;
const StreamsTwitch(
this.data,
this.pagination,
);
factory StreamsTwitch.fromJson(Map<String, dynamic> json) => _$StreamsTwitchFromJson(json);
}

View file

@ -22,3 +22,11 @@ StreamTwitch _$StreamTwitchFromJson(Map<String, dynamic> json) => StreamTwitch(
(json['tag_ids'] as List<dynamic>?)?.map((e) => e as String).toList(),
json['is_mature'] as bool,
);
StreamsTwitch _$StreamsTwitchFromJson(Map<String, dynamic> json) =>
StreamsTwitch(
(json['data'] as List<dynamic>)
.map((e) => StreamTwitch.fromJson(e as Map<String, dynamic>))
.toList(),
Map<String, String>.from(json['pagination'] as Map),
);

View file

@ -1,9 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:frosty/models/channel.dart';
import 'package:frosty/screens/channel/video_chat.dart';
import 'package:frosty/screens/search/search_store.dart';
import 'package:mobx/mobx.dart';
class Search extends StatefulWidget {
final SearchStore searchStore;

View file

@ -38,11 +38,11 @@ abstract class _FollowedStreamsStoreBase with Store {
if (newFollowedStreams != null) {
if (_followedStreamsCurrentCursor == null) {
_followedStreams = ObservableList.of(newFollowedStreams['streams']);
_followedStreams = ObservableList.of(newFollowedStreams.data);
} else {
_followedStreams.addAll(newFollowedStreams['streams']);
_followedStreams.addAll(newFollowedStreams.data);
}
_followedStreamsCurrentCursor = newFollowedStreams['cursor'];
_followedStreamsCurrentCursor = newFollowedStreams.pagination['cursor'];
}
_isLoading = false;

View file

@ -38,11 +38,11 @@ abstract class _TopStreamsStoreBase with Store {
if (newTopStreams != null) {
if (_topStreamsCurrentCursor == null) {
_topStreams = ObservableList.of(newTopStreams['streams']);
_topStreams = ObservableList.of(newTopStreams.data);
} else {
_topStreams.addAll(newTopStreams['streams']);
_topStreams.addAll(newTopStreams.data);
}
_topStreamsCurrentCursor = newTopStreams['cursor'];
_topStreamsCurrentCursor = newTopStreams.pagination['cursor'];
}
_isLoading = false;