视频解析接口调用

替换v.qq.com搜索页播放链接

// ==UserScript==
// @name         视频解析接口调用
// @namespace    vqq
// @version      0.2
// @description  替换v.qq.com搜索页播放链接
// @author       unknownuser001
// @match        https://v.qq.com/x/search/?q=*
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAdBJREFUWEftlrtLw1AYxc+X3rZpY3FxFGd3cRH8AxxFECcfLT4WK2qkgh2iiw/qi6qLoC4uDuLi7tBNwcFJBRcdRURabfr6pEVBBZNrG8nSzIfv/O6537mE4PJHLvujDlBPwDaB5V1u9gj0MINLRRzHhunBycW1BFjZ506FcQogVDFlZEFIpPNYNEbp1QkQS4DEHl8AaPtpxIx7APpMhI5qhbADyAMQFiZnCiE6NURX1YLYAbDE4BIYhyhgSh+lRwn9N4kTAB/rgSciLLRo2OrtpaIsiGMAn4YMXBIjqkcoJQPhOEClLAwmwgELjM/0U8YK5F8Avhju62EKuwfAyKXvoRkGFX6DsExgIG7KtODXAxIBoWefmkyS6QpAQ4Cut+d8rVVfQbUJlE8eVOk24Pd2rOrWb4PjV+D34k1Thb4e8+zUXMO/JKAQs6Z5Tpqyos8wKCdjXtY4koCm0p0a8HatTdONrPGnzhJgMG6yVQ1UPz03BpTIii6O/2osBTAyb2bMPII/hwsPiqGgktyIeSerNZYCmE4Ux55e8julUnmvgUqvVSXl84tuu+2WBbP9JZtI5NpRoNnKQMFLm7rvXHa4jM4WQGZILZo6QD0B1xN4B/iKmyF8Ne2sAAAAAElFTkSuQmCC
// @grant		 GM_addStyle
// @grant		 GM_getValue
// @grant		 GM_setValue
// @grant		 GM_registerMenuCommand
// @license      AGPL License
// ==/UserScript==


