0
Fork 0
mirror of https://codeberg.org/SafeTwitch/safetwitch-backend.git synced 2024-12-22 05:02:58 -05:00

Add endpoint for the emotes

This commit is contained in:
dragongoose 2023-04-29 23:09:53 -04:00
parent 075c5ea9f7
commit 17c63912e2
No known key found for this signature in database
GPG key ID: 50DB99B921579009
7 changed files with 186 additions and 4 deletions

View file

@ -87,4 +87,14 @@ profileRouter.get('/search', async (req, res, next) => {
})
})
profileRouter.get('/emotes/:streamerName', async (req, res, next) => {
const emotes = await twitch.getEmotes(req.params.streamerName)
.catch(next)
if(emotes)
res.send(emotes)
})
export default profileRouter

View file

@ -82,8 +82,6 @@ proxyRouter.get('/stream/segment/:encodedUrl', async (req: Request, res: Respons
res.send(buf)
})
const twitchChatServer = new TwitchChatServer();
export const wsServer = new ws.Server({ noServer: true });
twitchChatServer.startWebSocketServer(wsServer);

View file

@ -0,0 +1,18 @@
export type bttvData = SharedEmotesEntity[]
export interface SharedEmotesEntity {
id: string;
code: string;
imageType: string;
animated: boolean;
user: User;
width?: number | null;
height?: number | null;
codeOriginal?: string | null;
}
export interface User {
id: string;
name: string;
displayName: string;
providerId: string;
}

View file

@ -0,0 +1,52 @@
export interface ffzData {
room: Room;
sets: Sets;
}
export interface Room {
_id: number;
twitch_id: number;
youtube_id?: null;
id: string;
is_group: boolean;
display_name: string;
set: number;
}
export interface Sets {
[k: number]: SetData;
}
export interface SetData {
id: number;
_type: number;
title: string;
emoticons: EmoteData[];
}
export interface EmoteData {
id: number;
name: string;
height: number;
width: number;
public: boolean;
hidden: boolean;
modifier: boolean;
modifier_flags: number;
owner: Owner;
urls: Urls;
status: number;
usage_count: number;
created_at: string;
last_updated: string;
}
export interface Owner {
_id: number;
name: string;
display_name: string;
}
export interface Urls {
[k: number]: string
}

View file

@ -0,0 +1,2 @@
export * from './bttv'
export * from './ffz'

View file

@ -0,0 +1,53 @@
import { Urls, bttvData, ffzData } from "../../../types/scraping/emotes"
interface Emote {
name: string
urls: Urls
}
export const ffzEmotesHandler = (emoteData: ffzData) => {
const sets = emoteData.sets[emoteData.room.set]
const emotes: Emote[] = []
for (let emote of sets.emoticons) {
const data: Emote = {
name: emote.name,
urls: emote.urls
}
emotes.push(data)
}
return emotes
}
const generateBttvEmoteUrls = (id: string) => {
const bttvApi = 'https://cdn.betterttv.net/emote/'
const urls: Urls = {}
// Creates urls like "https://cdn.betterttv.net/emote/6368b11b9013520589f5ac0c/3x" from 1x to 3x
for (let i = 1; i < 4; i++) {
urls[i] = `${bttvApi}${id}/${i}x`
}
return urls
}
export const bttvEmotesHandler = (emoteData: bttvData) => {
const rawEmoteArray = emoteData
console.log(emoteData.length)
const emotes: Emote[] = []
for (let rawEmote of rawEmoteArray) {
const formattedEmote: Emote = {
name: rawEmote.code,
urls: generateBttvEmoteUrls(rawEmote.id)
}
emotes.push(formattedEmote)
}
console.log(emotes.length)
console.log(emotes)
return emotes
}

View file

@ -3,6 +3,7 @@ import { StreamerData, StreamData, Social, Badge } from "../../../types/scraping
import { Category, Tag } from "../../../types/scraping/Category"
import { CategoryData, CategoryMinifiedStream } from "../../../types/scraping/CategoryData"
import { SearchResult } from "../../../types/scraping/Search"
import { bttvEmotesHandler, ffzEmotesHandler } from "./emoteHandler"
const base64 = (data: String) => {
return Buffer.from(data).toString('base64url')
@ -259,8 +260,6 @@ export class TwitchAPI {
headers: this.headers
})
console.log(res.status)
return await res.text()
}
@ -589,4 +588,54 @@ export class TwitchAPI {
return finalData
}
public getStreamerId = async (channelName: string) => {
const payload = {
"operationName": "ChannelRoot_AboutPanel",
"variables": {
"channelLogin": channelName,
"skipSchedule": true
},
"extensions": {
"persistedQuery": {
"version": 1,
"sha256Hash": "6089531acef6c09ece01b440c41978f4c8dc60cb4fa0124c9a9d3f896709b6c6"
}
}
}
const res = await fetch(this.twitchUrl, {
method: 'POST',
body: JSON.stringify(payload),
headers: this.headers
})
const data = await res.json()
if (!data.data.user) {
return Promise.reject(new Error(`Steamer ${channelName} is offline.`))
}
return Number(data.data.user.id)
}
public getEmotes = async (channelName: string) => {
let id = await this.getStreamerId(channelName)
const ffzUrl = 'https://api.frankerfacez.com/v1/room/id/' + id
const bttvGlobalUrl = 'https://api.betterttv.net/3/cached/users/twitch/121059319'
const bttvChannelUrl = 'https://api.betterttv.net/3/cached/users/twitch/' + id
let res = await fetch(ffzUrl)
let data = await res.json()
const ffzEmotes = ffzEmotesHandler(data)
res = await fetch(bttvGlobalUrl)
data = await res.json()
const bttvGlobalEmotes = bttvEmotesHandler([...data.channelEmotes, ...data.sharedEmotes])
res = await fetch(bttvChannelUrl)
data = await res.json()
const bttvChannelEmotes = bttvEmotesHandler(data.channelEmotes)
return [ ...ffzEmotes, ...bttvGlobalEmotes, ...bttvChannelEmotes]
}
}