// ==UserScript==
// @name 国家智慧教育公共服务平台助手(原国家中小学智慧教育平台书籍下载)
// @namespace github.com/hmjz100
// @version 1.0.3
// @description 《也许同类型中最好用?》系列 - 国家智慧教育公共服务平台辅助工具,顶栏毛玻璃,页脚一言诗,增强原有 PDFJS 预览页面,可使用网页全屏、下载 PDF 等功能,确保舒适地在线看书;国家中小学智慧教育平台支持免登录查看文档和单个视频,显示隐藏黑暗模式,教材原件 PDF 支持切换版本、多版本批量下载等
// @author hmjz100
// @match *://*.smartedu.cn/*
// @match *://*.edu.cn/*
// @match *://*.eduyun.cn/*
// @icon data:image/webp;base64,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
// @license MIT
// @grant GM_getResourceText
// @grant GM_xmlHttpRequest
// @grant GM.xmlHttpRequest
// @grant unsafeWindow
// @connect smartedu.cn
// @connect edu.cn
// @connect eduyun.cn
// @connect ykt.cbern.com.cn
// @connect hitokoto.cn
// @require https://unpkg.com/jquery@3.6.3/dist/jquery.min.js
// @require https://unpkg.com/hls.js@1.5.10/dist/hls.min.js
// @require https://unpkg.com/artplayer@5.1.6/dist/artplayer.legacy.js
// ==/UserScript==
(async function SmartEduDownload() {
'use strict';
/*
防止代码因其他原因被执行多次
这段代码出自 Via轻插件,作者谷花泰
*/
const key = encodeURIComponent('国家中小学智慧教育平台助手:主代码');
if (unsafeWindow[key]) return;
unsafeWindow[key] = true;
Artplayer.LOG_VERSION = false
console.log("【国家中小学智慧教育平台助手】即时\n运行中…")
unsafeWindow.open = function (url, name, specs) {
const cUrl = new URL(location.href);
if (cUrl.searchParams.get('x-edu-theme') === 'dark') {
const xUrl = new URL(url, location.href);
if (xUrl.host === location.host) {
xUrl.searchParams.set('x-edu-theme', 'dark');
return window.open.call(window, xUrl.href, name, specs);
}
}
return window.open.call(window, url, name, specs);
};
addDownStyle();
// 给顶栏加个时钟
let img_question = "data:image/png;base64,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"
waitForKeyElements('[class^="index-module_menu-container_"]', (element) => {
var timebar = $(`
![](${img_question})
,现在是
感谢您使用本脚本~
`);
timebar.append(``);
timebar.find("#smartEduGood").on('click', function () {
window.open('https://greasyfork.org/scripts/459404/feedback', '_blank')
})
if (/((en.|)basic.smartedu.cn|(xue\-test|web\-bd|en\-test|test\d).ykt.eduyun.cn)/.test(location.host)) {
timebar.append(``);
timebar.find("#smartEduTheme").on('click', function () {
let url = new URL(location);
if (url.searchParams.get("x-edu-theme") === 'dark') {
url.searchParams.delete('x-edu-theme');
} else {
url.searchParams.set("x-edu-theme", "dark");
}
$(this).remove();
location.href = url.toString();
});
// 默认收起侧栏
waitForKeyElements('[class^="index-module_collapse_"]', (element) => {
element.click();
}, true)
}
if (element && element.length > 0) {
element.after(timebar);
window.setInterval(function () {
timebar.find("#smartEduTime").text(Time());
timebar.find("#smartEduGreeting").text(Greeting());
}, 500);
}
}, true);
// 移除顶部客户端相关内容
if (location.host !== 'www.smartedu.cn') waitForKeyElements('[class^="index-module_top-bar"], [class^="index-module_download"], [class^="index-module_float-download"], #app div.bg-no-repeat div[class^="bg"], #app header.el-header.plang div.topLine1, div.header div.headbar', (element) => {
element.remove()
}, true)
// 给底栏增加个一言
waitForKeyElements('.main-wrapper #main-content div.content', (element) => {
var poembar = $(``)
if (element && element.length > 0) {
let text = poembar.find(".todayPoem")
element.after(poembar)
text.on('click', function () {
if (text.text() === "加载中……") return;
text.text("加载中……")
text.css({ "cursor": "default" });
Poem(text)
})
text.text("加载中……")
text.css({ "cursor": "default" });
Poem(text)
}
}, true)
// 教材选择页加个下载按钮
waitForKeyElements('li[class^="index-module_item"]', listElement);
function listElement(element) {
if (!element.find('[class^="index-module_cover"] img[src]')[0]) return;
let base = element.find('[class^="index-module_cover"] img[src]')[0].src.match(/r(\d)-ndr/)[1]
let contentId = element.find('[class^="index-module_cover"] img[src]')[0].src.match(/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/i)[1]
let data = {
titleNew: element.find('[class^="index-module_line"] span[title]')[0].title,
titleOld: element.find('[class^="index-module_line"] span[title]')[0].title + " 旧版",
urlNew: `https://r${base}-ndr.ykt.cbern.com.cn/edu_product/esp/assets/${contentId}.pkg/pdf.pdf`,
urlOld: `https://r${base}-ndr.ykt.cbern.com.cn/edu_product/esp/assets_document/${contentId}.pkg/pdf.pdf`
}
element.css({ "border-bottom": "none" })
let button = $(`
阅读
下载
阅读旧版
下载旧版
`)
element.after(button)
getFileSize(data.urlNew).then(size => {
button.find('.index-module_item.download.new .size').text(`(${formatFileSize(size)})`);
}).catch(() => {
button.find('.index-module_item.read.new').off('click').text("暂无新版...");
button.find('.index-module_item.download.new').off('click').text("暂无新版...");
});
getFileSize(data.urlOld).then(size => {
button.find('.index-module_item.download.old .size').text(`(${formatFileSize(size)})`);
}).catch(() => {
button.find('.index-module_item.read.old').off('click').text("暂无旧版...");
button.find('.index-module_item.download.old').off('click').text("暂无旧版...");
});
button.find(".index-module_item.read.new").on('click', async function () {
unsafeWindow.window.open(`//${location.host}/tchMaterial/detail?contentType=assets_document&contentId=${contentId}&catalogType=tchMaterial&subCatalog=tchMaterial`, "_blank")
})
button.find(".index-module_item.read.old").on('click', async function () {
unsafeWindow.window.open(`//${location.host}/tchMaterial/detail?contentType=assets_document&contentId=${contentId}&catalogType=tchMaterial&subCatalog=tchMaterial&contentOld=true`, "_blank")
})
button.find(".index-module_item.download").on('click', async function () {
let element = $(this)
let ins = {};
let progress = {};
let index = element.data('index');
let orgtext = element.find('.text').text()
element.prop('disabled', true);
ins[index] = setInterval(function () {
let prog = +progress[index] || 0;
element.find('.text').text(prog + "%");
}, 10);
try {
let response = await fetch(element.hasClass('old') ? data.urlOld : data.urlNew);
if (!response.ok) throw new Error('网络响应失败');
let totalSize = response.headers.get('Content-Length') || 0;
let reader = response.body.getReader();
let receivedLength = 0;
let chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
receivedLength += value.length;
progress[index] = Math.floor((receivedLength / totalSize) * 100);
}
let blob = new Blob(chunks);
clearInterval(ins[index]);
progress[index] = 100;
element.find('.text').text("完成~");
// 下载文件
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = downloadUrl;
a.download = `${element.hasClass('old') ? data.titleOld : data.titleNew}.pdf`;
a.click();
URL.revokeObjectURL(downloadUrl);
setTimeout(function () {
element.find('.text').text(orgtext);
$(this).prop('disabled', false);
}.bind(this), 3000);
} catch (error) {
clearInterval(ins[index]);
element.find('.text').text("失败,重试?");
$(this).prop('disabled', false).one('click', async function () {
$(this).trigger('click');
});
}
});
// 使用 MutationObserver 监听 li 元素的删除
let observer = new MutationObserver((mutationsList) => {
for (let mutation of mutationsList) {
if (mutation.removedNodes.length > 0) {
mutation.removedNodes.forEach((node) => {
if (node === element[0]) {
button.remove();
observer.disconnect();
}
});
}
if (mutation.type === 'attributes' && mutation.attributeName === 'src') {
button.remove();
listElement(element);
observer.disconnect();
}
}
});
observer.observe(element.parent()[0], { childList: true });
observer.observe(element.find('[class^="index-module_cover"] img[src]')[0], { attributes: true });
}
let contentType = new URL(location.href).searchParams.get("contentType") || '';
let contentId = new URL(location.href).searchParams.get("contentId") || '';
let resourceId = new URL(location.href).searchParams.get("resourceId") || '';
let contentOld = new URL(location.href).searchParams.get("contentOld") || '';
// 若是教材阅读页
if (/^\/tchMaterial\/detail/.test(location.pathname) && (contentType === 'assets_document' || contentType === 'x_document') && contentId) {
try {
// 教材信息
let data = await Promise.any(["1", "2", "3"].map(async base => {
try {
let data = await request({
url: `https://s-file-${base}.ykt.cbern.com.cn/zxx/ndrv2/resources/tch_material/details/${contentId}.json`,
headers: {
"referer": "https://basic.smartedu.cn/",
'Cache-Control': 'no-cache'
}
});
let item = {
id: data.id,
title: data.global_title['zh-CN'],
cover: data.custom_properties?.thumbnails[0],
author: data.provider_list[0]?.name,
url: `https://r${base}-ndr.ykt.cbern.com.cn/edu_product/esp/assets/${contentId}.pkg/pdf.pdf`,
};
if (contentOld === "true") {
item.title = data.global_title['zh-CN'] + ' 旧版'
item.url = `https://r${base}-ndr.ykt.cbern.com.cn/edu_product/esp/assets_document/${contentId}.pkg/pdf.pdf`
}
return item
} catch (error) {
console.error('【国家中小学智慧教育平台助手】\n获取数据时发生错误:', error);
}
}));
// 遇到默认弹窗
waitForKeyElements('div.fish-modal-content div.fish-modal-body div.fish-modal-confirm-body-wrapper', (elemlogin) => {
if (!elemlogin.find('div.fish-modal-confirm-content').text().match("需要登录才可以查看")) return;
waitForKeyElements('div[class^="index-module_special-edu-detail_"] div[class^="index-module_content-wrap_"] div[class^="index-module_wrapper_"]', (element) => {
// 点击登录提示中隐藏的取消按钮
elemlogin.find('button[type="button"].fish-btn').filter(function () {
return $(this).text().includes("取 消");
}).click();
// 既然不给页面内容,那就抄一个放上去吧
element.html(`
`)
}, true)
})
} catch (error) {
console.error('【国家中小学智慧教育平台助手】\n获取数据时发生错误:', error);
}
}
// 若是文档阅读页
if ((contentType === 'assets_document' || contentType === 'x_document') && contentId && !/^\/tchMaterial\/detail/.test(location.pathname)) {
try {
// 文档信息
let data = await Promise.any([1, 2, 3].map(async base => {
try {
let data = await request({
url: `https://s-file-${base}.ykt.cbern.com.cn/zxx/ndrs/special_edu/resources/details/${contentId}.json`,
headers: {
"referer": "https://basic.smartedu.cn/",
'Cache-Control': 'no-cache'
}
});
let item = {
id: data.id,
title: data.global_title['zh-CN'],
cover: data.custom_properties?.thumbnails[0],
author: data.provider_list[0]?.name,
url: data.ti_items[0]?.ti_storages[base - 1]
};
return item
} catch (error) {
console.error('【国家中小学智慧教育平台助手】\n获取数据时发生错误:', error);
}
}));
waitForKeyElements("div.course-document div.viewerContainer", (element) => {
element.html(`
`)
element.css({ "border-radius": "8px" })
element.parent().css({ "border-radius": "8px" })
element.parent().parent().css({ "border-radius": "8px" })
waitForKeyElements('div.course-document div[class^="doc-"]', (element) => {
element.css({ "display": "none" })
})
})
} catch (error) {
console.error('【国家中小学智慧教育平台助手】\n获取数据时发生错误:', error);
}
}
// 若是视频播放页
if ((contentType === 'assets_video' || contentType === 'x_video') && contentId) {
try {
// 视频信息
let data = await Promise.any([1, 2, 3].map(async base => {
try {
let data = await request({
url: `https://s-file-${base}.ykt.cbern.com.cn/zxx/ndrs/special_edu/resources/details/${contentId}.json`,
headers: {
"referer": "https://basic.smartedu.cn/",
'Cache-Control': 'no-cache'
}
});
let item = {
id: data.id,
title: data.global_title?.['zh-CN'],
cover: data.custom_properties?.thumbnails?.[0],
author: data.provider_list?.[0]?.name,
url: null,
urls: []
};
let seenMd5 = new Set();
let maxQuality = null;
data.ti_items.forEach(ti_item => {
let md5 = ti_item.ti_md5;
if (!seenMd5.has(md5) && ti_item?.custom_properties?.requirements) {
let quality = null;
ti_item.custom_properties.requirements.forEach(req => {
if (req.name === 'Height') {
quality = Number(req.value);
if (maxQuality === null || quality > maxQuality) {
maxQuality = quality;
}
}
});
let url = {
"url": ti_item.ti_storages[base - 1],
"html": quality <= 360 ? `流畅 ${quality}P` : quality <= 480 ? `标清 ${quality}P` : quality <= 720 ? `高清 ${quality}P` : quality <= 1080 ? `全高清 ${quality}P` : quality <= 1440 ? `2K ${quality}P` : quality <= 2160 ? `超高清 4K ${quality}P` : `${quality}P`,
"quality": quality
};
item.urls.push(url);
seenMd5.add(md5);
}
});
item.urls.sort((a, b) => (b.quality || 0) - (a.quality || 0));
item.urls.forEach(url => {
if (url.quality === maxQuality) {
url.default = true;
item.url = url.url
}
});
return item
} catch (error) {
console.error('【国家中小学智慧教育平台助手】\n获取数据时发生错误:', error);
}
}));
console.log(data)
waitForKeyElements("div.course-video div.fish-video", (element) => {
element.html(`
`)
play(data.id, data.url, data.urls, data.cover, (art) => {
art.controls.add({
name: 'hideList',
index: 50,
position: 'right',
html: '',
tooltip: '宽屏模式',
click: function () {
$('[class^="index-module_comp-related-recommend"]').fadeToggle()
},
})
})
element.css({ "height": "auto", "width": "auto", "aspect-ratio": "16/9" })
element.parent().css({ "border-radius": "8px", "height": "auto", "width": "auto" })
element.parent().parent().css({ "border-radius": "8px", "height": "auto", "width": "auto" })
}, true)
} catch (error) {
console.error('【国家中小学智慧教育平台助手】\n获取数据时发生错误:', error);
}
}
/* 若是多视频播放页
if (contentType === 'thematic_course' && contentId) {
}*/
// 遇到 PDF 预览器的 iframe
waitForKeyElements("iframe[src*='/web/viewer.html']", (element) => {
let parent = element.parent();
let button = $(`
`)
element.parent().parent().css({ "border-radius": "8px", "border": "5px solid #232d2a", "background": "#232d2a" })
element.parent().parent().parent().css({ "border-radius": "8px", "border": "5px solid #232d2a", "background": "#232d2a" })
element.css({ "background": "#232d2a" })
let pdfWindow = element[0].contentWindow
button.find('.index-module_pdf-refresh').on('click', function () {
let element = $(this)
element.find('.text').text('等待');
pdfWindow.location.reload();
pdfWindow.onload = element.find('.text').text('刷新');
})
button.find('.index-module_pdf-fullscreen').on('click', function () {
let element = $(this)
if (!parent.hasClass('fullscreen-div')) {
// 进入全屏模式
$('body').addClass('no-scroll');
parent.addClass('fullscreen-div');
element.html('退出全屏 (Esc)');
$('#header').fadeToggle();
button.find('.index-module_pdf-rating').fadeToggle();
button.find('.index-module_pdf-refresh').fadeToggle();
button.find('.index-module_pdf-download').fadeToggle();
} else {
// 退出全屏模式
$('body').removeClass('no-scroll');
parent.removeClass('fullscreen-div');
element.html('网页全屏 (Esc)');
$('#header').fadeToggle();
button.find('.index-module_pdf-rating').fadeToggle();
button.find('.index-module_pdf-refresh').fadeToggle();
button.find('.index-module_pdf-download').fadeToggle();
}
});
$(document).off('keydown').on('keydown', function (event) {
if (event.key === 'Escape' || event.which === 27) button.find('.index-module_pdf-fullscreen').click();
});
element.on('load', function () {
const iframeDocument = this.contentDocument || this.contentWindow.document;
$(iframeDocument).off('keydown').on('keydown', function (event) {
if (event.key === 'Escape' || event.which === 27) {
button.find('.index-module_pdf-fullscreen').click();
}
});
});
button.find('.index-module_pdf-download').on('click', async function () {
let src = new URL(pdfWindow.location.href)
let title = $("document").find('[class^="index-module_line"] span[title]').attr("title") || document.title
let data = {
title: title,
url: src.searchParams.get("file")
}
let element = $(this)
let ins = {};
let progress = {};
let index = element.data('index');
element.prop('disabled', true);
ins[index] = setInterval(function () {
let prog = +progress[index] || 0;
element.find('.text').text(prog + "%");
}, 10);
try {
let response = await fetch(data.url);
if (!response.ok) throw new Error('网络响应失败');
let totalSize = response.headers.get('Content-Length') || 0;
let reader = response.body.getReader();
let receivedLength = 0;
let chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
receivedLength += value.length;
progress[index] = Math.floor((receivedLength / totalSize) * 100);
}
let blob = new Blob(chunks);
clearInterval(ins[index]);
progress[index] = 100;
element.find('.text').text("完成~");
// 下载文件
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = downloadUrl;
a.download = `${data.title}.pdf`;
a.click();
URL.revokeObjectURL(downloadUrl);
setTimeout(function () {
element.find('.text').text("下载");
$(this).prop('disabled', false);
}.bind(this), 3000);
} catch (error) {
clearInterval(ins[index]);
console.error("下载失败:", error);
element.find('.text').text("失败,重试?");
$(this).prop('disabled', false).one('click', async function () {
$(this).trigger('click');
});
}
});
element.before(button)
})
// 预览页面增强
if (/^\/pdfjs\/.*\/web\/viewer.html/.test(location.pathname) || /^\/web\/viewer.html/.test(location.pathname)) {
let file = new URL(location.href).searchParams.get("file");
if (file) {
let noPrivateFile = file.replace(/(r\d)-ndr-\w+/, '$1-ndr');
let url = new URL(`${location.origin}${location.pathname}?file=${noPrivateFile}&disableAutoFetch=true&page=1`).toString()
if (url !== location.href) location.replace(url);
}
if (file.includes("edu_product/esp/assets/") || file.includes("edu_product/esp/assets_document/")) {
let version
if (file.includes('edu_product/esp/assets/')) {
file = file.replace('edu_product/esp/assets/', 'edu_product/esp/assets_document/')
version = '旧版'
} else if (file.includes('edu_product/esp/assets_document/')) {
file = file.replace('edu_product/esp/assets_document/', 'edu_product/esp/assets/')
version = '新版'
}
let url = new URL(`${location.origin}${location.pathname}?file=${file}&disableAutoFetch=true&page=1`).toString()
getFileSize(file).then(size => {
let button = $(`
`)
button.on('click', function () {
if (url !== location.href) location.replace(url);
})
$("#sidebarToggle").after(button)
});
}
$('html').css({
"background-color": "#232d2a",
"--body-bg-color": "#232d2a",
"--toolbar-bg-color": "#2a3632",
"--sidebar-toolbar-bg-color": "#2a3632",
"--doorhanger-border-color": "#232d2a",
"--doorhanger-bg-color": "#2a3632",
"--dropdown-btn-bg-color": "#232d2a",
"--button-hover-color": "#32403b",
"--doorhanger-hover-bg-color": "#32403b",
"--overlay-button-bg-color": "#232d2a",
"--overlay-button-hover-bg-color": "#32403b",
"--field-bg-color": "#232d2a",
"--field-border-color": "#32403b",
})
$('#loadingBar').css({ "height": "10px", "top": "-10px" })
$('#loadingBar .progress').css({ "border-radius": "50px" })
$('#toolbarViewerMiddle').attr('id', 'toolbarViewerLeft');
$('#viewerContainer').css({ "background-color": "#232d2a" })
$('#sidebarContent').css({ "background-color": "#2a3632" })
// 取消隐藏预览PDF页面的隐藏功能(例如下载等功能,打印没法用除外)
waitForKeyElements('button[hidden]:not(#print)', function (element) {
if (element.attr('hidden') !== undefined) {
element.removeAttr('hidden');
}
});
}
function Time() {
function repair(i) {
if (i >= 0 && i <= 9) {
return "0" + i;
} else {
return i;
}
}
var date = new Date();
var year = date.getFullYear();
var month = repair(date.getMonth() + 1);
var day = repair(date.getDate());
var hours = repair(date.getHours());
var minute = repair(date.getMinutes());
var second = repair(date.getSeconds());
var curTime = year + "年 - " + month + "月 - " + day + "日 " + hours + "时 : " + minute + "分 : " + second + "秒";
return curTime;
}
function Greeting() {
var date = new Date();
var hour = date.getHours();
var greeting = '';
if (hour >= 0 && hour <= 10) {
greeting = '早上好';
} else if (hour > 10 && hour <= 14) {
greeting = '中午好';
} else if (hour > 14 && hour <= 18) {
greeting = '下午好';
} else if (hour > 18 && hour <= 24) {
greeting = '晚上好';
}
return greeting;
}
async function Poem(element) {
try {
let data = await request({
data: "",
url: "https://v1.hitokoto.cn/?encode=json&c=i",
headers: {
"origin": "https://hitokoto.cn",
"referer": "https://hitokoto.cn",
'Cache-Control': 'no-cache'
}
})
// 使用数据更新页面元素
element.text(`「${data.hitokoto}」${data.from_who || ""}`);
element.css({ "cursor": "pointer" });
} catch (error) {
// 处理错误情况
console.error('获取诗词时发生错误:', error);
element.text('诗词加载失败');
element.css({ "cursor": "pointer" });
}
}
function request(option) {
return new Promise((resolve, reject) => {
let httpRequest = typeof GM_xmlhttpRequest !== "undefined" ? GM_xmlhttpRequest : GM.xmlHttpRequest;
httpRequest({
method: 'get',
...option,
onload: (response) => {
if (response.responseText === undefined) return;
let res = JSON.parse(response.responseText);
resolve(res);
},
onerror: (error) => {
reject(error);
},
});
});
}
function addStyle(id, tag, css) {
tag = tag || 'style';
let doc = document, styleDom = doc.getElementById(id);
if (styleDom) styleDom.remove();
let style = doc.createElement(tag);
style.rel = 'stylesheet';
style.id = id;
tag === 'style' ? style.innerHTML = css : style.href = css;
doc.getElementsByTagName('body')[0].appendChild(style);
}
function addDownStyle() {
const url = new URL(location);
let deColor = url.searchParams.get("x-edu-theme") === 'dark' ? "#0e9aff" : "#1e62ec";
let hvColor = url.searchParams.get("x-edu-theme") === 'dark' ? "#1e62ec" : "#4079ef";
let bgColor = url.searchParams.get("x-edu-theme") === 'dark' ? "rgba(42, 54, 50, 0.5)" : "rgba(255, 255, 255, 0.5)";
let spColor = url.searchParams.get("x-edu-theme") === 'dark' ? "#323e3a" : "#eee";
let css = `
a, button, ul li, ui, label, input, select {
transition: all 0.25s !important;
-webkit-transition: all 0.25s !important;
}
[class^="index-module_header-wrap_"], [class*="index-module_header"] {
height: auto !important;
}
[class^="index-module_header"] [class^="index-module_nav-normal"],
[class^="index-module_header-wrap_"] [class^="index-module_header"] .theme-menu-sticky {
height: auto !important;
-webkit-backdrop-filter: blur(15px);
backdrop-filter: blur(15px);
background-color: ${bgColor};
}
#smartEduTime{
margin: 0 5px;
color: ${deColor};
}
.index-module_tip {
cursor: default;
text-align: center;
display: inline-flex;
justify-content: center;
align-items: center;
margin: 10px 0;
width: 100%;
transition: all 0.3s !important;
-webkit-transition: all 0.3s !important;
}
.index-module_tip img,
.index-module_tip svg {
margin: 0 5px;
width: 20px;
height: 20px;
}
.index-module_tip svg {
color: ${deColor};
cursor: pointer;
}
.index-module_tip svg:hover {
color: ${hvColor};
transition: all 0.3s !important;
-webkit-transition: all 0.3s !important;
}
.index-module_pdf-control {
display: flex;
justify-content: center;
position: absolute;
top: 5%;
pointer-events: none;
width: auto !important;
height: auto !important;
}
.index-module_pdf-control.left {
left: 3%;
}
.index-module_pdf-control.right {
right: 3%;
}
.index-module_pdf-button {
background-color: ${deColor}cc;
text-align: center;
color: #fff;
padding: 7px 20px;
border-radius: 144.889px;
border: 0;
margin: 0 5px;
display: inline-flex;
vertical-align: middle;
pointer-events: all;
transition: all 0.3s !important;
-webkit-transition: all 0.3s !important;
}
.index-module_pdf-button:hover,.index-module_pdf-button:disabled {
background-color: ${hvColor}cc;
}
.index-module_pdf-button svg {
height: 18px;
width: 17px;
margin-right: 5px;
vertical-align: middle;
}
.index-module_item {
cursor: pointer;
font-size: 15px;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
vertical-align: middle;
display: flex;
align-items: center;
padding: 5px 0;
justify-content: center;
border-bottom: 1px solid ${spColor};
width: 25%;
transition: all 0.3s !important;
-webkit-transition: all 0.3s !important;
}
.index-module_item svg {
height: 20px;
width: 20px;
margin-right: 4px;
vertical-align: middle;
}
.index-module_item:hover {
color: #fff;
background-color: ${deColor};
}
div .fullscreen-div {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
z-index: 99999 !important;
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
background-color: transparent;
z-index: 999999999999999;
}
::-webkit-scrollbar-thumb {
background: ${deColor};
border-radius: 3px;
z-index: 999999999999999;
}
::-webkit-scrollbar-thumb:hover {
background: ${hvColor};
z-index: 999999999999999;
}
.no-scroll {
overflow: hidden !important;
}
`;
addStyle('BasicSmartEdu-User', 'style', css);
return deColor
}
function play(id, url, urls, cover, actionFunction) {
var art = new Artplayer({
id: id,
container: '.index-module_art-player',
url: url,
volume: 1,
autoPlayback: true,
customType: {
m3u8: function (video, url, art) {
if (Hls.isSupported()) {
if (art.hls) art.hls.destroy();
const hls = new Hls();
hls.loadSource(url);
hls.attachMedia(video);
art.hls = hls;
art.on('destroy', () => hls.destroy());
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = url;
} else {
art.notice.show = 'Unsupported playback format: m3u8';
}
},
},
controls: [
{
name: 'goodRing',
index: 21,
position: 'left',
html: '',
tooltip: '赏个好评',
click: function () {
window.open('https://greasyfork.org/scripts/459404/feedback', '_blank')
},
}
],
icons: {
state: '',
indicator: '
',
play: '',
pause: '',
setting: '',
fullscreenOn: '',
fullscreenOff: '',
playbackRate: '',
aspectRatio: '',
check: '',
flip: '',
arrowUp: '',
arrowDown: '',
arrowLeft: '',
arrowRight: '',
download: '',
info: '',
close: '',
},
setting: true,
theme: addDownStyle(),
hotkey: true,
autoMini: true,
flip: true,
playbackRate: true,
aspectRatio: true,
miniProgressBar: true,
fullscreen: true,
fullscreenWeb: true,
})
cover ? (art.poster = cover) : ""
urls ? (art.quality = [...urls]) : ""
var contextmenuStyle = {
"display": "flex",
"justify-content": "center",
"align-items": "center",
"border-bottom": "none"
}
art.contextmenu.add({
name: 'appTitle',
index: 1,
html: `
国家智慧教育公共服务平台助手`,
style: contextmenuStyle,
click: function () {
window.open('https://greasyfork.org/scripts/459404/feedback', '_blank')
},
})
art.contextmenu.update({
name: 'version',
index: 2,
html: `
Artplayer Ultra ${Artplayer.version}`,
click: function () {
window.open('https://artplayer.org/', '_blank')
},
style: contextmenuStyle
})
art.contextmenu.update({
name: 'info',
index: 40,
html: `${$(art.icons.info).html()}${art.i18n.language["Video Info"]}`,
style: contextmenuStyle
})
art.contextmenu.update({
name: 'close',
index: 50,
html: `${$(art.icons.close).html()}${art.i18n.language["Close"]}`,
style: contextmenuStyle
})
art.on('fullscreen', (state) => {
$('#header').fadeToggle();
$(art.controls.fullscreenWeb).toggle();
$(art.controls.hideList).toggle();
$(art.controls.goodRing).toggle();
if (!$('body').hasClass('no-scroll')) {
$('body').addClass('no-scroll');
} else {
$('body').removeClass('no-scroll');
}
});
art.on('fullscreenWeb', (state) => {
$('#header').fadeToggle();
$(art.controls.fullscreen).toggle();
$(art.controls.hideList).toggle();
$(art.controls.goodRing).toggle();
if (!$('body').hasClass('no-scroll')) {
$('body').addClass('no-scroll');
} else {
$('body').removeClass('no-scroll');
}
});
$(art.template.$container).find(".icon").removeClass("icon")
addStyle('Artplayer-User', 'style', `
.art-contextmenu svg, .art-contextmenu img {
vertical-align: top;
margin-right: 5px
}
`);
actionFunction ? actionFunction(art) : ""
}
// 格式化文件大小函数
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// 获取文件大小函数
function getFileSize(url) {
return new Promise((resolve, reject) => {
fetch(url, { method: 'HEAD' })
.then(response => {
if (!response.ok) throw new Error('网络响应失败');
let contentLength = response.headers.get('Content-Length');
resolve(parseInt(contentLength));
})
.catch(error => {
reject(error);
});
});
}
function waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector) {
var targetbadges, btargetsFound;
if (typeof iframeSelector == "undefined")
targetbadges = $(selectorTxt);
else
targetbadges = $(iframeSelector).contents().find(selectorTxt);
if (targetbadges && targetbadges.length > 0) {
btargetsFound = true;
targetbadges.each(function () {
var jThis = $(this);
var alreadyFound = jThis.data('alreadyFound') || false;
if (!alreadyFound) {
var cancelFound = actionFunction(jThis);
if (cancelFound) {
btargetsFound = false;
} else {
jThis.data('alreadyFound', true);
}
}
});
} else {
btargetsFound = false;
}
var controlObj = waitForKeyElements.controlObj || {};
var controlKey = selectorTxt.replace(/[^\w]/g, "_");
var timeControl = controlObj[controlKey];
if (btargetsFound && bWaitOnce && timeControl) {
clearInterval(timeControl);
delete controlObj[controlKey];
} else {
if (!timeControl) {
timeControl = setInterval(function () {
waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector);
}, 1000);
controlObj[controlKey] = timeControl;
}
}
waitForKeyElements.controlObj = controlObj;
}
$("head").before($(`
`))
})();