# safetwitch-backend The backend for [SafeTwitch](https://codeberg.org/dragongoose/safetwitch) # Documentation ## API Endpoints ### Disclaimer Every endpoint can return a 500 status code, and it follows this schema: ```json { status: "error", message: "Error message..." } ``` ### /api/users/:username **GET** - :username is any streamer Gets a specific twitch streamer #### Responses ###### 200 The request was successful, returns data of type [StreamerData](https://codeberg.org/dragongoose/safetwitch-backend/src/branch/master/types/scraping/Streamer.ts) *Example:* ```json { "status": "ok", "data": { "username": "filian", "about": "Welcome to my Vtuber alpha! 3D streaming and variety games! Join the discord! n_n", "pfp": "https://safetwitch.dragongoose.us/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC9qdHZfdXNlcl9waWN0dXJlcy9mNzVkNDEwMy1hMjY1LTRlMjEtODhiNS00NDc0NWZjMWJmNDQtcHJvZmlsZV9pbWFnZS0zMDB4MzAwLnBuZw", "followers": 579463, "socials": [ { "type": "discord", "name": "discord.gg/filian", "link": "https://discord.gg/filian" }, { "type": "twitter", "name": "twitter.com/filianIsLost", "link": "https://twitter.com/filianIsLost" } ], "isLive": false, "isPartner": true, "colorHex": "#8040E0", "id": 198633200, "stream": null } } ``` ##### 404 The streamer was not found ### /api/discover **GET** Gets the discover page of twitch, a list of categories #### Responses ##### 200 The request was successful, returns a [Category[]](https://codeberg.org/dragongoose/safetwitch-backend/src/branch/master/types/scraping/Category.ts) *Example:* ```json { "status": "ok", "data": [ { "name": "Just Chatting", "displayName": "Just Chatting", "viewers": 510365, "tags": [ "IRL" ], "createdAt": null, "cursor": "eyJzIjoxLCJkIjpmYWxzZSwidCI6dHJ1ZX0=", "image": "https://safetwitch.dragongoose.us/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC90dHYtYm94YXJ0LzUwOTY1OC0yODV4MzgwLmpwZw" }, ... } ``` ### /api/discover/:game **GET** - :game is a name of a twitch category Gets a specific twitch category #### Responses ##### 200 The server found the category, returns data of type [CategoryData[]](https://codeberg.org/dragongoose/safetwitch-backend/src/branch/master/types/scraping/CategoryData.ts) *Example:* ```json { "status": "ok", "data": { "name": "Just Chatting", "cover": "https://safetwitch.dragongoose.us/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC90dHYtYm94YXJ0LzUwOTY1OC0xNDR4MTkyLmpwZw", "description": null, "viewers": 533593, "followers": 23147702, "tags": [ "IRL" ], "streams": [ { "title": "CIERRE DEL MERCATO DE LA KINGS LEAGUE | ÚLTIMO DÍA DE MERCATO | ÚLTIMOS CLAUSULAZOS | SE VIENEN LLOROS", "viewers": 60897, "preview": "https://safetwitch.dragongoose.us/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC9wcmV2aWV3cy10dHYvbGl2ZV91c2VyX2liYWktNDQweDI0OC5qcGc", "tags": [ "Español", "KOI", "KingsLeague" ], "cursor": "eyJzIjo2MDg5Ny40NDU3NDY0NjY4NSwiZCI6ZmFsc2UsInQiOnRydWV9", "streamer": { "name": "ibai", "pfp": "https://safetwitch.dragongoose.us/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC9qdHZfdXNlcl9waWN0dXJlcy81NzQyMjhiZS0wMWVmLTRlYWItYmMwZS1hNGY2YjY4YmVkYmEtcHJvZmlsZV9pbWFnZS01MHg1MC5wbmc", "colorHex": "2A2B62" } }, ... ] } } ``` ##### 404 The category was not found ### /api/badges?streamerName=NAME **GET** Gets global twitch chat badges streamerName query is optional, if given it will only provide the badges for that streamer. #### Responses ##### 200 Server retrieved the badges, returns type [Badge[]](https://codeberg.org/dragongoose/safetwitch-backend/src/branch/master/types/scraping/Streamer.ts) *Example:* ```json { "status": "ok", "data": [ { "id": "getting-over-it_2;1;", "setId": "getting-over-it_2", "title": "Getting Over It", "version": "1", "images": { "image1x": "https://safetwitch.dragongoose.us/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC9iYWRnZXMvdjEvYmI2MjBiNDItZTBlMS00MzczLTkyOGUtZDRhNzMyZjk5Y2NiLzE", "image2x": "https://safetwitch.dragongoose.us/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC9iYWRnZXMvdjEvYmI2MjBiNDItZTBlMS00MzczLTkyOGUtZDRhNzMyZjk5Y2NiLzI", "image4x": "https://safetwitch.dragongoose.us/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC9iYWRnZXMvdjEvYmI2MjBiNDItZTBlMS00MzczLTkyOGUtZDRhNzMyZjk5Y2NiLzM" } }, ... ] } ``` ### /api/search?query=SEARCHQUERY **GET** - SEARCHQUERY is any string Searches for categories, streamers, tags, and live streamers. Returns data of type [SearchResult]() #### Responses ##### 200 The server found the search data, returns: *Example:* ```json { "status": "ok", "data": { "channels": [ { "username": "filian", "followers": 580066, "isLive": false, "about": "Welcome to my Vtuber alpha! 3D streaming and variety games! Join the discord! n_n", "pfp": "https://safetwitch.dragongoose.us/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC9qdHZfdXNlcl9waWN0dXJlcy9mNzVkNDEwMy1hMjY1LTRlMjEtODhiNS00NDc0NWZjMWJmNDQtcHJvZmlsZV9pbWFnZS0xNTB4MTUwLnBuZw", "isPartner": null, "colorHex": "#fff", "id": 198633200 }, ... ], "categories": [ { "name": "Lilian: The beginning of the end", "displayName": "Lilian: The beginning of the end", "viewers": null, "tags": [ "" ], "image": "https://safetwitch.dragongoose.us/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC9wcmV2aWV3cy10dHYvbGl2ZV91c2VyX2VsbHllbi0xMjgweDcyMC5qcGc" } ], "relatedChannels": [ { "username": "EllyEN", "about": "HI I'M ELLY❗❗ I'm a cwiminal Vtuber who loves cars, boba, games, & getting into trouble~❗❗", "pfp": "https://safetwitch.dragongoose.us/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC9qdHZfdXNlcl9waWN0dXJlcy8xZjJjNmQ2Yi1hZmZmLTQ4NGYtYTdjMy1iNGRhZTU2MzllOGMtcHJvZmlsZV9pbWFnZS0zMDB4MzAwLmpwZWc", "followers": 100538, "socials": [ { "type": "twitter", "name": "Twitter", "link": "https://www.twitter.com/EllyVtuber" }, { "type": "tiktok", "name": "Tiktok", "link": "https://www.tiktok.com/@ellyvtuber" }, { "type": "youtube", "name": "YouTube", "link": "https://www.youtube.com/EllyEN" } ], "isLive": true, "isPartner": true, "colorHex": "#FA2929", "id": 141045387, "stream": { "title": "little bit of valheim THEN FFXIV! 🌱 I'M OBSESSED LOL | SUBATHON PART 2 DAY 16 | #AlienwareHive !GamerSupps", "topic": "I'm Only Sleeping", "startedAt": 1682363001000, "tags": [ "LGBTQIA", "NoBackseating", "Vtuber", "ENVtuber", "English" ], "viewers": 654, "preview": "https://safetwitch.dragongoose.us/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC9wcmV2aWV3cy10dHYvbGl2ZV91c2VyX2VsbHllbi0xMjgweDcyMC5qcGc" } }, ... ], "channelsWithTag": [] } } ``` ### /api/emotes/:streamerName **GET** Gets all of the emotes for a streamer #### Resposnes ##### 200 Returns the found Emotes *Example:* ```json { "name": "fillyTailChase", "urls": { "1": "..." } }, ... ``` ## Proxying Endpoints ### /proxy/img/:base64Url **GET** Proxies an image through the server :base64Url can be any base64 encoded Url #### Responses ##### 200 Server returns the requested image ##### 404 The requested image was invalid ### /proxy/stream/:username/hls.m3u8 **GET** Gets the m3u8 manifest for a streamer. This manifest will contain all stream qualities if they are live #### Responses ##### 200 Returns the manifest ##### 400 The streamer is not live *Example:* ```json { "status": "error", "message": "Streamer is not live" } ``` ### /proxy/stream/sub/:encodedUrl **GET** Returns the m3u8 manifest for a specific quality under the [master manifest](#/proxy/stream/:username/hls.m3u8) ### 200 Returns the manifest file ### /proxy/stream/segment/:encodedUrl **GET** Gets a segment from one of the quality's manifest file. This is the actual video thats displayed on your screen ### 200 Returns the stream segment, HLS streaming.