您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
网页端首页推荐视频
当前为
// ==UserScript== // @name b站首页推荐 // @namespace kasw // @version 2.0 // @description 网页端首页推荐视频 // @author kaws // @match *://www.bilibili.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=bilibili.com // @source https://github.com/kawS/bilibili-recommend-app // @include https://www.mcbbs.net/template/mcbbs/image/special_photo_bg.png?* // @connect app.bilibili.com // @connect api.bilibili.com // @connect passport.bilibili.com // @connect www.mcbbs.net // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_setClipboard // @run-at document-idle // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js // @license MIT // ==/UserScript== (function() { 'use strict'; let $list = null; let isWait = false; let isLoading = false; let options = { maxClientWidth: $(window).width(), sizes: null, accessKey: GM_getValue('biliAppHomeKey'), dateKey: GM_getValue('biliAppHomeKeyDate'), timeoutKey: 30 * 24 * 60 * 60 * 1000, refresh: 1, itemHeight: 0, oneItemHeight: $('.bili-grid').eq(0).find('.bili-video-card').height(), isShowDanmaku: GM_getValue('biliAppDanmaku') || false, isShowRec: GM_getValue('biliAppRec') || false } function init(){ if (location.href.startsWith('https://www.mcbbs.net/template/mcbbs/image/special_photo_bg.png?')) { window.stop(); return window.top.postMessage(location.href, 'https://www.bilibili.com') } localStorage.setItem('bilibili_player_force_DolbyAtmos&8K&HDR', 1); Object.defineProperty(navigator, 'userAgent', { value: "Mozilla/5.0 (Macintosh; Intel Mac OS X 12_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15" }); if(location.pathname != '/'){ return } setSize(options.maxClientWidth, options.isShowRec ? true : false); initStyle(); intiHtml(); initEvent(); checkKey(); getRecommendList() } function initStyle(){ const style = ` <style> @keyframes turn{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg)}} .taglike{position: absolute;bottom: 25px;left: 8px;padding: 0 2px;height: 18px;line-height: 18px;font-size: 12px;} .load-state{position: absolute;top: 0;left: 0;background: rgba(255,255,255,.8);width: 100%;height: 100%;min-height: 240px;border-radius: 4px;font-size: 3rem;text-align: center;z-index: 50} .load-state .loading{line-height: 240px} .load-state .loading svg{margin:0 10px 0 0;width:2rem;height:2rem;transform: rotate(0deg);animation:turn 1s linear infinite;transition: transform .5s ease} .toast{position: fixed;top: 30%;left: 50%;z-index: 999999;margin-left: -180px;padding: 12px 24px;font-size: 14px;background: rgba(0,0,0,.8);width: 360px;border-radius: 6px;color: #fff;text-align: center} .BBDown{margin-top: 4px;width: 60%;line-height: 1;font-size: 12px;display: inline-block;} .v-inline-danmaku{position: absolute;top: 0;left: 0;width: 100%;height: 100%;z-index: 2;pointer-events: none;user-select: none;border-radius: inherit;opacity: 0;transition: opacity .2s linear;overflow: hidden} .v-inline-danmaku.visible{opacity: 1} .v-inline-danmaku p{position: absolute;color: #fff;text-shadow: #000 1px 0px 1px, #000 0px 1px 1px, #000 0px -1px 1px, #000 -1px 0px 1px;white-space: nowrap;opacity: 0} .be-switch-container{position:relative;display:flex;margin:0 0 0 8px;height:20px;cursor:pointer;white-space:nowrap;align-items: center;} .be-switch-container.is-checked .be-switch{background-color:#00a1d6} .be-switch-container.is-checked .be-switch-cursor{left:17px} .be-switch{position:relative;width:30px;height:16px;border-radius:8px;background-color:#ccd0d7;vertical-align:middle;cursor:pointer;transition:background-color .2s ease} .be-switch-cursor{position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:12px;background:#fff;transition:left .2s ease} .be-switch-label{line-height:20px;font-size:14px;margin-left:3px;vertical-align:middle} .be-switch-input{position:absolute;left:0;top:0;margin:0;opacity:0;width:100%;height:100%;z-index:2;display: none} #recommend .area-header{height: 34px;} #recommend .roll-btn-wrap{top: 380px;z-index: 15} </style>`; $('head').append(style) } function intiHtml(){ const $position = $('.bili-grid').eq(1); const $fullpage = $('#i_cecream'); const html = ` <section class="bili-grid" data-area='推荐' id="recommend"> <div class="eva-extension-area"> <div class="area-header"> <div class="left"> <a href="javascript:;" class="title"><span>油猴插件推荐</span></a> </div> <div class="right"> <div class="be-switch-container setting-privacy-switcher${options.isShowRec ? ' is-checked': ''}" id="JShowRec"> <input type="checkbox" class="be-switch-input" value="${options.isShowRec}"> <div class="be-switch"><i class="be-switch-cursor"></i></div> <div class="be-switch-label"><span>是否只保留推荐视频</span></div> </div> <div class="be-switch-container setting-privacy-switcher${options.isShowDanmaku ? ' is-checked': ''}" id="JShowDanmaku"> <input type="checkbox" class="be-switch-input" value="${options.isShowDanmaku}"> <div class="be-switch"><i class="be-switch-cursor"></i></div> <div class="be-switch-label"><span>是否预览弹幕</span></div> </div> <button class="primary-btn roll-btn" id="JaccessKey"}> <span>${options.accessKey ? '删除授权' : '获取授权'}</span> </button> <button class="primary-btn roll-btn"${options.isShowRec ? ' style="display: none"' : ''} id="Jrefresh"> <svg style="transform: rotate(0deg);"><use xlink:href="#widget-roll"></use></svg> <span>换一换</span> </button> </div> </div> <div class="eva-extension-body" id="recommend-list"></div> </div> <div class="roll-btn-wrap"${options.isShowRec ? ' style="display: none"' : ''}> <button class="primary-btn roll-btn" id="JrefreshRight"> <svg style="transform:rotate(0deg);"><use xlink:href="#widget-roll"></use></svg> <span>换一换</span> </button> </div> </section>`; if(options.isShowRec){ $fullpage.find('.bili-layout').hide().after(`<main class="bili-layout" id="scrollwrap">${html}</main>`); }else{ $position.after(html); } $list = $('#recommend-list'); } function initEvent(){ $('#JaccessKey').on('click', function(){ const $this = $(this); let type = $this.text().trim(); if(isWait){ return } isWait = true if(type == '删除授权'){ $this.find('span').text('获取授权'); delAccessKey() } if(type == '获取授权' || type == '重新获取授权'){ $this.find('span').text('获取中...'); getAccessKey($this) } return false }) $('#Jrefresh, #JrefreshRight').on('click', function(){ if($('.load-state').length > 0) return const $this = $(this); const reg = /(rotate\([\-\+]?((\d+)(deg))\))/i; let $svg = $this.find('svg'); let css = $svg.attr('style'); let wts = css.match(reg); $svg.css('transform', `rotate(${parseFloat(wts[3]) + 360}deg)`); options.maxClientWidth = $(window).width(); setSize(options.maxClientWidth); getRecommendList(); return false }) $list.on('mouseenter', '.bili-video-card__image', function(e){ e.stopPropagation(); const $this = $(this); let rect = e.currentTarget.getBoundingClientRect(); if($this.data('go') == 'av'){ $this.find('.bili-watch-later').stop().fadeIn(); $this.find('.v-inline-player').addClass('mouse-in visible'); getPreviewImage($this, e.clientX - rect.left); if(options.isShowDanmaku){ $this.find('.v-inline-danmaku').addClass('mouse-in visible'); getPreviewDanmaku($this) } } }).on('mouseleave', '.bili-video-card__image', function(e){ e.stopPropagation(); const $this = $(this); if($this.data('go') == 'av'){ $this.find('.bili-watch-later').stop().fadeOut(); $this.find('.v-inline-player, .v-inline-danmaku').removeClass('mouse-in visible'); } }).on('mousemove', '.bili-video-card__image', function(e){ e.stopPropagation(); const $this = $(this); let rect = e.currentTarget.getBoundingClientRect(); if($this.data('go') == 'av'){ if($this[0].pvData){ setPosition($this, e.clientX - rect.left, $this[0].pvData) } } }).on('mouseenter', '.bili-watch-later', function(e){ e.stopPropagation(); const $this = $(this); $this.find('span').stop().fadeIn() }).on('mouseleave', '.bili-watch-later', function(e){ e.stopPropagation(); const $this = $(this); $this.find('span').stop().fadeOut() }).on('click', '.bili-watch-later', function(){ const $this = $(this); watchlater($this); return false }).on('click', '.BBDown', function(){ const $this = $(this); let id = $this.data('id'); GM_setClipboard(`BBDown -app -token ${options.accessKey} -mt -ia -p all "${id}"`); toast('复制BBDown命令行成功') return false }) $('#JShowDanmaku').on('click', function(){ const $this = $(this); const $inp = $this.find('input'); let val = JSON.parse($inp.val()); options.isShowDanmaku = !val; GM_setValue('biliAppDanmaku', options.isShowDanmaku); $inp.val(options.isShowDanmaku); if(options.isShowDanmaku){ $this.addClass('is-checked') }else{ $this.removeClass('is-checked') } return false }) $('#JShowRec').on('click', function(){ const $this = $(this); const $inp = $this.find('input'); let val = JSON.parse($inp.val()); options.isShowRec = !val; GM_setValue('biliAppRec', options.isShowRec); $inp.val(options.isShowRec); if(options.isShowRec){ $this.addClass('is-checked') }else{ $this.removeClass('is-checked') } toast('2秒后刷新页面,请稍后!', function(){ location.reload() }) return false }) if(options.isShowRec){ $(window).on('scroll', function(){ const $this = $(this); if(($this.scrollTop() + options.oneItemHeight * 3) > ($(document).height() - $(window).height())){ if(isLoading) return; isLoading = true; options.maxClientWidth = $(window).width(); setSize(options.maxClientWidth, true); getRecommendList() } }) } } function toast(msg, cb, duration = 2000){ const $toast = $(`<div class="toast">${msg}</div>`); $toast.appendTo($('body')); setTimeout(() => { $toast.remove(); typeof cb == 'function' && cb() }, duration) } function showLoading(minHeight){ $list.prepend(` <div class="load-state spread-module" style="min-height:${minHeight}px"> <p class="loading" style="line-height:${minHeight / 2}px"> <svg><use xlink:href="#widget-roll"></use></svg>正在加载... </p> </div>`) } function setSize(width, setRow){ let row = setRow ? 6 : 4; if(width < 1684){ options.sizes = 5 * row }else if(width >= 2183){ options.sizes = 7 * row }else{ options.sizes = 6 * row } } function delAccessKey(){ isWait = false; options.accessKey = null; options.dateKey = null; GM_deleteValue('biliAppHomeKey'); GM_deleteValue('biliAppHomeKeyDate'); toast('获取删除成功'); } async function getAccessKey(el){ let url = null; let res = null; let data = null; try { res = await fetch('https://passport.bilibili.com/login/app/third?appkey=27eb53fc9058f8c3&api=https%3A%2F%2Fwww.mcbbs.net%2Ftemplate%2Fmcbbs%2Fimage%2Fspecial_photo_bg.png&sign=04224646d1fea004e79606d3b038c84a', { method: 'GET', credentials: 'include' }) } catch (error) { toast(error) } try { data = await res.json(); } catch (error) { toast(error) } if (data.code || !data.data) { el.find('span').text('获取授权'); toast(data.msg || data.message || data.code) } else if (!data.data.has_login) { el.find('span').text('获取授权'); toast('你必须登录(不可用)B站之后才能使用授权') } else if (!data.data.confirm_uri) { el.find('span').text('获取授权'); toast('无法获得授权网址') } else { url = data.data.confirm_uri } if(url == null){ isWait = false; return } const $iframe = $(`<iframe src='${url}' style="display: none;" />`); $iframe.appendTo($('body')); let timeout = setTimeout(() => { $iframe.remove(); el.find('span').text('获取授权');; toast('获取授权超时') }, 5000); window.onmessage = ev => { if (ev.origin != 'https://www.mcbbs.net' || !ev.data) { isWait = false; return } const key = ev.data.match(/access_key=([0-9a-z]{32})/); if (key) { GM_setValue('biliAppHomeKey', options.accessKey = key[1]); GM_setValue('biliAppHomeKeyDate', options.dateKey = +new Date()); toast('获取授权成功'); el.find('span').text('删除授权');; clearTimeout(timeout); $iframe.remove(); } else { toast('没有获得匹配的密钥') } } isWait = false; } function checkKey(){ const nowDate = +new Date(); if(!options.dateKey) return; if(options.dateKey == -1){ $('#JaccessKey').find('span').text('重新获取授权'); return } if(nowDate - options.dateKey > options.timeoutKey){ $('#JaccessKey').find('span').text('重新获取授权'); GM_setValue('biliAppHomeKeyDate', options.dateKey = -1); GM_deleteValue('biliAppHomeKey'); options.accessKey = null; } } function getRecommend(url, type){ const errmsg = '获取推荐视频失败'; return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url: url, onload: res => { try { const rep = JSON.parse(res.response); if (rep.code != 0) { reject(errmsg) } if(type == 'new'){ resolve(rep.data.item) }else{ resolve(rep.data) } } catch(e) { reject(errmsg) } }, onerror: e => { reject(errmsg) } }) }) } async function getRecommendList(){ if(!options.isShowRec){ options.itemHeight = $('.bili-grid').eq(0).find('.bili-video-card').height() * 4 + 20 * 3; showLoading(options.itemHeight); } const token = options.accessKey ? '&access_key=' + options.accessKey : ''; const url1 = `https://api.bilibili.com/x/web-interface/index/top/rcmd?fresh_type=3&version=1&ps=10&fresh_idx=${options.refresh}&fresh_idx_1h=${options.refresh}`; const url2 = 'https://app.bilibili.com/x/feed/index?build=1&mobi_app=android&idx=' + ((Date.now() / 1000).toFixed(0)) + token; let result = null; let data = null; let list = null; let isLar = options.sizes - 10 > 10; if(options.isShowRec){ result = Promise.all([getRecommend(url1, 'new'), getRecommend(url2), getRecommend(url1, 'new'), getRecommend(url2), getRecommend(url1, 'new')]); }else{ if(isLar){ result = Promise.all([getRecommend(url1, 'new'), getRecommend(url2), getRecommend(url1, 'new'), getRecommend(url2)]) }else{ result = Promise.all([getRecommend(url1, 'new'), getRecommend(url2)]) } } try { data = await result; } catch (error) { toast(error) } if(options.isShowRec || isLar){ data[0] = new2old(data[0]); data[2] = new2old(data[2]); options.isShowRec && (data[4] = new2old(data[4])) }else{ data[0] = new2old(data[0]) } list = unique(data); options.refresh += 1; updateRecommend(list); !$('.bili-footer').is('hidden') && $('.bili-footer').hide() } function new2old(data){ return data.map((item) => { return { autoplay: 1, cid: item.cid, cover: item.pic, ctime: item.pubdate, danmaku: item.stat.danmaku, desc: `${item.stat.danmaku}弹幕`, duration: item.duration, face: item.owner.face, goto: item.goto, idx: item.id, like: item.stat.like, mid: item.owner.mid, name: item.owner.name, param: item.id, play: item.stat.view, title: item.title, tname: '', uri: item.uri, rcmd_reason: { content: item.rcmd_reason?.reason_type == 1 ? '已关注' : item.rcmd_reason?.content ? item.rcmd_reason.content : '' } } }) } function unique(data){ const arr = data[0].concat(data[1], data[2] || [], data[3] || [], data[4] || []); let result = []; let cidList = {}; for(let item of arr){ if(!cidList[item.cid]){ result.push(item); cidList[item.cid] = true } } return result.sort(function(){ return Math.random() - 0.5 }) } function updateRecommend(list){ let html = ''; for(let i=0;i<options.sizes;i++){ let data = list[i]; if(!data){ continue } html += ` <div class="bili-video-card" style="display: block !important"> <div class="bili-video-card__skeleton hide"> <div class="bili-video-card__skeleton--cover"></div> <div class="bili-video-card__skeleton--info"> <div class="bili-video-card__skeleton--face"></div> <div class="bili-video-card__skeleton--right"> <p class="bili-video-card__skeleton--text"></p> <p class="bili-video-card__skeleton--text short"></p> <p class="bili-video-card__skeleton--light"></p> </div> </div> </div> <div class="bili-video-card__wrap __scale-wrap"> <a href="${data.goto == 'av' ? 'https://www.bilibili.com/video/av' + data.param : data.uri}" target="${data.goto == 'av' ? 'https://www.bilibili.com/video/av' + data.param : data.uri}" class="cardwp"> <div class="bili-video-card__image __scale-player-wrap" data-go="${data.goto}" data-aid="${data.param}" data-duration="${data.goto == 'av' ? data.duration : ''}"> <div class="bili-video-card__image--wrap"> <div class="bili-watch-later" data-aid="${data.param}" style="display: none;"> <svg class="bili-watch-later__icon"><use xlink:href="#widget-watch-later"></use></svg> <span class="bili-watch-later__tip" style="display: none;">稍后再看</span> </div> <picture class="v-img bili-video-card__cover"> <source srcset="${data.cover.replace('http:', 'https:')}@672w_378h_1c_100q.webp" type="image/webp"/> <img src="${data.cover.replace('http:', 'https:')}@672w_378h_1c_100q" alt="${data.title}" loading="eager" onload=""/> </picture> <div class="v-inline-player"></div> <div class="v-inline-danmaku"></div> </div> <div class="bili-video-card__mask"> <div class="taglike" style="background:${data.badge ? ' #ff8f00' : data.tname ? ' #fff' : ' #ff005d'};color:${data.badge ? ' #fff' : data.tname ? ' #333' : ' #fff'};display: none">${data.badge || data.tname || '官方新版推荐'}</div> ${data.badge ? `<div class="taglike" style="background: #ff8f00;color: #fff;">${data.badge}</div>` : data.rcmd_reason && data.rcmd_reason.content == '已关注' ? `<div class="taglike" style="background: #ff8f00;color: #fff;">已关注</div>` : ''} <div class="bili-video-card__stats"> <div class="bili-video-card__stats--left"> <span class="bili-video-card__stats--item"> <svg class="bili-video-card__stats--icon"> <use xlink:href="#widget-play-count"></use> </svg> <span class="bili-video-card__stats--text">${formatNumber(data.play)}</span> </span> <span class="bili-video-card__stats--item"${data.goto == 'av' ? '' : ' style="display: none"'}> <svg class="bili-video-card__stats--icon"><use xlink:href="#widget-agree"></use></svg> <span class="bili-video-card__stats--text">${formatNumber(data.like)}</span> </span> </div> <span class="bili-video-card__stats__duration">${data.goto == 'av' ? formatNumber(data.duration, 'time') : formatNumber(data.favorite) + '收藏'}</span> </div> </div> </div> </a> <div class="bili-video-card__info __scale-disable"> <div> <a href="https://space.bilibili.com/${data.mid}" target="https://space.bilibili.com/${data.mid}"> <div class="v-avatar bili-video-card__avatar"> <picture class="v-img v-avatar__face"> <source srcset="${data.face.replace('http:', 'https:')}@72w_72h.webp" type="image/webp"/> <img src="${data.face.replace('http:', 'https:')}@72w_72h" alt="${data.name || data.badge}" loading="lazy" onload=""/> </picture> </div> </a> <a href="javascript:;" class="BBDown" data-id="${data.goto == 'av' ? 'av' + data.param : data.uri}">BBDown下载</a> </div> <div class="bili-video-card__info--right"> <a href="${data.goto == 'av' ? 'https://www.bilibili.com/video/av' + data.param : data.uri}" target="${data.goto == 'av' ? 'https://www.bilibili.com/video/av' + data.param : data.uri}"> <h3 class="bili-video-card__info--tit" title="${data.title}">${data.title}</h3> </a> <p class="bili-video-card__info--bottom" style="${(data.rcmd_reason && data.rcmd_reason.content == '已关注') ? 'color: #f00' : data.badge ? 'color: #ff8f00' : ''}"> <a class="bili-video-card__info--owner" href="https://space.bilibili.com/${data.mid}" target="https://space.bilibili.com/${data.mid}" ${data.name ? 'title="' + data.name + '"' : ''}> <svg class="bili-video-card__info--owner__up"> <use xlink:href="#widget-up"></use> </svg> <span class="bili-video-card__info--author">${data.name || data.badge + ' - ' + data.desc}</span> <span class="bili-video-card__info--date"${data.goto == 'av' ? '' : ' style="display: none"'}>${returnDateTxt(data.ctime)}</span> </a> </p> </div> </div> </div> </div>`; } if(options.isShowRec){ $list.append(html); setTimeout(() => { isLoading = false }, 300) }else{ $list.html(html) } } function formatNumber(input, format = 'number'){ if (format == 'time') { let second = input % 60; let minute = Math.floor(input / 60); let hour; if (minute > 60) { hour = Math.floor(minute / 60); minute = minute % 60; } if (second < 10) second = '0' + second; if (minute < 10) minute = '0' + minute; return hour ? `${hour}:${minute}:${second}` : `${minute}:${second}` } else { return input > 9999 ? `${(input / 10000).toFixed(1)}万` : input || 0 } } function returnDateTxt(time){ if (!time) return ''; let date = new Date(time * 1000); let year = date.getFullYear(); let month = date.getMonth() + 1; let day = date.getDate(); return `· ${year}-${month < 10 ? '0' + month : month}-${day < 10 ? '0' + day : day}` } function token(){ try { return document.cookie.match(/bili_jct=([0-9a-fA-F]{32})/)[1] } catch(e) { return '' } } async function watchlater(el){ const aid = el.data('aid'); let type = el.hasClass('del') ? 'del' : 'add'; let res = null; let data = null; try { res = await fetch(`https://api.bilibili.com/x/v2/history/toview/${type}`, { method: 'POST', credentials: 'include', headers: { 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8' }, body: `aid=${aid}&csrf=${token()}` }) } catch (error) { toast(error) } try { data = await res.json(); } catch (error) { toast(error) } if(data.code == 0){ if(type == 'add'){ el.addClass('del').find('span').text('移除'); el.find('svg').html('<use xlink:href="#widget-watch-save"></use>'); toast('添加成功') }else{ el.removeClass('del').find('span').text('稍后再看'); el.find('svg').html('<use xlink:href="#widget-watch-later"></use>'); toast('移除成功') } }else{ toast(data.message) } } async function getPreviewImage(el, e){ const aid = el.data('aid'); let pvData = el[0].pvData; if(!pvData){ let res = null; let data = null; try { res = await fetch(`https://api.bilibili.com/pvideo?aid=${aid}`); } catch (error) { toast(error) } try { data = await res.json(); } catch (error) { toast(error) } pvData = el[0].pvData = data.data; } setPosition(el, e, pvData) } async function getPreviewDanmaku(el){ const aid = el.data('aid'); let danmakuData = el[0].danmakuData; if(!danmakuData){ let res = null; let data = null; try { res = await fetch(`https://api.bilibili.com/x/v2/dm/ajax?aid=${aid}`); } catch (error) { toast(error) } try { data = await res.json(); } catch (error) { toast(error) } danmakuData = el[0].danmakuData = data.data } setDanmakuRoll(el, danmakuData); } function setPosition(el, mouseX, pvData){ const $tarDom = el.find('.v-inline-player'); // const $duration = el.data('duration'); const $pvbox = $tarDom.find('pv-box'); const width = $tarDom.width(); const height = $tarDom.height(); const sizeX = width * pvData.img_x_len; const sizeY = height * pvData.img_y_len; const onePageImgs = pvData.img_x_len * pvData.img_y_len; const rIndexList = pvData.index.slice(1); const pageSize = Math.ceil(rIndexList.length / onePageImgs); let percent = mouseX / width; if (percent < 0) percent = 0; if (percent > 1) percent = 1; const durIndex = Math.floor(percent * rIndexList.length) const page = Math.floor(durIndex / (pvData.img_x_len * pvData.img_y_len)); const imgUrl = pvData.image[page]; const imgIndex = durIndex - page * onePageImgs; const x = ((imgIndex - 1) % pvData.img_x_len) * width; // const y = Math.floor(imgIndex / (pvData.img_x_len)) * (width * pvData.img_y_size / pvData.img_x_size); const y = Math.floor(imgIndex / (pvData.img_x_len)) * height; const imgY = (Math.floor(imgIndex / pvData.img_x_len)) + 1; const imgX = imgIndex - (imgY - 1) * pvData.img_x_len; const bar = percent * 100; if($pvbox.length > 0){ $pvbox.css({ 'background': `url(https:${imgUrl}) -${x}px -${y}px no-repeat` }) $pvbox.next().css({ 'width': `${bat}%` }) return } $tarDom.html(` <div class="pv-box" style="background: url(https:${imgUrl}) -${x}px -${y}px no-repeat;background-size: ${sizeX}px ${sizeY}px;height: 100%;pointer-events:none"></div> <div class="pv-bar" style="position: absolute;left: 0;bottom: 0;background: #fb7299;width: ${bar}%;height: 2px;z-index: 2"></div> `) } function setDanmakuRoll(el, danmakuData){ if(danmakuData.length <= 0) return; const $tarDom = el.find('.v-inline-danmaku'); let $items = $tarDom.find('p'); let outWidth = $tarDom.width(); let lastWait = new Array(5).fill(600); let defaultMoveOpts = { pageSize: 5, size: Math.ceil(danmakuData.length / 5), defaultHeight: 18, topSalt: 5, dur: 5 } if($items.length > 0) $tarDom.empty(); for(let i = 0;i < danmakuData.length;i++){ let options = { channel: i % defaultMoveOpts.pageSize, startPosX: outWidth, startPosY: i % 5 * defaultMoveOpts.defaultHeight + defaultMoveOpts.topSalt }; let $html = $(`<p data-channel="${options.channel}" style="top: ${options.startPosY}px;left: ${options.startPosX}px">${danmakuData[i]}</p>`); let wait = (lastWait[options.channel] + (Math.floor(Math.random() * 1000 + 100))) / 1000; $tarDom.append($html); options.width = $html.width(); options.moveX = options.width + outWidth; options.dur = (options.width + outWidth) / (outWidth / defaultMoveOpts.dur); $html.css({ 'transform': `translateX(-${options.moveX}px)`, 'transition': `transform ${options.dur}s linear ${wait}s`, 'opacity': 1 }) lastWait[options.channel] = (wait + options.dur * 0.6) * 1000 } } init() })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址