首页推荐卡片展示 — JM Shelf 推荐脚本的模块库,通过 @require 被主脚本引用。
This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.sleazyfork.org/scripts/581111/1842612/JM%20Shelf%20-%20UI%20Recs.js
// ==UserScript==
// @name JM Shelf - UI Recs
// @namespace jmshelf-lib
// @version 1.0.0
// @author Kesdi
// @description 首页推荐卡片展示 — JM Shelf 推荐脚本的模块库,通过 @require 被主脚本引用。
// @license MIT
// ==/UserScript==
//
// 此文件是 GreasyFork 库(library),不直接安装。
// 请安装主脚本: JM Shelf 给杂鱼的个性化推荐
//
// ═══ [13] UI RECOMMENDATIONS ═══ (on homepage)
// ============================================================
function injectRecommendations(recommendations) {
const existing = document.getElementById('jms-recommendations');
if (existing) existing.remove();
if (!recommendations || recommendations.length === 0) return;
const displayItems = recommendations.slice(0, CONFIG.DISPLAY_COUNT);
const wrapper = document.createElement('div');
wrapper.id = 'jms-recommendations';
wrapper.className = 'col-lg-12 col-md-12';
const headerRow = document.createElement('div');
headerRow.className = 'row';
headerRow.innerHTML = '<div class="pull-left"><h4 class="talk-title"><img class="img-circle" src="https://cdn-msp3.18comic.vip/templates/frontend/airav/img/title-png/title-circle.png" alt=""><span class="p-r-15 p-l-15 p-t-5 p-b-5" style="margin-left:5px">' + '\uD83C\uDFAF' + ' 为你推荐</span></h4></div><div class="pull-right m-t-10" style="cursor:pointer" title="点击刷新推荐"><span class="talk-more-btn"><span id="jms-refresh-btn" class="p-r-10 p-l-10 p-t-5 p-b-5" style="cursor:pointer;color:#fff;margin-right:3px" title="点击刷新推荐">刷新</span><img class="img-circle" src="https://cdn-msp3.18comic.vip/templates/frontend/airav/img/title-png/more-ms-jm.webp" alt=""></span></div>';
wrapper.appendChild(headerRow);
const carouselRow = document.createElement('div');
carouselRow.className = 'row m-b-10';
const carousel = document.createElement('div');
carousel.className = 'owl-comic-block';
carousel.style.cssText = 'display:flex;flex-direction:row;overflow-x:auto;overflow-y:hidden;padding-left:1.5rem;list-style:none';
carouselRow.appendChild(carousel);
wrapper.appendChild(carouselRow);
const firstHeading = document.querySelector('.talk-title');
if (firstHeading) {
const sd = firstHeading.closest('.col-lg-12,.col-md-12') || firstHeading.closest('.row') ? firstHeading.closest('.row').parentElement : null;
if (sd && sd.parentNode) sd.parentNode.insertBefore(wrapper, sd);
else (document.querySelector('.container') || document.body).insertBefore(wrapper, (document.querySelector('.container') || document.body).firstChild);
} else {
(document.querySelector('.container, [class*="content"], main') || document.body).insertBefore(wrapper, (document.querySelector('.container, [class*="content"], main') || document.body).firstChild);
}
setTimeout(() => {
const pr = wrapper.querySelector('.pull-right.m-t-10');
if (pr) {
pr.addEventListener('click', (e) => {
_cachedReranked = lightRescore();
_lastLightRescore = Date.now(); _lastCachedT = CONFIG.TEMPERATURE;
if (_cachedReranked.length > 0) {
injectRecommendations(_cachedReranked);
}
showNotification('🔄 已刷新 (T='+CONFIG.TEMPERATURE.toFixed(2)+')');
});
}
}, 100);
// Build one card
function _b(item) {
const al = State.getAlbumCache()[item.id];
const ti = al ? al.title || item.title || '' : item.title || '';
const ta = al ? al.tags || [] : [];
const au = al ? al.authors || [] : [];
const tt = al && al.typeTags ? al.typeTags[0] || '' : '';
const st = al && al.typeTags ? al.typeTags[1] || ta[0] || '' : ta[0] || '';
const lc = al ? al.likes || al.views || 0 : 0;
const ls = lc >= 1000 ? (lc/1000).toFixed(0)+'K' : String(lc);
const mp = Math.round(item.score * 100);
let rl = '\uD83D\uDCCA 综合', rc = '#0f9';
var wm = item._wm || '';
if (wm === 'author+') { rl = '\u270F\uFE0F 作者'; rc = '#e91e63'; }
else if (wm === 'tag+') { rl = '\uD83C\uDFF7\uFE0F 标签'; rc = '#2196f3'; }
else if (wm === 'surprise') { rl = '\uD83C\uDFB2 新发现'; rc = '#ff5722'; }
else if ((item.channels||[]).includes('author')) { rl = '\u270F\uFE0F 作者'; rc = '#e91e63'; }
else if ((item.channels||[]).some(function(x){return x==='explore'||x==='discover'})) { rl = '\uD83C\uDFB2 探索'; rc = '#9c27b0'; }
else if ((item.channels||[]).length >= 5) { rl = '\uD83D\uDD17 多源'; rc = '#ff9800'; }
var tu = 'https://cdn-msp2.18comic.vip/media/albums/' + item.id + '_3x4.jpg';
var cd = document.createElement('div');
cd.className = 'owl-item';
cd.style.cssText = 'width:180px;margin-right:8px;flex-shrink:0';
cd.innerHTML = '<div class="p-b-15 p-l-5 p-r-5" style="padding-top:0;background:initial;box-shadow:none;margin:0"><div class="thumb-overlay-albums"><a href="/album/' + item.id + '/"><img src="' + tu + '" title="' + escapeHtml(ti) + '" alt="' + escapeHtml(ti) + '" class="img-responsive img-rounded" style="width:100%;aspect-ratio:3/4;object-fit:cover" loading="lazy" referrerpolicy="no-referrer" onerror="var s=this,t=s.src;t.onerror=function(){t.onerror=null;t.src=\'https://cdn-msp.18comic.vip/media/albums/' + item.id + '_3x4.jpg\'};t.src=s.indexOf(\'cdn-msp2\')>-1?\'https://cdn-msp3.18comic.vip/media/albums/' + item.id + '_3x4.jpg\':s.indexOf(\'cdn-msp3\')>-1?\'https://cdn-msp.18comic.vip/media/albums/' + item.id + '_3x4.jpg\':\'https://cdn-msp2.18comic.vip/media/albums/' + item.id + '_3x4.jpg\'"></a><div class="label-loveicon"><a><i class="glyphicon glyphicon-heart"></i><span class="text-white">' + ls + '</span></a></div><div class="label-star" style="cursor:pointer" data-jms-dismiss="' + item.id + '" title="' + '\u4E0D\u611F\u5174\u8DA3' + '"><i style="color:#f66" class="far fa-times-circle"></i></div><div class="label-latest"><div class="label-sub" style="background-color:' + rc + ';font-size:10px">' + rl + '</div><br><div class="label-sub" style="background:#2a2a4a;color:#ffd166;padding:1px 4px;border-radius:2px;margin-top:2px">' + mp + '%</div></div>' + (tt ? '<div class="category-icon"><div class="label-category">' + escapeHtml(tt) + '</div>' + (st ? '<div class="label-sub" style="background-color:#ff7a00">' + escapeHtml(st) + '</div>' : '') + '</div>' : '') + '</div><span class="video-title title-truncate-index m-t-5" style="display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;text-overflow:ellipsis;font-size:13px">' + escapeHtml(ti.substring(0, 80)) + '</span><div class="title-truncate-index hidden-xs" style="font-size:11px;color:#888">' + au.slice(0, 2).map(function(a){return '<a href="/search/photos?search_query=' + encodeURIComponent(a) + '&main_tag=2">' + escapeHtml(a) + '</a>'}).join(', ') + ' ' + ta.slice(0, 2).filter(function(t){return !getAllBlacklistedTags().includes(t)}).map(function(t){return '<a href="/search/photos?search_query=' + encodeURIComponent(t) + '">' + escapeHtml(t) + '</a>'}).join(' ') + '</div><div class="clearfix"></div></div>';
var dis = cd.querySelector('[data-jms-dismiss]');
if (dis) dis.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); dismissRecommendation(item.id); cd.remove(); });
return cd;
}
var _i = 0, _B = 12;
function _r() {
var end = Math.min(_i + _B, displayItems.length);
for (; _i < end; _i++) carousel.appendChild(_b(displayItems[_i]));
if (_i < displayItems.length) { requestAnimationFrame(_r); }
}
requestAnimationFrame(_r);
}
function dismissRecommendation(id) {
const bl = getBlacklist();
bl.albums.push(id);
setBlacklist(bl);
const recs = State.getRecommendations();
State.saveRecommendations(recs.filter(r => r.id !== id));
showNotification('已隐藏,不再推荐此漫画');
}
function escapeHtml(str) {
const div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
}