Initial commit

This commit is contained in:
Rapougnac 2024-05-07 00:14:45 +02:00
commit 5010af7384
Signed by: Lexedia
GPG Key ID: 89F8229836528B69
20 changed files with 3542 additions and 0 deletions

3
CHANGELOG.md Normal file
View File

@ -0,0 +1,3 @@
## 1.0.0
- Initial version.

1
README.md Normal file
View File

@ -0,0 +1 @@
# Overfast

30
analysis_options.yaml Normal file
View File

@ -0,0 +1,30 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.
include: package:lints/recommended.yaml
# Uncomment the following section to specify additional rules.
# linter:
# rules:
# - camel_case_types
# analyzer:
# exclude:
# - path/to/excluded/files/**
# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints
# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options

25
bin/main.dart Normal file
View File

@ -0,0 +1,25 @@
import 'dart:convert';
import 'package:overfast_api/client.dart';
import 'package:overfast_api/utils/types.dart';
void main(List<String> args) async {
final client = Overfast();
// final me = client.players.player('Rapougnac-2980');
// final stats = await me.statsSummary();
// print(stats.heroes['doomfist']!.gamesWon);
// final doom = await client.heroes.hero(Hero.doomfist,locale: Locale.frFr);
// print(doom.description);
// final heroes = await client.heroes.heroes(locale: Locale.frFr);
// print(jsonEncode(heroes));
final hero = client.heroes.hero(HeroKey.junkerqueen, locale: Locale.frFr);
print(hero);
}

40
lib/client.dart Normal file
View File

@ -0,0 +1,40 @@
import 'package:http/http.dart' as http;
import 'package:overfast_api/heroes/heroes.dart';
import 'package:overfast_api/players/players.dart';
import './utils/utils.dart' as utils;
import 'maps/maps.dart';
class Overfast {
final Uri baseUri;
late final Future<T> Function<T>(
String, [
Map<String, dynamic>,
]) get;
late final Future<List<T>> Function<T>(
String, [
Map<String, dynamic>,
]) getList;
final client = http.Client();
late final Maps maps;
late final Players players;
late final Heroes heroes;
Overfast([Uri? baseUri])
: baseUri = baseUri ?? Uri.https('overfast-api.tekrop.fr') {
get = utils.get(client, this.baseUri);
getList = utils.getList(client, this.baseUri);
maps = Maps(this);
players = Players(this);
heroes = Heroes(this);
}
void close() {
client.close();
}
}

34
lib/heroes/heroes.dart Normal file
View File

@ -0,0 +1,34 @@
import 'package:overfast_api/client.dart';
import 'package:overfast_api/heroes/heroes_data.dart' as data;
import 'package:overfast_api/utils/types.dart';
class Heroes {
final Overfast _client;
const Heroes(this._client);
Future<List<data.Hero>> heroes({Role? role, Locale? locale}) =>
_client.getList<data.Hero>(
'/heroes',
{
if (role != null) 'role': role.toString(),
if (locale != null) 'locale': locale.toString(),
},
);
Future<data.HeroDetails> hero(HeroKey hero, {Locale? locale}) =>
_client.get<data.HeroDetails>(
'/heroes/${hero.heroName}',
{
if (locale != null) 'locale': locale.toString(),
},
);
Future<List<data.Roles>> roles({Locale? locale}) =>
_client.getList<data.Roles>(
'/roles',
{
if (locale != null) 'locale': locale.toString(),
},
);
}

284
lib/heroes/heroes_data.dart Normal file
View File

