# 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", data: "Error message..." } ``` ### https://streamapi.whateveritworks.org/api/users/xqc **GET** - :username is any streamer Gets a specific twitch streamer #### Responses ###### 200 The request was successful, returns data of type [Streamer](https://codeberg.org/dragongoose/safetwitch-backend/src/branch/master/extractor/structs/parsed.go) *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", "banner": "https://safetwitch.dragongoose.us/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC9qdHZfdXNlcl9waWN0dXJlcy9kMjY2OTZlMC1hYjJhLTRlZjEtYTI3Ni0wZmZjZWM5NmM3NzYtcHJvZmlsZV9iYW5uZXItNDgwLnBuZw==", "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 ### https://streamapi.whateveritworks.org/api/discover **GET** Gets the discover page of twitch, a list of categories #### Responses ##### 200 The request was successful, returns a [CategoryData[]](https://codeberg.org/dragongoose/safetwitch-backend/src/branch/master/extractor/structs/parsed.go) *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" }, ... } ``` ### https://streamapi.whateveritworks.org/api/discover/Grand Theft Auto V **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 [CategoryPreview[]](https://codeberg.org/dragongoose/safetwitch-backend/src/branch/master/extractor/structs/parsed.go) *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 ### https://streamapi.whateveritworks.org/api/badges?streamerName=xqc **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[]](hhttps://codeberg.org/dragongoose/safetwitch-backend/src/branch/master/extractor/structs/parsed.go) *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" } }, ... ] } ``` ### https://streamapi.whateveritworks.org/api/search?query=xqc **GET** - SEARCHQUERY is any string Searches for categories, streamers, tags, and live streamers. Returns data of type [SearchResult](https://codeberg.org/dragongoose/safetwitch-backend/src/branch/master/extractor/structs/parsed.go) #### 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": [] } } ``` ### https://streamapi.whateveritworks.org/api/vods/1872917122 **GET** - vodID is any id of a vod Gets metadata of a VOD, returns [Video](https://codeberg.org/dragongoose/safetwitch-backend/src/branch/master/extractor/structs/parsed.go) #### Responses ##### 200 The server found the VOD *Example:* ```json { "status": "ok", "data": { "type": "vod", "preview": "http://localhost:8080/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC9jZl92b2RzL2QxbTdqZm9lOXpkYzFqL2JjODQyZGVhNmY2MWVlODM5MzNkX2ZpbGlhbl80MTY0NzEwMjg3M18xNjg5NDU4NzA2Ly90aHVtYi90aHVtYjAtOTB4NjAuanBn", "game": { "image": "http://localhost:8080/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC90dHYtYm94YXJ0LzUwOTY1OC17d2lkdGh9eHtoZWlnaHR9LmpwZw==", "id": "509658", "name": "Just Chatting", "displayName": "Just Chatting" }, "duration": 17520, "title": "🦂 YOU LAUGH, YOU LOSE today! Eating a Scorpion today. This is it. After 10 laughs it's guaranteed no matter what. Wait I hear something beh", "publishedAt": "2023-07-15T22:05:11Z", "views": 81357, "streamer": { "username": "filian", "login": "filian", "about": "Welcome to my Vtuber alpha! 3D streaming and variety games! Join the discord! n_n", "pfp": "http://localhost:8080/proxy/img/aHR0cHM6Ly9zdGF0aWMtY2RuLmp0dm53Lm5ldC9qdHZfdXNlcl9waWN0dXJlcy9mNzVkNDEwMy1hMjY1LTRlMjEtODhiNS00NDc0NWZjMWJmNDQtcHJvZmlsZV9pbWFnZS0zMDB4MzAwLnBuZw==", "banner": null, "followers": 656278, "socials": [ { "type": "discord", "name": "discord.gg/filian", "url": "https://discord.gg/filian" }, { "type": "twitter", "name": "twitter.com/filianIsLost", "url": "https://twitter.com/filianIsLost" } ], "isLive": false, "isPartner": true, "colorHex": "8040E0", "id": "198633200" }, "id": "1872917122" } } ``` ### https://streamapi.whateveritworks.org/api/vods/1872917122/10 **GET** - vodID is any id of a vod, offset is the seconds into the vod Gets comments at that second of a song, returns [VodComment[]](https://codeberg.org/dragongoose/safetwitch-backend/src/branch/master/extractor/structs/parsed.go) #### Responses ##### 200 The server found the VOD *Example:* ```json { "status": "ok", "data": [ { "message": "Pog", "messager": { "name": "equiro", "login": "equiro", "pfp": "", "colorHex": "#FF4500" }, "offset": 6, "cursor": "eyJpZCI6ImMwM2M0Mzg2LTRhMTUtNGVlMC05NGQ2LTMyYWExZTZjYjFhYSIsImhrIjoiYnJvYWRjYXN0OjQxNjQ3MTAyODczIiwic2siOiJBQUFBQmpwT0Z3QVhjaW5GZjk5a0FBIn0", "badges": [] }... ] } ``` ## Proxying Endpoints ### https://streamapi.whateveritworks.org/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 ### https://streamapi.whateveritworks.org/proxy/stream/xqc/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", "data": "Streamer is not live" } ``` ### https://streamapi.whateveritworks.org/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 ### https://streamapi.whateveritworks.org/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. ### https://streamapi.whateveritworks.org//proxy/vod/:vodID/video.m3u8 **GET** Gets the master manifest for a VOD ### 200 Returns the manifest file ### https://streamapi.whateveritworks.org//proxy/vod/sub/:encodedUrl/video.m3u8 **GET** Gets the sub manifest for a VOD encodedUrl is the url to the sub manifiest from twitch encoded in base64 ### 200 Returns the manifest file ### https://streamapi.whateveritworks.org//proxy/vod/sub/:encodedUrl/:segment **GET** Gets the sub manifest for a VOD encodedUrl is the url to the sub manifiest from twitch encoded in base64 segment is the segment from the playlist file, etc 0.ts, 1.ts ### 200 Returns the manifest file