// ==SiteScript==
// @siteName xHamster
// @siteUrl http://xhamster.com/
// @author DarkKnight
// @authorUrl http://darkknightlabs.com/
// @scriptUrl http://darkknightlabs.com/site-script/
// @description revise by Mayan, 2018/02/12
// @date 2010/09/19
// @version 0.6.0.12
// ==/SiteScript==
function CravingSiteScript() {
this._initialize();
}
CravingSiteScript.prototype = {
_xhr: null,
_initialize: function() {},
_getXmlHttpRequest: function() {
if ( this._xhr != null ) {
return this._xhr;
}
var xhr = null;
var these = [
function() { return new XMLHttpRequest(); }
, function() { return new ActiveXObject( "Msxml2.XMLHTTP" ); }
, function() { return new ActiveXObject( "Microsoft.XMLHTTP" ); }
, function() { return new ActiveXObject( "Msxml2.XMLHTTP.4.0" ); }
];
for ( var i = 0, length = these.length; i < length; i++ ) {
var func = these[ i ];
try {
xhr = func();
break;
}
catch( e ) {}
}
this._xhr = xhr;
return this._xhr;
},
_load: function( url, data, method ) {
var req = this._getXmlHttpRequest();
var mtd = ( method == null ) ? "GET" : "POST";
req.open( mtd, url, false );
if ( mtd == "POST" ) {
req.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );
}
req.send( data );
return req.responseText;
},
getResponseText: function( url, data, method ) {
return this._load( url, data, method );
},
getResponseJSON: function( url, data, method ) {
var text = this._load( url, data, method );
return eval( "("+text+")" );
},
/// Math
random: function( limit ) {
return Math.floor( Math.random() * limit );
},
/// String
decodeHtml: function( str ) {
return str.replace( /&(quot|#0*34);/ig, "\"" )
.replace( /&(amp|#0*38);/ig, "&" )
.replace( /&(apos|#0*39);/ig, "'" )
.replace( /&(lt|#0*60);/ig, "<" )
.replace( /&(gt|#0*62);/ig, ">" )
.replace( /&(nbsp|#0*160);/ig, " " )
.replace( /&(frasl|#8260);/ig, "/" );
}
}
function isSiteUrl( url ) {
if ( url.match( /https?:\/\/(?:[^/?]+\.)?xhamster\.com\/videos\/(?:[^/?]*-)?\d+/ ) ) return true;
if ( url.match( /https?:\/\/(?:[^/?]+\.)?xhamster\.com\/movies\/\d+\/[^/?]*\.html/ ) ) return true;
if ( url.match( /https?:\/\/(?:[^/?]+\.)?xhamster\.com\/xembed\.php(\?.+)/ )
&& RegExp.$1.match( /[?&]video=\d+/ ) ) return true;
return false;
}
function getVideoDetail( url ) {
url = url.replace( /https?:\/\/www\.xhamster\.com\//, "https://xhamster.com/" );
var vid = "";
var type = "unknown";
if ( url.match( /https?:\/\/(?:[^/?]+\.)?xhamster\.com\/videos\/(?:[^/?]*-)?(\d+)/ ) ) {
vid = RegExp.$1;
type = "page";
} else
if ( url.match( /https?:\/\/(?:[^/?]+\.)?xhamster\.com\/movies\/(\d+)\/[^/?]*\.html/ ) ) {
vid = RegExp.$1;
var type = "page";
} else
if ( url.match( /https?:\/\/(?:[^/?]+\.)?xhamster\.com\/xembed\.php(\?.+)/ )
&& RegExp.$1.match( /[?&]video=(\d+)/ ) ) {
vid = RegExp.$1;
type = "embed";
} else {
//return null;
type = "unknown";
}
//if ( !vid ) return null;
var craving = new CravingSiteScript();
var errNo = -1;
try {
var text = craving.getResponseText( url );
} catch ( e ) {
text = "";
var errNo = e.number & 0xffff;
}
if ( errNo == 5 ) {
var accept_language = "ja-JP";
url = getRedirect( url, accept_language );
try {
var objHttp = craving._getXmlHttpRequest();
objHttp.open( "GET", url, false );
objHttp.setRequestHeader( "Accept-Language", accept_language );
objHttp.send();
text = objHttp.responseText;
} catch ( e ) {
text = "";
}
}
if ( !text ) return null;
var title = "";
if ( type == "page" ) {
if ( !title &&
text.match( /
]*?itemprop\s*=\s*("|')?name\1[^>]*>\s*(.*?)\s*<\/h1\s*>/im ) ) {
title = craving.decodeHtml( RegExp.$2 );
}
if ( !title &&
text.match( /]*)?>\s*(.*?)\s*<\/title\s*>/im ) ) {
title = craving.decodeHtml( RegExp.$1 ).replace( /\s*:[^:]*$/, "" );
}
}
if ( !title &&
text.match( /[{,]\s*("|')?title\1\s*:\s*("|')(.*?)\2\s*[},]/m ) ) {
title = RegExp.$3;
if ( type == "page" ) title = title.replace( /\s*:[^:]*$/, "" );//2018/02/12,not necessary?
}
if ( !title ) title = "xhamster_" + ( vid || new Date().getTime() );
title = title.replace(/[\\\/:*?"<>|]/g, "_");
var realUrl = "";
var objReg = /[,}]\s*("|')?sources\1\s*:\s*\{/gm;
var objSrcs = { "vms":"", "xss":"", "xsffs":"" };
while ( objReg.test( text ) ) {
var tmp = pairChar( RegExp.rightContext );
if ( !tmp ) continue;
if ( tmp.match( /[,{]\s*("|')(?:mp4|flv)\1\s*:\s*\{/m ) ) {
objSrcs.vms = tmp;
} else if ( tmp.match( /[,{]\s*("|')?(?:mp4|flv)\1\s*:\s*\[/m ) ) {
objSrcs.xss = tmp;
} else if ( tmp.match( /[,{]\s*("|')?\d+p\1\s*:\s*("|')/m ) ) {
objSrcs.xsffs = tmp;
}
if ( objSrcs.vms && objSrcs.xss && objSrcs.xsffs ) break;
}
if ( !realUrl && objSrcs.vms ) {
if ( !realUrl &&
objSrcs.vms.match( /[,{]\s*("|')?mp4\1\s*:\s*(\{[^}]*?\})\s*[,}]/m ) ) {
realUrl = selectRealUrl_vms( RegExp.$2 );
}
if ( !realUrl &&
objSrcs.vms.match( /[,{]\s*("|')?flv\1\s*:\s*(\{[^}]*?\})\s*[,}]/m ) ) {
realUrl = selectRealUrl_vms( RegExp.$2 );
}
//download link省略
}
if ( !realUrl && objSrcs.xsffs ) {
realUrl = selectRealUrl_vms( objSrcs.xsffs );
}
if ( !realUrl && objSrcs.xss ) {
if ( !realUrl &&
objSrcs.xss.match( /[,{]\s*("|')?mp4\1\s*:\s*(\[[^\]]*?\])\s*[,}]/m ) ) {
realUrl = selectRealUrl_xss( RegExp.$2 );
}
if ( !realUrl &&
objSrcs.xss.match( /[,{]\s*("|')?flv\1\s*:\s*(\[[^\]]*?\])\s*[,}]/m ) ) {
realUrl = selectRealUrl_xss( RegExp.$2 );
}
}
//old, video > file 削除
//old, noflash 削除
//old, vars 削除
if ( !realUrl ) return null;
return { videoTitle0: title, videoUrl0: realUrl };
//sub
function selectRealUrl_vms( srcs ) {
var arrDat = [];
var objReg = /[{,]\s*("|')?(\d+)p?\1\s*:\s*("|')(.*?)\3\s*(?=[,}])/igm;
while ( objReg.test( srcs ) ) {
var obj = {};
obj.url = RegExp.$4;
if ( !obj.url ) continue;
obj.p = parseInt( RegExp.$2, 10 );
obj.url = obj.url.replace( /\\\//g,"/" );
arrDat.push( obj );
}
if ( arrDat.length <= 0 ) return "";
arrDat.sort( function(a,b){return b.p - a.p;} );
return arrDat[0].url;
}
function selectRealUrl_xss( srcs ) {
var arrDat = [];
var objReg = /[[,]\s*(\{[^}]*?\})\s*(?=[,\]])/gm;
while ( objReg.test( srcs ) ) {
var elm = RegExp.$1;
var obj = {};
obj.url = elm.match( /[,{]\s*("|')?url\1\s*:\s*("|')(.*?)\2\s*[,}]/m )? RegExp.$3: "";
if ( !obj.url ) continue;
obj.p = elm.match( /[,{]\s*("|')?quality\1\s*:\s*("|')(\d+)p\2\s*[,}]/m )? parseInt( RegExp.$3, 10 ): 0;
obj.url = obj.url.replace( /\\\//g,"/" );
arrDat.push( obj );
}
if ( arrDat.length <= 0 ) return "";
arrDat.sort( function(a,b){return b.p - a.p;} );
return arrDat[0].url;
}
function pairChar( str ) {
//strには、{の次の文字列を指定
var open = 0x7B;//{
var close = 0x7D;//}
var count = 1;
var len = str.length;
var p = -1;
for ( var i = 0; i < len; i++ ) {
var chrCode = str.charCodeAt( i );
if ( chrCode == open ) {
count++;
} else if ( chrCode == close ) {
count--;
}
if ( count <= 0 ) {
p = i + 1;
break;
}
}
if ( p < 0 ) return "";//対応なし
return "{" + str.substr( 0, p );
}
}
function getRedirect( url, al ) {
try {
var objHttp = new ActiveXObject( "WinHttp.WinHttpRequest.5.1" );
objHttp.option(12) = true;
objHttp.open( "HEAD", url, false );
if ( al ) objHttp.setRequestHeader( "Accept-Language", al );
objHttp.send();
var rdurl = objHttp.option(1);
} catch( e ) {
rdurl = "";
}
if ( rdurl ) return rdurl;
else return url;
}