@ -0,0 +1,284 @@
import 'package:overfast_api/utils/types.dart';
class Hero {
final String name;
final HeroKey key;
final String? portrait;
final Role role;
const Hero({
required this.name,
required this.key,
this.portrait,
required this.role,
});
factory Hero.fromJson(Map<String, dynamic> json) {
return Hero(
name: json['name'],
key: HeroKey.fromString(json['key']),
portrait: json['portrait'],
role: Role.fromString(json['role']),
);
}
Map<String, dynamic> toJson() {
return {
'name': name,
'key': key.name,
'portrait': portrait,
'role': role.toString(),
};
}
}
class HeroDetails extends Hero {
final String location;
final List<Ability> abilities;
final Map? hitpoints;
final Story story;
final String description;
final int age;
final String? birthday;
const HeroDetails({
required super.name,
required super.role,
super.portrait,
required this.description,
required this.story,
required this.location,
required this.abilities,
this.hitpoints,
// Stub
super.key = HeroKey.eemptyy,
required this.age,
required this.birthday,
});
factory HeroDetails.fromJson(Map<String, dynamic> json) {
return HeroDetails(
name: json['name'],
description: (json['description']),
portrait: json['portrait'],
role: Role.fromString(json['role']),
location: json['location'],
abilities:
(json['abilities'] as List).map((e) => Ability.fromJson(e)).toList(),
hitpoints: json['hitpoints'],
story: Story.fromJson(json['story']),
age: json['age'],
birthday: json['birthday'],
);
}
@override
Map<String, dynamic> toJson() {
return {
'name': name,
'description': description,
'portrait': portrait,
'role': role.toString(),
'location': location,
'abilities': abilities.map((e) => e.toJson()).toList(),
'hitpoints': hitpoints,
'story': story.toJson(),
'age': age,
'birthday': birthday,
};
}
}
class Ability {
final String name;
final String description;
final String icon;
final Video video;
const Ability({
required this.name,
required this.description,
required this.icon,
required this.video,
});
factory Ability.fromJson(Map<String, dynamic> json) {
return Ability(
name: json['name'],
description: json['description'],
icon: json['icon'],
video: Video.fromJson(json['video']),
);
}
Map<String, dynamic> toJson() {
return {
'name': name,
'description': description,
'icon': icon,
'video': video.toJson(),
};
}
}
class Video {
final String thumbnail;
final Link link;
const Video({
required this.thumbnail,
required this.link,
});
factory Video.fromJson(Map<String, dynamic> json) {
return Video(
thumbnail: json['thumbnail'],
link: Link.fromJson(json['link']),
);
}
Map<String, dynamic> toJson() {
return {
'thumbnail': thumbnail,
'link': link.toJson(),
};
}
}
class Link {
final String mp4;
final String webm;
const Link({
required this.mp4,
required this.webm,
});
factory Link.fromJson(Map<String, dynamic> json) {
return Link(
mp4: json['mp4'],
webm: json['webm'],
);
}
Map<String, dynamic> toJson() {
return {
'mp4': mp4,
'webm': webm,
};
}
}
class Story {
final String summary;
final Media? media;
final List<Chapter> chapters;
const Story({
required this.summary,
required this.media,
required this.chapters,
});
factory Story.fromJson(Map<String, dynamic> json) {
return Story(
summary: json['summary'],
media: json['media'] != null ? Media.fromJson(json['media']) : null,
chapters:
(json['chapters'] as List).map((e) => Chapter.fromJson(e)).toList(),
);
}
Map<String, dynamic> toJson() {
return {
'summary': summary,
if (media != null) 'media': media!.toJson(),
'chapters': chapters.map((e) => e.toJson()).toList(),
};
}
}
class Media {
final String type;
final String link;
const Media({
required this.type,
required this.link,
});
factory Media.fromJson(Map<String, dynamic> json) {
return Media(
type: json['type'],
link: json['link'],
);
}
Map<String, dynamic> toJson() {
return {
'type': type,
'link': link,
};
}
}
class Chapter {
final String title;
final String content;
final String picture;
const Chapter({
required this.title,
required this.content,
required this.picture,
});
factory Chapter.fromJson(Map<String, dynamic> json) {
return Chapter(
title: json['title'],
content: json['content'],
picture: json['picture'],
);
}
Map<String, dynamic> toJson() {
return {
'title': title,
'content': content,
'picture': picture,
};
}
}
class Roles {
final Role key;
final String name;
final String icon;
final String description;
const Roles({
required this.key,
required this.name,
required this.icon,
required this.description,
});
factory Roles.fromJson(Map<String, dynamic> json) {
return Roles(
key: Role.fromString(json['key']),
name: json['name'],
icon: json['icon'],
description: json['description'],
);
}
Map<String, dynamic> toJson() {
return {
'key': key.toString(),
'name': name,
'icon': icon,
'description': description,
};
}
}

