import 'package:frosty/constants/constants.dart'; import 'package:json_annotation/json_annotation.dart'; part 'emotes.g.dart'; // * Twitch Emotes * @JsonSerializable(createToJson: false) class ImagesTwitch { @JsonKey(name: 'url_1x') final String url1x; @JsonKey(name: 'url_2x') final String url2x; @JsonKey(name: 'url_4x') final String url4x; const ImagesTwitch( this.url1x, this.url2x, this.url4x, ); factory ImagesTwitch.fromJson(Map json) => _$ImagesTwitchFromJson(json); } @JsonSerializable(createToJson: false, fieldRename: FieldRename.snake) class EmoteTwitch { final String id; final String name; final ImagesTwitch images; final String? tier; final String? emoteType; final String? emoteSetId; final String? ownerId; final List format; final List scale; final List themeMode; const EmoteTwitch( this.id, this.name, this.images, this.tier, this.emoteType, this.emoteSetId, this.ownerId, this.format, this.scale, this.themeMode, ); factory EmoteTwitch.fromJson(Map json) => _$EmoteTwitchFromJson(json); } // * BTTV Emotes * @JsonSerializable(createToJson: false) class EmoteBTTV { final String id; final String code; final String imageType; final String? userId; final UserBTTV? user; const EmoteBTTV( this.id, this.code, this.imageType, this.userId, this.user, ); factory EmoteBTTV.fromJson(Map json) => _$EmoteBTTVFromJson(json); } @JsonSerializable(createToJson: false) class UserBTTV { final String id; final String name; final String displayName; final String providerId; const UserBTTV( this.id, this.name, this.displayName, this.providerId, ); factory UserBTTV.fromJson(Map json) => _$UserBTTVFromJson(json); } @JsonSerializable(createToJson: false) class EmoteBTTVChannel { final String id; final List bots; final List channelEmotes; final List sharedEmotes; const EmoteBTTVChannel( this.id, this.bots, this.channelEmotes, this.sharedEmotes, ); factory EmoteBTTVChannel.fromJson(Map json) => _$EmoteBTTVChannelFromJson(json); } // * FFZ Emotes * @JsonSerializable(createToJson: false, fieldRename: FieldRename.snake) class RoomFFZ { final int set; final String? moderatorBadge; final ImagesFFZ? vipBadge; final ImagesFFZ? modUrls; // final Map> userBadges; // final Map> userBadgesIds; const RoomFFZ( this.set, this.moderatorBadge, this.vipBadge, this.modUrls, ); factory RoomFFZ.fromJson(Map json) => _$RoomFFZFromJson(json); } @JsonSerializable(createToJson: false) class ImagesFFZ { @JsonKey(name: '1') final String url1x; @JsonKey(name: '2') final String? url2x; @JsonKey(name: '4') final String? url4x; const ImagesFFZ( this.url1x, this.url2x, this.url4x, ); factory ImagesFFZ.fromJson(Map json) => _$ImagesFFZFromJson(json); } @JsonSerializable(createToJson: false) class EmoteFFZ { final int id; final String name; final int height; final int width; final OwnerFFZ owner; final ImagesFFZ urls; const EmoteFFZ( this.id, this.name, this.height, this.width, this.owner, this.urls, ); factory EmoteFFZ.fromJson(Map json) => _$EmoteFFZFromJson(json); } @JsonSerializable(createToJson: false, fieldRename: FieldRename.snake) class OwnerFFZ { @JsonKey(name: '_id') final int id; final String name; final String displayName; const OwnerFFZ( this.id, this.name, this.displayName, ); factory OwnerFFZ.fromJson(Map json) => _$OwnerFFZFromJson(json); } // * 7TV Emotes * @JsonSerializable(createToJson: false) class Role7TV { final String id; final String name; final int position; final int color; final int allowed; final int denied; @JsonKey(name: 'default') final bool? defaults; const Role7TV( this.id, this.name, this.position, this.color, this.allowed, this.denied, this.defaults, ); factory Role7TV.fromJson(Map json) => _$Role7TVFromJson(json); } @JsonSerializable(createToJson: false, fieldRename: FieldRename.snake) class Owner7TV { final String id; final String twitchId; final String login; final String displayName; final Role7TV role; const Owner7TV( this.id, this.twitchId, this.login, this.displayName, this.role, ); factory Owner7TV.fromJson(Map json) => _$Owner7TVFromJson(json); } @JsonSerializable(createToJson: false, fieldRename: FieldRename.snake) class Emote7TV { final String id; final String name; final Owner7TV? owner; final int visibility; final List visibilitySimple; final String mime; final int status; final List tags; final List width; final List height; final List> urls; const Emote7TV( this.id, this.name, this.owner, this.visibility, this.visibilitySimple, this.mime, this.status, this.tags, this.width, this.height, this.urls, ); factory Emote7TV.fromJson(Map json) => _$Emote7TVFromJson(json); } /// The common emote class. class Emote { final String name; final int? width; final int? height; final bool zeroWidth; final String url; final EmoteType type; const Emote({ required this.name, this.width, this.height, required this.zeroWidth, required this.url, required this.type, }); factory Emote.fromTwitch(EmoteTwitch emote, EmoteType type) => Emote( name: emote.name, zeroWidth: false, url: 'https://static-cdn.jtvnw.net/emoticons/v2/${emote.id}/default/dark/3.0', type: type, ); factory Emote.fromBTTV(EmoteBTTV emote, EmoteType type) => Emote( name: emote.code, zeroWidth: zeroWidthEmotes.contains(emote.code), url: 'https://cdn.betterttv.net/emote/${emote.id}/3x', type: type, ); factory Emote.fromFFZ(EmoteFFZ emote, EmoteType type) => Emote( name: emote.name, zeroWidth: false, url: 'https:' + (emote.urls.url4x ?? emote.urls.url2x ?? emote.urls.url1x), type: type, ); factory Emote.from7TV(Emote7TV emote, EmoteType type) => Emote( name: emote.name, width: emote.width.first, height: emote.height.first, zeroWidth: emote.visibilitySimple.isNotEmpty ? emote.visibilitySimple.first == "ZERO_WIDTH" : false, url: emote.urls[3][1], type: type, ); } enum EmoteType { twitchSub, twitchGlobal, twitchUnlocked, twitchChannel, ffzGlobal, ffzChannel, bttvGlobal, bttvChannel, bttvShared, sevenTvGlobal, sevenTvChannel, }