From 38202de4f953fca28aa884246ced0aadf0d25a4d Mon Sep 17 00:00:00 2001
From: dec05eba <dec05eba@protonmail.com>
Date: Fri, 25 Jun 2021 12:44:53 +0200
Subject: Add a http server proxy for better youtube downloading (bypassing
 rate limit cased by http range header). Fix youtube live streams

---
 plugins/youtube/YoutubeMediaProxy.hpp | 100 ++++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)
 create mode 100644 plugins/youtube/YoutubeMediaProxy.hpp

(limited to 'plugins/youtube')

diff --git a/plugins/youtube/YoutubeMediaProxy.hpp b/plugins/youtube/YoutubeMediaProxy.hpp
new file mode 100644
index 0000000..2d6ea93
--- /dev/null
+++ b/plugins/youtube/YoutubeMediaProxy.hpp
@@ -0,0 +1,100 @@
+#pragma once
+
+#include "../../include/Program.hpp"
+#include <string>
+
+// TODO: Sync sequence for video and audio (for live stream).
+
+namespace QuickMedia {
+    class YoutubeMediaProxy {
+    public:
+        enum Error {
+            OK,
+            ERROR
+        };
+
+        virtual ~YoutubeMediaProxy() = default;
+
+        virtual bool start(const std::string &youtube_media_url, int content_length) = 0;
+        // This should be the last call. Do not call |start| after this. TODO: Allow restarting with |start| after |stop| is called.
+        virtual void stop() = 0;
+        virtual Error update() = 0;
+        virtual bool get_address(std::string &address) = 0;
+
+        bool start_download(const std::string &media_url, ReadProgram &read_program, int range_start, bool include_header, bool is_livestream = false, int livestream_sequence = -1);
+    private:
+        int rn = 0;
+        int rbuf = 0;
+    };
+
+    class YoutubeStaticMediaProxy : public YoutubeMediaProxy {
+    public:
+        YoutubeStaticMediaProxy() = default;
+        YoutubeStaticMediaProxy(YoutubeStaticMediaProxy&) = delete;
+        YoutubeStaticMediaProxy&operator=(YoutubeStaticMediaProxy&) = delete;
+        ~YoutubeStaticMediaProxy();
+
+        bool start(const std::string &youtube_media_url, int content_length) override;
+        void stop() override;
+        Error update() override;
+        bool get_address(std::string &address) override;
+    private:
+        void on_client_disconnect();
+        Error read_client_data();
+        void clear_download_state();
+        // If |new_range_start| is not -1 then the start range is set to that
+        Error update_download_program_status(bool client_disconnected, int new_range_start = -1, bool restart_download = false);
+        Error continue_send(const char *buffer_start, size_t total_bytes_to_write, int &buffer_offset);
+        Error handle_download();
+        // Returns the client fd or -1
+        int accept_client();
+    private:
+        int socket_fd = -1;
+        int port = 0;
+        int client_fd = -1;
+        std::string youtube_media_url;
+        int content_length = 0;
+        ReadProgram downloader_read_program;
+        int download_read_buffer_offset = 0;
+        ssize_t downloader_num_read_bytes = 0;
+        int download_range_start = 0;
+        int current_download_range = 0;
+        std::string download_header;
+        bool download_header_finished = false;
+        bool download_header_sent = false;
+        bool download_header_remaining_sent = false;
+        int download_header_written_offset = 0;
+        int download_header_offset_to_end_of_header = 0;
+        bool client_request_finished = false;
+        std::string client_request_buffer;
+        char download_read_buffer[16384];
+    };
+
+    class YoutubeLiveStreamMediaProxy : public YoutubeMediaProxy {
+    public:
+        YoutubeLiveStreamMediaProxy() = default;
+        YoutubeLiveStreamMediaProxy(YoutubeLiveStreamMediaProxy&) = delete;
+        YoutubeLiveStreamMediaProxy&operator=(YoutubeLiveStreamMediaProxy&) = delete;
+        ~YoutubeLiveStreamMediaProxy();
+
+        bool start(const std::string &youtube_media_url, int content_length) override;
+        void stop() override;
+        Error update() override;
+        bool get_address(std::string &address) override;
+    private:
+        Error update_download_program_status();
+        Error continue_send(const char *buffer_start, size_t total_bytes_to_write, int &buffer_offset);
+    private:
+        ReadProgram downloader_read_program;
+        std::string youtube_media_url;
+        int fd[2];
+        int livestream_sequence_num = -1;
+        std::string download_header;
+        bool download_header_finished = false;
+        bool download_header_remaining_sent = false;
+        int download_header_written_offset = 0;
+        int download_read_buffer_offset = 0;
+        ssize_t downloader_num_read_bytes = 0;
+        char download_read_buffer[16384];
+    };
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2