92
lib/maps/maps.dart Normal file
View File

@ -0,0 +1,92 @@
import 'dart:convert';
import 'package:overfast_api/client.dart';
import 'package:overfast_api/utils/utils.dart';
enum Gamemode {
assault,
captureTheFlag,
control,
deathmatch,
elimination,
escort,
hybrid,
push,
teamDeathmatch,
flashpoint,
clash;
@override
String toString() => toKebabCase(name);
static Gamemode fromString(String value) {
return Gamemode.values.firstWhere((e) => e.toString() == value);
}
}
final class GameMap {
final String name;
final List<Gamemode> gamemodes;
final String screenshot;
final String location;
final String? countryCode;
const GameMap({
required this.name,
required this.gamemodes,
required this.screenshot,
required this.location,
this.countryCode,
});
// Stub empty constructor
GameMap.empty() : this(name: '', gamemodes: [], screenshot: '', location: '');
factory GameMap.fromJson(Map<String, dynamic> json) {
return GameMap(
name: json['name'],
gamemodes: (json['gamemodes'] as List)
.map((e) => Gamemode.fromString(e))
.cast<Gamemode>()
.toList(),
screenshot: json['screenshot'],
location: json['location'],
countryCode: json['countryCode'],
);
}
Map<String, dynamic> toJson() {
return {
'name': name,
'gamemode': gamemodes.map((e) => e.toString()).toList(),
'screenshot': screenshot,
'location': location,
'countryCode': countryCode,
};
}
}
final class Maps {
final Overfast _client;
Maps(this._client);
Future<List<GameMap>> maps({Gamemode? gameMode}) => _client.getList<GameMap>(
'/maps',
gameMode != null ? {'gamemode': gameMode.toString()} : {},
);
Future<List<Gamemode>> gamemodes() async {
// Special case, manual request
final response = await _client.client.get(
_client.baseUri.replace(path: '/maps/gamemodes'),
);
throwIfNecessary(response.statusCode, response.body);
return (json.decode(response.body) as List)
.map((e) => Gamemode.fromString(e))
.cast<Gamemode>()
.toList();
}
}

1
lib/overfast_api.dart Normal file
View File

@ -0,0 +1 @@
export 'client.dart';

1928
lib/players/data_types.dart Normal file

File diff suppressed because it is too large Load Diff

314
lib/players/player.dart Normal file
View File

