123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- #ifndef PEERTUBE_HTP
- #define PEERTUBE_HPP
- int interpret(const std::string &user_input, std::string &host, std::string &id) {
- // what did the user link?
- char *token = new char[user_input.length() + 1];
- strcpy(token, user_input.c_str());
- token = strtok(token, "/");
- unsigned int state = 0;
- bool is_playlist = false;
- while (token != NULL) {
- switch (state) {
- case 0: // protocol
- if (strcmp(token, "https:") != 0
- && strcmp(token, "http:") != 0) {
- goto endwhile;
- }
- state++;
- break;
- case 1: // domain
- host = std::string(token);
- state++;
- break;
- case 2: // can be either api or 'w'
- if (strcmp(token, "w") == 0) {
- state++;
- } else if (strcmp(token, "api") == 0) {
- state = 'a';
- } break;
- case 3: // can either be playlist indicator or a video id
- if (strcmp(token, "p") == 0) {
- state++;
- } else {
- id = std::string(token);
- } break;
- case 4: // playlist id
- id = std::string(token);
- break;
- case 'a': // api version indicator
- state++;
- break;
- case 'b':
- if (strcmp(token, "videos") == 0) {
- state++;
- } else if (strcmp(token,"video-playlists") == 0) {
- is_playlist = true;
- state++;
- } break;
- case 'c':
- id = std::string(token);
- break;
- }
- token = strtok(NULL, "/");
- }
- endwhile:
- delete [] token;
- if (is_playlist) {
- state++; // so caller func knows api video vs api playlist
- }
- return state;
- }
- // https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo
- // https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideoPlaylistVideos
- std::string get_endpoint(const std::string &user_input, bool &is_playlist) {
- std::string host;
- std::string id;
- int what = 0;
- what = interpret(user_input, host, id);
- std::string url = std::string("");
- std::string api;
- std::stringstream ss;
- switch (what) {
- default:
- std::cout << what << std::endl;
- case 0:
- case 1:
- std::cout << "URL not recognized." << std::endl;
- break;
- case 3:
- std::cout << "video page" << std::endl;
- api = "/api/v1/videos/"; //(host, id)
- ss << "https://" << host << api << id;
- url = ss.str();
- break;
- case 'c': // video api
- std::cout << "video api endpoint" << std::endl;
- url = user_input;
- break;
- case 'd':
- std::cout << "playlist api endpoint" << std::endl;
- url = user_input;
- break;
- case 4:
- std::cout << "playlist page" << std::endl;
- api = "/api/v1/video-playlists/";
- ss << "https://" << host << api << id << "/videos";
- url = ss.str();
- break;
- }
- return url;
- }
- // #include "peertube/model/video.h" <- model does not compile
- // https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo
- // salvage the stuff that didn't compile.'
- #define FILE_T_STR_COUNT 6
- enum {
- MAGNET_URI,
- TORRENT_URL,
- TORRENTDOWNLOAD_URL,
- FILE_URL,
- FILEDOWNNLOAD_URL,
- METADATA_URL
- } file_t_attribs;
- struct file_t {
- // char *magnetUri;
- int resolution; // ignore label
- int size;
- // char *torrentUrl;
- // char *torrentDownloadUrl;
- // char *fileUrl;
- // char *fileDownloadUrl;
- int fps;
- // char *metadataurl;
- char *attribs[FILE_T_STR_COUNT]; // B)
- };
- struct file_t* file_init (int resolution,
- int size,
- int fps,
- unsigned int len_data,
- const char **data) {
- struct file_t *f = (file_t*)malloc(sizeof(file_t));
- f -> resolution = resolution;
- f -> size = size;
- f -> fps = fps;
- if (len_data != FILE_T_STR_COUNT) {
- return NULL;
- }
- // not going to take any cues
- // on how to initialize a struct from openapigenerator
- unsigned int len;
- unsigned int i = 0;
- for (i; i < FILE_T_STR_COUNT; ++i) {
- if (data[i] == NULL) {
- return NULL;
- }
- len = strlen(data[i]) * sizeof(char);
- f -> attribs[i] = (char*)malloc(len);
- strcpy(f -> attribs[i], data[i]);
- }
- return f;
- }
- void file_print(const struct file_t * const f) {
- unsigned int i = 0;
- for (i; i < FILE_T_STR_COUNT; ++i) {
- fprintf(stdout, "%s\n", f -> attribs[i]);
- }
- }
- void file_free(struct file_t* f) {
- unsigned int i = 0;
- for (i; i < FILE_T_STR_COUNT; ++i) {
- free(f -> attribs[i]);
- }
- free(f);
- }
- struct video_t {
- int id;
- char *uuid;
- char *short_uuid;
- // int is_live;
- // char *created_at; //date time
- // char *published_at; //date time
- // char *updated_at; //date time
- // char *originally_published_at; //date time
- // skip other models
- char *description; // string
- int duration; //numeric
- // int is_local; //boolean
- char *name; // string
- int views; //numeric
- int likes; //numeric
- int dislikes; //numeric
- int nsfw; //boolean
- // skip other models again
- int file_count;
- struct file_t** files;
- };
- struct video_t *video_init(int id,
- const char *uuid,
- const char *short_uuid,
- const char *description,
- int duration,
- const char *name,
- int views,
- int likes,
- int dislikes,
- int nsfw,
- int file_count,
- struct file_t** files) {
- struct video_t *v = (video_t*)malloc(sizeof(video_t));
- if (!v) {
- return NULL;
- }
- v -> id = id;
- v -> duration = duration;
- v -> views = views;
- v -> likes = likes;
- v -> dislikes = dislikes;
- v -> nsfw = nsfw;
- unsigned int len;
- if (uuid != NULL) {
- len = strlen(uuid) * sizeof(char);
- v -> uuid = (char *)malloc(len);
- strcpy(v -> uuid, uuid);
- }
- if (short_uuid != NULL) {
- len = strlen(short_uuid) * sizeof(char);
- v -> short_uuid = (char*)malloc(len);
- strcpy(v -> short_uuid, short_uuid);
- }
- if (description != NULL) {
- len = strlen(description) * sizeof(char);
- v -> description = (char*)malloc(len);
- strcpy(v -> description, description);
- }
- if (name != NULL) {
- len = strlen(name) * sizeof(char);
- v -> name = (char*)malloc(len);
- strcpy(v -> name, name);
- }
- v -> file_count = file_count;
- if (files != NULL) {
- v -> files = files;
- }
- return v;
- }
- void video_free(struct video_t *v) {
- if (v == NULL) {
- return;
- }
- if (v -> uuid != NULL) {
- free(v -> uuid);
- }
- if (v -> short_uuid != NULL) {
- free(v -> short_uuid);
- }
- if (v -> description != NULL) {
- free(v -> description);
- }
- if (v -> name != NULL) {
- free(v -> name);
- }
- unsigned int i;
- for (i = 0; i < v-> file_count; ++i) {
- file_free(v -> files[i]);
- }
- free(v -> files);
- free(v);
- }
- void video_print(const struct video_t * const v) {
- if (v == NULL) {
- return;
- }
- fprintf(stdout, "%s\n", v -> name);
- fprintf(stdout, "%s\n", v -> description);
- fprintf(stdout, "%i views\n%i:%i (likes:dislikes)\n",
- v -> views, v -> likes, v -> dislikes);
- }
- #include <cmath>
- #include <climits>
- // pick file download of a target resolution
- struct file_t *video_pick_file(const struct video_t* const v, int target_res=0) {
- if (v == NULL) {
- return NULL;
- }
- if (v -> files == NULL) {
- return NULL;
- }
- if (target_res == 0) {
- // default behavior => pick best quality
- return v-> files[0];
- }
- int lowest_delta = INT_MAX;
- struct file_t *best_file = NULL;
- unsigned int i;
- for (i = 0; i < v -> file_count; ++i) {
- int res = v -> files[i] -> resolution;
- int delta = std::abs(target_res - res);
- if (delta < lowest_delta) {
- lowest_delta = delta;
- best_file = v -> files[i];
- }
- }
- return best_file;
- }
- #include <rapidjson/document.h>
- #include <rapidjson/writer.h>
- #include <rapidjson/stringbuffer.h>
- rapidjson::Value& get_video_files(rapidjson::Document& root) {
- rapidjson::Document *ptr = &root;
- rapidjson::Value& out = root["files"];
- assert(out.IsArray());
- if (out.Size() > 0) {
- return out;
- }
- // if the list is empty - HLS is enabled on the server
- // therefore, look under streamingPlaylists
- rapidjson::Value &playlists = root["streamingPlaylists"];
- assert(playlists.IsArray());
- for (rapidjson::SizeType i = 0; i < playlists.Size(); ++i) {
- if (!playlists[i]["type"].IsInt()) {
- continue;
- }
- // don't know what type other than 1 is.'
- if (playlists[i]["type"].GetInt() == 1) {
- out = playlists[i]["files"];
- break;
- } else {
- std::cout << "Found streamingPlaylist type != 1" << std::endl;
- }
- }
- return out;
- }
- struct file_t *init_from_json(const rapidjson::Value& file) {
- const char *elem_ints[] = {
- // "resolution", // id is nested inside resolution
- "size",
- "fps"
- };
- int ints[2];
- // keep order -see enum above struct file_t definition
- const char *elem_strs[FILE_T_STR_COUNT] = {
- "magnetUri",
- "torrentUrl",
- "torrentDownloadUrl",
- "fileUrl",
- "fileDownloadUrl",
- "metadataUrl"
- };
- const char *strs[FILE_T_STR_COUNT];
- int resolution;
- if (!file["resolution"]["id"].IsInt()) {
- return NULL;
- }
- resolution = file["resolution"]["id"].GetInt();
- unsigned int i = 0;
- for (i; i < 2; ++i) {
- const char *element = elem_ints[i];
- const rapidjson::Value &v = file[element];
- if (!v.IsInt()) {
- return NULL;
- }
- ints[i] = v.GetInt();
- }
- i = 0;
- for (i; i < FILE_T_STR_COUNT; ++i) {
- const char *element = elem_strs[i];
- const rapidjson::Value &v = file[element];
- if (!v.IsString()) {
- return NULL;
- }
- strs[i] = v.GetString();
- }
- struct file_t *foo = file_init(
- resolution, ints[0], ints[1], FILE_T_STR_COUNT, strs);
- return foo;
- }
- struct video_t *init_from_json(rapidjson::Document& root) {
- #define INT_ATTRIB_COUNT 5
- const char *elem_int[INT_ATTRIB_COUNT] = {
- "id",
- "duration",
- "views",
- "likes",
- "dislikes",
- };
- int ints[INT_ATTRIB_COUNT];
- #define STR_ATTRIB_COUNT 4
- const char *elem_str[STR_ATTRIB_COUNT] = {
- "uuid",
- "shortUUID",
- "description",
- "name"
- };
- std::string strs[STR_ATTRIB_COUNT];
- unsigned int i;
- for (i = 0; i < INT_ATTRIB_COUNT; ++i) {
- const char *element = elem_int[i];
- rapidjson::Value& v = root[element];
- if (!v.IsInt()) {
- return NULL;
- }
- ints[i] = v.GetInt();
- }
- for (i = 0; i < STR_ATTRIB_COUNT; ++i) {
- const char *element = elem_str[i];
- rapidjson::Value& v = root[element];
- if (!v.IsString()) {
- return NULL;
- }
- strs[i] = v.GetString();
- }
- rapidjson::Value &v = root["nsfw"];
- if (!v.IsBool()) {
- return NULL;
- }
- bool is_nsfw = v.GetBool();
- int nsfw = (is_nsfw) ? 1 : 0;
- const rapidjson::Value &vf = get_video_files(root);
- unsigned int file_count = vf.Size();
- unsigned int size = file_count * sizeof(struct file_t**);
- struct file_t ** f = (struct file_t**)malloc(size);
- for (rapidjson::SizeType i = 0; i < vf.Size(); ++i) {
- f[i] = init_from_json(vf[i]);
- }
- struct video_t *bar = video_init(
- ints[0],
- strs[0].c_str(),
- strs[1].c_str(),
- strs[2].c_str(),
- ints[1],
- strs[3].c_str(),
- ints[2],
- ints[3],
- ints[4],
- nsfw,
- file_count,
- f
- );
- return bar;
- }
- std::string get_magnet_link(const rapidjson::Value& files) {
- unsigned int highest = 0;
- std::string best_video;
- // peertube tends to order highest to lowest, but just to make sure...
- for (rapidjson::SizeType i = 0; i < files.Size(); ++i ) {
- assert(files[i]["resolution"]["id"].IsInt());
- unsigned int resolution = files[i]["resolution"]["id"].GetInt();
- std::string magnet_link = files[i]["magnetUri"].GetString();
- if (resolution > highest) {
- highest = resolution;
- best_video = magnet_link;
- }
- }
- std::cout << "The best quality video is " << best_video << std::endl;
- return best_video;
- }
- #endif
|