豆瓣小组展示功能增强:高亮包含指定关键字的帖子;隐藏包含指定关键字的帖子;去除标题省略号,展示全部文本;新标签页打开帖子;展示是否是楼主的标识;展示楼层号;淡化已读帖子标题;增加帖子内内容跳转; 去广告功能
// ==UserScript== // @name 豆瓣小组功能增强 // @version 0.2.1.0 // @license MIT // @namespace https://tcatche.github.io/ // @description 豆瓣小组展示功能增强:高亮包含指定关键字的帖子;隐藏包含指定关键字的帖子;去除标题省略号,展示全部文本;新标签页打开帖子;展示是否是楼主的标识;展示楼层号;淡化已读帖子标题;增加帖子内内容跳转; 去广告功能 // @author tcatche // @match https://www.douban.com/group/* // @homepageURL https://github.com/tcatche/douban-group-enhance // @supportURL https://github.com/tcatche/douban-group-enhance/issues // @grant none // ==/UserScript== (function() { const utils = { // save user config saveConfig: config => { const configString = JSON.stringify(config); localStorage.setItem('douban_group_enhance_config', configString); }, // load user config getConfig: () => { const configString = localStorage.getItem('douban_group_enhance_config'); const oldConfigString = localStorage.getItem('douban_group_filter_config'); try { const config = JSON.parse(configString || oldConfigString); return config; } catch (e) { return {}; } }, bindedEles: [], bindClick: function(selector, callback) { this.bindedEles.push(selector); $(selector).click(callback); }, unbindClick: (selector) => { $(selector).unbind(); }, unbindAllClick: function() { this.bindedEles.forEach(selector => { $(selector).click(callback); }) } } const createEnhancer = () => { // run user filters const runFilter = (config, self) => { const title = self.attr('title') || ''; const isInInclude = title => (config.include || []).find(keyword => title.indexOf(keyword) >= 0); const isInDeclude = title => (config.declude || []).find(keyword => title.indexOf(keyword) >= 0); const isTitleInInclude = isInInclude(title); const isTitleInDeclude = isInDeclude(title); if (isTitleInInclude && !isTitleInDeclude) { self.addClass('douban_group_enhance_highlight'); } if (isInDeclude(title)) { self.parents('tr').hide(); } } // open in new tab const runOpenInNewTab = (config, self) => { if (config.openInNewTab) { self.attr('target', '_blank'); } } // show full title without cliped! const runShowFullTitle = (config, self) => { if (config.showFullTitle) { const title = self.attr('title') || self.text(); self.text(title); } } // run fade visited topic const runFadeVisitedTitle = config => { if (config.fadeVisited) { if ($('#fadeVisitedStyle').length === 0) { $('body').append(` <style id="fadeVisitedStyle" class="douban_group_added"> .topics .td-subject a:visited, .title a:visited { color: #ddd } .douban_group_enhance_highlight:visited{ color: #ddd; background: #ccc; } </style> `); } } else { $('#fadeVisitedStyle').remove(); } } // show reply number const runShowReplyNumber = (options, self, index) => { if (options.config.showReplyNumber) { const replyHead = self.find('h4')[0]; const isInserted = $(replyHead).find('.douban_group_enhance_replay_number').length > 0; if (!isInserted) { const start = +(options.params.start || 0); const replayNumber = start + 1 + index; $(replyHead).append(`<span class="douban_group_enhance_replay_tag douban_group_enhance_replay_number douban_group_added">${replayNumber}楼</span>`); } } else { $('.douban_group_enhance_replay_number').remove(); } } // show if is topic owner const runShowOwnerTag = (options, self) => { if (options.config.showOwnerTag) { const replyHead = self.find('h4')[0]; const isInserted = $(replyHead).find('.douban_group_enhance_owner_tag').length > 0; if (!isInserted) { const replyName = self.find('h4 a').text().trim(); if (replyName === options.topicUser) { $(replyHead).append('<span class="douban_group_enhance_replay_tag douban_group_enhance_owner_tag douban_group_added">楼主</span>'); } } } else { $('.douban_group_enhance_owner_tag').remove(); } } // add jump to top, comments and pager button const runAddJumptoButton = options => { if (options.config.jumpTo) { const isAdded = $('#douban_group_enhance_jump').length > 0; if (!isAdded) { $(document.body).append(` <div id="douban_group_enhance_jump" class="douban_group_enhance_jump douban_group_added"> 跳转到: <span class="douban_group_enhance_jump_target douban_group_enhance_jump_target_title">标题</span>/ <span class="douban_group_enhance_jump_target douban_group_enhance_jump_target_comments">评论</span>/ <span class="douban_group_enhance_jump_target douban_group_enhance_jump_target_end">页尾</span> </div> `); setTimeout(() => { utils.bindClick('.douban_group_enhance_jump_target_title', e => { $('h1')[0].scrollIntoView({behavior: 'smooth'}); }); utils.bindClick('.douban_group_enhance_jump_target_comments', e => { $('.topic-reply ')[0].scrollIntoView({behavior: 'smooth'}); }); utils.bindClick('.douban_group_enhance_jump_target_end', e => { $('#footer')[0].scrollIntoView({behavior: 'smooth'}); }); }, 0) } } else { $('.douban_group_enhance_jump').remove(); } } // run remove google ads const runRemoveAd = options => { if (options.config.removeAd) { setTimeout(function() { $('[ad-status]').remove() }) } } const runEnhancer = config => { const isTopicDetailPage = location.pathname.indexOf('/group/topic/') >= 0; const search = location.search ? location.search.substr(1) : ''; const params = {}; search.split('&').filter(v => !!v).map(item => { const items = item.split('='); if (items.length >= 1) { params[items[0]] = items[1]; } }); const global = { config: config, params: params, }; runRemoveAd(global); if (isTopicDetailPage) { // 帖子内容 $('#comments li').each(function(index) { global.topicUser = $('.topic-doc .from > a').text().trim(); const $this = $(this); runShowReplyNumber(global, $this, index); runShowOwnerTag(global, $this); }); runAddJumptoButton(global); } else { // 帖子列表 $('.topics .td-subject a, .title a').each(function() { const $this = $(this); runFilter(config, $this); runOpenInNewTab(config, $this); runShowFullTitle(config, $this); }); runFadeVisitedTitle(config); } } // init form elements const initDom = () => { // init config dom let configDivHtml = ` <div id="douban_group_enhance_container" class="douban_group_enhance douban_group_added"> <div class="douban_group_enhance_mask"></div> <div class="douban_group_enhance_inner"> <div class="douban_group_enhance_inner_content"> <h1>小组优化设置</h1> <h2>通用设置</h2> <div class="douban_group_enhance_config_block"> <input type="checkbox" id="removeAd" value="1"> 勾选则去广告 </div> <h2>帖子列表页优化</h2> <div class="douban_group_enhance_config_block">请填入要高亮的关键字,多个关键字用空格隔开:</div> <textarea placeholder="请填入要高亮的关键字,多个关键字用空格隔开"></textarea> <br /> <div class="douban_group_enhance_config_block">请填入要排除的关键字,多个关键字用空格隔开:</div> <textarea placeholder="请填入要排除的关键字,多个关键字用空格隔开 "></textarea> <div class="douban_group_enhance_config_block"> <input type="checkbox" id="openInNewTab" value="1"> 勾选则使用新标签打开帖子 </div> <div class="douban_group_enhance_config_block"> <input type="checkbox" id="showFullTitle" value="1"> 勾选则去除标题省略号,显示完整标题 </div> <div class="douban_group_enhance_config_block"> <input type="checkbox" id="fadeVisited" value="1"> 勾选则淡化已经访问过的帖子标题(无痕/隐私模式下不生效) </div> <h2>帖子主题页优化</h2> <div class="douban_group_enhance_config_block"> <input type="checkbox" id="showReplyNumber" value="1"> 勾选则显示帖子里回复的楼层号 </div> <div class="douban_group_enhance_config_block"> <input type="checkbox" id="showOwnerTag" value="1"> 勾选则为楼主添加“楼主”的标签 </div> <div class="douban_group_enhance_config_block"> <input type="checkbox" id="jumpTo" value="1"> 勾选则添加跳转到标题、评论、页码位置的按钮(在屏幕左下角) </div> <p class="douban_group_enhance_buttons"> <button id="douban_group_enhance_sure" class="douban_group_enhance_button">确定</button> <button id="douban_group_enhance_cancel" class="douban_group_enhance_button" >取消</button> </p> </div> </div> </textarea> `; let styleHtml = ` <style id="douban_group_enhance_style" class="douban_group_added"> .douban_group_enhance_config { color: #ca6445; padding: 5px 20px; font-size: 13px; background: #fae9da; font-weight: normal; cursor: pointer; } .douban_group_enhance { width: 100vw; height: 100vh; position: absolute; top: 0; left: 0; display:none; } .douban_group_enhance_mask { position: absolute; background: rgba(0,0,0,.6); width: 100%; height: 100%; z-index: 99; } .douban_group_enhance_inner { width: 500px; text-align: center; margin: auto; top: 100px; position: relative; background: #fff; padding: 30px; height: 300px; overflow: auto; z-index: 100; } .douban_group_enhance_config_block { margin-top: 5px; } .douban_group_enhance_inner_content { text-align: left; } .douban_group_enhance_inner_content h1 { padding: 0; } .douban_group_enhance_inner_content h2 { color: #037b82; margin-top: 20px; } .douban_group_enhance_inner textarea { width: 100%; height: 60px; resize: auto; resize: vertical; min-height: 50px; padding: 10px; } .douban_group_enhance_inner textarea:focus { border: 1px solid #072; box-shadow: 0px 0px 1px 0px #072; } .douban_group_enhance_buttons { float: right; } a.douban_group_enhance_highlight { background: #037b82; color: #fff; } .douban_group_enhance_replay_tag { float: right; color: #666; padding: 0 5px; } .douban_group_enhance_button { padding: 5px 20px; font-size: 13px; border: 1px solid #037b82; color: #037b82; background-color: #f0f6f3; font-weight: normal; cursor: pointer; } .douban_group_enhance_button:hover { background-color: #037b82; color: #fff; } .douban_group_enhance_jump { position: fixed; bottom: 10px; left: 10px; background: #f0f6f3; border-radius: 2px; padding: 6px; } .douban_group_enhance_jump_target { cursor: pointer; color: #037b82; padding-right: 5px; } .douban_group_enhance_jump_target:hover { font-weight: bold; } </style> `; $(document.body).append(configDivHtml); $(document.body).append(styleHtml); // init config btn const insertPos = $('#db-global-nav .top-nav-doubanapp'); if (insertPos && insertPos[0]) { $(insertPos[0]).after('<div id="douban_group_enhance_config" class="top-nav-doubanapp douban_group_added"><span class="douban_group_enhance_button">小组增强插件设置</span></div>'); } } // init dom events const initDomEvents = () => { const $contain = $('#douban_group_enhance_container'); const $body = $(document.body); // bind events utils.bindClick('#douban_group_enhance_config', e => { $contain.show(); $body.css('overflow', 'hidden'); }); utils.bindClick('#douban_group_enhance_cancel', e => { $contain.hide(); $body.css('overflow', 'initial'); }); utils.bindClick('.douban_group_enhance_mask', e => { $contain.hide(); $body.css('overflow', 'initial'); }); utils.bindClick('#douban_group_enhance_sure', e => { const config = { include: $('#douban_group_enhance_container textarea')[0].value.split(' ').filter(v => !!v), declude: $('#douban_group_enhance_container textarea')[1].value.split(' ').filter(v => !!v), openInNewTab: $('#openInNewTab')[0].checked, showFullTitle: $('#showFullTitle')[0].checked, showReplyNumber: $('#showReplyNumber')[0].checked, showOwnerTag: $('#showOwnerTag')[0].checked, fadeVisited: $('#fadeVisited')[0].checked, jumpTo: $('#jumpTo')[0].checked, removeAd: $('#removeAd')[0].checked, } utils.saveConfig(config); runEnhancer(config); $contain.hide(); $body.css('overflow', 'initial'); }); } // init form values const initDomValue = config => { $('#douban_group_enhance_container textarea')[0].value = (config.include || []).join(' '); $('#douban_group_enhance_container textarea')[1].value = (config.declude || []).join(' '); $('#openInNewTab')[0].checked = config.openInNewTab; $('#showFullTitle')[0].checked = config.showFullTitle; $('#showReplyNumber')[0].checked = config.showReplyNumber; $('#showOwnerTag')[0].checked = config.showOwnerTag; $('#fadeVisited')[0].checked = config.fadeVisited; $('#jumpTo')[0].checked = config.jumpTo; $('#removeAd')[0].checked = config.removeAd; } const init = () => { const config = utils.getConfig() || {}; initDom(); initDomValue(config); initDomEvents(); runEnhancer(config); } const destory = () => { // remove dom events utils.unbindAllClick(); // remove all added elements $('#.douban_group_added').remove(); } return { init, destory, _version: '0.2.1.0' } } // init if (window.doubanEnhancer) { const enhancer = createEnhancer(); if (!doubanEnhancer._version) { doubanEnhancer._version = '0' } if (window.doubanEnhancer._version < enhancer._version) { if (doubanEnhancer.destory) { doubanEnhancer.destory(); } window.doubanEnhancer = enhancer; doubanEnhancer.init(); } } else { window.doubanEnhancer = createEnhancer(); doubanEnhancer.init(); } })();