@ -0,0 +1,314 @@
import 'package:overfast_api/client.dart';
import 'package:overfast_api/utils/types.dart';
class PlayerSummary {
final String username;
final String? avatar;
final String? namecard;
final String? title;
final PlayerEndorsement endorsement;
final PlatformCompetitiveRank? competitiveRank;
const PlayerSummary({
required this.username,
this.avatar,
this.namecard,
this.title,
required this.endorsement,
required this.competitiveRank,
});
factory PlayerSummary.fromJson(Map<String, dynamic> json) {
return PlayerSummary(
username: json['username'],
avatar: json['avatar'],
namecard: json['namecard'],
title: json['title'],
endorsement: PlayerEndorsement.fromJson(json['endorsement']),
competitiveRank: PlatformCompetitiveRank.fromJson(json['competitive']),
);
}
Map<String, dynamic> toJson() {
return {
'username': username,
'avatar': avatar,
'namecard': namecard,
'title': title,
'endorsement': endorsement.toJson(),
'competitiveRank': competitiveRank?.toJson(),
};
}
}
class PlayerEndorsement {
final int level;
final String frame;
const PlayerEndorsement({
required this.level,
required this.frame,
});
factory PlayerEndorsement.fromJson(Map<String, dynamic> json) {
return PlayerEndorsement(
level: json['level'],
frame: json['frame'],
);
}
Map<String, dynamic> toJson() {
return {
'level': level,
'frame': frame,
};
}
}
class PlatformCompetitiveRank {
final CompetitiveRank? pc;
final CompetitiveRank? console;
const PlatformCompetitiveRank({
this.pc,
this.console,
});
factory PlatformCompetitiveRank.fromJson(Map<String, dynamic> json) {
return PlatformCompetitiveRank(
pc: json['pc'] != null ? CompetitiveRank.fromJson(json['pc']) : null,
console: json['console'] != null
? CompetitiveRank.fromJson(json['console'])
: null,
);
}
Map<String, dynamic> toJson() {
return {
'pc': pc?.toJson(),
'console': console?.toJson(),
};
}
}
class CompetitiveRank {
final int season;
final RoleDetails? tank;
final RoleDetails? damage;
final RoleDetails? support;
final RoleDetails? openQueue;
const CompetitiveRank({
required this.season,
required this.tank,
required this.damage,
required this.support,
required this.openQueue,
});
factory CompetitiveRank.fromJson(Map<String, dynamic> json) {
return CompetitiveRank(
season: json['season'],
tank: json['tank'] == null ? null : RoleDetails.fromJson(json['tank']),
damage:
json['damage'] == null ? null : RoleDetails.fromJson(json['damage']),
support: json['support'] == null
? null
: RoleDetails.fromJson(json['support']),
openQueue:
json['open'] == null ? null : RoleDetails.fromJson(json['open']),
);
}
Map<String, dynamic> toJson() {
return {
'season': season,
'tank': tank?.toJson(),
'damage': damage?.toJson(),
'support': support?.toJson(),
};
}
}
class RoleDetails {
final String division;
final int tier;
final String roleIcon;
final String rankIcon;
final String tierIcon;
const RoleDetails({
required this.division,
required this.tier,
required this.roleIcon,
required this.rankIcon,
required this.tierIcon,
});
factory RoleDetails.fromJson(Map<String, dynamic> json) {
return RoleDetails(
division: json['division'],
tier: json['tier'],
roleIcon: json['role_icon'],
rankIcon: json['rank_icon'],
tierIcon: json['tier_icon'],
);
}
Map<String, dynamic> toJson() {
return {
'division': division,
'tier': tier,
'roleIcon': roleIcon,
'rankIcon': rankIcon,
'tierIcon': tierIcon,
};
}
}
class StatsSummary {
final StatsRecap general;
final Map<String, StatsRecap> heroes;
final Map<String, StatsRecap> roles;
const StatsSummary({
required this.general,
required this.heroes,
required this.roles,
});
factory StatsSummary.fromJson(Map<String, dynamic> json) {
return StatsSummary(
general: StatsRecap.fromJson(json['general']),
heroes: Map.from(json['heroes']).map(
(key, value) => MapEntry(key, StatsRecap.fromJson(value)),
),
roles: Map.from(json['roles']).map(
(key, value) => MapEntry(key, StatsRecap.fromJson(value)),
),
);
}
Map<String, dynamic> toJson() {
return {
'general': general.toJson(),
'heroes': heroes.map((key, value) => MapEntry(key, value.toJson())),
'roles': roles.map((key, value) => MapEntry(key, value.toJson())),
};
}
}
class StatsRecap {
final int gamesPlayed;
final int gamesWon;
final int gamesLost;
final Duration timePlayed;
final double winrate;
final double kda;
final SubStatsRecap total;
final SubStatsRecap average;
const StatsRecap({
required this.gamesPlayed,
required this.gamesWon,
required this.gamesLost,
required this.timePlayed,
required this.winrate,
required this.kda,
required this.total,
required this.average,
});
factory StatsRecap.fromJson(Map<String, dynamic> json) {
return StatsRecap(
gamesPlayed: json['games_played'],
gamesWon: json['games_won'],
gamesLost: json['games_lost'],
timePlayed: Duration(seconds: json['time_played']),
winrate: json['winrate'],
kda: json['kda'],
total: SubStatsRecap.fromJson(json['total']),
average: SubStatsRecap.fromJson(json['average']),
);
}
Map<String, dynamic> toJson() {
return {
'games_played': gamesPlayed,
'games_won': gamesWon,
'games_lost': gamesLost,
'time_played': timePlayed.inSeconds,
'winrate': winrate,
'kda': kda,
'total': total.toJson(),
'average': average.toJson(),
};
}
}
class SubStatsRecap {
final num eliminations;
final num assists;
final num deaths;
final num damage;
final num healing;
const SubStatsRecap({
required this.eliminations,
required this.assists,
required this.deaths,
required this.damage,
required this.healing,
});
factory SubStatsRecap.fromJson(Map<String, dynamic> json) {
return SubStatsRecap(
eliminations: json['eliminations'],
assists: json['assists'],
deaths: json['deaths'],
damage: json['damage'],
healing: json['healing'],
);
}
Map<String, dynamic> toJson() {
return {
'eliminations': eliminations,
'assists': assists,
'deaths': deaths,
'damage': damage,
'healing': healing,
};
}
}
class Player {
final String playerId;
final Overfast _client;
const Player(this._client, {required this.playerId});
// I.. don't know how to properly type this.
Future<Map> career({
Platform? platform,
Gamemode gamemode = Gamemode.competitive,
HeroKey? hero = HeroKey.allHeroes,
}) {
return _client.get<Map>(
'/players/$playerId/stats/career',
{
if (platform != null) 'platform': platform.toString(),
'gamemode': gamemode.name,
if (hero != null) 'hero': hero.toString(),
},
);
}
Future<PlayerSummary> summary() =>
_client.get<PlayerSummary>('/players/$playerId/summary');
Future<StatsSummary> statsSummary() =>
_client.get<StatsSummary>('/players/$playerId/stats/summary');
}