// 解析接口来自
// https://greasyfork.org/zh-CN/scripts/418804
const originalInterfaceList = [
	{"name":"乐多资源","category":"1","url":"https://api.leduotv.com/wp-api/ifr.php?isDp=1&vid=", "id":"leduotv"},
	{"name":"M3U8.TV","category":"1","url":"https://jx.m3u8.tv/jiexi/?url=", "id":"m3u8"},
	{"name":"人人迷","category":"1","url":"https://jx.blbo.cc:4433/?url=", "id":"blbo"},
	{"name":"七哥","category":"1","url":"https://jx.mmkv.cn/tv.php?url=", "id":"mmkv"},
	{"name":"冰豆","category":"1","url":"https://api.qianqi.net/vip/?url=", "id":"qianqi"},
	{"name":"迪奥","category":"1","url":"https://123.1dior.cn/?url=", "id":"1dior"},
	{"name":"CK","category":"1","url":"https://www.ckplayer.vip/jiexi/?url=", "id":"ckplayer"},
	{"name":"游艺","category":"1","url":"https://api.u1o.net/?url=", "id":"u1o"},
	{"name":"LE","category":"1","url":"https://lecurl.cn/?url=", "id":"lecurl"},
	{"name":"ckmov","category":"1","url":"https://www.ckmov.vip/api.php?url=", "id":"ckmovvip"},
	{"name":"ccyjjd","category":"1","url":"https://ckmov.ccyjjd.com/ckmov/?url=", "id":"ccyjjd"},
	{"name":"爱豆","category":"1","url":"https://jx.aidouer.net/?url=", "id":"aidouer"},
	{"name":"诺诺","category":"1","url":"https://www.ckmov.com/?url=", "id":"ckmovcom"},
	{"name":"H8","category":"1","url":"https://www.h8jx.com/jiexi.php?url=", "id":"h8jx"},
	{"name":"BL","category":"1","url":"https://vip.bljiex.com/?v=", "id":"bljiex"},
	{"name":"解析la","category":"1","url":"https://api.jiexi.la/?url=", "id":"jiexila"},
	{"name":"MUTV","category":"1","url":"https://jiexi.janan.net/jiexi/?url=", "id":"janan"},
	{"name":"MAO","category":"1","url":"https://www.mtosz.com/m3u8.php?url=", "id":"mtosz"},
	{"name":"老板","category":"1","url":"https://vip.laobandq.com/jiexi.php?url=", "id":"laobandq"},
	{"name":"盘古","category":"1","url":"https://www.pangujiexi.cc/jiexi.php?url=", "id":"pangujiexi"},
	{"name":"盖世","category":"1","url":"https://www.gai4.com/?url=", "id":"gai4"},
	{"name":"小蒋","category":"1","url":"https://www.kpezp.cn/jlexi.php?url=", "id":"kpezp"},
	{"name":"YiTV","category":"1","url":"https://jiexi.us/?url=", "id":"jiexius"},
	{"name":"星空","category":"1","url":"http://60jx.com/?url=", "id":"60jx"},
	{"name":"0523","category":"1","url":"https://go.yh0523.cn/y.cy?url=", "id":"yh0523"},
	{"name":"17云","category":"1","url":"https://www.1717yun.com/jx/ty.php?url=", "id":"1717yun"},
	{"name":"4K","category":"1","url":"https://jx.4kdv.com/?url=", "id":"4kdv"},
	{"name":"云析","category":"1","url":"https://jx.yparse.com/index.php?url=", "id":"yparse"},
	{"name":"8090","category":"1","url":"https://www.8090g.cn/?url=", "id":"8090g"},
	{"name":"江湖","category":"1","url":"https://api.jhdyw.vip/?url=", "id":"jhdyw"},
	{"name":"诺讯","category":"1","url":"https://www.nxflv.com/?url=", "id":"nxflv"},
	{"name":"PM","category":"1","url":"https://www.playm3u8.cn/jiexi.php?url=", "id":"playm3u8"},
	{"name":"奇米","category":"1","url":"https://qimihe.com/?url=", "id":"qimihe"},
	{"name":"思云","category":"1","url":"https://jx.ap2p.cn/?url=", "id":"ap2p"},
	{"name":"听乐","category":"1","url":"https://jx.dj6u.com/?url=", "id":"dj6u"},
	{"name":"aijx","category":"1","url":"https://jiexi.t7g.cn/?url=", "id":"t7g"},
	{"name":"52","category":"1","url":"https://vip.52jiexi.top/?url=", "id":"52jiexi"},
	{"name":"黑米","category":"1","url":"https://www.myxin.top/jx/api/?url=", "id":"myxin"},
	{"name":"豪华啦","category":"1","url":"https://api.lhh.la/vip/?url=", "id":"lhh"},
	{"name":"凉城","category":"1","url":"https://jx.mw0.cc/?url=", "id":"mw0"},
	{"name":"33t","category":"1","url":"https://www.33tn.cn/?url=", "id":"33tn"},
	{"name":"180","category":"1","url":"https://jx.000180.top/jx/?url=", "id":"000180"},
	{"name":"无名","category":"1","url":"https://www.administratorw.com/video.php?url=", "id":"administratorw"},
	{"name":"黑云","category":"1","url":"https://jiexi.380k.com/?url=", "id":"380k"},
	{"name":"九八","category":"1","url":"https://jx.youyitv.com/?url=", "id":"youyitv"},
	{"name":"综合线路解析","category":"2","url":"https://www.xixicai.top/mov/s/?sv=3&url=", "id":"xixicai"},
	{"name":"纯净/B站","category":"2","url":"https://z1.m1907.cn/?jx=", "id":"m1907"},
	{"name":"高速接口","category":"2","url":"https://jsap.attakids.com/?url=", "id":"attakids"},
	{"name":"综合/B站1","category":"2","url":"https://vip.parwix.com:4433/player/?url=", "id":"parwix"},
	{"name":"OK解析","category":"2","url":"https://okjx.cc/?url=", "id":"okjx"},
	{"name":"夜幕","category":"2","url":"https://www.yemu.xyz/?url=", "id":"yemu"},
	{"name":"虾米","category":"2","url":"https://jx.xmflv.com/?url=", "id":"xmflv"},
	{"name":"全民","category":"2","url":"https://jx.quanmingjiexi.com/?url=", "id":"quanmingjiexi"},
];

const noSiteId = '__no_parse_site__';

let SelectedSite;
initSelectedSite();

const __app_main__ = function() {

	injectCss();
	injectSiteSelectorButton();
	setTimeout(openFoldItemsAdnInjectLink, 1000);
	GM_registerMenuCommand('选择解析站点', showSiteSelectorWindow);
}

function openFoldItemsAdnInjectLink() {
	if (openFoldItems()) {
		setTimeout(injectLink, 1000);
	} else {
		injectLink();
	}
}

