挖掘视频网站【优酷】上被截断的视频的地址--002
上一篇博客(这里)寻找视频地址的时候,有些细节没有弄很清楚,这两天继续弄,发现原来路径里边的sid是个随机生成数,不需要找它。对于k值,现在的是服务器直接返回来的,而里边也有通过返回的json里边的key1计算获得: PlayListProxy.as文件里边: param1.key1 = (Number("0x" + param2.key1) ^ Number("0xA55AA5A5")).toString(16); 而关键之处是就剩下了那个fileid,这是我从它的播放器里边找到的源码: private function parseMainData(param1:PlayListData,param2:Object) : void { var _loc_5:String = null;//临时变量 var _loc_9:String = null;//临时变量 var _loc_10:String = null;//flvmp4分段视频信息 var _loc_11:Object = null;//streamfileids var _loc_12:String = null; var _loc_13:Array = null; var _loc_14:RandomProxy = null; var _loc_15:Dictionary = null;//segs里边几种视频类型的数据 var _loc_16:String = null;//视频类型 var _loc_17:int = 0;//临时变量,长度计数用 var _loc_18:String = null; var _loc_19:Array = null;//存放视频数据 var _loc_20:String = null; var _loc_21:Object = null;//临时变量 var _loc_22:VideoSegmentData = null;//视频数据:no,size.type,seconds,k值 if (param1 == null || param2 == null) { return; } param1.drm = param2.drm; param1.rtmp = param2.rtmp; param1.ct = param2.ct; param1.show = this.parseShowData(param2.show); param1.programList = this.parseProgramListData(param2.list,param2.list_pre,param2.list_next); param1.dvdinfo = this.parseDVDData(param2.dvd); param1.trial = this.pareseTrialData(param2.trial); param1.caption = this.parseCaptionData(param2.dvd); param1.threeD = this.parseThreeDData(param2.dvd); param1.tt = param2.tt; param1.ct = param2.ct; param1.cs = param2.cs; param1.logo = param2.logo; param1.seed = Number(param2.seed); param1.tags = param2.tags; param1.categories = param2.categories; param1.videoId = String(param2.videoid); param1.vidEncoded = param2.vidEncoded; param1.userName = param2.username; param1.userId = param2.userid; param1.title = unescape(param2.title); param1.key1 = (Number("0x" + param2.key1) ^ Number("0xA55AA5A5")).toString(16); param1.key2 = param2.key2; param1.seconds = Number(param2.seconds); if (param2.sourceVid != null) { param1.sourceVid = Number(param2.sourceVid); } param1.streamFileIds = param2.streamfileids; param1.segs = param2.segs; param1.streamSizes = param2.streamsizes; param1.streamTypes = param2.streamtypes; param1.error = param2.error; param1.errorlink = param2.link; param1.up = param2.up; param1.down = param2.down; if (param2.lastpoint) { param1.lastpoint = Number(param2.lastpoint); } param1.token = param2.ts ? (param2.ts) : (""); var _loc_3:* = new HashCash(); param1.hashcash = _loc_3.getHashCash(param1.token + "o"); param1.tokenup = param2.tsup ? (param2.tsup) : (""); param1.hashcashup = _loc_3.getHashCash(param1.tokenup); param1.currentLang = ""; if (param1.dvdinfo && param1.dvdinfo.audioLangs.length > 1) { _loc_17 = 0; while (_loc_17 < param1.dvdinfo.audioLangs.length) { if (param1.vidEncoded == param1.dvdinfo.audioLangs[_loc_17].vid || param1.videoId == param1.dvdinfo.audioLangs[_loc_17].vid) { param1.currentLang = param1.dvdinfo.audioLangs[_loc_17].lang; param1.currentLangID = param1.dvdinfo.audioLangs[_loc_17].langid; } _loc_17++; } } var _loc_4:Array = [];//视频类型 for (_loc_5 in param2.streamfileids) { if (!this.isValidType(_loc_5)) { continue; } _loc_4.push(_loc_5); } param1.typeArr = _loc_4; this._playListData.fileType = _loc_4[0]; if (_loc_4.length > 1) { } var _loc_6:Number = 0; var _loc_7:* = Number.MAX_VALUE; var _loc_8:* = param2.segs; for (_loc_9 in _loc_8) { if (_loc_9 == "flv" || _loc_9 == "mp4" || _loc_9 == "flvhd" || _loc_9 == "hd2" || _loc_9 == "hd3") { _loc_6 = 0; for (_loc_18 in _loc_8[_loc_9]) { _loc_6 = _loc_6 + Number(_loc_8[_loc_9][_loc_18].seconds); } if (_loc_6 < _loc_7) { _loc_7 = _loc_6; } } } param1.totalTime = _loc_7; _loc_10 = ""; _loc_11 = param2.streamfileids; for (_loc_12 in _loc_11) { if (_loc_12 == param1.fileType) { _loc_10 = _loc_11[_loc_12]; break; } } _loc_13 = []; _loc_14 = new RandomProxy(param1.seed); _loc_15 = new Dictionary(); for (_loc_16 in param2.segs) { if (!this.isValidType(_loc_16)) { continue; } _loc_19 = []; //_loc_16 -- flv //_loc_16 -- mp4 //_loc_20 -- 0,1,2,3 for (_loc_20 in param2.segs[_loc_16]) { _loc_21 = param2.segs[_loc_16][_loc_20]; _loc_22 = new VideoSegmentData(); _loc_22.no = _loc_21.no; _loc_22.size = _loc_21.size; _loc_22.seconds = _loc_21.seconds; if (_loc_21.k) { _loc_22.key = _loc_21.k; } //streamfileids,mp4/flv,i,RandomProxy(param1.seed) _loc_22.fileId = this.getFileId(_loc_11,_loc_16,int(_loc_20),_loc_14); _loc_22.type = _loc_16; _loc_19.push(_loc_22); } _loc_15[_loc_16] = _loc_19; } param1.videoSegmentsDic = _loc_15; param1.watermarks = param2.streamlogos; if (param2.hasOwnProperty("paike")) { param1.paike = param2.paike as Boolean; } else { param1.paike = false; } if (param2.hasOwnProperty("share")) { param1.share = param2.share as Boolean; } else { param1.share = false; } param1.previews = this.parsePreviews(param2.preview); return; }// end function里边的注释是我理解的备注,目前很疑惑的是这个: _loc_22.fileId = this.getFileId(_loc_11,_loc_14); 知道它是计算fileId的关键代码,但是RandomProxy是什么结构的有人知道吗?为什么怎么搜索都找不到呢? getFileId函数代码: //streamfileids,RandomProxy(param1.seed) private function getFileId(param1:Object,param2:String,param3:int,param4:RandomProxy) : String { var _loc_6:String = null;//mp4/flv var _loc_5:String = "";//"66*59*66*66*66*9*66*30*66*66*57*66*53*47*47*67*11*3.......... for (_loc_6 in param1) { if (_loc_6 == param2) { _loc_5 = param1[_loc_6]; break; } } if (_loc_5 == "") { return ""; } var _loc_7:String = ""; var _loc_8:* = param4.cg_fun(_loc_5); var _loc_9:* = param4.cg_fun(_loc_5).slice(0,8); var _loc_10:* = int(param3); var _loc_11:* = int(param3).toString(16); if (int(param3).toString(16).length == 1) { _loc_11 = "0" + _loc_11; } _loc_11 = _loc_11.toUpperCase(); var _loc_12:* = _loc_8.slice(10,_loc_8.length); _loc_7 = _loc_9 + _loc_11 + _loc_12; return _loc_7; }// end function关键部分就是这个随机的函数cg_fun()是干什么的。 比如fileid是:0300080400510C15B61CF004ED56DCBD905FF1-B527-63DA-87D3-6C0D90F804E1 很显然,_loc_9得到的是前边8位,_loc_11得到的是中间两位,而_loc_12是通过函数cg_fun()得到的那个字符串出去前边被替换的10位的剩余字符串。 所有的核心就剩下这个函数了,一时间找不到办法解决,之后查了一下其他人做的方法,那些几乎都是以前的早起版本,但是现在依然可以用: ?最新的优酷真实下载地址解析 http://blog.csdn.net/feige2008/article/details/8198434? 优酷视频真实地址解析?http://blog.csdn.net/amor2006/article/details/7055902
import time import random import math def createSid(): nowTime = int(time.time() *1000) random1 = random.randint(1000,1998) random2 = random.randint(1000,9999) return "%d%d%d" %(nowTime,random1,random2) def getFileIDMixString(seed): mixed=[] source=list("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/:._-1234567890") seed=float(seed) for i in range(len(source)): seed = (seed * 211 + 30031 ) % 65536 index = math.floor(seed /65536 *len(source)) mixed.append(source[int(index)]) source.remove(source[int(index)]) #return ''.join(mixed) return mixed def getFileId(fileId,seed): mixed=getFileIDMixString(seed) ids=fileId.split('*') realId=[] for ch in ids: realId.append(mixed[int(ch)]) return ''.join(realId) if __name__ == '__main__': #print createSid() print getFileIDMixString(4528) fileId='49*48*49*49*49*12*49*5*49*49*1*42*49*16*42*1*32*11*42*16*55*49*49*5*63*38*1*11*38*16*32*38*19*49*1*55*55*42*64*32*1*2*23*64*11*48*38*15*64*12*23*38*48*64*11*16*49*38*19*49*55*12*49*5*63*42' seed=2034 print getFileId(fileId,seed) 整体的源码: test.html ?使用的时候使用IE浏览器,其他的还在研究中 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>JSON</title> </head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript"> var xmlhttp; var message=""; //本源码只能在IE浏览器或者IE模式下可以使用,因为ActiveXObject有足够的权限,而XMLHttpRequest不能跨域请求json //创建http 请求的对象 function createxmlhttpRequest() { try { xmlhttp = new ActiveXObject("Msxml2.xmlhttp"); } catch (e) { try { xmlhttp = new ActiveXObject("Microsoft.xmlhttp"); } catch (e2) { xmlhttp = false; } } if (!xmlhttp && typeof XMLHttpRequest != "udefined") { try { xmlhttp = new XMLHttpRequest (); } catch (e2) { xmlhttp = false; } } } //工具函数,删除一个字符串指定位置的字符 function remove(str,index) { if(str == null) return null; if(index < 0) return str; if(index < str.length) { str=str.substring(0,index)+str.substring(index+1); return str; } else { return null; } } //通过seed计算得到解密的“种子” function getFileIDMixString(_seed) { var mixed = []; var source = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/:._-1234567890"; var seed = parseFloat(_seed)+0.00; var source_length = source.length; for(var i = 0 ; i < source_length ; i ++) { seed = (seed * 211 + 30031) % 65536; var index = Math.floor(seed /65536 * (source.length)); index = parseInt(index); mixed[i] = source.charAt(index); source = remove(source,index); } return mixed; } //通过上边的解密种子,将fileid解密 function getFileId(fileId,seed) { var mixed = getFileIDMixString(seed); var ids = fileId.split('*'); var realId = []; for(var i = 0 ; i < ids.length ; i ++) { if(ids[i] == "")break realId[i] = mixed[ids[i]]; } return realId; } function getInfo() { createxmlhttpRequest(); try { //实验方法: //找到一个优酷视频的链接: http://v.youku.com/v_show/id_XMjQwOTM4NDQ4.html //将id后边的XMjQwOTM4NDQ4取出,连接成字符串: http://v.youku.com/player/getPlayList/VideoIDS/XMjQwOTM4NDQ4 xmlhttp.open("get","http://v.youku.com/player/getPlayList/VideoIDS/XMjQwOTM4NDQ4",false); xmlhttp.onreadystatechange = returnInfo; xmlhttp.send(null); } catch(e) { } } //回调函数,处理传回来的json function returnInfo() { if(xmlhttp.readyState == 4) { var info = xmlhttp.responseText; eval("var json= " + info); var seed = ""; var title = ""; var streamtypes = []; var streamfileids = []; var segs = []; var mixed = []; var FileId = []; var video = []; var videorealurl = []; seed = json.data[0].seed; document.getElementById("seed").innerHTML = "随机种子: "+seed;//显示此时的随机种子 mixed = getFileIDMixString(seed); title += json.data[0].title; document.getElementById("title").innerHTML = "视频名字: "+title+"<br/>";//显示当前播放视频的名字 streamtypes = json.data[0].streamtypes; document.getElementById("streamtypes").innerHTML = "视频格式: "; document.getElementById("streamfileids").innerHTML = "加密的stream id: <br/>"; document.getElementById("FileId").innerHTML = "解密的stream id: <br/>"; document.getElementById("video").innerHTML = "视频加密的K值:<br/>"; for(var i = 0 ; i < streamtypes.length ; i ++) { streamfileids[i] = json.data[0].streamfileids[""+streamtypes[i]]; document.getElementById("streamtypes").innerHTML +=" "+streamtypes[i];//显示当前视频可以选择的种类 document.getElementById("streamfileids").innerHTML+=streamtypes[i]+": "+streamfileids[i]+"<br/>";//显示当前视频加密后的stream id FileId[i] = getFileId(streamfileids[i],seed); var temp_fileid = ""; for(var j = 0 ; j < FileId[i].length ; j ++) { temp_fileid += FileId[i][j]; } FileId[i] = temp_fileid; document.getElementById("FileId").innerHTML += streamtypes[i]+": FileId: "+FileId[i]+"<br/>";//显示当前播放视频的名字 document.getElementById("video").innerHTML += streamtypes[i]+" :<br/>"; segs = json.data[0].segs[""+streamtypes[i]]; var url = []; for(var j = 0 ; j < segs.length ; j ++) { document.getElementById("video").innerHTML += segs[j].k+"<br/>";//显示当前播放视频的名字 //http://f.youku.com/player/getFlvPath/sid/138846963736713671615_00/st/flv/fileid/ url[j] = "http://f.youku.com/player/getFlvPath/sid/00_00/st/";//基本路径 url[j]+= streamtypes[i];//视频类型 temp_fileid = FileId[i]; if(j < 16) temp_fileid = temp_fileid.substring(0,8)+"0"+parseInt(j).toString(16)+temp_fileid.substring(10); else temp_fileid = temp_fileid.substring(0,8)+parseInt(j).toString(16)+temp_fileid.substring(10); url[j]+= "/fileid/"+temp_fileid;//增加file的id url[j]+= "?K="+segs[j].k;//增加K值验证 document.getElementById("videorealurl").innerHTML += j+": <a href=""+url[j]+"">"+url[j]+"</a><br/>";//显示当前播放视频的名字 } videorealurl[i] = url; } } } </script> <body> <br/><br/> <h2 style="color: red;">JSON</h2> <br/> <input type="button" value="JSON" onclick="getInfo()" /> <table> <tr><td><div id="test"></div></td></tr> <tr><td><div id="seed"></div></td></tr> <tr><td><span id="title"><span></td></tr> <tr><td><span id="streamtypes"><span></td></tr> <tr><td><span id="streamfileids"><span></td></tr> <tr><td><span id="FileIDMixString"><span></td></tr> <tr><td><span id="FileId"><span></td></tr> <tr><td><span id="video"><span></td></tr> <tr><td><span id="videorealurl"><span></td></tr> </table> </body> </html>实验结果: (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |