2018年9月


# coding: utf-8

# In[1]:


import requests
import json
import time
import hashlib
import re

# In[2]:


def getckey(vid, platform):
    tm = str(int(time.time()))
    string = "4244ce1b{}{}*#06#10201".format(vid, tm)#encryptVer=7.2
    ckey = hashlib.md5(string.encode('utf-8')).hexdigest()
    flowid = "{}_{}".format(hashlib.md5(tm.encode('utf-8')).hexdigest(), platform)
    return tm, ckey, flowid


# In[3]:


def proxyhttp(url, data):
    s = requests.Session()
    s.headers.update({"user-agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"})
    s.headers.update({"referer":url})

    cookie = "your cookie"
    c = {}
    for _ in cookie.split(';'):
        key,value = _.strip().split('=',1)
        c.update({key:value})
    requests.utils.add_dict_to_cookiejar(s.cookies,c)
    r = s.post("https://vd.l.qq.com/proxyhttp", data=data)
    return (r)


# In[4]:


def getdata(url,vid, coverid, guid, unid, sdtfrom):
    platform = ["10201"]
    tm, ckey, flowid = getckey(vid, platform[0])
    defn = ["fhd","shd","hd","sd"]
    data = {
        "buid": "onlyvinfo",
        "vinfoparam": "charge=0&defaultfmt=auto&otype=ojson&guid={}&flowid={}"
        "&platform=10201&sdtfrom=v1010&defnpayver=1&appVer=3.5.56&host=v.qq.com"
        "&ehost={}&refer=v.qq.com&sphttps=1&tm={}&spwm=4&unid={}&vid={}&defn={}"
        "&fhdswitch=1&show1080p=1&isHLS=1&onlyGetinfo=true&dtype=3&sphls=2&spgzip=1"
        "&dlver=2&defsrc=2&encryptVer=7.2&cKey={}&fp2p=1".format(guid,flowid,url,tm,unid,vid,'fhd',ckey)
    }
    return json.dumps(data)


# In[5]:


def getid(url):
    mode = [
        '.*v\.qq\.com/x/cover/(.*)\.html\?vid=(.*)',
        '.*v\.qq\.com/x/cover/(.*)/(.*)\.html',
        '.*v\.qq\.com/x/page/(.*)\.html',
    ]
    for _ in mode:
        matchres = re.match(_, url)
        if matchres == None:
            pass
        else:
            matchres = matchres.groups()
            vid = matchres[-1]
            if len(matchres) == 2:
                coverid = matchres[0]
            else:
                coverid = ""
    return vid, coverid


# In[6]:


def dl_qq(url):
    guid = "5ab01a7ab3b68b62787b5d1df507ba5c"#固定值
    unid = "1cbe987dbf1111e89d19a0424b63310a"#也是一个固定值
    sdtfrom = "v1010"
    #url = "https://v.qq.com/x/cover/y4g7p8eka7bshz3/i0544naygqq.html"
    vid, coverid = getid(url)
    # vid = "w00273lvxjp"
    # coverid = "0913mhn6zhnk66b"
    data = getdata(url, vid, coverid, guid, unid, sdtfrom)
    res = proxyhttp(url, data)
    resdict = json.loads(res.content.decode('utf-8'))
    resdict.get("errCode")
    if resdict.get("errCode") == 0:
        pass
    else:
        print(resdict.get("errCode"))
    resdict = json.loads(resdict["vinfo"])['vl']['vi'][0]
    title = re.sub('[\/:*?"<>|]','',resdict.get("ti"))
    urllist = resdict.get("ul").get("ui")
    m3u8_url = urllist[-1].get("url")
    type = "m3u8"
    if ".m3u8" in m3u8_url:
        pass
    else:
        m3u8_url = m3u8_url + urllist[-1].get("hls").get("pt")
    screensize = "{}x{}".format(resdict.get("vw"),resdict.get("vh"))
    try:
        vkey = resdict["fvkey"]
    except KeyError:
        urllist = [m3u8_url]
        print(title, screensize)
        print(m3u8_url)
    else:
        type = "list"
        urllist = []
        if len(resdict["cl"]["ci"]) == 1:
            keyid = resdict["cl"]["ci"][0]["keyid"]
            keyid = keyid.replace(".10",".p")
            directlink = "{}{}.mp4?sdtfrom={}&guid={}&vkey={}".format(m3u8_url, keyid, sdtfrom, guid, vkey)
            print(directlink)
            urllist.append(directlink)
        else:
            pass
    dlinfo = {"title":title,"url":urllist,"type":type,"referer":"https://v.qq.com"}
    print(dlinfo)
    return dlinfo
    
