//<METADATA>
//##Name=youtube.com
//##Version=1
//##RegExp=https?://.*youtube\.com/(?:#)?watch\?v=.+
//##Country=[-];CN
//<!METADATA>
var idPattern = /youtu\.be\/([^\/]+)/;
var idPattern2 = /youtube\.com\/embed\/([^\/?]+)/;
var idPattern3 = /youtube\.com\/v\/([^\/?]+)/;
var idPattern4 = /youtube\.com\/(?:#\/)?watch\?v=([^\/?]+)/;
var playerConfigPattern = /ytplayer\.config\s*=\s*([^\n]+\});ytplayer/;
var playerConfigPattern2 = /ytplayer\.config\s*=\s*([^\n]+?\});/;
var cacheTime = 3600000; //1小时过期

var API = 'https://www.youtube.com/get_video_info?video_id=';
var PAGE = 'https://www.youtube.com/watch?v=';

var STEAM_TABLE = [
    {'itag': '38', 'type': 'MP4', 'name': '4K'},

    {'itag': '46', 'type': 'WebM', 'name': 'FHD'},
    {'itag': '37', 'type': 'MP4', 'name': 'FHD'},

    {'itag': '45', 'type': 'WebM', 'name': 'SHD'},
    {'itag': '22', 'type': 'MP4', 'name': 'SHD'},
    {'itag': '120', 'type': 'FLV', 'name': 'SHD'},

    {'itag': '44', 'type': 'WebM', 'name': 'HD'},
    {'itag': '35', 'type': 'FLV', 'name': 'HD'},

    {'itag': '43', 'type': 'WebM', 'name': 'SD'},
    {'itag': '34', 'type': 'FLV', 'name': 'SD'},
    {'itag': '18', 'type': 'MP4', 'name': 'SD'},

    {'itag': '5', 'type': 'FLV', 'name': 'SPEED'},
    {'itag': '36', 'type': '3GP', 'name': 'SPEED'},
    ];

function getVid(url) {
    if (idPattern.exec(url)) {
        return RegExp.$1;
    }

    if (idPattern2.exec(url)) {
        return RegExp.$1;
    }

    if (idPattern3.exec(url)) {
        return RegExp.$1;
    }

    if (idPattern4.exec(url)) {
        return RegExp.$1;
    }
}

function parseStream(mapString) {
    var strArray = mapString.split(',');
    var streamArray = [];

    for (var i=0; i<strArray.length; i ++) {
        var tmp = strArray[i];
        var tmpArray = tmp.split('&');
        if (tmpArray.length > 0) {
            var json = {};
            for (var j=0; j<tmpArray.length; j++) {
                var t = tmpArray[j];
                json[t.slice(0, t.indexOf('='))] = decodeURIComponent(t.slice(t.indexOf('=') + 1));
            }
            streamArray.push(json);
        }
    }

    return streamArray;
}

function getQueryString(name, data) {
    var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
    var r = data.match(reg);
    if (r) {
        return decodeURIComponent(r[2]);
    }
}

function getInfo(vid) {

    var httpData = parserJs.httpGet(API + vid, null);

    var videoInfo = {};
    var status;
    var streamsMap;
    var paygated;
    var error;
    var useCipherSignature;

    var tmpQs = getQueryString('title', httpData);

    if (tmpQs) {
        videoInfo['title'] = tmpQs;
    }

    tmpQs = getQueryString('thumbnail_url', httpData);
    if (tmpQs) {
        videoInfo['thumb'] = tmpQs;
    } else {
        tmpQs = getQueryString('iurl', httpData);
         if (tmpQs) {
             videoInfo['thumb'] = tmpQs;
         }
    }

    tmpQs = getQueryString('use_cipher_signature', httpData);
    if (tmpQs) {
        useCipherSignature = tmpQs;
    }

    tmpQs = getQueryString('length_seconds', httpData);
    if (tmpQs) {
        videoInfo['duration'] = tmpQs;
    }

    tmpQs = getQueryString('status', httpData);
    if (tmpQs) {
        status = tmpQs;
    }

    tmpQs = getQueryString('paygated', httpData);
    if (tmpQs) {
        paygated = tmpQs;
    }

    tmpQs = getQueryString('errorcode', httpData);
    if (tmpQs) {
        error = tmpQs;
    }

    tmpQs = getQueryString('url_encoded_fmt_stream_map', httpData);
    if (tmpQs) {
        streamsMap = tmpQs;
    }

    if ('1' == paygated) {
        videoInfo['error'] = 'pay';
        return videoInfo;
    }


    if (status == 'ok' && 'true' != useCipherSignature) {
        videoInfo['streams'] = parseStream(streamsMap);
        return videoInfo;
    } else if ((status == 'ok' && 'true' == useCipherSignature) || '150' == error) {
        var page = PAGE + vid;
        httpData = parserJs.httpGet(page, null);
        var pattern = playerConfigPattern;
        if ('150' == error) {
            pattern = playerConfigPattern2;
        }

        if (pattern.exec(httpData)) {
            var playerConfigString = RegExp.$1;
            var playJsonObject = JSON.parse(playerConfigString);
            var argsJsonObject = playJsonObject['args'];

            if ('title' in argsJsonObject) {
                videoInfo['title'] = argsJsonObject['title'];
                videoInfo['duration'] = argsJsonObject['length_seconds'];
                videoInfo['thumb'] = argsJsonObject['thumbnail_url'];
                videoInfo['html5Player'] = 'https://www.youtube.com' + playJsonObject['assets']['js'];
                videoInfo['streams'] = parseStream(argsJsonObject['url_encoded_fmt_stream_map']);
//                parserJs.log(0, JSON.stringify(videoInfo['streams']));
                return videoInfo;
            }
        }

        videoInfo['error'] = 'unknown';
        return videoInfo;
    }

}