function openFoldItems() {
	//展开所有剧集
	let foldBtns = document.querySelectorAll('div.item_fold > a');
	let foldClicked = false;
	for (let i = 0; i < foldBtns.length; i++) {
		if (foldBtns[i].parentElement.className.indexOf('item_unfold') < 0) {
			foldBtns[i].click();
			foldClicked = true;
		}
	}
	return foldClicked;
}

function injectLink() {
	let link1 = Array.prototype.slice.call(document.querySelectorAll('div.item > a'), 0);
	let link2 = Array.prototype.slice.call(document.querySelectorAll('div._playlist > div.result_btn_line > a.btn_primary'), 0);
	let link3 = Array.prototype.slice.call(document.querySelectorAll('div._infos > div > a.figure'), 0);
	let link4 = Array.prototype.slice.call(document.querySelectorAll('div._infos > div > h2.result_title > a'), 0);
	let link5 = Array.prototype.slice.call(document.querySelectorAll('div.info_item.info_item_desc > span.desc_text > a.desc_more'), 0);
	let aniLinks = [];
	let itemLinks = link1.concat(link2).concat(link3).concat(link4).concat(link5);
	for (let i = 0; i < itemLinks.length; i++) {
		let itemLink = itemLinks[i];
		let noClassItemFold = (itemLink.parentElement.className.indexOf('item_unfold') < 0);
		let noClassItemUnFold = (itemLink.parentElement.className.indexOf('item_fold') < 0);
		let parsedUrl = parseUrl(itemLink.href);
		let isRedirectSearchReuslt = (parsedUrl.pathname.indexOf('search_redirect.html') > 0);
		let oUrl;
		if (itemLink.attributes.oUrl == undefined) {
			if (isRedirectSearchReuslt) {
				oUrl = parsedUrl.query.url;
				if (oUrl.indexOf('?') > 0) {
					oUrl = oUrl.split('?')[0];
				} else {
					oUrl = '';
				}
			} else {
				oUrl = itemLink.href;
			}
		} else {
			oUrl = itemLink.attributes.oUrl;
		}

		if (noClassItemUnFold && noClassItemFold) {
			itemLink.attributes.oUrl = oUrl;
			itemLink.href = SelectedSite.url + oUrl;
			if (itemLink.parentNode.classList.contains('item')) {
				let mark = itemLink.parentNode.querySelector('span');
				aniLinks.push(itemLink);
				if (mark != undefined && mark.attributes.labelFree != true) {
				    mark.className += " hide-mark";
				} else {
					mark = document.createElement('span');
					itemLink.parentNode.appendChild(mark);
				}
			}
		} else if (!noClassItemUnFold) {
			itemLink.parentNode.remove();
		}
	}

	setTimeout(function(){
		for (let i = 0; i < aniLinks.length;i++) {
			let itemLink = aniLinks[i];
			let mark = itemLink.parentNode.querySelector('span');
			if (mark == undefined) {
				mark = document.createElement('span');
				itemLink.parentNode.appendChild(mark);
			}
			if (mark.attributes.labelFree == true) {
				continue;
			}
			mark.className = "mark_v";
			mark.className += ' free-video';
			mark.innerHTML = '免';
			mark.className += ' free-video-ani';
			mark.attributes.labelFree = true;
		}


		let tabResult = document.querySelectorAll('div._playlist div.result_tabs > a');
		if (tabResult == undefined) {
			return;
		}

		for ( let i = 0; i < tabResult.length; i++) {
			let t = tabResult[i];
			if (t.__event_added) {
				continue;
			}
			t.__event_added = true;
			t.addEventListener('click', function () {
				setTimeout(openFoldItemsAdnInjectLink, 1000);
			});
		}


	}, 1000);
	let allCover = document.querySelectorAll('div._infos > div > a > span.mark_v');
	for ( let i = 0 ; i < allCover.length; i++){
		allCover[i].innerHTML = '免费';
		allCover[i].className = allCover[i].className +' free-video-2';
	}
}



function parseQuery(search) {
	var args = search.substring(1).split('&');
	var argsParsed = {};
	var i, arg, kvp, key, value;
	for (i = 0; i < args.length; i++) {
		arg = args[i];
		if (-1 === arg.indexOf('=')) {
			argsParsed[decodeURIComponent(arg).trim()] = true;
		} else {
			kvp = arg.split('=');
			key = decodeURIComponent(kvp[0]).trim();
			value = decodeURIComponent(kvp[1]).trim();
			argsParsed[key] = value;
		}
	}
	return argsParsed;
}

