// ==UserScript== // @name Bangumi User Hover Panel-change // @name:zh-CN Bangumi 用户悬浮面板-改 // @namespace https://github.com/stay206/bangumi/ // @version 1.0.0 // @description fork of https://bgm.tv/dev/app/2647. Display a hover panel when mouse hover on user link. // @description:zh-CN https://bgm.tv/dev/app/2647 的修改版,鼠标悬浮在用户链接上方时出现悬浮框,添加了wiki协助记录 // @author cureDovahkiin + CryoVit + 墨云 // @match https://bangumi.tv/* // @match https://bgm.tv/* // @match https://chii.in/* // @icon https://bgm.tv/img/favicon.ico // @grant none // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/504802/Bangumi%20User%20Hover%20Panel-change.user.js // @updateURL https://update.greasyfork.icu/scripts/504802/Bangumi%20User%20Hover%20Panel-change.meta.js // ==/UserScript== (function () { /* 2 = timeline 4 = stats 8 = sinkuro 16 = anime 32 = game 64 = book 128 = [reserved] for music 256 = [reserved] for real the value is the sum of the entries to show, e.g. 28 = 4 + 8 + 16, means show stats, sinkuro and anime */ if (localStorage.getItem('hover-panel-config') === null) { // default config localStorage.setItem('hover-panel-config', '28'); // 4 + 8 + 16 } const entryStates = [ ['在看', '看过', '想看', '搁置', '抛弃'], ['在玩', '玩过', '想玩', '搁置', '抛弃'], ['在读', '读过', '想读', '搁置', '抛弃'] ]; const cfgNames = ['时间线', '统计', '同步率', '动画', '游戏', '书籍']; const cfgTimeline = 2; const cfgStats = 4; const cfgSinkuro = 8; const cfgAnime = 16; let locker = false $('[href*="/user/"],#pm_sidebar a[onclick^="AddMSG"]').each(function () { let timer = null $(this).hover(function () { timer = setTimeout(() => { if (locker) return false if (this.text == "查看好友列表" || $(this).find('.avatarSize75').length > 0) return false locker = true const layout = document.createElement('div') let timer = null $(layout).addClass('user-hover') if ($(this).hasClass('avatar')) { $(layout).addClass('fix-avatar-hover') } if (document.body.clientWidth - this.getBoundingClientRect().right < 430) { $(layout).addClass('fix-right-hover') } layout.innerHTML = `
` const userData = {} if (this.onclick) { userData.id = this.onclick.toString().split("'")[1] } else { let urlSplit = /.*\/user\/([^\/]*)\/?(.*)/.exec(this.href) if (urlSplit[2]) return userData.id = urlSplit[1] } userData.href = '/user/' + userData.id const req = { req1: null, req2: null } Promise.all([ new Promise((r, j) => { req.req1 = $.ajax({ url: userData.href, dataType: 'text', success: e => { userData.self = //.exec(e)[1].split('/').pop() if (userData.self != userData.id) { userData.sinkuro = /mall class="hot">\/([^<]*)<\/small>/.exec(e)[1] userData.sinkuroritsu = //.exec(e)[1] userData.addFriend = //.exec(e) userData.addFriend = userData.addFriend ? userData.addFriend[1] : false } userData.joinDate = /Bangumi<\/span> ([^<]*)<\/span>/.exec(e)[1] // userData.lastEvent = /([^<]*)<\/small><\/li>/.exec(e) userData.entry = [ Array.from(e.match(/=]*>([0-9]{1,4}[^<]*)/g) || [], el => />([0-9]{1,5}.*)/.exec(el)[1]).map(el => el.split('部')), Array.from(e.match(/([\s\S]*)<\/div>/.exec(e)[1] userData.stats = Array.from(userData.stats.match(/]*>([\s\S]*?)<\/div>/g).slice(0, 6), el => /]*>([\s\S]*?)<\/div>/.exec(el)[1]) userData.stats = userData.stats.map(el => Array.from(el.match(/]*>([\s\S]*?)<\/span>/g), el => /]*>([\s\S]*?)<\/span>/.exec(el)[1])) userData.timeline = /