93
lib/players/players.dart Normal file
View File

@ -0,0 +1,93 @@
import 'package:overfast_api/client.dart';
import 'package:overfast_api/players/player.dart';
class SearchResponse {
final int total;
final List<SearchResult> results;
const SearchResponse({
required this.total,
required this.results,
});
factory SearchResponse.fromJson(Map<String, dynamic> json) {
return SearchResponse(
total: json['total'],
results: (json['results'] as List)
.map((e) => SearchResult.fromJson(e))
.toList(),
);
}
Map<String, dynamic> toJson() {
return {
'total': total,
'results': results.map((e) => e.toJson()).toList(),
};
}
}
class SearchResult {
final String playerId;
final String name;
final String? avatar;
final String? namecard;
final String? title;
final String careerUrl;
final String blizzardId;
const SearchResult({
required this.playerId,
required this.name,
this.avatar,
this.namecard,
this.title,
required this.careerUrl,
required this.blizzardId,
});
factory SearchResult.fromJson(Map<String, dynamic> json) {
return SearchResult(
playerId: json['player_id'],
name: json['name'],
avatar: json['avatar'],
namecard: json['namecard'],
title: json['title'],
careerUrl: json['career_url'],
blizzardId: json['blizzard_id'],
);
}
Map<String, dynamic> toJson() {
return {
'playerId': playerId,
'name': name,
'avatar': avatar,
'namecard': namecard,
'title': title,
'careerUrl': careerUrl,
'blizzardId': blizzardId,
};
}
}
class Players {
final Overfast _client;
const Players(this._client);
Future<SearchResponse> search(
String query, {
String orderBy = 'name:desc',
int? offset,
int? limit,
}) async {
return _client.get<SearchResponse>('/players', {
'name': query,
'orderBy': orderBy,
if (offset != null) 'offset': offset.toString(),
if (limit != null) 'limit': limit.toString(),
});
}
Player player(String playerId) => Player(_client, playerId: playerId);
}

