zoukankan      html  css  js  c++  java
  • hls 直播视频下载器

    -----------------------------------------------------------------------------------
    #include <curl/curl.h>
    #include <string>
    #include <iostream>
    #include <unistd.h>
    #include <stdio.h>
    #include <conio.h>
    #include <regex>
    #include <iterator>
    #include <io.h>
    #include <fstream>
    #include <getopt.h>
    #include <list>
    
    using namespace std;
    
    static char m3u8[1024];
    static char g_useragent[1024];
    static char g_proxy[100];
    static char g_maxlen[50];
    static double g_maxduration = 0.0;
    //static size_t totalsize = 0;
    static unsigned long long int totalsize = 0;
    static char strtotalsize[100];
    
    static string baseurl;
    static int isDEBUG = 0;
    
    static list<pthread_t>listpthreads;
    
    void putmsg(const char * msg)
    {
        if (!msg) return;
        FILE * m3u8h = fopen(m3u8, "ab+");
        if (m3u8h) {
            fwrite(msg, 1, strlen(msg), m3u8h);
            fwrite("
    ", 1, 2, m3u8h);
            fclose(m3u8h);
        }
    }
    
    typedef struct targ {
        char url[1024];
        char fn[1024];
    } targ;
    
    size_t writeFunction(void *ptr, size_t size, size_t nmemb, string* data) {
        data->append((char*) ptr, size * nmemb);
        return size * nmemb;
    }
    size_t writeFunction2(void *ptr, size_t size, size_t nmemb, string* data) {
        data->append((char*) ptr, size * nmemb);
        return size * nmemb;
    }
    static void deleteNode(pthread_t tid)
    {
        list<pthread_t>::iterator it;
        for (it = listpthreads.begin(); it != listpthreads.end(); it++)
        {
            if (tid == *it)
            {
                listpthreads.erase(it);
            }
        }
    }
    
    static void waitThreads()
    {
        list<pthread_t>::iterator it;
        cout << "Waiting for the end of download threads" << endl;
        for (it = listpthreads.begin(); it != listpthreads.end(); it++)
        {
            //cout << "      thread ID " << *it << endl;
            pthread_join(*it, NULL);
        }
    }
    
    static void * downts(void *arg)
    {
        targ *ta= (targ *)arg;
        string fullurl = ta->url;;
        string fn = ta->fn;
        
        //cout << fn << endl;
        auto curl = curl_easy_init();
        if (curl) {
            curl_easy_setopt(curl, CURLOPT_URL, fullurl.c_str());
            curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
            //curl_easy_setopt(curl, CURLOPT_USERPWD, "user:pass");
            curl_easy_setopt(curl, CURLOPT_USERAGENT, g_useragent);
            curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L);
            curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
            curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 10000L);
            if(strlen(g_proxy)>0)
                curl_easy_setopt(curl, CURLOPT_PROXY, g_proxy);
            string response_string;
            string header_string;
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunction2);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA,  & response_string);
            curl_easy_setopt(curl, CURLOPT_HEADERDATA,  & header_string);
    
            char * url;
            long response_code;
            double elapsed;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE,  & response_code);
            curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME,  & elapsed);
            curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL,  & url);
    
            CURLcode res = curl_easy_perform(curl);
            if (res != CURLE_OK)
            {
                if(isDEBUG) fprintf(stderr, "thread curl_easy_perform() failed: %s
    ", curl_easy_strerror(res));
                if(isDEBUG) cout << "pthread remove " << fn << endl;
                cout << "*** failed [" << fn << "] ***" <<endl;
                remove(fn.c_str());
            }
            else
            {
                if(isDEBUG) cout << "thread response_code " << response_code << endl;
                if(isDEBUG) cout << "thread response_string size " << response_string.size() << endl;
                //cout << "elapsed       " << elapsed << endl;
                //cout << "effective url " << url << endl;
                //cout << "response_string 
    " << response_string << endl;
                //cout << "header_string 
    " << header_string << endl;
                if( response_string.size() > 0 )
                {
                    //cout << fn << endl;
                    FILE *tsh = fopen(fn.c_str(), "wb");
                    if(tsh)
                    {
                        fwrite(response_string.c_str(), 1, response_string.size(), tsh);
                        fclose(tsh);
                    }
                    totalsize += response_string.size();
                    if(totalsize<1024)                sprintf(strtotalsize,"%10ld    ", totalsize);
                    else if(totalsize<1024*1024)      sprintf(strtotalsize,"%10.03f KB", (double)totalsize/1024);
                    else if(totalsize<1024*1024*1024) sprintf(strtotalsize,"%10.03f MB", (double)totalsize/1024/1024);
                    else                              sprintf(strtotalsize,"%10.03f GB", (double)totalsize/1024/1024/1024);
                }
                else
                {
                    cout << "*** response error [" << fn << "] ***" <<endl;
                    remove(fn.c_str());
                }
            }
        }
        curl_easy_cleanup(curl);
        curl = NULL;
        if(isDEBUG) cout << "pthread exit" << endl;
        deleteNode(pthread_self());
        pthread_exit(NULL);
        return NULL;    
    }
    
    string getbaseurl(string url)
    {
        string text=url;
        string pattern = "((.*)/)";
        regex express(pattern);
        regex_iterator<string::const_iterator> begin(text.cbegin(), text.cend(), express);
        for (auto iter = begin; iter != sregex_iterator(); iter++)
        {
            //cout << iter->str() << endl;
            return iter->str();
        }
    }
    
    string getindex(string text)
    {
        string ret = "";
        string pattern = "([0-9]{1,15})";
        regex express(pattern);
        regex_iterator<string::const_iterator> begin(text.cbegin(), text.cend(), express);
        for (auto iter = begin; iter != sregex_iterator(); iter++)
        {
            ret = iter->str();
        }
        if (ret == "" || ret.size() <= 0 ) return text;
        return ret;
    }
    
    static double duration = 0.0;
    static char strduration[100];
    static unsigned int dlidx = 1;
    static int isMAX = 0;
    double getlen(string text)
    {
        double rd = 0.0;
        string ret = "";
        string pattern = "([0-9.]{1,8})";
        regex express(pattern);
        regex_iterator<string::const_iterator> begin(text.cbegin(), text.cend(), express);
        for (auto iter = begin; iter != sregex_iterator(); iter++)
        {
            ret = iter->str();
        }
        if (ret == "" || ret.size() <= 0 ) return 0.0;
        rd = atof(ret.c_str());
        duration = duration + rd;
        
        int dhh=(unsigned int)(duration/3600);
        int dmm=(unsigned int)(duration)%3600/60;
        int dss=(unsigned int)(duration)%3600%60;
        int dms=(unsigned int)(duration*1000)%1000;
        sprintf(strduration,"%4d %5.03f %02d:%02d:%02d.%03d",
            dlidx, rd, dhh, dmm, dss, dms);
        dlidx++;
        if(g_maxduration != 0.0 && duration >= g_maxduration)
            isMAX = 1;
        return rd;
    }
    
    void string_replace( string &strBig, const string &strsrc, const string &strdst)
    {
        string::size_type pos = 0;
        string::size_type srclen = strsrc.size();
        string::size_type dstlen = strdst.size();
    
        while( (pos=strBig.find(strsrc, pos)) != string::npos )
        {
            strBig.replace( pos, srclen, strdst );
            pos += dstlen;
        }
    }
    
    static unsigned int dlcount = 0;
    static unsigned int firstdl = 0;
    static unsigned int dladdcount = 0;
    static unsigned int checknodowncount = 0;
    
    void gettsurl(string str)
    {
        string fullurl;
        string text=str;
        if(dlcount==0)
        {
            string pattern = "(#EXT-X(.*)|#EXTM3U)";
            regex express(pattern);
            regex_iterator<string::const_iterator> begin(text.cbegin(), text.cend(), express);
            for (auto iter = begin; iter != sregex_iterator(); iter++)
            {
                cout << iter->str() << endl;
                putmsg(iter->str().c_str());
            }
        }
        //string pattern = "((.*).ts)";
        string pattern = "(#EXTINF:(.*)|(.*).ts)";
        regex express(pattern);
        regex_iterator<string::const_iterator> begin(text.cbegin(), text.cend(), express);
        string extinfo;
    
        for (auto iter = begin; iter != sregex_iterator(); iter++)
        {
            fullurl = baseurl + iter->str();
            //cout << fullurl << endl;
            //cout << iter->str() << endl;
            //downts(fullurl, iter->str());
            if( iter->str().substr(0,1) == "#" )
            {
                extinfo = iter->str();
            }
            else 
            {
                string newfn = getindex(iter->str());
                string_replace(newfn, "/", "-");
                
                if(newfn.size()<=4)
                {
                    char tmp[50];
                    sprintf(tmp, "%05d", atoi(newfn.c_str()));
                    newfn = tmp;
                }
                newfn = newfn + ".ts";
                
                if (access(newfn.c_str(), 0)) {
                    getlen(extinfo);
                    cout << " " << strduration << " " << strtotalsize << " " << newfn << endl;
                    //cout << newfn << endl;
                    putmsg(extinfo.c_str());
                    putmsg(newfn.c_str());
                    FILE * tsh = fopen(newfn.c_str(), "wb");
                    if (tsh) {
                        fclose(tsh);
                    }
                    pthread_t thread;
                    targ ta;
                    memset( & ta, 0x00, sizeof(ta));
                    strcpy(ta.url, fullurl.c_str());
                    strcpy(ta.fn, newfn.c_str());
                    pthread_create( & thread, NULL, downts,  & ta);
                    listpthreads.push_back(thread);
                    dladdcount ++;
                }
            }
        }
        dlcount++;
    }
    
    void help()
    {
        cout << "Usage: hlslivedl [options] -i [http://...m3u8]" << endl;
        cout << "    -o set output filename" << endl;
        cout << "    -p set proxy http: https: socks4: socks4a: socks5: socks5h:" << endl;
        cout << "    -u set useragent" << endl;
        cout << "    -t set duration seconds" << endl;
        cout << "    -d debug mode" << endl;
        cout << "    Press [Q] to stop download" << endl;
        cout << "    Version 1.0.7 by NLSoft 2020.07" << endl;
    }
    
    int main(int argc, char** argv) {
        CURLcode res;
        static char urlm3u8[1024];
        memset(urlm3u8,0,1024);
        memset(g_proxy,0,100);
        memset(strduration,0,100);
        memset(strtotalsize,0,100);
        strcpy(strtotalsize, "             ");
    
        if(argc == 1)
        {
            help();
            exit(0);
        }
        strcpy(m3u8, "_index.m3u8");
        strcpy(g_useragent, "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1");
        
        int option_index = 0;
        char * user_name = NULL;
        while ((option_index = getopt(argc, argv, "p:o:u:i:t:d")) != -1) {
            switch (option_index) {
            case 'o':
                strcpy(m3u8, optarg);
                if(isDEBUG) printf("output filename is %s
    ", m3u8);
                break;
            case 'u':
                strcpy(g_useragent, optarg);
                if(isDEBUG) printf("useragent is %s
    ", g_useragent);
                break;
            case 'p':
                strcpy(g_proxy, optarg);
                if(isDEBUG) printf("proxy is %s
    ", g_proxy);
                break;
            case 'i':
                strcpy(urlm3u8, optarg);
                if(isDEBUG) printf("m3u8 url is %s
    ", urlm3u8);
                break;
            case 't':
                strcpy(g_maxlen, optarg);
                g_maxduration = atof(g_maxlen);
                if(isDEBUG) printf("g_maxlen is %s
    ", g_maxlen);
                break;
            case 'd':
                isDEBUG = 1;
                if(isDEBUG) printf("select debug mode
    ");
                break;
            }
        }
    
        if(strlen(urlm3u8)<=0)
        {
            help();
            exit(0);
        }
    
        FILE * m3u8h = fopen(m3u8, "wb");
        if (m3u8h) {
            fclose(m3u8h);
        }
    
        curl_global_init(CURL_GLOBAL_DEFAULT);    
        baseurl = getbaseurl(urlm3u8);
        if(isDEBUG) cout << baseurl << endl;
        auto curl = curl_easy_init();
        if (curl) {
            while (1) {
                dladdcount = 0;
                //curl_easy_setopt(curl, CURLOPT_URL, "https://api.github.com/repos/whoshuu/cpr/contributors?anon=true&key=value");
                curl_easy_setopt(curl, CURLOPT_URL, urlm3u8);
                curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
                //curl_easy_setopt(curl, CURLOPT_USERPWD, "user:pass");
                curl_easy_setopt(curl, CURLOPT_USERAGENT, g_useragent);
                curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L);
                curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
                curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
                curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
                curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 5000L);
                if(strlen(g_proxy)>0)
                    curl_easy_setopt(curl, CURLOPT_PROXY, g_proxy);
    
                string response_string;
                string header_string;
                curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunction);
                curl_easy_setopt(curl, CURLOPT_WRITEDATA,  & response_string);
                curl_easy_setopt(curl, CURLOPT_HEADERDATA,  & header_string);
    
                char * url;
                long response_code;
                double elapsed;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE,  & response_code);
                curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME,  & elapsed);
                curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL,  & url);
    
                res = curl_easy_perform(curl);
                if (res != CURLE_OK)
                {
                    if(isDEBUG) fprintf(stderr, "main curl_easy_perform() failed: %s
    ", curl_easy_strerror(res));
                }
                else 
                {
                    if(isDEBUG) cout << "main response_code " << response_code << endl;
                    //cout << "elapsed       " << elapsed << endl;
                    //cout << "effective url " << url << endl;
                    //cout << "response_string 
    " << response_string << endl;
                    //cout << "header_string 
    " << header_string << endl;
    
                    if( response_code == 0 ) continue;
                    if( response_code == 200 )
                    {
                        // skip first ts
                        if(firstdl != 0)
                            gettsurl(response_string);
                        firstdl ++;
                    }
                    else
                    {
                        waitThreads();
                        if(isDEBUG) cout << "#EXT-X-ENDLIST
    " << endl;
                        putmsg("#EXT-X-ENDLIST");
                        if(isDEBUG) cout << "main response_code " << response_code << "
    " << endl;
                        break;
                    };
                }
                char exitflag = '';
                if (_kbhit())
                {
                    exitflag = _getch();
                    if (exitflag == 'q' || exitflag == 'Q')
                    {
                        waitThreads();
                        if(isDEBUG) cout << "#EXT-X-ENDLIST
    " << endl;
                        putmsg("#EXT-X-ENDLIST");
                        break;
                    }
                }
                
                if(dladdcount>0) checknodowncount = 0;
                else checknodowncount ++;
                //printf("dladdcount %d checknodowncount %ld
    ", dladdcount, checknodowncount);
                
                // No files were downloaded in 60 seconds
                if(checknodowncount>=60 || isMAX)
                {
                    waitThreads();
                    if(isDEBUG) cout << "#EXT-X-ENDLIST
    " << endl;
                    putmsg("#EXT-X-ENDLIST");
                    break;
                }
                usleep(1000 * 1000);
                //sleep(1);
            }
        }
        curl_easy_cleanup(curl);
        curl = NULL;
        curl_global_cleanup();
        if(isDEBUG) cout << "main exit" << endl;
        return 0;
    }
    -----------------------------------------------------------------------------------
    echo g++ hlslivedl.cpp
    g++ -w hlslivedl.cpp -o hlslivedl.exe -DCURL_STATICLIB -ID:/MSYS/local/include -LD:/MSYS/local/lib -lcurl -lssl -lcrypto -lssl -lcrypto -lgdi32 -lwldap32 -lz -lws2_32 -lpsapi -lws2_32 -lmswsock -lshlwapi -lcrypt32 -static
    
    echo strip hlslivedl.exe
    strip hlslivedl.exe
    -----------------------------------------------------------------------------------
  • 相关阅读:
    vue开发chrome扩展,数据通过storage对象获取
    Vue手动集成less预编译器
    Google Translate寻找之旅
    Javascript Range对象的学习
    Javascript Promises学习
    SublimeText 建立构建Node js系统
    We're sorry but demo3 doesn't work properly without JavaScript enabled. Please enable it to continue.
    npm安装包出现UNMET DEPENDENCY报错
    (转载)命令行说明中格式 尖括号 中括号的含义
    Linux重启网卡服务Failed to start LSB: Bring up/down networking.
  • 原文地址:https://www.cnblogs.com/nlsoft/p/13347294.html
Copyright © 2011-2022 走看看