function findDefinition(itag) {
    for (var i in STEAM_TABLE) {
        var def = STEAM_TABLE[i];
        if (itag == def['itag']) {
        return def;
        }
    }
}

function getVideoInfo(url) {
    try{
        var vid = getVid(url);
        if (!vid) {
            parserJs.log(0, "can;t get vid");
        } else {
            parserJs.log(0, "vid is " + vid);

            var info = getInfo(vid);

            if ('error' in info) {
                return info;
            }

            var streams = info['streams'];

            var outStreams = [];
            for(var i in streams) {
                var stream = streams[i];
                var def = findDefinition(stream['itag']);

                if (def) {
                    stream['name'] = def['name'];
                    stream['type'] = def['type'];
                    stream['stream_id'] = def['itag'];
                    outStreams.push(stream);
                }
            }

            info['streams'] = outStreams;
            info['vid'] = vid;
            info['url'] = url;
            info['expired'] = new Date().getTime() + cacheTime;
            return info;

        }
    }catch(err) {
        parserJs.log(0, "err " + err);
    }finally{
    }
}

function getSigFunction(jsUrl) {
    var jsData = parserJs.httpGet(jsUrl, null);
    jsData = jsData.replace(/\n/g, ' ');
    var pattern = /"signature",([$\w]+)\(\w+\.\w+\)/;
    if (pattern.exec(jsData)) {
        var f1 = RegExp.$1;
        var f1def;
        var f3;
        var f3def;
        var tmp = 'function\\s' + f1 + '(\\(\\w+\\)\\{[^\\{]+\\})';

        pattern = new RegExp(tmp);

        if (pattern.exec(jsData)) {
            f1def = RegExp.$1;
        } else {
            tmp = '\\W' + f1 + '=function(\\(\\w+\\)\\{[^\\{]+\\})';
            pattern = new RegExp(tmp);
            if (pattern.exec(jsData)){
                f1def = RegExp.$1;
            }
        }

        if (f1def) {
            f1def = 'function ' + f1 + f1def;
            pattern = /split.*;(\w+)\./;
            if (pattern.exec(f1def)) {
                f3 = RegExp.$1;
            }

            if (f3) {
                tmp = '(var\\s*' + f3 + '\\s*=\\s*\\{.+?\\}\\};)';
                pattern = new RegExp(tmp);
                if (pattern.exec(jsData)) {
                    f3def = RegExp.$1;
                    return [f3def + ' ' + f1def, f1];
                }
            }

        }
    }
}

function getVideoUrl(vinfo, stream_id) {
    try{
        var segInfos = [];

        var streams = vinfo['streams'];
        for (var i in streams) {
            var stream = streams[i];
            if (stream_id == stream['stream_id']) {
                var trueUrl = stream['url'];
                if ('sig' in stream) {
                    trueUrl = trueUrl + '&signature=' + stream['sig'];
                } else if ('s' in stream) {
                    if ('html5Player' in vinfo) {
                        var js = getSigFunction(vinfo['html5Player']);
                        if (js) {
                            var sig = eval(js['0'] + ';' + js['1'] + '(\'' + stream['s'] + '\');')
                            trueUrl = trueUrl + '&signature=' + sig;
                        }
                    }
                }

                var seg = {};
                seg['url'] = trueUrl;
                seg['du'] = vinfo['duration'];

                segInfos.push(seg);

                var playJson = {};
                playJson['segs'] = segInfos;
                playJson['expired'] = new Date().getTime() + cacheTime;
                playJson['stream_id'] = stream_id;
                //playJson['size'] = 0;
                //playJson['m3u8'] = '';
                //playJson['headers'] = {};
                return playJson;
            }
        }

    }catch(err) {
        parserJs.log(0, "err " + err);
    }finally {
    }
}