def main():
    url = input("请输入链接:\n")
    dl_qq(url)
        
if __name__ == "__main__":
    main()

使用CF的CDN后,发现ip地址清一色的美国,后来才想起来访客ip这回事。
实际上服务器会得到访客的真实ip,只不过typecho获取ip的方法会默认先得到cdn的ip。

按网络的方法:

https://kotori.love/archives/typecho-plugin-access.html

在typecho的config.inc.php中配置define('__TYPECHO_IP_SOURCE__', 'HTTP_CF_CONNECTING_IP');

完全OK...

如果是其他cdn,可以在主页根目录下新建info.php
内容是<?php phpinfo(); ?>

然后访问你的网址/info.php

就能看到详细信息,在PHP Variables这个部分有访问的记录

我用的是CF,有$_SERVER['HTTP_CF_CONNECTING_IP']这样的字段,同时$_SERVER['HTTP_X_FORWARDED_FOR']这个字段也是真实ip,那么就可以按前面说的那样在config.inc.php添加配置,优先通过这个地方获取ip,那么就可以正常显示访客ip了。

不过数据库中Access插件的ip对于ipv6全部为0。
看了下源代码,作者使用的是ip2long和long2ip来处理ip,这对于ipv6没法正确处理。
在Access_Core.php中可以看到如下代码:

public function long2ip($long) {
    if ($long < 0 || $long > 4294967295) return false;
    $ip = "";
    for ($i=3;$i>=0;$i--) {
        $ip .= (int)($long / pow(256,$i));
        $long -= (int)($long / pow(256,$i))*pow(256,$i);
        if ($i>0) $ip .= ".";
    }
    return $ip;
}

long传入是ip转换后的十进制数,ipv6转换后大于4294967295,然后一系列的值就置0了。

根据官方文档,对于ipv6有人给出ip2bin和bin2ip的函数,如下:

function ip2bin($ip) 
{ 
    if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) 
        return base_convert(ip2long($ip),10,2); 
    if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) 
        return false; 
    if(($ip_n = inet_pton($ip)) === false) return false; 
    $bits = 15; // 16 x 8 bit = 128bit (ipv6) 
    while ($bits >= 0) 
    { 
        $bin = sprintf("%08b",(ord($ip_n[$bits]))); 
        $ipbin = $bin.$ipbin; 
        $bits--; 
    } 
    return $ipbin; 
} 

function bin2ip($bin) 
{ 
   if(strlen($bin) <= 32) // 32bits (ipv4) 
       return long2ip(base_convert($bin,2,10)); 
   if(strlen($bin) != 128) 
       return false; 
   $pad = 128 - strlen($bin); 
   for ($i = 1; $i <= $pad; $i++) 
   { 
       $bin = "0".$bin; 
   } 
   $bits = 0; 
   while ($bits <= 7) 
   { 
       $bin_part = substr($bin,($bits*16),16); 
       $ipv6 .= dechex(bindec($bin_part)).":"; 
       $bits++; 
   } 
   return inet_ntop(inet_pton(substr($ipv6,0,-1))); 
}

动手尝试更改了源代码,但是有些小问题,本身不懂php也不敢多折腾,暂时先不改...
tip:数据库ip的类型也需要更改。
在github的issue里面有ipv6显示正常的图,不过那里的ip的类型是varchar,目前的新版本又是int(32)。

相关链接:

https://kotori.love/archives/typecho-plugin-access.html?c
http://blog.lanyus.com/archives/323.html
https://github.com/kokororin/typecho-plugin-Access
http://php.net/manual/zh/function.ip2long.php

mysql版本

mysql Ver 15.1 Distrib 10.1.26-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2

网上很多方法都不提这个...
要先允许外部地址访问才行
更改/etc/mysql/mariadb.conf.d中的bind-address为0.0.0.0

bind-address = 0.0.0.0

其他版本可能在/etc/mysql/my.cnf里面。总之在/etc/mysql

然后就和网上的大部分教程一样了。
root登录mysql,没错-u和root时挨着的、-p也是这样。
修改root的host为%,如果是给其他用户开权限user对应换一下。
最后刷新下。

mysql -uroot -pyourpassword
use mysql;
update user set host = '%' where user = 'root';
flush privileges;

现在就可以远程连接了~