mirror of
https://github.com/fireinrain/JHS-enhance.git
synced 2026-09-28 15:46:38 +08:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 39f252fa0b | |||
| d99af94e74 | |||
| 2383406ede | |||
| 8da5c36bf2 |
@@ -12,43 +12,29 @@
|
||||
|
||||
### 一键安装
|
||||
|
||||
[](https://github.com/替换为你的用户名/JHS-enhance/releases/latest/download/jhs-enhance.user.js)
|
||||
[](https://github.com/fireinrain/JHS-enhance/releases/latest/download/jhs-enhance.user.js)
|
||||
|
||||
> 点击上方按钮,Tampermonkey 会自动弹出安装提示。安装后脚本会自动更新(Tampermonkey 默认每天检查一次更新)。
|
||||
|
||||
### 手动安装
|
||||
|
||||
1. 从 [Releases](https://github.com/替换为你的用户名/JHS-enhance/releases) 页面下载最新 `jhs-enhance.user.js`
|
||||
1. 从 [Releases](https://github.com/fireinrain/JHS-enhance/releases) 页面下载最新 `jhs-enhance.user.js`
|
||||
2. 打开 Tampermonkey 管理面板 → 拖入文件安装
|
||||
|
||||
---
|
||||
|
||||
## 自动部署配置
|
||||
## 自动部署
|
||||
|
||||
本项目使用 GitHub Actions 在推送代码时自动构建并发布到 [GitHub Releases](https://github.com/替换为你的用户名/JHS-enhance/releases)。首次使用只需一步:
|
||||
|
||||
### 修改 README 中的安装链接
|
||||
|
||||
将 README.md 中所有 `替换为你的用户名` 替换为你的 GitHub 用户名:
|
||||
|
||||
```
|
||||
https://github.com/你的用户名/JHS-enhance/releases/latest/download/jhs-enhance.user.js
|
||||
```
|
||||
|
||||
推送代码后,GitHub Actions 自动构建并将脚本上传到 Release,无需额外配置。
|
||||
|
||||
### 工作原理
|
||||
本项目使用 GitHub Actions 在推送代码时自动构建并发布到 [GitHub Releases](https://github.com/fireinrain/JHS-enhance/releases)。
|
||||
|
||||
```
|
||||
git push → GitHub Actions 自动构建 → 发布 GitHub Release
|
||||
↓
|
||||
https://github.com/用户名/JHS-enhance/releases/latest/download/jhs-enhance.user.js
|
||||
https://github.com/fireinrain/JHS-enhance/releases/latest/download/jhs-enhance.user.js
|
||||
↓
|
||||
用户点击安装链接 → Tampermonkey 弹出安装提示
|
||||
```
|
||||
|
||||
> **为什么不用 GitHub Pages?** Release 方案更简单,不需要配置 Pages,不需要额外权限,`/releases/latest/download/` 是固定链接,每次发版自动指向最新脚本。
|
||||
|
||||
---
|
||||
|
||||
## 功能概览
|
||||
|
||||
Vendored
+152
-3
@@ -2,7 +2,7 @@
|
||||
// @name JAV-JHS
|
||||
// @namespace JAV-JHS
|
||||
// @version 3.3.6-fix
|
||||
// @author xie bro
|
||||
// @author xie bro,fireinrain
|
||||
// @description Jav-鉴黄师 收藏、屏蔽、标记已下载; 屏蔽标签、屏蔽演员、同步收藏演员、新作品检测; 免VIP查看热播、Top250排行榜、Fc2ppv、可查看所有评论信息、相关清单; 支持云盘备份; 以图识图; 字幕搜索; JavDb|JavBus
|
||||
// @license MIT
|
||||
// @icon https://www.google.com/s2/favicons?sz=64&domain=javdb.com
|
||||
@@ -8082,6 +8082,47 @@ ${err.stack}` : "");
|
||||
}
|
||||
return fileId;
|
||||
}
|
||||
async deleteOfflineTasksByKeyword(keyword) {
|
||||
try {
|
||||
const singInfo = await (async () => {
|
||||
const res = await gmHttp.get("https://115.com/?ct=offline&ac=space&_=" + (/* @__PURE__ */ new Date()).getTime());
|
||||
return "object" == typeof res ? res : null;
|
||||
})();
|
||||
if (!singInfo) {
|
||||
console.error("删除离线任务: 未登录115网盘");
|
||||
return;
|
||||
}
|
||||
const {sign, time} = singInfo, uid = singInfo.uid || (() => {
|
||||
const match = document.cookie.match(/UID=(\d+)_/);
|
||||
return match ? match[1] : null;
|
||||
})() || await this.getUserId();
|
||||
const taskListRes = await gmHttp.postForm("https://115.com/web/lixian/?ct=lixian&ac=task_lists", {
|
||||
page: 1,
|
||||
uid,
|
||||
sign,
|
||||
time
|
||||
});
|
||||
const tasks = (null == taskListRes ? void 0 : taskListRes.tasks) || [];
|
||||
const keyword2 = keyword.toLowerCase().replace("fc2-", "");
|
||||
let deletedCount = 0;
|
||||
for (const task of tasks) {
|
||||
if (task.name && task.name.toLowerCase().includes(keyword2)) {
|
||||
console.log(`删除离线任务: ${task.name} (hash: ${task.info_hash})`);
|
||||
await gmHttp.postForm("https://115.com/web/lixian/?ct=lixian&ac=task_del", {
|
||||
"hash[0]": task.info_hash,
|
||||
flag: 1,
|
||||
uid,
|
||||
sign,
|
||||
time
|
||||
});
|
||||
deletedCount++;
|
||||
}
|
||||
}
|
||||
deletedCount > 0 && console.log(`共删除 ${deletedCount} 个离线任务`);
|
||||
} catch (error) {
|
||||
console.error("删除离线任务失败:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
class ScreenShotPlugin extends BasePlugin {
|
||||
getName() {
|
||||
@@ -8666,11 +8707,25 @@ ${err.stack}` : "");
|
||||
}
|
||||
}
|
||||
updateMatchStatus($box2, carNum2, matchList) {
|
||||
matchList.length > 0 ? $box2.find(".jhs-match-btn").replaceWith(`<a class='jhs-match-btn a-success'
|
||||
if (matchList.length > 0) {
|
||||
$box2.find(".jhs-match-btn").replaceWith(`<a class='jhs-match-btn a-success'
|
||||
data-keyword="${carNum2}"
|
||||
data-match='${JSON.stringify(matchList)}'
|
||||
title="点击查看匹配详情">匹配${matchList.length}个</a>`) : $box2.find(".jhs-match-btn").replaceWith(`<a class='jhs-match-error-btn a-info' data-keyword="${carNum2}"
|
||||
title="点击查看匹配详情">匹配${matchList.length}个</a>`);
|
||||
const $deleteBtn = $box2.find(".delete115Svg");
|
||||
if ($deleteBtn.length > 0 && matchList[0].dirId) {
|
||||
$deleteBtn.attr("data-match", JSON.stringify(matchList));
|
||||
$deleteBtn.show();
|
||||
}
|
||||
} else {
|
||||
$box2.find(".jhs-match-btn").replaceWith(`<a class='jhs-match-error-btn a-info' data-keyword="${carNum2}"
|
||||
title="点击重新尝试匹配">未匹配</a>`);
|
||||
const $deleteBtn = $box2.find(".delete115Svg");
|
||||
if ($deleteBtn.length > 0) {
|
||||
$deleteBtn.removeAttr("data-match");
|
||||
$deleteBtn.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
async handleLoginRedirect() {
|
||||
window.open("https://115.com");
|
||||
@@ -8680,6 +8735,7 @@ ${err.stack}` : "");
|
||||
let searchKeyword = carNum2.toLowerCase().replace("fc2-", "");
|
||||
return (null == (_a2 = (await searchFiles(searchKeyword)).data) ? void 0 : _a2.map(((data) => ({
|
||||
folderId: data.fid,
|
||||
dirId: data.cid,
|
||||
videoId: data.pc,
|
||||
name: data.n,
|
||||
createTime: utils.formatDate(new Date(1e3 * data.te)),
|
||||
@@ -8729,6 +8785,11 @@ ${err.stack}` : "");
|
||||
data-keyword="${carNum2}"
|
||||
data-match='${JSON.stringify(matchList)}'
|
||||
title="${title}">匹配${matchList.length}个</a>`);
|
||||
const $deleteBtn = $box2.find(".delete115Svg");
|
||||
if ($deleteBtn.length > 0 && matchList[0].dirId) {
|
||||
$deleteBtn.attr("data-match", JSON.stringify(matchList));
|
||||
$deleteBtn.show();
|
||||
}
|
||||
} else $box2.find(".video-title").prepend(`<a class='jhs-match-error-btn a-info'
|
||||
data-keyword="${carNum2}"
|
||||
title="未匹配,点击重试">未匹配</a>`);
|
||||
@@ -9805,6 +9866,7 @@ ${err.stack}` : "");
|
||||
if (!($box2.find(".tool-box").length > 0)) {
|
||||
isJavDb$1 && $box2.find(".tags").append(`
|
||||
<div class="tool-box" style="margin-left: auto; display: flex; align-items: center">
|
||||
<span class="delete115Svg" title="删除115作品" style="margin-right: 15px; display: none;">${this.removeSvg}</span>
|
||||
<span class="screenSvg" title="长缩略图" style="margin-right: 15px;">${this.screenSvg}</span>
|
||||
|
||||
<span class="videoSvg" title="播放视频" style="margin-right: 15px;">${this.videoSvg}</span>
|
||||
@@ -9867,6 +9929,7 @@ ${err.stack}` : "");
|
||||
if ($box2.find(".avatar-box").length > 0) return;
|
||||
$box2.find(".photo-info").append(`
|
||||
<div class="tool-box" style="display: flex; align-items: center;justify-content: flex-end">
|
||||
<span class="delete115Svg" title="删除115作品" style="margin-right: 15px; display: none;">${this.removeSvg}</span>
|
||||
<span class="screenSvg" title="长缩略图" style="margin-right: 15px;">${this.screenSvg}</span>
|
||||
|
||||
<span class="videoSvg" title="播放视频" style="margin-right: 15px;">${this.videoSvg}</span>
|
||||
@@ -10039,6 +10102,92 @@ ${err.stack}` : "");
|
||||
utils.download(blob, carNum2 + " " + title + ".jpg");
|
||||
}));
|
||||
}));
|
||||
$(document).on("click", ".delete115Svg", (async (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const $btn = $(event.currentTarget);
|
||||
const matchData = $btn.attr("data-match");
|
||||
if (!matchData) {
|
||||
show.error("未找到115匹配数据");
|
||||
return;
|
||||
}
|
||||
const matchList = JSON.parse(matchData);
|
||||
const $box2 = $btn.closest(".item");
|
||||
const { carNum: carNum2 } = this.getBoxCarInfo($box2);
|
||||
this.showDeleteDialog(carNum2, matchList, $box2);
|
||||
}));
|
||||
}
|
||||
|
||||
showDeleteDialog(carNum2, matchList, $box2) {
|
||||
const formatSize = (bytes) => {
|
||||
if (!bytes) return "-";
|
||||
const units = ["B", "KB", "MB", "GB", "TB"];
|
||||
let size = parseFloat(bytes), unit = 0;
|
||||
for (; size >= 1024 && unit < units.length - 1;) size /= 1024, unit++;
|
||||
return size.toFixed(2) + " " + units[unit];
|
||||
};
|
||||
let html = '<div style="padding: 15px; max-height: 400px; overflow-y: auto;">';
|
||||
html += `<div style="margin-bottom: 12px; font-size: 14px;">作品 <b>${carNum2}</b> 匹配到 <b>${matchList.length}</b> 个文件夹:</div>`;
|
||||
html += '<div style="margin-bottom: 10px;"><label style="cursor: pointer;"><input type="checkbox" class="jhs-delete-select-all" checked> <b>全选</b></label></div>';
|
||||
for (let i = 0; i < matchList.length; i++) {
|
||||
const m = matchList[i];
|
||||
html += `<div style="margin-bottom: 6px; padding: 8px 10px; border: 1px solid #e0e0e0; border-radius: 4px; background: #fafafa;">
|
||||
<label style="display: flex; align-items: flex-start; cursor: pointer; width: 100%;">
|
||||
<input type="checkbox" class="jhs-delete-folder-cb" data-index="${i}" checked style="margin-top: 3px; flex-shrink: 0;">
|
||||
<span style="margin-left: 8px; flex: 1;">
|
||||
<div style="word-break: break-all;">${m.name}</div>
|
||||
<div style="font-size: 12px; color: #888; margin-top: 2px;">${formatSize(m.size)} | ${m.createTime}</div>
|
||||
</span>
|
||||
</label>
|
||||
</div>`;
|
||||
}
|
||||
html += "</div>";
|
||||
const layerIndex = layer.open({
|
||||
type: 1,
|
||||
title: `删除115作品文件夹`,
|
||||
content: html,
|
||||
area: ["520px", "auto"],
|
||||
btn: ["确定删除", "取消"],
|
||||
shadeClose: false,
|
||||
yes: async (index) => {
|
||||
const $layer = $(`#layui-layer${index}`);
|
||||
const checked = $layer.find(".jhs-delete-folder-cb:checked");
|
||||
if (0 === checked.length) {
|
||||
show.error("请至少选择一个文件夹");
|
||||
return;
|
||||
}
|
||||
const selected = checked.map((function () {
|
||||
return parseInt($(this).data("index"));
|
||||
})).get();
|
||||
layer.close(index);
|
||||
let loadObj = loading();
|
||||
let deletedCount = 0;
|
||||
try {
|
||||
for (const i of selected) {
|
||||
const m = matchList[i];
|
||||
const result = await gmHttp.postForm("https://webapi.115.com/rb/delete", {
|
||||
pid: m.dirId,
|
||||
"fid[0]": m.folderId
|
||||
});
|
||||
result && result.state ? deletedCount++ : console.error(`删除失败: ${m.name}`, result);
|
||||
}
|
||||
loadObj.close();
|
||||
show.ok(`作品 "${carNum2}" 已删除 ${deletedCount} 个文件夹`);
|
||||
const matchPlugin = this.getBean("WangPan115MatchPlugin");
|
||||
const newMatchList = await matchPlugin.searchFiles(carNum2);
|
||||
matchPlugin.updateMatchStatus($box2, carNum2, newMatchList);
|
||||
this.getBean("WangPan115TaskPlugin").deleteOfflineTasksByKeyword(carNum2);
|
||||
} catch (error) {
|
||||
loadObj.close();
|
||||
console.error("删除115文件失败:", error);
|
||||
show.error(`删除失败: ${error.message || "网络错误"}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
$(`#layui-layer${layerIndex}`).on("change", ".jhs-delete-select-all", (function () {
|
||||
const checked = $(this).prop("checked");
|
||||
$(`#layui-layer${layerIndex} .jhs-delete-folder-cb`).prop("checked", checked);
|
||||
}));
|
||||
}
|
||||
showImg($svgElement, $img, carNum2) {
|
||||
$svgElement.html(this.videoSvg).attr("title", "播放视频");
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -145,6 +145,49 @@ class WangPan115TaskPlugin extends BasePlugin {
|
||||
}
|
||||
return fileId;
|
||||
}
|
||||
|
||||
//TODO: 暂时没有删除离线任务
|
||||
// async deleteOfflineTasksByKeyword(keyword) {
|
||||
// try {
|
||||
// const singInfo = await (async () => {
|
||||
// const res = await gmHttp.get("https://115.com/?ct=offline&ac=space&_=" + (new Date).getTime());
|
||||
// return "object" == typeof res ? res : null;
|
||||
// })();
|
||||
// if (!singInfo) {
|
||||
// console.error("删除离线任务: 未登录115网盘");
|
||||
// return;
|
||||
// }
|
||||
// const {sign: sign, time: time} = singInfo, uid = singInfo.uid || (() => {
|
||||
// const match = document.cookie.match(/UID=(\d+)_/);
|
||||
// return match ? match[1] : null;
|
||||
// })() || await this.getUserId();
|
||||
// const taskListRes = await gmHttp.postForm("https://115.com/web/lixian/?ct=lixian&ac=task_lists", {
|
||||
// page: 1,
|
||||
// uid: uid,
|
||||
// sign: sign,
|
||||
// time: time
|
||||
// });
|
||||
// const tasks = (null == taskListRes ? void 0 : taskListRes.tasks) || [];
|
||||
// const keyword2 = keyword.toLowerCase().replace("fc2-", "");
|
||||
// let deletedCount = 0;
|
||||
// for (const task of tasks) {
|
||||
// if (task.name && task.name.toLowerCase().includes(keyword2)) {
|
||||
// console.log(`删除离线任务: ${task.name} (hash: ${task.info_hash})`);
|
||||
// await gmHttp.postForm("https://115.com/web/lixian/?ct=lixian&ac=task_del", {
|
||||
// "hash[0]": task.info_hash,
|
||||
// flag: 1,
|
||||
// uid: uid,
|
||||
// sign: sign,
|
||||
// time: time
|
||||
// });
|
||||
// deletedCount++;
|
||||
// }
|
||||
// }
|
||||
// deletedCount > 0 && console.log(`共删除 ${deletedCount} 个离线任务`);
|
||||
// } catch (error) {
|
||||
// console.error("删除离线任务失败:", error);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -341,7 +341,21 @@ const _WangPan115MatchPlugin = class _WangPan115MatchPlugin extends BasePlugin {
|
||||
}
|
||||
}
|
||||
updateMatchStatus($box2, carNum2, matchList) {
|
||||
matchList.length > 0 ? $box2.find(".jhs-match-btn").replaceWith(`<a class='jhs-match-btn a-success' \n data-keyword="${carNum2}"\n data-match='${JSON.stringify(matchList)}'\n title="点击查看匹配详情">匹配${matchList.length}个</a>`) : $box2.find(".jhs-match-btn").replaceWith(`<a class='jhs-match-error-btn a-info' data-keyword="${carNum2}" \n title="点击重新尝试匹配">未匹配</a>`);
|
||||
if (matchList.length > 0) {
|
||||
$box2.find(".jhs-match-btn").replaceWith(`<a class='jhs-match-btn a-success' \n data-keyword="${carNum2}"\n data-match='${JSON.stringify(matchList)}'\n title="点击查看匹配详情">匹配${matchList.length}个</a>`);
|
||||
const $deleteBtn = $box2.find(".delete115Svg");
|
||||
if ($deleteBtn.length > 0 && matchList[0].dirId) {
|
||||
$deleteBtn.attr("data-match", JSON.stringify(matchList));
|
||||
$deleteBtn.show();
|
||||
}
|
||||
} else {
|
||||
$box2.find(".jhs-match-btn").replaceWith(`<a class='jhs-match-error-btn a-info' data-keyword="${carNum2}" \n title="点击重新尝试匹配">未匹配</a>`);
|
||||
const $deleteBtn = $box2.find(".delete115Svg");
|
||||
if ($deleteBtn.length > 0) {
|
||||
$deleteBtn.removeAttr("data-match");
|
||||
$deleteBtn.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
async handleLoginRedirect() {
|
||||
window.open("https://115.com");
|
||||
@@ -351,6 +365,7 @@ const _WangPan115MatchPlugin = class _WangPan115MatchPlugin extends BasePlugin {
|
||||
let searchKeyword = carNum2.toLowerCase().replace("fc2-", "");
|
||||
return (null == (_a2 = (await searchFiles(searchKeyword)).data) ? void 0 : _a2.map((data => ({
|
||||
folderId: data.fid,
|
||||
dirId: data.cid,
|
||||
videoId: data.pc,
|
||||
name: data.n,
|
||||
createTime: utils.formatDate(new Date(1e3 * data.te)),
|
||||
@@ -392,6 +407,11 @@ const _WangPan115MatchPlugin = class _WangPan115MatchPlugin extends BasePlugin {
|
||||
if (!($box2.find("[class^='jhs-match-']").length > 0)) if (this.loginStatus === _WangPan115MatchPlugin.LoginStatus.LOGGED_OUT) $box2.find(".video-title").prepend(`<a class='jhs-match-no-login-btn a-info' \n data-keyword="${carNum2}" \n title="未登录115网盘">未登录</a>`); else if (matchList.length > 0) {
|
||||
const title = 1 === matchList.length ? "点击直接播放" : `点击查看${matchList.length}个匹配结果`;
|
||||
$box2.find(".video-title").prepend(`<a class='jhs-match-btn a-success' \n data-keyword="${carNum2}"\n data-match='${JSON.stringify(matchList)}'\n title="${title}">匹配${matchList.length}个</a>`);
|
||||
const $deleteBtn = $box2.find(".delete115Svg");
|
||||
if ($deleteBtn.length > 0 && matchList[0].dirId) {
|
||||
$deleteBtn.attr("data-match", JSON.stringify(matchList));
|
||||
$deleteBtn.show();
|
||||
}
|
||||
} else $box2.find(".video-title").prepend(`<a class='jhs-match-error-btn a-info' \n data-keyword="${carNum2}" \n title="未匹配,点击重试">未匹配</a>`);
|
||||
}
|
||||
formatSize(bytes) {
|
||||
|
||||
Reference in New Issue
Block a user