76
lib/utils/get.dart Normal file
View File

@ -0,0 +1,76 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:overfast_api/heroes/heroes_data.dart';
import 'package:overfast_api/maps/maps.dart';
import 'package:overfast_api/players/data_types.dart';
import 'package:overfast_api/players/player.dart';
import 'package:overfast_api/players/players.dart';
// import 'package:overfast_api/players/data_types.dart';
final fromJsonMap = <Type, Function(Map<String, dynamic>)>{
GameMap: GameMap.fromJson,
Map: (json) => json,
PlayerSummary: PlayerSummary.fromJson,
SearchResponse: SearchResponse.fromJson,
CareerProfile: CareerProfile.fromJson,
Hero: Hero.fromJson,
HeroDetails: HeroDetails.fromJson,
Roles: Roles.fromJson,
StatsSummary: StatsSummary.fromJson,
};
Future<T> Function<T>(String, [Map<String, dynamic>]) get(
http.Client client,
Uri baseUri,
) {
return <T>(
String path, [
Map<String, dynamic> params = const {},
]) async {
final uri = baseUri.replace(path: path, queryParameters: params);
final response = await client.get(uri);
throwIfNecessary(response.statusCode, response.body);
return fromJsonMap[T]!(json.decode(response.body));
};
}
Future<List<T>> Function<T>(String, [Map<String, dynamic>])
getList(
http.Client client,
Uri baseUri,
) {
return <T>(
String path, [
Map<String, dynamic> params = const {},
]) async {
final uri = baseUri.replace(path: path, queryParameters: params);
final response = await client.get(uri);
throwIfNecessary(response.statusCode, response.body);
return (json.decode(response.body) as List)
.map((e) => fromJsonMap[T]!(e)).cast<T>()
.toList();
};
}
void throwIfNecessary(int code, String body) {
if (code == 422) {
throw Exception('Invalid parameters\n${json.decode(body)['detail']}');
}
if (code == 500) {
throw Exception('Internal server error');
}
if (code == 504) {
throw Exception('Blizzard Server error');
}
if (code == 404) {
throw Exception('Not found\n${json.decode(body)['error']}');
}
}

99
lib/utils/types.dart Normal file
View File

@ -0,0 +1,99 @@
import 'utils.dart';
enum HeroKey {
allHeroes,
ana,
ashe,
baptiste,
bastion,
brigitte,
cassidy,
dva,
doomfist,
echo,
genji,
hanzo,
illari,
junkrat,
junkerqueen('junker-queen'),
kiriko,
lifeweaver,
lucio,
mauga,
mei,
mercy,
moira,
orisa,
pharah,
ramattra,
reaper,
reinhardt,
roadhog,
sigma,
sojourn,
soldier76('soldier-76'),
sombra,
symmetra,
torbjorn,
tracer,
widowmaker,
winston,
wreckingball('wrecking-ball'),
venture,
zarya,
zenyatta,
eemptyy;
final String? _properName;
const HeroKey([this._properName]);
String get heroName => _properName ?? name;
static HeroKey fromString(String value) {
return HeroKey.values.firstWhere((e) => e.name == value || e._properName == value);
}
}
enum Locale {
deDe,
enGb,
enUs,
esEs,
esMx,
frFr,
itIt,
jaJp,
koKr,
plPl,
ptBr,
ruRu,
zhCn;
@override
String toString() => toKebabCase(name);
static Locale fromString(String value) {
return Locale.values.firstWhere((e) => e.name == value);
}
}
enum Platform {
pc,
console,
}
enum Gamemode {
quickplay,
competitive,
}
enum Role {
tank,
damage,
support;
static Role fromString(String value) {
return Role.values.firstWhere((e) => e.name == value);
}
}