function parseUrl(url) {
	let urlParser = document.createElement('a');
	urlParser.href = url;
	return {
		protocol: urlParser.protocol,
		host: urlParser.host,
		hostname: urlParser.hostname,
		port: urlParser.port,
		pathname: urlParser.pathname,
		query: parseQuery(urlParser.search),
		hash: urlParser.hash
	};
}

//https://codepen.io/avstorm/pen/jxjKGj
function injectCss() {
	let modalDialogCss = `
		#siteSelectorPopDiv{
			display: none;
			background-color: #f5f5f5;
			z-index: 11;
			width: 300px;
			height: 400px;
			position:fixed;
			top:0;
			right:0;
			left:0;
			bottom:0;
			margin:auto;
			border-radius: 10px;
			border: 2px solid #7d7d7d;
			border-width: 2px;
			box-shadow: 0 0 15px #7d7d7d;
		}

		#siteSelectorPopDiv .content-wrapper {
			overflow-y: scroll;
			height: 350px;
			width:295px;
		}
		#siteSelectorPopDiv .content {
			width: 95%;
			margin-top: 6px;
			display: grid;
			padding:5px;
			grid-template-columns: repeat(2, 130px);
			grid-column-gap: 10px;
			grid-row-gap: 5px;
			font-size: 9px;
		}
		#siteSelectorPopDiv .buttons {
			width:80%;
			margin:auto;
			display: flex;
			justify-content: space-between;
			padding-top: 8px;
		}

		#siteSelectorPopDiv .buttons > button {
			box-shadow:inset 0px 1px 0px 0px #ffffff;
			background:linear-gradient(to bottom, #f9f9f9 5%, #e9e9e9 100%);
			background-color:#f9f9f9;
			border-radius:6px;
			border:1px solid #dcdcdc;
			display:inline-block;
			cursor:pointer;
			color:#666666;
			font-family:Arial;
			font-size:15px;
			font-weight:bold;
			padding:6px 24px;
			text-decoration:none;
			text-shadow:0px 1px 0px #ffffff;
		}
		#siteSelectorPopDiv .buttons > button:hover {
			background:linear-gradient(to bottom, #e9e9e9 5%, #f9f9f9 100%);
			background-color:#e9e9e9;
		}
		#siteSelectorPopDiv .buttons > button:active {
			position:relative;
			top:1px;
		}

		input[type="radio"] {
		  vertical-align:middle;
		}

		.radio {
		  position: relative;
		  cursor: pointer;
		  font-size: 16px;
		  margin: 5px;
		  height: 24px;
		  overflow-y: hidden;
		  color: black;
		}
		.radio .label {
		  position: relative;
		  display: block;
		  float: left;
		  margin-right: 10px;
		  width: 20px;
		  height: 20px;
		  border: 2px solid #c8ccd4;
		  border-radius: 100%;
		  -webkit-tap-highlight-color: transparent;
		}
		.radio .label:after {
		  content: '';
		  position: absolute;
		  top: 5px;
		  left: 5px;
		  width: 10px;
		  height: 10px;
		  border-radius: 100%;
		  background: #0080c0;
		  transform: scale(0);
		  transition: all 0.2s ease;
		  opacity: 0.08;
		  pointer-events: none;
		}
		.radio:hover .label:after {
		  transform: scale(3.6);
		}
		input[type="radio"]:checked + .label {
		  border-color: #0080c0;
		}
		input[type="radio"]:checked + .label:after {
		  transform: scale(1);
		  transition: all 0.2s cubic-bezier(0.35, 0.9, 0.4, 0.9);
		  opacity: 1;
		}
		.hidden {
		  display: none;
		}

		.free-video {
		    color: #f8f8f8!important;
		    width: 16px!important;
		    height: 16px!important;
		    font-size: 12px!important;
		    text-align: center!important;
		    vertical-align: middle!important;
		    border-radius: 10px!important;
		    margin: 0!important;
		    background-image: linear-gradient(to right, #ff9569 0%, #e92758 100%)!important;
		    top: -2px!important;
		    right: -2px!important;
		    transform: rotate(30deg)!important;
			padding-bottom: 2px;
			padding-left: 1px;
			opacity: 90%;

		}

		.free-video-ani {
			transition: opacity 1s linear;
		}

		.free-video-2 {
			color: white!important;
			width: 30px!important;
			height: 20px!important;
			font-size: 12px!important;
			text-align: center!important;
			vertical-align: middle!important;
			border-radius: 5px!important;
			margin: 0!important;
			background-image: linear-gradient(#ff6429, #f5f900c9)!important;
			top: 2px!important;
			right: 2px!important;
			opacity: 70%;
		}

		.hide-mark {
		  visibility: hidden;
		  opacity: 0;
		  transition: visibility 0s 2s, opacity 1s linear;
		}
	`;
	GM_addStyle(modalDialogCss);
}

