import { BasePlugin } from '../core/base-plugin.js';
import { __publicField } from '../core/constants.js';
import { CDN_SOURCES, STORE_NAME, dbHelper } from './task.js';
class NewVideoPlugin extends BasePlugin {
constructor() {
super(...arguments);
__publicField(this, "currentPage", 1);
__publicField(this, "pageSize", 30);
}
getName() {
return "NewVideoPlugin";
}
async initCss() {
return "\n \n ";
}
async showNewVideoCount() {
const totalNewVideoCount = (await storageManager.getFavoriteActressList()).reduce(((accumulator, actress) => {
var _a2;
return accumulator + ((null == (_a2 = actress.newVideoList) ? void 0 : _a2.length) ?? 0);
}), 0);
$("#newVideoCount").text(`${totalNewVideoCount}`);
}
async resetBtnTip() {
const taskPlugin = this.getBean("TaskPlugin"), settingObj = await storageManager.getSetting(), lastCheckTimeStr = localStorage.getItem(taskPlugin.lastCheckFavoriteActressTimeKey) || "无", checkFavoriteActress_IntervalTime = settingObj.checkFavoriteActress_IntervalTime, lastCheckNewVideoTimeStr = localStorage.getItem(taskPlugin.lastCheckNewVideoTimeKey) || "无", checkNewVideo_intervalTime = settingObj.checkNewVideo_intervalTime;
$("#checkFavoriteActress").attr("data-tip", `上次自动同步时间: ${lastCheckTimeStr}; 检测间隔时间: ${checkFavoriteActress_IntervalTime}小时`);
$("#checkNewVideo").attr("data-tip", `上次检测时间: ${lastCheckNewVideoTimeStr}; 检测间隔时间: ${checkNewVideo_intervalTime}小时`);
}
async openDialog() {
const taskPlugin = this.getBean("TaskPlugin"), settingObj = await storageManager.getSetting(), lastCheckTimeStr = localStorage.getItem(taskPlugin.lastCheckFavoriteActressTimeKey) || "无", checkFavoriteActress_IntervalTime = settingObj.checkFavoriteActress_IntervalTime, lastCheckNewVideoTimeStr = localStorage.getItem(taskPlugin.lastCheckNewVideoTimeKey) || "无", checkNewVideo_intervalTime = settingObj.checkNewVideo_intervalTime;
let html = `\n
\n `;
layer.open({
type: 1,
title: '新作品检测 ❓',
content: html,
scrollbar: !1,
area: utils.getResponsiveArea([ "80%", "90%" ]),
anim: -1,
success: async (layero, index) => {
this.loadData();
this.bindClick();
utils.setupEscClose(index);
}
});
}
bindClick() {
const taskPlugin = this.getBean("TaskPlugin");
$("#reLoad").on("click", (event => {
this.loadData();
$("#checkNewVideoMsg").text("");
}));
$("#toSetting").on("click", (event => {
this.getBean("SettingPlugin").openSettingDialog("task-panel", (() => {
$("#setting-checkFavoriteActress").css({
border: "1px solid #f40"
});
$("#setting-checkNewVideo").css({
border: "1px solid #f40"
});
}));
}));
$("#checkFavoriteActress").on("click", (event => {
utils.q({
clientX: event.clientX,
clientY: event.clientY + 20
}, "是否手动同步演员?", (() => {
navigator.locks.request(taskPlugin.singleTaskKey, {
ifAvailable: !0
}, (async lock => {
if (!lock) {
show.error("当前有定时任务在后台执行中, 无法发起手动任务");
return;
}
if ($('a[href*="/users/profile"]').length > 0) {
await taskPlugin.checkFavoriteActress();
this.loadData();
} else show.error("未登录JavDb, 同步失败");
})).catch((error => {
console.error("锁任务出现错误:", error);
clog.error("锁任务出现错误:", error);
}));
}));
}));
$("#checkNewVideo").on("click", (event => {
utils.q({
clientX: event.clientX,
clientY: event.clientY + 20
}, "是否手动检测最新作品?", (() => {
navigator.locks.request(taskPlugin.singleTaskKey, {
ifAvailable: !0
}, (async lock => {
lock ? await taskPlugin.checkNewVideo(!0) : show.error("当前有定时任务在后台执行中, 无法发起手动任务");
})).catch((error => {
console.error("锁任务出现错误:", error);
clog.error("锁任务出现错误:", error);
}));
}));
}));
$("#paramActressType").on("change", (event => {
this.loadData();
}));
}
loadData() {
this.currentPage = 1;
this.renderActressCards().then();
}
async renderActressCards() {
const $actressCardContainer = $("#actress-card-container");
if (!$actressCardContainer.length) return;
let favoriteActressesList = await storageManager.getFavoriteActressList();
const paramActressType = $("#paramActressType").val();
"all" !== paramActressType && (favoriteActressesList = favoriteActressesList.filter((actress => actress.actressType === paramActressType)));
const fullActressList = utils.genericSort(favoriteActressesList, [ {
key: item => {
var _a2;
return (null == (_a2 = item.newVideoList) ? void 0 : _a2.length) ?? 0;
},
order: "desc"
}, {
key: "lastPublishTime",
order: "desc"
} ]), totalCount = fullActressList.length, totalPages = Math.ceil(totalCount / this.pageSize), startIndex = (this.currentPage - 1) * this.pageSize, endIndex = startIndex + this.pageSize, pagedData = fullActressList.slice(startIndex, endIndex), javDbUrl = await this.getBean("OtherSitePlugin").getJavDbUrl(), taskPlugin = this.getBean("TaskPlugin"), checkNewVideo_ruleTime = await storageManager.getSetting("checkNewVideo_ruleTime") || 8760, cardsHtml = pagedData.map((data => {
var _a2, _b, _c;
const allNamesStr = Array.isArray(data.allName) ? data.allName.join(",") : "";
Array.isArray(data.newVideoList) && data.newVideoList.join(",");
const detailLink = `${javDbUrl}/actors/${data.starId}?t=d`;
let isUnCheck = !1;
data.lastPublishTime && (isUnCheck = !taskPlugin.isUnnecessaryCheck(data.lastPublishTime, checkNewVideo_ruleTime));
let actressTypeText = "未知", actressTypeBgc = "#9E9E9E";
if ("uncensored" === data.actressType) {
actressTypeText = "无码";
actressTypeBgc = "#4CAF50";
} else if ("censored" === data.actressType) {
actressTypeText = "有码";
actressTypeBgc = "#FF9800";
}
let cardUnnecessaryBtnCss = "";
isUnCheck && (cardUnnecessaryBtnCss = "background: linear-gradient(145deg, #e0e0e0 0%, #cabdbd 100%);box-shadow: none");
return `\n \n
\n
\n \n\n
\n \n
\n 上次检测: ${data.lastCheckTime || ""}\n
\n
\n 最后发行作品: ${data.lastPublishTime || ""}\n
\n\n
\n ${isUnCheck ? "停更" + checkNewVideo_ruleTime / 24 / 365 + "年以上, 下轮任务不再进行检测" : ""}\n
\n \n
\n ${data.remark || ""}\n
\n \n
\n \n
${actressTypeText}
\n
\n 🔔 ${(null == (_c = data.newVideoList) ? void 0 : _c.length) || 0} \n
\n
\n `;
})).join("");
$actressCardContainer.html(cardsHtml);
$(".btn-delete-actress").off("click").on("click", (e => {
e.preventDefault();
const starId = $(e.currentTarget).attr("data-starId"), actress = fullActressList.find((item => item.starId === starId));
utils.q(e, `是否取消收藏 ${actress.name}?`, (async () => {
let deleteActressUrl = `${await this.getBean("OtherSitePlugin").getJavDbUrl()}/actors/${starId}/uncollect`;
const csrfToken = document.querySelector("meta[name=csrf-token]").content, res = await gmHttp.post(deleteActressUrl, null, {
"x-csrf-token": csrfToken
});
if (res.includes("removeClass")) {
await storageManager.removeFavoriteActress(starId);
this.loadData();
} else {
show.error("移除失败");
clog.error("移除失败,返回值:", res);
}
}));
}));
$(".btn-edit-actress").off("click").on("click", (e => {
e.preventDefault();
const starId = $(e.currentTarget).attr("data-starId"), actress = fullActressList.find((item => item.starId === starId));
actress ? this.editActress(actress) : show.error(`未找到 starId 为 ${starId} 的女优记录。`);
}));
$(".btn-check-actress").off("click").on("click", (e => {
e.preventDefault();
navigator.locks.request(taskPlugin.singleTaskKey, {
ifAvailable: !0
}, (async lock => {
if (!lock) {
show.error("当前有定时任务在后台执行中, 无法发起手动任务");
return;
}
const starId = $(e.currentTarget).attr("data-starId"), actress = fullActressList.find((item => item.starId === starId));
await taskPlugin.checkOneNewVideo(actress);
})).catch((error => {
console.error("锁任务出现错误:", error);
clog.error("锁任务出现错误:", error);
}));
}));
this.renderPagination(totalCount, totalPages);
show.ok("加载完成");
}
async editActress(actress) {
const initialName = actress.name, initialAvatar = actress.avatar, initialRemark = actress.remark || "", initialAllName = Array.isArray(actress.allName) ? actress.allName.join(",") : "", initialNewVideoList = Array.isArray(actress.newVideoList) ? actress.newVideoList.join(",") : "", starId = actress.starId, textareaStyle = "width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; min-height: 60px; overflow-y: hidden;", initActressType = actress.actressType || "", editFormHtml = `\n \n
\n

\n
\n
\n
\n
\n \n \n
\n
\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n `;
layer.open({
type: 1,
title: `编辑女优: ${initialName} (${starId})`,
area: [ "500px", "750px" ],
content: editFormHtml,
btn: [ "保存", "取消" ],
success: (layero, index) => {
const autoResizeTextarea = $textarea => {
$textarea.css("height", "auto");
$textarea.css("height", $textarea[0].scrollHeight + 15 + "px");
};
$("#edit-actress-avatar").on("input", (function() {
const newUrl = $(this).val();
$("#edit-avatar-preview").attr("src", newUrl);
}));
const $allNameTextarea = $("#edit-actress-allname");
$allNameTextarea.on("input", (function() {
autoResizeTextarea($(this));
}));
autoResizeTextarea($allNameTextarea);
const $videoListTextarea = $("#edit-actress-newvideolist");
$videoListTextarea.on("input", (function() {
autoResizeTextarea($(this));
}));
autoResizeTextarea($videoListTextarea);
$("#search-avatar-btn").on("click", (async () => {
await this.searchAvatar();
}));
$("#select-cdn-btn").on("click", (async () => {
await async function() {
const initialIndex = currentCdnIndex, radioOptions = CDN_SOURCES.map(((source, index) => `\n \n \n \n
\n `)).join(""), cdnSelectHtml = `\n \n
请选择头像数据源 (当前: ${CDN_SOURCES[initialIndex].name}):
\n ${radioOptions}\n
切换源会清除本地缓存的数据,并在下次搜索时重新加载。
\n
\n `;
layer.open({
type: 1,
title: "选择 CDN 源",
area: [ "400px", "auto" ],
content: cdnSelectHtml,
btn: [ "确定", "取消" ],
success: (layero, index) => {
utils.setupEscClose(index);
},
yes: async index => {
const newIndexStr = $('input[name="cdn-source"]:checked').val(), newIndex = parseInt(newIndexStr, 10);
if (newIndex !== currentCdnIndex) {
currentCdnIndex = newIndex;
localStorage.setItem("jhs_img_cdn_index", newIndex.toString());
window.G_FRIENDS_JSON_URL = CDN_SOURCES[newIndex].json;
window.CDN_BASE_URL = CDN_SOURCES[newIndex].base;
window.G_FRIENDS_DATA_CACHE = null;
window.G_FRIENDS_AVATAR_MAP = null;
try {
await dbHelper.set("filetree_data", null);
} catch (e) {
clog.error("清除 IndexedDB 缓存失败:", e);
}
show.ok(`CDN 源已切换为: ${CDN_SOURCES[newIndex].name}`);
layer.close(index);
} else layer.close(index);
}
});
}();
}));
utils.setupEscClose(index);
},
yes: async index => {
const newAvatar = $("#edit-actress-avatar").val().trim(), newName = $("#edit-actress-name").val().trim(), newAllNameStr = $("#edit-actress-allname").val().trim(), newVideoListStr = $("#edit-actress-newvideolist").val().trim(), newRemark = $("#edit-remark").val().trim(), newActressType = $("#actressType").val();
if (!newName) {
show.error("主名称不能为空");
return !1;
}
const newAllName = newAllNameStr.split(/[\uff0c,]/).map((n => n.trim())).filter((n => n.length > 0)), newVideoList = newVideoListStr.split(/[\uff0c,]/).map((n => n.trim())).filter((n => n.length > 0));
actress.avatar = newAvatar;
actress.name = newName;
actress.allName = newAllName;
actress.newVideoList = newVideoList;
actress.actressType = newActressType;
actress.remark = newRemark;
if (await storageManager.updateFavoriteActress(actress)) show.error("修改失败"); else {
show.ok(`女优 ${newName} 信息已更新`);
await this.renderActressCards();
layer.close(index);
}
}
});
}
renderPagination(totalCount, totalPages) {
const currentPage = this.currentPage;
let paginationHtml = "";
const $actressPagination = $("#actress-pagination");
if (0 === totalPages) {
paginationHtml = '共 0 条记录';
$actressPagination.html(paginationHtml);
return;
}
currentPage > 1 && totalPages > 5 && (paginationHtml += '');
currentPage > 1 && (paginationHtml += ``);
let startPage = Math.max(1, currentPage - Math.floor(2.5)), endPage = Math.min(totalPages, startPage + 5 - 1);
endPage - startPage < 4 && (startPage = Math.max(1, endPage - 5 + 1));
for (let i = startPage; i <= endPage; i++) {
paginationHtml += ``;
}
currentPage < totalPages && (paginationHtml += ``);
currentPage < totalPages && totalPages > 5 && (paginationHtml += ``);
paginationHtml += `共 ${totalCount} 条记录 (第 ${currentPage}/${totalPages} 页)`;
$actressPagination.html(paginationHtml);
$(".pagination-btn").off("click").on("click", (e => {
if ($(e.currentTarget).is("[disabled]")) return;
const newPage = parseInt($(e.currentTarget).data("page"));
if (newPage >= 1 && newPage <= totalPages && newPage !== this.currentPage) {
this.currentPage = newPage;
this.renderActressCards();
}
}));
}
async searchAvatar() {
const $mainNameInput = $("#edit-actress-name"), $aliasInput = $("#edit-actress-allname"), currentName = $mainNameInput.val().trim(), searchNames = $aliasInput.val().trim().split(/[\uff0c,]/).map((n => n.trim())).filter((n => n.length > 0));
currentName && searchNames.unshift(currentName);
if (0 === searchNames.length) {
show.error("请先填写女优主名称或别名进行搜索。");
return;
}
const loadObj = loading("正在搜索头像...");
let imageLinks = [];
try {
imageLinks = await searchActorAvatars(searchNames);
} catch (e) {
show.error(`头像数据加载或搜索失败: ${e.message || e}`);
return;
} finally {
loadObj.close();
}
if (0 === imageLinks.length) {
show.error(`未找到与 '${searchNames.join("、")}' 相关的头像。请检查名称。`);
return;
}
const imageItems = imageLinks.map(((url, index) => `\n \n

\n
...
\n
\n `)).join(""), imageListHtml = `\n \n \n \n
\n 点击图片即可选择(初始共 ${imageLinks.length} 张)\n
\n
\n
\n `;
let errorCount = 0;
layer.open({
type: 1,
title: `选择女优头像 (${imageLinks.length} 张)`,
area: utils.getResponsiveArea([ "900px", "85%" ]),
content: imageListHtml,
btn: [ "关闭" ],
success: (selectionLayero, selectionIndex) => {
const $container = $(selectionLayero), $images = $container.find(".gfriends-selectable-img"), $prompt = $container.find("#gfriends-prompt");
$images.each((function() {
const $img = $(this), wrapperId = $img.data("wrapper-id"), $wrapper = $container.find(`#${wrapperId}`), $sizeTag = $container.find(`.gfriends-size-tag[data-size-for="${wrapperId}"]`);
$img.on("load", (function() {
const width = this.naturalWidth, height = this.naturalHeight;
$sizeTag.text(`${width} x ${height}`);
}));
$img.on("error", (function() {
$wrapper.remove();
errorCount++;
const validCount = imageLinks.length - errorCount;
$prompt.text(`点击图片即可选择(已移除 ${errorCount} 张错误图片,剩余 ${validCount} 张)`);
if (0 === validCount) {
show.error("所有搜索到的头像链接均已失效,无法选择。");
layer.close(selectionIndex);
}
}));
this.complete && (this.naturalWidth > 0 ? $img.trigger("load") : $img.trigger("error"));
}));
$images.on("click", (function() {
const $clickedImg = $(this), selectedUrl = $clickedImg.data("url");
$("#edit-actress-avatar").val(selectedUrl);
$("#edit-avatar-preview").attr("src", selectedUrl);
$images.removeClass("is-selected");
$clickedImg.addClass("is-selected");
setTimeout((() => {
layer.close(selectionIndex);
}), 150);
}));
utils.setupEscClose(selectionIndex);
}
});
}
}
export { NewVideoPlugin };