7
lib/utils/utils.dart Normal file
View File

@ -0,0 +1,7 @@
export './get.dart';
String toKebabCase(String text) {
return text.replaceAllMapped(RegExp(r'([A-Z])'), (match) {
return '-${match.group(1)?.toLowerCase()}';
});
}

66
out.json Normal file
View File

@ -0,0 +1,66 @@
{
"best": {
"eliminations_most_in_game": 56,
"final_blows_most_in_game": 32,
"all_damage_done_most_in_game": 27149,
"healing_done_most_in_game": 16982,
"defensive_assists_most_in_game": 34,
"offensive_assists_most_in_game": 21,
"objective_kills_most_in_game": 26,
"objective_time_most_in_game": 355,
"multikill_best": 4,
"solo_kills_most_in_game": 32,
"time_spent_on_fire_most_in_game": 98,
"melee_final_blows_most_in_game": 8,
"environmental_kills_most_in_game": 3,
"kill_streak_best": 22,
"hero_damage_done_most_in_game": 22881,
"barrier_damage_done_most_in_game": 7789,
"assists_most_in_game": 35,
"objective_contest_time_most_in_game": 216,
"recon_assists_most_in_game": 9
},
"average": {
"objective_kills_avg_per_10_min": 5.71,
"objective_time_avg_per_10_min": 77,
"final_blows_avg_per_10_min": 8.65,
"time_spent_on_fire_avg_per_10_min": 89,
"objective_contest_time_avg_per_10_min": 42,
"solo_kills_avg_per_10_min": 1.4,
"hero_damage_done_avg_per_10_min": 7948,
"deaths_avg_per_10_min": 6.45,
"eliminations_avg_per_10_min": 17.39,
"assists_avg_per_10_min": 4.69,
"healing_done_avg_per_10_min": 1160
},
"game": {
"time_played": 274097,
"games_played": 413,
"games_won": 219,
"games_tied": 2,
"games_lost": 192,
"hero_wins": 219
},
"combat": {
"environmental_kills": 63,
"deaths": 2948,
"objective_kills": 2608,
"final_blows": 3950,
"objective_time": 35000,
"melee_final_blows": 526,
"time_spent_on_fire": 40814,
"eliminations": 7946,
"objective_contest_time": 18984,
"solo_kills": 641,
"multikills": 59,
"hero_damage_done": 3631039,
"damage_done": 3631039
},
"assists": {
"recon_assists": 136,
"healing_done": 529954,
"defensive_assists": 651,
"offensive_assists": 377,
"assists": 2143
}
}

389
pubspec.lock Normal file
View File

