您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
add time filter to bilibili search results
当前为
// ==UserScript== // @name Bilibili Search Filter By Time // @namespace https://github.com/KID-joker/userscript // @version 1.0.1 // @supportURL https://github.com/KID-joker/userscript/issues // @description add time filter to bilibili search results // @author KID-joker // @match https://search.bilibili.com/* // @icon https://www.bilibili.com/favicon.ico?v=1 // @resource css https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/flatpickr.min.js // @grant GM_log // @grant GM_addStyle // @grant GM_getResourceText // @grant unsafeWindow // @run-at document-start // @license MIT // ==/UserScript== (function() { // 设置样式 let css = ` @media (max-width: 1099.9px) { #i_cecream .video-list-item { display:block!important; } } @media (max-width: 1439.9px) { #i_cecream .video-list-item { display:block!important; } } @media (max-width: 1699.9px) { #i_cecream .video-list-item { display:block!important; } } @media (max-width: 1919.9px) { #i_cecream .video-list-item { display:block!important; } } @media (max-width: 2199.9px) { #i_cecream .video-list-item { display:block!important; } } ` GM_addStyle(css) GM_addStyle(GM_getResourceText('css')); // 获取过滤日期 function getQueryObject(url) { url = url == null ? window.location.href : url const search = url.substring(url.lastIndexOf('?') + 1) const obj = {} const reg = /([^?&=]+)=([^?&=]*)/g search.replace(reg, (rs, $1, $2) => { const name = decodeURIComponent($1) let val = decodeURIComponent($2) val = String(val) obj[name] = val return rs }) return obj } let queryObj = getQueryObject(); let date = queryObj.date || 'none'; let dateRange = queryObj.date_range; if(date !== 'none') { dateRange = dateRange.split('_'); } // 返回json结果 let responseJson = null; // 过滤的结果 let result = []; // 日期过滤的页码 let actualPage = 1; // b站对应页面 let requestPage = 1; // 数量 let pageSize = 0; // 没有更多数据 let finished = false; // 最大页码 let maxPage = 1; // 自定义日期选择弹窗 let fp = null; // 重写fetch,拦截fetch请求 const originFetch = fetch; unsafeWindow.fetch = async function(url, options) { // 只针对视频搜索接口 let params = getQueryObject(url); if(url.indexOf('x/web-interface/search/type') > -1 && params.search_type === 'video' && date !== 'none') { actualPage = params.page; pageSize = params.page_size; if(result.length < actualPage * pageSize) { await requestData(url, options); } let reponseResult = result.slice((actualPage - 1) * pageSize, actualPage * pageSize); let response = new Response(); response.json = function() { return new Promise(resolve => { responseJson.data.page = +actualPage; responseJson.data.result = reponseResult; resolve(responseJson); }) } setTimeout(() => { changePagenationBtn(); }, 0); return response; } else { return originFetch(url, options); } } // 获取vue实例、vue-router实例 let app = null, router = null, route = null; document.addEventListener('DOMContentLoaded', function() { app = document.querySelector('#i_cecream').__vue_app__; router = app.config.globalProperties.$router; route = app.config.globalProperties.$route; if(route.name === 'video') { insertComponent(); } router.afterEach(route => { if(route.name === 'video') { insertComponent(); } }) // 重写replace方法,拦截跳转,更新route,初始化数据 const routerReplace = router.replace; router.replace = function(toRoute) { // 筛选条件改变 if(!toRoute.query.date || toRoute.query.date === 'none' || !toRoute.query.page) { route = toRoute; result = []; actualPage = 1; requestPage = 1; pageSize = 0; finished = false; return routerReplace.call(this, toRoute); } } }) // 插入日期过滤组件 function insertComponent() { if(document.querySelector('#date-search-confitions')) { return; } let element = document.createElement('div'); element.id = 'date-search-confitions'; element.className = 'search-condition-row'; element.addEventListener('click', clickDateCondition); let fragment = document.createDocumentFragment(); let list = [{ name: 'none', title: '时间不限' }, { name: 'day', title: '过去1天内' }, { name: 'week', title: '过去1周内' }, { name: 'month', title: '过去1月内' }, { name: 'year', title: '过去1年内' }, { name: 'custom', title: '自定日期范围' }] list.forEach(function(ele) { let button = document.createElement('button'); button.textContent = ele.title; button.className = 'vui_button vui_button--tab mt_sm mr_sm'; button.dataset.datecondition = ele.name; if(ele.name === date) { button.className += ' vui_button--active'; } fragment.appendChild(button); }); element.appendChild(fragment); document.querySelector('.more-conditions').appendChild(element); } // 日期过滤点击事件 function clickDateCondition(evt) { let datecondition = evt.target.dataset.datecondition; if(datecondition === 'none') { // 时间不限 let { date, date_range, ...query } = route.query; router.replace({ 'name': 'video', query }); setTimeout(() => { router.go(0); }, 0); } else if(datecondition === 'custom') { // 自定义日期范围,弹出日期选择弹窗 if(!fp) { fp = evt.target.flatpickr({ clickOpens: false, maxDate: 'today', mode: 'range', onChange: function(selectedDates) { if(selectedDates.length == 2) { let startTime = +selectedDates[0]; let endTime = +selectedDates[1]; if(startTime == endTime) { endTime += 86400000; } endTime = Math.min(Date.now(), endTime); filterByDate(datecondition, startTime, endTime); } } }); } fp.open(); } else if(datecondition) { // 固定日期范围选择 let endTime = Date.now(); let timeMap = { 'day': 86400000, 'week': 604800000, 'month': 2592000000, 'year': 31536000000 } filterByDate(datecondition, endTime - timeMap[datecondition], endTime); } } function filterByDate(datecondition, startTime, endTime) { let { page, o, ...query } = route.query; query.date = datecondition; query.date_range = `${Math.floor(startTime / 1000)}_${Math.floor(endTime / 1000)}`; router.replace({ name: 'video', query }); setTimeout(() => { router.go(0); }, 0); } // 隐藏分页按钮 function changePagenationBtn() { if(date !== 'none') { let pagenationBtnList = document.querySelectorAll('.vui_pagenation--btn-num'); if(pagenationBtnList.length > 0) { for(let btn of pagenationBtnList) { btn.remove(); } } let pagenationText = document.querySelector('.vui_pagenation--extend'); if(pagenationText) { pagenationText.remove(); } let pagenationParent = document.querySelector('.vui_pagenation--btns'); if(pagenationParent) { let nextPagenation = pagenationParent.lastChild; if(finished && actualPage === maxPage) { nextPagenation.className += ' vui_button--disabled'; nextPagenation.setAttribute('disabled', 'disabled') } else { nextPagenation.className = nextPagenation.className.replace(' vui_button--disabled', ''); nextPagenation.removeAttribute('disabled'); } } } } // 请求数据保存 async function requestData(url, options) { while(true) { url = url.replace(/page=[0-9]+/, `page=${requestPage}`); // 应该是浏览的偏移量,必须跟页码数量保持一致,不然会有重复数据 url = url.replace(/dynamic_offset=[0-9]+/, `dynamic_offset=${(requestPage - 1) * pageSize}`); let _responseJson = await originFetch(url, options).then(response => { return response.json(); }); if(_responseJson.data && _responseJson.data.result) { if(_responseJson.data.result.length < pageSize) { finished = true; maxPage = actualPage; } responseJson = _responseJson; let list = responseJson.data.result.filter(ele => ele.pubdate >= dateRange[0] && ele.pubdate <= dateRange[1]); result = result.concat(list); } else { // 没有更多数据了 finished = true; maxPage = actualPage; } requestPage++; if(finished || result.length >= actualPage * pageSize) { return; } else { let time = Math.round(Math.random() * 200) + 300; await delay(time); } } } // 防止请求频繁,被封ip function delay(n){ return new Promise(function(resolve){ setTimeout(resolve, n); }); } })();