diff options
author | Mole Shang <[email protected]> | 2023-08-09 22:39:30 +0800 |
---|---|---|
committer | Mole Shang <[email protected]> | 2023-08-10 12:09:42 +0800 |
commit | 06feb4557af89dfa8e695a5e89f77d38e6342fb4 (patch) | |
tree | 92790010a675f6e9408a82fb5c45cf9935d701dc /src/extractors/youku.c | |
parent | f7ccf916d9755700c655499afb0c8c636be07242 (diff) | |
download | hinata-06feb4557af89dfa8e695a5e89f77d38e6342fb4.tar.gz hinata-06feb4557af89dfa8e695a5e89f77d38e6342fb4.tar.bz2 hinata-06feb4557af89dfa8e695a5e89f77d38e6342fb4.zip |
extractors: initial youku support
Diffstat (limited to 'src/extractors/youku.c')
-rw-r--r-- | src/extractors/youku.c | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/extractors/youku.c b/src/extractors/youku.c new file mode 100644 index 0000000..4e5bc47 --- /dev/null +++ b/src/extractors/youku.c @@ -0,0 +1,179 @@ +#include "youku.h" +#include "../logger.h" +#include "../process_url.h" +#include "../utils/ffmpeg.h" +#include "../utils/utils.h" +#include <cjson/cJSON.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static callback_struct_t callback_struct; + +static int generate_api(Youku_options *youku_options) { + char params[UCHAR_MAX]; + snprintf(params, sizeof(params), + "vid=%s&ccode=%s&client_ip=192.168.1.1&client_ts=%d&utid=%s", + youku_options->vid, youku_options->ccode, + (int)(youku_options->client_ts / 1000), youku_options->utid); + youku_options->api = malloc(strlen(YOUKU_API) + strlen(params) + 1); + strcpy(youku_options->api, YOUKU_API); + strcat(youku_options->api, params); + return 0; +} + +static int parse_jsondata(cJSON *json, Youku_data *youku_data) { + cJSON *data_obj = cJSON_GetObjectItem(json, "data"); + if (!data_obj) { + LOG("cJSON", "Parse API data failed.\n"); + return 1; + } + + cJSON *video_obj = cJSON_GetObjectItem(data_obj, "video"); + cJSON *streams_obj = cJSON_GetObjectItem(data_obj, "stream"); + if (!video_obj || !streams_obj) { + LOG("cJSON", "Parse API data child object failed.\n"); + return 1; + } + cJSON *title_obj = cJSON_GetObjectItem(video_obj, "title"); + if (!title_obj) { + LOG("cJSON", "Parse API data.video.title failed.\n"); + return 1; + } + youku_data->title = title_obj->valuestring; + DEBUG_PRINT("data.video.title: %s\n", youku_data->title); + + cJSON *e; + int max_size = 0; + cJSON_ArrayForEach(e, streams_obj) { + cJSON *size_obj = cJSON_GetObjectItem(e, "size"); + cJSON *width_obj = cJSON_GetObjectItem(e, "width"); + cJSON *height_obj = cJSON_GetObjectItem(e, "height"); + cJSON *m3u8_url_obj = cJSON_GetObjectItem(e, "m3u8_url"); + if (!size_obj || !width_obj || !height_obj || !m3u8_url_obj) { + LOG("cJSON", "Parse API data.stream child object failed.\n"); + return 1; + } + if (size_obj->valueint > max_size) { + max_size = size_obj->valueint; + youku_data->width = width_obj->valueint; + youku_data->height = height_obj->valueint; + youku_data->m3u8_url = m3u8_url_obj->valuestring; + } + } + DEBUG_PRINT("width: %d, height: %d\n", youku_data->width, youku_data->height); + + return 0; +} + +static void youku_options_cleanup(Youku_options *youku_options) { + free_and_nullify((void **)&youku_options->vid); + free_and_nullify((void **)&youku_options->utid); + free_and_nullify((void **)&youku_options->api); + cJSON_Delete(youku_options->json); +} + +static int youku_convert(void *v) { + callback_struct_t *callback_struct = (callback_struct_t *)v; + const char *m3u8fn = get_str_element(callback_struct, 0); + const char *filename = get_str_element(callback_struct, 1); + DEBUG_PRINT("m3u8fn: %s\n", m3u8fn); + DEBUG_PRINT("filename: %s\n", filename); + + int r = remux(m3u8fn, filename); + LOG("Youku", "All done!\n"); + free_str_array(callback_struct); + return r; +} + +void youku_extract(Options *options) { + Youku_options youku_options = {0}; + str_array_t results = create_str_array(0); + { + const char *patterns_str[2] = {"id_(.+?)\\.html", "id_(.+)"}; + const str_array_t patterns = {(char **)patterns_str, 2}; + int r = regex_match(options->URL, patterns, &results); + if (r) { + LOG("Youku", "Parse URL failed.\n"); + goto end; + } + // for (unsigned short i = 0; i < results.n; i++) { + // DEBUG_PRINT("%s\n", results.str[i]); + // } + if (!results.str[0]) { + LOG("Youku", "Get vid failed.\n"); + goto end; + } + youku_options.vid = malloc(strlen(results.str[0]) + 1); + strcpy(youku_options.vid, results.str[0]); + DEBUG_PRINT("vid: %s\n", youku_options.vid); + } + + { + resize_str_array(&results, 0); + char *cookie = NULL; + set_referer("https://v.youku.com"); + get_info("http://log.mmstat.com/eg.js", NULL, NULL, &cookie); + if (!cookie) { + goto end; + } + const char *patterns_str[1] = {"cna=(.+?);"}; + const str_array_t patterns = {(char **)patterns_str, 1}; + int r = regex_match(cookie, patterns, &results); + if (r) { + LOG("Youku", "Parse cookie failed.\n"); + goto end; + } + // for (unsigned short i = 0; i < results.n; i++) { + // DEBUG_PRINT("%s\n", results.str[i]); + // } + if (!results.str[0]) { + LOG("Youku", "Get utid failed.\n"); + goto end; + } + youku_options.utid = malloc(strlen(results.str[0]) + 1); + strcpy(youku_options.utid, results.str[0]); + DEBUG_PRINT("utid: %s\n", youku_options.utid); + } + + youku_options.ccode = "0524"; + youku_options.client_ip = "192.168.1.1"; + youku_options.client_ts = time(NULL); + if (generate_api(&youku_options)) { + LOG("Youku", "Generate API failed.\n"); + goto end; + } + DEBUG_PRINT("Generated API: %s\n", youku_options.api); + char *resp = NULL; + if (get(youku_options.api, &resp)) { + LOG("Youku", "Get API data failed.\n"); + free_and_nullify((void **)&resp); + goto end; + } + // DEBUG_PRINT("resp: %s\n", resp); + + youku_options.json = cJSON_Parse(resp); + free_and_nullify((void **)&resp); + Youku_data youku_data = {0}; + if (parse_jsondata(youku_options.json, &youku_data)) { + LOG("Youku", "Parse jsondata failed.\n"); + goto end; + } + + callback_struct = create_str_array(2); + char *m3u8fn = malloc(strlen(youku_data.title) + 18); + sprintf(m3u8fn, "%s-[%dx%d].m3u8", youku_data.title, youku_data.width, + youku_data.height); + set_str_element(&callback_struct, 0, m3u8fn); + char *filename = malloc(strlen(youku_data.title) + 17); + sprintf(filename, "%s-[%dx%d].mp4", youku_data.title, youku_data.width, + youku_data.height); + set_str_element(&callback_struct, 1, filename); + add_url(youku_data.m3u8_url, NULL, m3u8fn, youku_convert, &callback_struct); + free_and_nullify((void **)&m3u8fn); + free_and_nullify((void **)&filename); + +end: + free_str_array(&results); + youku_options_cleanup(&youku_options); +} |