// ==UserScript== // @name agefans Enhance // @namespace https://github.com/IronKinoko/agefans-enhance // @version 1.9.0 // @description 增强agefans播放功能,实现自动换集、无缝换集、画中画、历史记录、断点续播、显示视频源、获取当前页面全部视频等功能 // @author IronKinoko // @include https://www.agefans.net/* // @include https://www.agefans.cc/* // @include https://www.agefans.vip/* // @include http://www.yhdm.so/v/* // @resource plyrCSS https://cdn.jsdelivr.net/npm/plyr@3.6.4/dist/plyr.min.css // @require https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js // @require https://cdn.jsdelivr.net/npm/plyr@3.6.4/dist/plyr.min.js // @require https://cdn.jsdelivr.net/npm/hls.js@1.0.9/dist/hls.min.js // @grant GM_getResourceText // @grant GM_addStyle // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; try { let plyrCSS = GM_getResourceText('plyrCSS') GM_addStyle(plyrCSS) } catch(e) { /* empty */ } })(); (function ($, Plyr, Hls) { 'use strict'; function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var $__default = /*#__PURE__*/_interopDefaultLegacy($); var Plyr__default = /*#__PURE__*/_interopDefaultLegacy(Plyr); var Hls__default = /*#__PURE__*/_interopDefaultLegacy(Hls); var e = [], t = []; function n(n, r) { if (n && "undefined" != typeof document) { var a, s = !0 === r.prepend ? "prepend" : "append", d = !0 === r.singleTag, i = "string" == typeof r.container ? document.querySelector(r.container) : document.getElementsByTagName("head")[0]; if (d) { var u = e.indexOf(i); -1 === u && (u = e.push(i) - 1, t[u] = {}), a = t[u] && t[u][s] ? t[u][s] : t[u][s] = c(); } else a = c(); 65279 === n.charCodeAt(0) && (n = n.substring(1)), a.styleSheet ? a.styleSheet.cssText += n : a.appendChild(document.createTextNode(n)); } function c() { var e = document.createElement("style"); if (e.setAttribute("type", "text/css"), r.attributes) for (var t = Object.keys(r.attributes), n = 0; n < t.length; n++) e.setAttribute(t[n], r.attributes[t[n]]); var a = "prepend" === s ? "afterbegin" : "beforeend"; return i.insertAdjacentElement(a, e), e; } } var css$6 = ".agefans-wrapper .nav_button {\n cursor: pointer;\n}\n.agefans-wrapper .res_links {\n word-break: break-all;\n word-wrap: break-word;\n}"; n(css$6,{}); function renderHistroyStyle() { // add a tag visited style let styleDom = document.createElement('style'); styleDom.innerHTML = `.movurl li a:visited { color: red; }`; document.head.appendChild(styleDom); } function detailModule() { renderHistroyStyle(); } var css$5 = ".agefans-wrapper #history {\n background: #202020;\n border: 4px solid #303030;\n}\n.agefans-wrapper #history .history-list {\n padding: 16px;\n display: flex;\n flex-wrap: wrap;\n}\n.agefans-wrapper #history .history-item {\n width: 115px;\n display: inline-block;\n margin: 4px;\n}\n.agefans-wrapper #history .history-item img {\n width: 100%;\n border-radius: 2px;\n}\n.agefans-wrapper #history .history-item .desc .title {\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n font-size: 14px;\n margin: 4px 0;\n}\n.agefans-wrapper #history .history-item .desc .position {\n font-size: 14px;\n}"; n(css$5,{}); class History { constructor() { this.cacheKey = 'v-his'; } get his() { return JSON.parse(localStorage.getItem(this.cacheKey) || '[]'); } set his(value) { if (Array.isArray(value)) { localStorage.setItem(this.cacheKey, JSON.stringify(value.slice(0, 100))); } } getAll() { return this.his; } get(id) { return this.his.find(o => o.id === id); } setTime(id, time = 0) { const his = this.his; his.find(o => o.id === id).time = time; this.his = his; } log(item) { const his = this.his; his.unshift(item); this.his = his; } refresh(id, data) { const his = this.his; const index = his.findIndex(o => o.id === id); const item = his.splice(index, 1)[0]; his.unshift(data || item); this.his = his; } has(id) { return Boolean(this.his.find(o => o.id === id)); } logHistory() { var _location$pathname$ma; const id = (_location$pathname$ma = location.pathname.match(/\/play\/(\d*)/)) === null || _location$pathname$ma === void 0 ? void 0 : _location$pathname$ma[1]; if (!id) return; const hisItem = {}; hisItem.id = id; hisItem.title = $__default['default']('#detailname a').text(); hisItem.href = location.href; hisItem.section = $__default['default']('li a[style*="color: rgb(238, 0, 0);"]').text(); hisItem.time = 0; hisItem.logo = $__default['default']('#play_poster_img').attr('src'); if (this.has(id)) { const oldItem = this.get(id); if (oldItem.href !== hisItem.href) { this.refresh(id, hisItem); } else { this.refresh(id); } } else { this.log(hisItem); } } } const his = new History(); function parseTime(time = 0) { return `${Math.floor(time / 60).toString().padStart(2, '0')}:${(time % 60).toString().padStart(2, '0')}`; } function renderHistoryList() { $__default['default']('#history').html('').append(() => { /** @type {any[]} */ const histories = his.getAll(); let html = ''; histories.forEach(o => { html += ` ${o.title}
${o.title}
${o.section} ${parseTime(o.time)}
`; }); return `
${html || '
暂无数据
'}
`; }); } function renderHistoryPage() { const currentDom = $__default['default']('.nav_button_current'); $__default['default']('
').insertAfter('#container').hide(); $__default['default'](`历史`).appendTo('#nav').on('click', e => { if ($__default['default']('#history').is(':visible')) { $__default['default']('#container').show(); $__default['default']('#history').hide(); changeActive(currentDom); } else { renderHistoryList(); $__default['default']('#container').hide(); $__default['default']('#history').show(); changeActive($__default['default'](e.currentTarget)); } }); $__default['default']('.nav_button_current').on('click', e => { $__default['default']('#container').show(); $__default['default']('#history').hide(); changeActive(e.currentTarget); }).removeAttr('href'); } function changeActive(dom) { $__default['default']('.nav_button_current').removeClass('nav_button_current'); $__default['default'](dom).addClass('nav_button_current'); } function historyModule() { renderHistoryPage(); renderHistoryList(); } var css$4 = "#k-player-wrapper {\n position: relative;\n width: 100%;\n height: 100%;\n background: #000;\n overflow: hidden;\n}\n#k-player-wrapper.k-player-widescreen {\n position: fixed;\n left: 0;\n top: 0;\n z-index: 100;\n}\n#k-player-wrapper .k-player-contianer {\n width: 100%;\n height: 100%;\n}\n#k-player-wrapper #k-player-loading,\n#k-player-wrapper #k-player-error {\n position: absolute;\n left: 0;\n top: 0;\n right: 0;\n bottom: 0;\n z-index: 10;\n font-size: 88px;\n color: white;\n pointer-events: none;\n background: black;\n}\n#k-player-wrapper .k-player-center {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n}\n#k-player-wrapper .error-info {\n text-align: center;\n padding: 24px;\n font-size: 18px;\n}\n#k-player-wrapper .plyr {\n width: 100%;\n height: 100%;\n}\n#k-player-wrapper video {\n display: block;\n}\n#k-player-wrapper .plyr__next svg {\n transform: scale(1.7);\n}\n#k-player-wrapper .plyr__widescreen svg {\n transform: scale(1.3);\n}\n#k-player-wrapper .plyr--hide-cursor {\n cursor: none;\n}\n#k-player-wrapper .plyr__control span:not(.plyr__tooltip) {\n color: inherit;\n}\n#k-player-wrapper .plyr--hide-controls .k-player-progress {\n opacity: 1;\n transition: opacity 0.3s ease-in 0.2s;\n}\n#k-player-wrapper .k-player-fullscreen .k-player-progress {\n display: none;\n}\n#k-player-wrapper .k-player-progress {\n opacity: 0;\n transition: opacity 0.2s ease-out;\n height: 2px;\n width: 100%;\n position: absolute;\n bottom: 0;\n}\n#k-player-wrapper .k-player-progress .k-player-progress-current {\n position: absolute;\n left: 0;\n top: 0;\n height: 100%;\n z-index: 2;\n background-color: #23ade5;\n}\n#k-player-wrapper .k-player-progress .k-player-progress-buffer {\n position: absolute;\n left: 0;\n top: 0;\n z-index: 1;\n height: 100%;\n background-color: var(--plyr-video-progress-buffered-background, rgba(255, 255, 255, 0.25));\n}\n#k-player-wrapper .plyr__controls .plyr__controls__item:first-child {\n margin-right: 0;\n}\n#k-player-wrapper .plyr__controls .plyr__controls__item.plyr__progress__container {\n position: absolute;\n top: 15px;\n left: 10px;\n right: 10px;\n --plyr-range-track-height: 2px;\n}\n#k-player-wrapper .plyr__controls .plyr__controls__item.plyr__progress__container .plyr__progress input[type=range]::-webkit-slider-thumb {\n transform: scale(0);\n transition: transform 0.2s ease;\n}\n#k-player-wrapper .plyr__controls .plyr__controls__item.plyr__progress__container:hover {\n --plyr-range-track-height: 4px;\n}\n#k-player-wrapper .plyr__controls .plyr__controls__item.plyr__progress__container:hover .plyr__progress input[type=range] {\n cursor: pointer;\n}\n#k-player-wrapper .plyr__controls .plyr__controls__item.plyr__progress__container:hover .plyr__progress input[type=range]::-webkit-slider-thumb {\n transform: scale(1);\n}\n#k-player-wrapper .plyr__controls .plyr__volume {\n margin-left: auto;\n}\n\n.lds-spinner {\n color: official;\n display: inline-block;\n position: relative;\n width: 80px;\n height: 80px;\n}\n\n.lds-spinner div {\n transform-origin: 40px 40px;\n animation: lds-spinner 1.2s linear infinite;\n}\n\n.lds-spinner div:after {\n content: \" \";\n display: block;\n position: absolute;\n top: 3px;\n left: 37px;\n width: 6px;\n height: 18px;\n border-radius: 20%;\n background: #fff;\n}\n\n.lds-spinner div:nth-child(1) {\n transform: rotate(0deg);\n animation-delay: -1.1s;\n}\n\n.lds-spinner div:nth-child(2) {\n transform: rotate(30deg);\n animation-delay: -1s;\n}\n\n.lds-spinner div:nth-child(3) {\n transform: rotate(60deg);\n animation-delay: -0.9s;\n}\n\n.lds-spinner div:nth-child(4) {\n transform: rotate(90deg);\n animation-delay: -0.8s;\n}\n\n.lds-spinner div:nth-child(5) {\n transform: rotate(120deg);\n animation-delay: -0.7s;\n}\n\n.lds-spinner div:nth-child(6) {\n transform: rotate(150deg);\n animation-delay: -0.6s;\n}\n\n.lds-spinner div:nth-child(7) {\n transform: rotate(180deg);\n animation-delay: -0.5s;\n}\n\n.lds-spinner div:nth-child(8) {\n transform: rotate(210deg);\n animation-delay: -0.4s;\n}\n\n.lds-spinner div:nth-child(9) {\n transform: rotate(240deg);\n animation-delay: -0.3s;\n}\n\n.lds-spinner div:nth-child(10) {\n transform: rotate(270deg);\n animation-delay: -0.2s;\n}\n\n.lds-spinner div:nth-child(11) {\n transform: rotate(300deg);\n animation-delay: -0.1s;\n}\n\n.lds-spinner div:nth-child(12) {\n transform: rotate(330deg);\n animation-delay: 0s;\n}\n\n@keyframes lds-spinner {\n 0% {\n opacity: 1;\n }\n 100% {\n opacity: 0;\n }\n}\n.script-info {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Open Sans\", \"Helvetica Neue\", sans-serif;\n width: 100%;\n}\n.script-info * {\n box-sizing: border-box;\n}\n.script-info tbody tr td:first-child {\n white-space: nowrap;\n width: 77px;\n}\n.script-info td {\n padding: 8px;\n border-bottom: 1px solid #f1f1f1;\n word-wrap: break-word;\n word-break: break-all;\n}\n.script-info .info-title {\n font-weight: 600;\n padding-top: 24px;\n}\n.script-info a {\n color: #1890ff;\n padding: 4px 8px;\n border-radius: 4px;\n text-decoration: none;\n}\n.script-info a:hover {\n text-decoration: underline;\n background-color: #f1f1f1;\n}\n.script-info .shortcuts-wrap {\n display: flex;\n width: 100%;\n margin: -8px;\n}\n.script-info .shortcuts-table {\n flex: 1;\n}\n.script-info .key {\n display: inline-block;\n position: relative;\n background: #333;\n text-align: center;\n color: #eee;\n border-radius: 4px;\n padding: 2px 0;\n width: 56px;\n box-sizing: border-box;\n border: 1px solid #444;\n box-shadow: 0 2px 0 1px #222;\n border-bottom-color: #555;\n user-select: none;\n}\n.script-info .carousel {\n position: relative;\n display: flex;\n flex-wrap: nowrap;\n overflow: hidden;\n}\n.script-info .carousel span {\n display: block;\n width: 100%;\n height: 100%;\n flex-basis: 100%;\n flex-shrink: 0;\n animation: carousel-3 6s infinite alternate;\n}\n\n@keyframes carousel-3 {\n 0% {\n transform: translateX(0);\n }\n 20% {\n transform: translateX(0);\n }\n 40% {\n transform: translateX(-100%);\n }\n 60% {\n transform: translateX(-100%);\n }\n 80% {\n transform: translateX(-200%);\n }\n 100% {\n transform: translateX(-200%);\n }\n}"; n(css$4,{}); const icons = ` `; $__default['default']('body').append(icons); const loadingHTML = ` `; const errorHTML = ` `; const scriptInfo = (video, githubIssueURL) => ` ${video ? `` : ''}
脚本版本${"1.9.0"}
脚本源码 GitHub 更新记录
报错/意见 GitHub Issues Greasy Fork 反馈
视频信息
视频链接${video.src}
视频信息${video.videoWidth} x ${video.videoHeight}
快捷键
W宽屏
F全屏
步退5s
步进5s
Shift+←步退30s
Shift+→步进30s
Alt+←步退60s
Altl+→步进60s
Ctrl+←步退90s
Ctrl+→步进90s
esc退出全屏/宽屏
[ P PgUp 上一集
] N PgDn 下一集
Z原速播放
X减速播放
C加速播放
音量+
音量-
M静音
?脚本信息
`; const issueBody = (src = '') => `# 文字描述 # 网址链接 ${window.location.href} # 视频链接 ${src} # 环境 userAgent: ${navigator.userAgent} 脚本版本: ${"1.9.0"} `; const progressHTML = `
`; function debounce(fn, delay = 300) { if (typeof fn !== 'function') { throw new TypeError('fn is not a function'); } let timeID = null; return function (...rest) { if (timeID) { clearTimeout(timeID); } timeID = setTimeout(() => { timeID = null; fn.apply(this, rest); }, delay); }; } var css$3 = ".k-modal {\n position: fixed;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n text-align: left;\n animation: fadeIn 0.3s ease forwards;\n color: rgba(0, 0, 0, 0.85);\n}\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.k-modal * {\n color: inherit;\n}\n.k-modal .k-modal-mask {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n background: rgba(0, 0, 0, 0.45);\n cursor: pointer;\n}\n.k-modal .k-modal-wrap {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n overflow: auto;\n text-align: center;\n user-select: none;\n}\n.k-modal .k-modal-wrap::before {\n content: \"\";\n display: inline-block;\n width: 0;\n height: 100%;\n vertical-align: middle;\n}\n.k-modal .k-modal-container {\n margin: 20px 0;\n display: inline-block;\n vertical-align: middle;\n text-align: left;\n position: relative;\n width: 520px;\n min-height: 100px;\n background: white;\n border-radius: 2px;\n user-select: text;\n}\n.k-modal .k-modal-header {\n font-size: 16px;\n padding: 16px;\n border-bottom: 1px solid #f1f1f1;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n.k-modal .k-modal-close {\n cursor: pointer;\n height: 55px;\n width: 55px;\n position: absolute;\n right: 0;\n top: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n user-select: none;\n}\n.k-modal .k-modal-close * {\n color: rgba(0, 0, 0, 0.45);\n transition: color 0.15s ease;\n}\n.k-modal .k-modal-close:hover * {\n color: rgba(0, 0, 0, 0.85);\n}\n.k-modal .k-modal-body {\n padding: 16px;\n font-size: 14px;\n}\n.k-modal .k-modal-footer {\n padding: 10px 16px;\n font-size: 14px;\n border-top: 1px solid #f1f1f1;\n display: flex;\n justify-content: flex-end;\n}\n.k-modal .k-modal-btn {\n user-select: none;\n display: flex;\n align-items: center;\n justify-content: center;\n height: 32px;\n border-radius: 2px;\n border: 1px solid #1890ff;\n background: #1890ff;\n color: white;\n min-width: 64px;\n cursor: pointer;\n}"; n(css$3,{}); function modal({ title, content, onClose, onOk }) { const store = $__default['default']('body').css(['width', 'overflow']); const ID = Math.random().toString(16).slice(2); $__default['default'](` `).appendTo('body'); // init css $__default['default']('body').css({ width: `calc(100% - ${window.innerWidth - document.body.clientWidth}px)`, overflow: 'hidden' }); $__default['default'](`#${ID} .k-modal-title`).append(title); $__default['default'](`#${ID} .k-modal-body`).append(content); $__default['default'](`#${ID} .k-modal-close`).on('click', () => { handleClose(); }); $__default['default'](`#${ID} .k-modal-container`).on('click', e => { e.stopPropagation(); }); $__default['default'](`#${ID} .k-modal-wrap`).on('click', () => { handleClose(); }); function reset() { $__default['default'](`#${ID}`).remove(); $__default['default']('body').css(store); window.removeEventListener('keydown', fn, { capture: true }); } function handleClose() { onClose === null || onClose === void 0 ? void 0 : onClose(); reset(); } function handleOk() { onOk(); reset(); } function fn(e) { if (['Escape', '?', '?'].includes(e.key)) { handleClose(); } e.stopPropagation(); } window.addEventListener('keydown', fn, { capture: true }); if (onOk) { $__default['default'](`#${ID} .k-modal-container`).append(` `); $__default['default'](`#${ID} .k-modal-ok`).on('click', () => { handleOk(); }); } } function genIssueURL({ title, body }) { const url = new URL(`https://github.com/IronKinoko/agefans-enhance/issues/new`); url.searchParams.set('title', title); url.searchParams.set('body', body); return url.toString(); } var css$2 = "#k-player-message {\n z-index: 999;\n position: absolute;\n left: 20px;\n bottom: 60px;\n}\n#k-player-message .k-player-message-item {\n display: block;\n width: max-content;\n padding: 8px 16px;\n background: rgba(0, 0, 0, 0.45);\n border-radius: 4px;\n color: white;\n font-size: 14px;\n white-space: nowrap;\n overflow: hidden;\n box-sizing: border-box;\n margin-top: 4px;\n}"; n(css$2,{}); class Message { constructor(selector) { this.$message = $__default['default']('
'); this.$message.appendTo($__default['default'](selector)); } info(text, duration = 1500) { this.$message.empty(); return new Promise(resolve => { $__default['default'](`
${text}
`).hide().appendTo(this.$message).fadeIn(150).delay(duration).fadeOut(150, function () { $__default['default'](this).remove(); resolve(); }); }); } destroy() { this.$message.empty(); } } const SHIFT_KEY = '~!@#$%^&*()_+{}|:"<>?' + '~!@#¥%…&*()——+「」|:“《》?'; /** * @param {string[]} keys * @param {(e:KeyboardEvent,key:string)=>void} cb */ function keybind(keys, cb) { const ua = navigator.userAgent; if (!ua.includes('Mac OS')) { keys = keys.filter(key => !key.includes('meta')); } $__default['default'](window).on('keydown', e => { let keyArr = []; e.ctrlKey && keyArr.push('ctrl'); e.metaKey && keyArr.push('meta'); e.shiftKey && !SHIFT_KEY.includes(e.key) && keyArr.push('shift'); e.altKey && keyArr.push('alt'); if (!['Control', 'Meta', 'Shift', 'Alt'].includes(e.key)) { keyArr.push(e.key); } keyArr = [...new Set(keyArr)]; const key = keyArr.join('+'); if (keys.includes(key)) { cb(e, key); } }); } const speedList = [0.5, 0.75, 1, 1.25, 1.5, 2, 4]; const MediaErrorMessage = { 1: '你中止了媒体播放', 2: '一个网络错误导致媒体下载中途失败', 3: '由于损坏问题或媒体使用了你的浏览器不支持的功能,媒体播放被中止了', 4: '媒体无法被加载,要么是因为服务器或网络故障,要么是因为格式不被支持', 5: '该媒体是加密的,我们没有解密的钥匙' }; class KPlayer { /** * Creates an instance of KPlayer. * @param {stromg} selector * @param {Plyr.Options} opts */ constructor(selector, opts) { const $wrapper = $__default['default']('
').replaceAll(selector); const $loading = $__default['default'](loadingHTML); const $error = $__default['default'](errorHTML); const $video = $__default['default']('