@ -0,0 +1,389 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
url: "https://pub.dev"
source: hosted
version: "67.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
url: "https://pub.dev"
source: hosted
version: "6.4.1"
args:
dependency: transitive
description:
name: args
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
url: "https://pub.dev"
source: hosted
version: "2.4.2"
async:
dependency: transitive
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.11.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.18.0"
convert:
dependency: transitive
description:
name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
coverage:
dependency: transitive
description:
name: coverage
sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76"
url: "https://pub.dev"
source: hosted
version: "1.7.2"
crypto:
dependency: transitive
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
version: "3.0.3"
file:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev"
source: hosted
version: "4.0.0"
glob:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
http:
dependency: "direct main"
description:
name: http
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
url: "https://pub.dev"
source: hosted
version: "3.2.1"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
io:
dependency: transitive
description:
name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
js:
dependency: transitive
description:
name: js
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
url: "https://pub.dev"
source: hosted
version: "0.7.1"
lints:
dependency: "direct dev"
description:
name: lints
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
url: "https://pub.dev"
source: hosted
version: "3.0.0"
logging:
dependency: transitive
description:
name: logging
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
meta:
dependency: transitive
description:
name: meta
sha256: "25dfcaf170a0190f47ca6355bdd4552cb8924b430512ff0cafb8db9bd41fe33b"
url: "https://pub.dev"
source: hosted
version: "1.14.0"
mime:
dependency: transitive
description:
name: mime
sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2"
url: "https://pub.dev"
source: hosted
version: "1.0.5"
node_preamble:
dependency: transitive
description:
name: node_preamble
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
package_config:
dependency: transitive
description:
name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
path:
dependency: transitive
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
pool:
dependency: transitive
description:
name: pool
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
url: "https://pub.dev"
source: hosted
version: "1.5.1"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
shelf:
dependency: transitive
description:
name: shelf
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
url: "https://pub.dev"
source: hosted
version: "1.4.1"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
shelf_static:
dependency: transitive
description:
name: shelf_static
sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
url: "https://pub.dev"
source: hosted
version: "1.1.2"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
source_maps:
dependency: transitive
description:
name: source_maps
sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703"
url: "https://pub.dev"
source: hosted
version: "0.10.12"
source_span:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.2"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test:
dependency: "direct dev"
description:
name: test
sha256: d87214d19fb311997d8128ec501a980f77cb240ac4e7e219accf452813ff473c
url: "https://pub.dev"
source: hosted
version: "1.25.3"
test_api:
dependency: transitive
description:
name: test_api
sha256: "2419f20b0c8677b2d67c8ac4d1ac7372d862dc6c460cdbb052b40155408cd794"
url: "https://pub.dev"
source: hosted
version: "0.7.1"
test_core:
dependency: transitive
description:
name: test_core
sha256: "2236f70be1e5ab405c675e88c36935a87dad9e05a506b57dd5c0f617f5aebcb2"
url: "https://pub.dev"
source: hosted
version: "0.6.1"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.2"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: a75f83f14ad81d5fe4b3319710b90dec37da0e22612326b696c9e1b8f34bbf48
url: "https://pub.dev"
source: hosted
version: "14.2.0"
watcher:
dependency: transitive
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
web:
dependency: transitive
description:
name: web
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
url: "https://pub.dev"
source: hosted
version: "0.5.1"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42"
url: "https://pub.dev"
source: hosted
version: "2.4.5"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
yaml:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.3.1 <4.0.0"

13
pubspec.yaml Normal file
View File

@ -0,0 +1,13 @@
name: overfast_api
description: A wrapper for the Overfast API.
version: 0.0.1
environment:
sdk: ^3.3.1
dependencies:
http: ^1.2.1
dev_dependencies:
lints: ^3.0.0
test: ^1.24.0

47
test.ts Normal file
View File

@ -0,0 +1,47 @@
type HEROES_KEYS =
| "ana"
| "ashe"
| "baptiste"
| "bastion"
| "brigitte"
| "cassidy"
| "dva"
| "doomfist"
| "echo"
| "genji"
| "hanzo"
| "junker-queen"
| "junkrat"
| "kiriko"
| "lucio"
| "mei"
| "mercy"
| "moira"
| "orisa"
| "pharah"
| "ramattra"
| "reaper"
| "reinhardt"
| "roadhog"
| "sigma"
| "sojourn"
| "soldier-76"
| "sombra"
| "symmetra"
| "torbjorn"
| "tracer"
| "widowmaker"
| "winston"
| "wrecking-ball"
| "zarya"
| "zenyatta";
type NEW_HEROES_KEYS<T extends string | number | symbol> = T extends HEROES_KEYS
? HEROES_KEYS
: T | HEROES_KEYS;
function fn<T extends string | number | symbol>(key: NEW_HEROES_KEYS<T>) {
console.log(key);
}
// fn('')

View File