function closeSiteSelectorWindow() {
	let ssw = document.getElementById('siteSelectorPopDiv');
	if (ssw != undefined) {
		ssw.remove()
	}
}

function saveSiteSelectorWindow() {
	var siteRadios = document.getElementsByName("siteRadio");
	for (let i = 0; i < siteRadios.length; i++) {
		if (siteRadios[i].checked) {
			SelectedSite.id = siteRadios[i].value;
			GM_setValue('selectedSite', SelectedSite.id);
			initSelectedSite();
			injectSiteSelectorButton();
			openFoldItemsAdnInjectLink();
		}
	}
	closeSiteSelectorWindow();
}

function showSiteSelectorWindow() {
	let siteSelectorPopDiv = document.createElement('div');
	siteSelectorPopDiv.id = 'siteSelectorPopDiv';
	siteSelectorPopDiv.innerHTML = `
	<div class='content-wrapper'>
		<div class="content">
		</div>
	</div>
	<div class="buttons">
	    <button class="save">保存</button><button class="close">关闭</button>
	</div>
	`;
	document.body.appendChild(siteSelectorPopDiv);
	document.querySelector('#siteSelectorPopDiv > div.buttons > button.save')
		.addEventListener('click', saveSiteSelectorWindow);
	document.querySelector('#siteSelectorPopDiv > div.buttons > button.close')
		.addEventListener('click', closeSiteSelectorWindow);

	let selectorHtml = `
	<label for="${noSiteId}" class="radio">
		<input ${isNoSiteId(SelectedSite.id) ? 'checked' : ''} type="radio" class="hidden" name="siteRadio" id="${noSiteId}" value="${noSiteId}"/>
		<span class="label"></span>无解析
	</label>
	<span></span>
	`;

	originalInterfaceList.forEach(function(item, index) {
		selectorHtml += `
		<label for="${item.id}" class="radio">
			<input ${SelectedSite.id == item.id ? 'checked' : ''} + type="radio" class="hidden" name="siteRadio" id="${item.id}" value="${item.id}"/>
			<span class="label"></span>${item.name}
		</label>
		`;
	});

	document.querySelector('#siteSelectorPopDiv div.content').innerHTML = selectorHtml;

	siteSelectorPopDiv.style.display = 'block';
	return siteSelectorPopDiv;
}

function injectSiteSelectorButton(){

	let lastElement = document.querySelector('#search_container > div.search_tools > div > div.filter_tip.none');

	if (document.querySelector('#search_container div.filter_item > a.doParseLink') == undefined) {
		let doParseLinkButton = document.createElement('div');
		doParseLinkButton.innerHTML = '<a class="doParseLink" href="javascript:void(0)">〖点此解析〗</a>';
		doParseLinkButton.className = 'filter_item';
		document.querySelector('#search_container > div.search_tools > div').insertBefore(doParseLinkButton, lastElement);
		document.querySelector('#search_container div.filter_item > a.doParseLink').addEventListener('click', openFoldItemsAdnInjectLink);
	}

	if (document.querySelector('#search_container div.filter_item > a.openSiteSelector') == undefined) {
		let parseSite = document.createElement('div');
		parseSite.innerHTML = `<a class="openSiteSelector" href="javascript:void(0)">选择解析(当前:${SelectedSite.name})</a>`;
		parseSite.className = 'filter_item';
		document.querySelector('#search_container > div.search_tools > div').insertBefore(parseSite, lastElement);
		document.querySelector('#search_container div.filter_item > a.openSiteSelector').addEventListener('click', function(){
			showSiteSelectorWindow();
		});
	} else {
		document.querySelector('#search_container div.filter_item > a.openSiteSelector').innerHTML = `选择解析(当前:${SelectedSite.name})`;
	}

}

function initSelectedSite() {
	let name;
	let url;
	let id = GM_getValue('selectedSite');
	if (id == undefined) {
		id = 'xixicai';
	}
	originalInterfaceList.forEach(function(item, index) {
		if (id == item.id) {
			id = item.id;
			url = item.url;
			name = item.name;
		}
	});
	if ( isNoSiteId(id) || name == undefined) {
		SelectedSite = {
			"name": '无解析',
			"id": noSiteId,
			"url": ''
		};
		return;
	}
	SelectedSite = {
		"name": name,
		"id": id,
		"url": url
	}
};

function isNoSiteId(id){
	return id == noSiteId;
}


__app_main__();