JM Shelf - UI Recs

首页推荐卡片展示 — JM Shelf 推荐脚本的模块库,通过 @require 被主脚本引用。

Ten skrypt nie powinien być instalowany bezpośrednio. Jest to biblioteka dla innych skyptów do włączenia dyrektywą meta // @require https://update.sleazyfork.org/scripts/581111/1842612/JM%20Shelf%20-%20UI%20Recs.js

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

Advertisement:

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

Advertisement:

// ==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;
  }