From 39b2d7df479843063b9b9573fbb8b7ca210e84ea Mon Sep 17 00:00:00 2001 From: Kartatz <105828205+Kartatz@users.noreply.github.com> Date: Tue, 14 Jan 2025 00:52:29 -0300 Subject: [PATCH] a --- CMakeLists.txt | 2 +- src/clioptions.c | 4 +- src/clioptions.h | 2 +- src/{m3u8httpclient.c => httpclient.c} | 26 ++++----- src/httpclient.h | 36 +++++++++++++ src/m3u8.c | 22 +++----- src/m3u8.h | 6 ++- src/m3u8download.c | 75 +++++++++++++++----------- src/m3u8download.h | 14 +++++ src/m3u8httpclient.h | 36 ------------- src/m3u8stream.h | 2 + src/m3u8types.h | 6 +-- src/main.c | 14 ++--- 13 files changed, 134 insertions(+), 111 deletions(-) rename src/{m3u8httpclient.c => httpclient.c} (86%) create mode 100644 src/httpclient.h delete mode 100644 src/m3u8httpclient.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b4dffc..2c37e9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -784,7 +784,7 @@ add_executable( src/errors.c src/argparser.c src/main.c - src/m3u8httpclient.c + src/httpclient.c src/m3u8sizeof.c src/m3u8parser.c src/m3u8stream.c diff --git a/src/clioptions.c b/src/clioptions.c index 166075f..50d394c 100644 --- a/src/clioptions.c +++ b/src/clioptions.c @@ -29,7 +29,7 @@ int clioptions_parse( struct CLIOptions* const options, struct ArgumentParser* const argparser, const struct Argument** argument, - struct M3U8HTTPClient* client + struct HTTPClient* client ) { int err = M3U8ERR_SUCCESS; @@ -45,7 +45,7 @@ int clioptions_parse( size_t index = 0; size_t select_media_index = 0; - struct M3U8HTTPClientError* cerror = m3u8httpclient_geterror(client); + struct HTTPClientError* cerror = httpclient_geterror(client); ssize_t nproc = 0; diff --git a/src/clioptions.h b/src/clioptions.h index 663b9f7..b141eae 100644 --- a/src/clioptions.h +++ b/src/clioptions.h @@ -67,7 +67,7 @@ int clioptions_parse( struct CLIOptions* const options, struct ArgumentParser* const argparser, const struct Argument** argument, - struct M3U8HTTPClient* client + struct HTTPClient* client ); void clioptions_free(struct CLIOptions* const options); diff --git a/src/m3u8httpclient.c b/src/httpclient.c similarity index 86% rename from src/m3u8httpclient.c rename to src/httpclient.c index b58a7a7..bc15589 100644 --- a/src/m3u8httpclient.c +++ b/src/httpclient.c @@ -2,10 +2,10 @@ #include #include "errors.h" -#include "m3u8httpclient.h" +#include "httpclient.h" #include "sslcerts.h" -int m3u8httpclient_init(struct M3U8HTTPClient* const client) { +int httpclient_init(struct HTTPClient* const client) { int err = M3U8ERR_SUCCESS; CURLcode code = CURLE_OK; @@ -133,14 +133,14 @@ int m3u8httpclient_init(struct M3U8HTTPClient* const client) { } if (err != M3U8ERR_SUCCESS) { - m3u8httpclient_free(client); + httpclient_free(client); } return err; } -void m3u8httpclient_errfree(struct M3U8HTTPClientError* const error) { +void httpclient_error_free(struct HTTPClientError* const error) { if (error == NULL) { return; @@ -153,26 +153,26 @@ void m3u8httpclient_errfree(struct M3U8HTTPClientError* const error) { } -void m3u8httpclient_free(struct M3U8HTTPClient* const client) { +void httpclient_free(struct HTTPClient* const client) { curl_easy_cleanup(client->curl); client->curl = NULL; } -struct M3U8HTTPClientError* m3u8httpclient_geterror(struct M3U8HTTPClient* const client) { +struct HTTPClientError* httpclient_geterror(struct HTTPClient* const client) { return &client->error; } -CURL* m3u8httpclient_getclient(struct M3U8HTTPClient* const client) { +CURL* httpclient_getclient(struct HTTPClient* const client) { return client->curl; } -int m3u8httpclient_retryable(CURL* const curl, const CURLcode code) { +int httpclient_retryable(CURL* const curl, const CURLcode code) { switch (code) { case CURLE_HTTP_RETURNED_ERROR: { @@ -199,7 +199,7 @@ int m3u8httpclient_retryable(CURL* const curl, const CURLcode code) { } -int m3u8httpclient_perform(struct M3U8HTTPClient* const client) { +int httpclient_perform(struct HTTPClient* const client) { int err = M3U8ERR_SUCCESS; int retryable = 0; @@ -213,7 +213,7 @@ int m3u8httpclient_perform(struct M3U8HTTPClient* const client) { break; } - retryable = m3u8httpclient_retryable(client->curl, client->error.code); + retryable = httpclient_retryable(client->curl, client->error.code); if (!retryable) { break; @@ -233,7 +233,7 @@ int m3u8httpclient_perform(struct M3U8HTTPClient* const client) { } -int m3u8mhttpclient_init(struct M3U8MultiHTTPClient* const client, const size_t concurrency) { +int multihttpclient_init(struct MultiHTTPClient* const client, const size_t concurrency) { int err = M3U8ERR_SUCCESS; CURLMcode code = CURLM_OK; @@ -292,14 +292,14 @@ int m3u8mhttpclient_init(struct M3U8MultiHTTPClient* const client, const size_t end:; if (err != M3U8ERR_SUCCESS) { - m3u8mhttpclient_free(client); + multihttpclient_free(client); } return err; } -void m3u8mhttpclient_free(struct M3U8MultiHTTPClient* const client) { +void multihttpclient_free(struct MultiHTTPClient* const client) { curl_multi_cleanup(client->curl_multi); client->curl_multi = NULL; diff --git a/src/httpclient.h b/src/httpclient.h new file mode 100644 index 0000000..95653ff --- /dev/null +++ b/src/httpclient.h @@ -0,0 +1,36 @@ +#if !defined(HTTPCLIENT_H) +#define HTTPCLIENT_H + +#include + +struct HTTPClientError { + CURLcode code; + char* message; +}; + +struct HTTPClient { + CURL* curl; + struct HTTPClientError error; + size_t retry; +}; + +struct MultiHTTPClient { + CURLM* curl_multi; + CURLSH* curl_share; +}; + +int httpclient_init(struct HTTPClient* const client); + +void httpclient_error_free(struct HTTPClientError* const error); +void httpclient_free(struct HTTPClient* const client); + +struct HTTPClientError* httpclient_geterror(struct HTTPClient* const client); +CURL* httpclient_getclient(struct HTTPClient* const client); + +int httpclient_retryable(CURL* const curl, const CURLcode code); +int httpclient_perform(struct HTTPClient* const client); + +int multihttpclient_init(struct MultiHTTPClient* const client, const size_t concurrency); +void multihttpclient_free(struct MultiHTTPClient* const client); + +#endif diff --git a/src/m3u8.c b/src/m3u8.c index 5971abb..7ab949d 100644 --- a/src/m3u8.c +++ b/src/m3u8.c @@ -12,7 +12,7 @@ #include "fstream.h" #include "filesystem.h" #include "readlines.h" -#include "m3u8httpclient.h" +#include "httpclient.h" #include "hex.h" #include "sutils.h" #include "guess_uri.h" @@ -2759,8 +2759,8 @@ void m3u8playlist_free(struct M3U8Playlist* const playlist) { playlist->suburi.uri = NULL; if (!playlist->subresource) { - m3u8httpclient_free(&playlist->client); - m3u8mhttpclient_free(&playlist->multi_client); + httpclient_free(&playlist->client); + multihttpclient_free(&playlist->multi_client); } playlist->subresource = 0; @@ -3599,16 +3599,6 @@ int m3u8_dump_file( } -const struct M3U8BaseURI* m3u8playlist_geturi(const struct M3U8Playlist* const playlist) { - /* - Get the base URI of the M3U8 playlist. - */ - - const struct M3U8BaseURI* const base_uri = (playlist->suburi.uri == NULL) ? &playlist->uri : &playlist->suburi; - return base_uri; - -} - static int m3u8playlist_seturi( struct M3U8Playlist* const playlist, const enum M3U8BaseURIType type, @@ -3824,13 +3814,13 @@ int m3u8playlist_load_url( buffer[0] = '\0'; - err = m3u8httpclient_init(&playlist->client); + err = httpclient_init(&playlist->client); if (err != M3U8ERR_SUCCESS) { goto end; } - curl = m3u8httpclient_getclient(&playlist->client); + curl = httpclient_getclient(&playlist->client); code = curl_easy_setopt(curl, CURLOPT_URL, url); @@ -3853,7 +3843,7 @@ int m3u8playlist_load_url( goto end; } - err = m3u8httpclient_perform(&playlist->client); + err = httpclient_perform(&playlist->client); if (err != M3U8ERR_SUCCESS) { goto end; diff --git a/src/m3u8.h b/src/m3u8.h index 04832a1..a0eff94 100644 --- a/src/m3u8.h +++ b/src/m3u8.h @@ -60,8 +60,6 @@ struct M3U8Tag* m3u8playlist_igettag( enum M3U8TagType type ); -const struct M3U8BaseURI* m3u8playlist_geturi(const struct M3U8Playlist* const playlist); - int m3u8playlist_tagexists( const struct M3U8Playlist* const playlist, enum M3U8TagType type @@ -115,3 +113,7 @@ int m3u8_dump_file( const struct M3U8Playlist* const playlist, const char* const filename ); + +#define m3u8playlist_geturi(playlist) (((playlist)->suburi.uri == NULL) ? &(playlist)->uri : &(playlist)->suburi) +#define m3u8playlist_getclient(playlist) (&(playlist)->client) +#define m3u8playlist_get_mclient(playlist) (&(playlist)->multi_client) diff --git a/src/m3u8download.c b/src/m3u8download.c index 53a6d37..d1c858e 100644 --- a/src/m3u8download.c +++ b/src/m3u8download.c @@ -8,22 +8,15 @@ #include "m3u8stream.h" #include "errors.h" #include "fstream.h" -#include "m3u8httpclient.h" +#include "httpclient.h" #include "pathsep.h" #include "biggestint.h" #include "m3u8download.h" #include "m3u8utils.h" #include "sutils.h" -struct M3U8Download { - char* filename; - struct FStream* stream; - CURL* curl; - struct M3U8StreamItem* item; - size_t retries; - struct M3U8HTTPClientError error; - int copy; -}; +static const char FILE_SCHEME[] = "file://"; +static const char BINARY_FILE_EXTENSION[] = ".bin"; void m3u8download_free(struct M3U8Download* const download) { @@ -39,7 +32,7 @@ void m3u8download_free(struct M3U8Download* const download) { fstream_close(download->stream); download->stream = NULL; - m3u8httpclient_errfree(&download->error); + httpclient_error_free(&download->error); } @@ -93,8 +86,8 @@ size_t curl_write_file_cb(char* ptr, size_t size, size_t nmemb, void* userdata) static int m3u8download_addqueue( struct M3U8DownloadQueue* const queue, - struct M3U8Stream* const root, - struct M3U8Stream* const resource, + struct M3U8Stream* const stream, + struct M3U8Stream* const substream, const char* const temporary_directory, const char* const uri, const struct M3U8ByteRange byterange, @@ -113,9 +106,21 @@ static int m3u8download_addqueue( struct M3U8Download source = {0}; struct M3U8Download* destination = &queue->items[queue->offset]; + struct M3U8Playlist* playlist = m3u8stream_getplaylist(stream); + struct M3U8Playlist* subplaylist = m3u8stream_getplaylist(substream); + + struct HTTPClient* client = m3u8playlist_getclient(playlist); + struct MultiHTTPClient* multi_client = m3u8playlist_get_mclient(playlist); + + const struct M3U8BaseURI* const base_uri = m3u8playlist_geturi(subplaylist); + source.item = item; - err = m3u8uri_resolve(&resource->playlist.uri, uri, &resolved_uri); + err = m3u8uri_resolve( + base_uri, + uri, + &resolved_uri + ); if (err != M3U8ERR_SUCCESS) { goto end; @@ -124,15 +129,15 @@ static int m3u8download_addqueue( /* Prepend the scheme "file://" for local files, otherwise curl will fail to parse it. */ - if (resource->playlist.uri.type == M3U8_BASE_URI_TYPE_LOCAL_FILE) { - char* new_resolved_uri = malloc(7 + strlen(resolved_uri) + 1); + if (base_uri->type == M3U8_BASE_URI_TYPE_LOCAL_FILE) { + char* new_resolved_uri = malloc(strlen(FILE_SCHEME) + strlen(resolved_uri) + 1); if (new_resolved_uri == NULL) { err = M3U8ERR_MEMORY_ALLOCATE_FAILURE; goto end; } - strcpy(new_resolved_uri, "file://"); + strcpy(new_resolved_uri, FILE_SCHEME); strcat(new_resolved_uri, resolved_uri); free(resolved_uri); @@ -175,7 +180,7 @@ static int m3u8download_addqueue( goto end; } - source.filename = malloc(strlen(temporary_directory) + strlen(PATHSEP) + uintptrlen((uintptr_t) uri) + 1 + 3 + 1); + source.filename = malloc(strlen(temporary_directory) + strlen(PATHSEP) + uintptrlen((uintptr_t) uri) + strlen(BINARY_FILE_EXTENSION) + 1); if (source.filename == NULL) { err = M3U8ERR_MEMORY_ALLOCATE_FAILURE; @@ -196,9 +201,9 @@ static int m3u8download_addqueue( goto end; } - strcat(source.filename, ".bin"); + strcat(source.filename, BINARY_FILE_EXTENSION); - source.curl = curl_easy_duphandle(root->playlist.client.curl); + source.curl = curl_easy_duphandle(client->curl); if (source.curl == NULL) { err = M3U8ERR_CURL_INIT_FAILURE; @@ -226,7 +231,7 @@ static int m3u8download_addqueue( goto end; } - code = curl_easy_setopt(source.curl, CURLOPT_REFERER, resource->playlist.uri.uri); + code = curl_easy_setopt(source.curl, CURLOPT_REFERER, base_uri->uri); if (code != CURLE_OK) { err = M3U8ERR_CURL_SETOPT_FAILURE; @@ -254,7 +259,7 @@ static int m3u8download_addqueue( goto end; } - code = curl_easy_setopt(source.curl, CURLOPT_SHARE, root->playlist.multi_client.curl_share); + code = curl_easy_setopt(source.curl, CURLOPT_SHARE, multi_client->curl_share); if (code != CURLE_OK) { err = M3U8ERR_CURL_SETOPT_FAILURE; @@ -312,7 +317,7 @@ static int m3u8download_addqueue( static int m3u8download_pollqueue( struct M3U8DownloadQueue* const queue, - struct M3U8Stream* const root, + struct M3U8Stream* const stream, const struct M3U8DownloadOptions* const options ) { @@ -329,7 +334,14 @@ static int m3u8download_pollqueue( struct M3U8Download* download = NULL; - CURLM* curl_multi = root->playlist.multi_client.curl_multi; + struct M3U8Playlist* playlist = m3u8stream_getplaylist(stream); + + struct HTTPClient* client = m3u8playlist_getclient(playlist); + struct MultiHTTPClient* multi_client = m3u8playlist_get_mclient(playlist); + + struct HTTPClientError* const error = httpclient_geterror(client); + + CURLM* curl_multi = multi_client->curl_multi; for (index = 0; index < queue->offset; index++) { struct M3U8Download* const download = &queue->items[index]; @@ -369,7 +381,7 @@ static int m3u8download_pollqueue( goto end; } - while ((msg = curl_multi_info_read(curl_multi, &left))) { + while ((msg = curl_multi_info_read(curl_multi, &left)) != NULL) { if (msg->msg != CURLMSG_DONE) { continue; } @@ -393,15 +405,14 @@ static int m3u8download_pollqueue( } if (msg->data.result != CURLE_OK) { - const int retryable = m3u8httpclient_retryable(msg->easy_handle, msg->data.result); + const int retryable = httpclient_retryable(msg->easy_handle, msg->data.result); if (download->retries++ > options->retry || !retryable) { - struct M3U8HTTPClientError* const error = m3u8httpclient_geterror(&root->playlist.client); - + /* Propagate the error to the main HTTP client so that we can retrieve it later */ strcpy(error->message, download->error.message); error->code = msg->data.result; - if (root->playlist.client.error.message[0] == '\0') { + if (error->message[0] == '\0') { const char* const message = curl_easy_strerror(error->code); strcpy(error->message, message); } @@ -411,6 +422,10 @@ static int m3u8download_pollqueue( } if (download->stream != NULL) { + /* + The download failed, but it is still retryable. Let's try again after + discarding any partially downloaded data. + */ const int status = fstream_seek(download->stream, 0, FSTREAM_SEEK_BEGIN); if (status == -1) { @@ -470,7 +485,7 @@ int m3u8stream_download( goto end; } - err = m3u8mhttpclient_init(&root->playlist.multi_client, options->concurrency); + err = multihttpclient_init(&root->playlist.multi_client, options->concurrency); if (err != M3U8ERR_SUCCESS) { goto end; diff --git a/src/m3u8download.h b/src/m3u8download.h index bb63483..331be9e 100644 --- a/src/m3u8download.h +++ b/src/m3u8download.h @@ -3,7 +3,21 @@ #include +#include + +#include "httpclient.h" #include "m3u8stream.h" +#include "fstream.h" + +struct M3U8Download { + CURL* curl; + char* filename; + struct FStream* stream; + struct M3U8StreamItem* item; + struct HTTPClientError error; + size_t retries; + int copy; +}; struct M3U8DownloadOptions { size_t concurrency; diff --git a/src/m3u8httpclient.h b/src/m3u8httpclient.h deleted file mode 100644 index 3caf6cd..0000000 --- a/src/m3u8httpclient.h +++ /dev/null @@ -1,36 +0,0 @@ -#if !defined(M3U8HTTPCLIENT_H) -#define M3U8HTTPCLIENT_H - -#include - -struct M3U8HTTPClientError { - CURLcode code; - char* message; -}; - -struct M3U8HTTPClient { - CURL* curl; - struct M3U8HTTPClientError error; - size_t retry; -}; - -struct M3U8MultiHTTPClient { - CURLM* curl_multi; - CURLSH* curl_share; -}; - -int m3u8httpclient_init(struct M3U8HTTPClient* const client); - -void m3u8httpclient_errfree(struct M3U8HTTPClientError* const error); -void m3u8httpclient_free(struct M3U8HTTPClient* const client); - -struct M3U8HTTPClientError* m3u8httpclient_geterror(struct M3U8HTTPClient* const client); -CURL* m3u8httpclient_getclient(struct M3U8HTTPClient* const client); - -int m3u8httpclient_retryable(CURL* const curl, const CURLcode code); -int m3u8httpclient_perform(struct M3U8HTTPClient* const client); - -int m3u8mhttpclient_init(struct M3U8MultiHTTPClient* const client, const size_t concurrency); -void m3u8mhttpclient_free(struct M3U8MultiHTTPClient* const client); - -#endif diff --git a/src/m3u8stream.h b/src/m3u8stream.h index 17e9a2e..c91edd0 100644 --- a/src/m3u8stream.h +++ b/src/m3u8stream.h @@ -319,4 +319,6 @@ const char* m3u8em_stringify(const enum M3U8EncryptionMethod value); const char* m3u8cc_stringify(const enum M3U8ClosedCaption value); const char* m3u8media_stringify(const enum M3U8MediaType value); +#define m3u8stream_getplaylist(stream) (&stream->playlist) + #endif diff --git a/src/m3u8types.h b/src/m3u8types.h index 2c18212..e6bba1b 100644 --- a/src/m3u8types.h +++ b/src/m3u8types.h @@ -4,7 +4,7 @@ #include #include "biggestint.h" -#include "m3u8httpclient.h" +#include "httpclient.h" enum M3U8VTagType { /* @@ -272,8 +272,8 @@ struct M3U8Playlist { struct M3U8Tags tags; struct M3U8BaseURI uri; struct M3U8BaseURI suburi; - struct M3U8HTTPClient client; - struct M3U8MultiHTTPClient multi_client; + struct HTTPClient client; + struct MultiHTTPClient multi_client; int livestream; int subresource; }; diff --git a/src/main.c b/src/main.c index b5f5fb6..541d0e6 100644 --- a/src/main.c +++ b/src/main.c @@ -11,7 +11,7 @@ #include "m3u8types.h" #include "m3u8utils.h" #include "m3u8download.h" -#include "m3u8httpclient.h" +#include "httpclient.h" #include "errors.h" #include "m3u8.h" #include "pathsep.h" @@ -123,8 +123,8 @@ int main(int argc, argv_t* argv[]) { thread_t thread = {0}; int status = 1; - struct M3U8HTTPClient* client = NULL; - struct M3U8HTTPClientError* cerror = NULL; + struct HTTPClient* client = NULL; + struct HTTPClientError* cerror = NULL; struct M3U8Stream stream = {0}; @@ -187,13 +187,13 @@ int main(int argc, argv_t* argv[]) { client = &stream.playlist.client; - err = m3u8httpclient_init(client); + err = httpclient_init(client); if (err != M3U8ERR_SUCCESS) { goto end; } - cerror = m3u8httpclient_geterror(client); + cerror = httpclient_geterror(client); err = clioptions_parse(&options, &argparser, &argument, client); @@ -217,7 +217,7 @@ int main(int argc, argv_t* argv[]) { } if (!options.disable_cookies) { - err = m3u8mhttpclient_init(&stream.playlist.multi_client, options.download_options.concurrency); + err = multihttpclient_init(&stream.playlist.multi_client, options.download_options.concurrency); if (err != M3U8ERR_SUCCESS) { goto end; @@ -751,7 +751,7 @@ int main(int argc, argv_t* argv[]) { m3u8stream_free(&stream); m3u8ds_free(&downloaded_streams); argparser_free(&argparser); - m3u8httpclient_errfree(cerror); + httpclient_error_free(cerror); free(name); free(temporary_file);