您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
To find the matched videos posted by followings
// ==UserScript== // @name MatchedVideosOfBili // @namespace http://tampermonkey.net/ // @version 0.1 // @description To find the matched videos posted by followings // @author Ouphi // @match https://search.bilibili.com/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant none // @license MPL // ==/UserScript== var cnt = 0 // 读取预处理好的关注列表文件(内容为uid) var href = "https://space.bilibili.com/208259" var iframe var dm var uids var videos_target var videos_src var author_name_src var n_pages_src var btn_next_src var btn_next_target // 主页面翻页时的临时信息 var saved = 0 var saved_up_i var saved_page_i var saved_source_i var saved_target_page var saved_video_target_href // 子页面翻页时的临时信息 var saved_video_src_href init() function init(){ // 等待主页面加载完成 if(checkElement(document, 'class', "vui_tabs--nav vui_tabs--nav-pl0") == null){ setTimeout(function(){init()}, 100) return } console.log('1 ---- 加载成功') // 添加子网页,读取关注列表 run_init(0, 1, document, 'class', "header-entry-avatar") } // flag=0代表需要继续等待,其他数字代表继续, function run_init(flag, next_flag, element = null, method = null, text = null) { // 限制访问次数,在连续搜索不到内容时,由于不同up的页面加载、run0的增加,会触发边界 cnt++ if(cnt >= 2000){ return } console.log('1 ---- flag, next_flag : ' + flag + "," + next_flag) // 每隔0.1s判断一次加载进度 if(flag == 0){ if(checkElement(element, method, text) == null){ if(next_flag == 2 || next_flag == 6 || next_flag == 8){ // 需要访问子页面的flag // 不能直接传之前的document,只能动态更新 dm = document.getElementById('child-iframe').contentDocument setTimeout(function(){run_init(0, next_flag, dm, method, text)}, 100) } else // 需要访问主页面的flag setTimeout(function(){run_init(0, next_flag, element, method, text)}, 100) } else{ run_init(next_flag, next_flag, element, method, text) } } // 第一段,得到当前用户uid,创建follow page if(flag == 1){ run1GetAndFixPage() if(saved == 0) run_init(0, 2, dm, 'id', "download-following-list-button") else run_init(0, 11, window.document, 'class', "vui_button--active-blue") } // 第二段,点击download按钮,等待follow page的信息 if(flag == 2){ run2ClickDownButton() run_init(0, 3, dm, 'id', "following-list-text") } // 第三段,得到following list信息 if(flag == 3){ run3GetFollowingUids() run_init(0, 4, window.document, 'class', "bili-video-card__wrap __scale-wrap") } // 第四段,得到主页面的视频列表 if(flag == 4){ run4GetTargetVideos() if(saved == 1) fixBannerTarget() if(saved == 1) run_continue() } // 第十一段,判断主页面加载完成 if(flag == 11){ if(run11CheckVideosTarget() == 1){ setTimeout(function(){run_init(0, 11, window.document, 'class', "vui_button--active-blue")}, 100) } else{ run_init(0, 4, window.document, 'class', "bili-video-card__wrap __scale-wrap") } } } function run_continue(){ // init后主页面加载完成,save前子页面加载完成,所以可以直接用 run_search(10, 10, document, '', '', 0, saved_up_i, saved_page_i, saved_source_i) } // flag=0代表需要继续等待,其他数字代表继续, function run_search(flag, next_flag, element = null, method = null, text = null, target_i = 0, up_i = 0, page_i = 0, source_i = 0) { cnt++ if(cnt >= 2000){ return } var result console.log('1 ---- flag, next_flag : ' + flag + "," + next_flag) console.log('1 ---- target_i, up_i, page_i, source_i : ' + target_i + "," + up_i + "," + page_i + "," + source_i) // 上条需要等待加载完成后再读取 // window.onload只能识别header条,不识别内容加载程度 // 每隔0.1s判断一次加载进度 if(flag == 0){ if(checkElement(element, method, text) == null){ // 带参数的需要写在函数内,不然会出错 if(next_flag == 2 || next_flag == 6 || next_flag == 8){ // 不能直接访问document,只能通过传值 dm = document.getElementById('child-iframe').contentDocument setTimeout(function(){run_search(0, next_flag, dm, method, text, target_i, up_i, page_i, source_i)}, 100) } else{ setTimeout(function(){run_search(0, next_flag, element, method, text, target_i, up_i, page_i, source_i)}, 100) } } else{ run_search(next_flag, next_flag, element, method, text, target_i, up_i, page_i, source_i) } } // 第五段,判断并跳转到每个up主的视频页,等待读取 if(flag == 5){ if(run5ReloadChildPage(up_i) == 0) run_search(0, 6, dm, 'id', "submit-video-type-filter", target_i, up_i, 0, 0) } // 读取当前up主信息 if(flag == 6){ result = run6GetUpVideosInfo(up_i) if(result == 0) // 判断成功,继续运行 run_search(8, 8, dm, 'class', "small-item fakeDanmu-item", target_i, up_i, 0, 0) else if(result == 1) // 等待当前页面加载 setTimeout(function(){run_search(0, 6, dm, 'id', "submit-video-type-filter", target_i, up_i, 0, 0)}, 100) else if(result == 2) // 搜索内容为空,结束当前up主 run_search(5, 5, element, method, text, target_i, up_i+1, 0, 0) } // 第七段,判断并跳转到当前up主的下一页,等待读取 if(flag == 7){ // TODO: 冗余判断 if(run7ClickNextPage(page_i) == 1){ // 页数读取完成,结束当前up主 run_search(5, 5, element, method, text, target_i, up_i + 1, 0, 0) }else{ // 读取下一页 run_search(0, 8, dm, 'class', "small-item fakeDanmu-item", target_i, up_i, page_i, 0) } } // 考虑是空的情况啊啊啊 // 第六段,读取当前页面的视频列表 if(flag == 8){ var result = run8GetSrcVideos(up_i) if(result == 1) setTimeout(function(){run_search(8, 8, dm, 'class', "small-item fakeDanmu-item", target_i, up_i, page_i, 0)}, 100) else run_search(9, 9, element, method, text, target_i, up_i, page_i, 0) } // 第七段,判断结束条件 if(flag == 9){ var result = run9checkBoundary(target_i, up_i, page_i, source_i) if(result == 0) // 判断成功,继续运行 run_search(10, 10, element, method, text, target_i, up_i, page_i, source_i) else if(result == 2) // 结束当前up主 run_search(5, 5, element, method, text, target_i, up_i+1, 0, 0) else if(result == 3) // 结束当前页面 run_search(7, 7, element, method, text, target_i, up_i, page_i + 1, 0) } // 第八段,循环 if(flag == 10){ run10ReplaceSingleVideo(target_i, up_i, source_i) run_search(9, 9, element, method, text, target_i+1, up_i, page_i, source_i+1) } } /*** * 运行流程相关函数 ***/ // 1.得到页面信息,并添加子页面 function run1GetAndFixPage(){ // 得到用户uid href = checkElement(document, 'class', "header-entry-avatar")[0].attributes['href'].nodeValue var patt = /.+\/([0-9]+).*/ var uid = regGroup(patt, href) console.log('1 ---- flag1 ' + '当前用户:' + '\r' + uid) // 初次访问 if(saved == 0){ // 创建关注页面 /********* 如果需要设置分组,请确保分组内有人,可以修改这里的后缀?tagid=xxx ************ */ var src = "https://space.bilibili.com/"+ uid + "/fans/follow" addChildIframe(src) } } // 2.点击下载按钮 function run2ClickDownButton(){ // 不再重复下载 var btn_down = checkElement(dm, 'id', "download-following-list-button") btn_down.click() } // 3.获取关注列表信息 function run3GetFollowingUids(){ var t_uids = checkElement(dm, 'id', "following-list-text").textContent uids = t_uids.split('\n') // 校验内容是否读取正确 if((uids.length - 1).toString() != uids[0]){ console.log('1 ---- flag3 uid wrong\n') } else uids.shift() // 预处理结束,增加筛选关注up主视频的按钮 addFollowLi() } // 4.获取目的视频列表(主页面) function run4GetTargetVideos(){ var main_target = checkElement(window.document, 'class', "video-list row")[0] videos_target = checkElement(main_target, 'class', "bili-video-card__wrap __scale-wrap") videos_target = selectNotHideElement(videos_target) } // 5.将子页面设为当前up主的搜索页面,重新加载 function run5ReloadChildPage(i){ // 判断结束条件 if(i >= uids.length){ endButton(btn_next_target) console.log('1 ---- flag5 ' + "The End:全部up主的视频读取完毕") return 1 } var patt = /.+keyword=([^&/]+).*/ var word = regGroup(patt, window.location.href) console.log('1 ---- flag5 ' + '搜索词:' + '\r' + word) var src = 'https://space.bilibili.com/' + uids[i] + '/search/video?keyword=' + word iframe.remove() addChildIframe(src) return 0 } // 6.当前up主的初始信息 function run6GetUpVideosInfo(up_i){ // 双重检验,确保加载成功 // TODO:由于remove重进了,可以不加这层判断 var src_videos_text_2 = dm.getElementsByClassName('v-search-count')[0].textContent console.log('1 ---- flag6 ' + "当前up匹配的视频数2-", src_videos_text_2) var src_videos_text = dm.getElementById('submit-video-type-filter').children[0].children[0].textContent console.log('1 ---- flag6 ' + "当前up匹配的视频数--", src_videos_text) if(src_videos_text_2 != src_videos_text || isNaN(src_videos_text_2) ||isNaN(src_videos_text)){ return 1 }else if(src_videos_text == '0'){ return 2 } var t_pages = dm.getElementsByClassName("be-pager-total")[0].textContent n_pages_src = regGroup(/.+([0-9]+).+/, t_pages) console.log('2 ---- ' + '当前up总页数:' + ' ' + n_pages_src) if(n_pages_src == '0'){ return 2 } // 再检验,确保加载为新up dm = document.getElementById('child-iframe').contentDocument if(dm == null){return 1} href = dm.getElementsByClassName('text router-link-exact-active router-link-active')[0].attributes['href'].nodeValue btn_next_src = dm.getElementsByClassName('be-pager-next')[0] var patt = /.*\/([0-9]+)\/.*/ var uid = regGroup(patt, href) if(uid != uids[up_i]){return 1} return 0 } // 当前up主的下一页 function run7ClickNextPage(page_i){ if(page_i >= n_pages_src) return 1 btn_next_src.click() return 0 } // 8.获取源视频列表(子页面) function run8GetSrcVideos(i){ // 获取源视频列表 videos_src = checkElement(dm, 'class', "small-item fakeDanmu-item") var e_video_href = checkElement(videos_src[0], 'class', "title") if(e_video_href == null) return 1 var video_src_href = e_video_href[0].attributes['href'].nodeValue if(saved_video_src_href == video_src_href) return 1 author_name_src = dm.getElementById('h-name') return 0 } // 9.判断越界情况 function run9checkBoundary(target_i, up_i, page_i, source_i){ console.log('1 ---- flag9 ' + "target--" + videos_target.length + ":" + target_i + " source" + up_i +"-" + page_i + "--" + videos_src.length + ":" + source_i) if(page_i >= n_pages_src){ console.log('1 ---- flag9 ' + "Mid:当前up主的所有页面读取完毕") return 2 } if(source_i >= videos_src.length){ console.log('1 ---- flag9 ' + "Mid:当前up主的当前页面读取完毕") return 3 } if(target_i >= videos_target.length){ saveTargrtInfo(up_i, page_i, source_i) btn_next_target.style.display = 'block' console.log('1 ---- flag9 ' + "当前主页面加载完成") return 1 } return 0 } // 10.替换单个视频内容 function run10ReplaceSingleVideo(target_i , i, source_i){ console.log('1 ---- flag10 ' + "target--" + videos_target.length + ":" + target_i + " source" + i + "--" + videos_src.length + ":" + source_i) var video_src = videos_src[source_i] var img_src = video_src.children[0].getElementsByTagName('img')[0] var title_src = video_src.getElementsByClassName('title')[0] var banner_time_src = video_src.getElementsByClassName('time')[0] var banner_duration_src = video_src.getElementsByClassName('length')[0] var banner_playback_src = video_src.getElementsByClassName('play')[0] var video_target = videos_target[target_i] var img_target = video_target.children[0].getElementsByTagName('img')[0] var img_source_target = video_target.children[0].getElementsByTagName('source')[0] var title_target = video_target.children[1].getElementsByTagName('a')[0] var author_link_target = video_target.getElementsByClassName('bili-video-card__info--owner')[0] var author_name_target = video_target.getElementsByClassName('bili-video-card__info--author')[0] var banner_time_target = video_target.getElementsByClassName('bili-video-card__info--date')[0] var banner_duration_target = video_target.getElementsByClassName('bili-video-card__stats__duration')[0] var banner_playback_target = video_target.getElementsByClassName('bili-video-card__stats--item')[0].getElementsByTagName('span')[0] var banner_barage_target = video_target.getElementsByClassName('bili-video-card__stats--item')[1] var player_target = video_target.getElementsByClassName('v-inline-player')[0] var later_target = video_target.getElementsByClassName('bili-watch-later')[0] img_target.parentElement.replaceChild(img_src, img_target) video_target.children[0].href = title_src.href author_link_target.href = iframe.src author_name_target.textContent = author_name_src.textContent img_source_target.srcset = img_src.src title_target.parentElement.replaceChild(title_src, title_target) banner_playback_target.textContent = banner_playback_src.textContent banner_duration_target.textContent = banner_duration_src.textContent banner_time_target.textContent = banner_time_src.textContent player_target.style.display = 'none' later_target.style.display = 'none' banner_barage_target.style.display = 'none' } // 11.当前页面的信息 function run11CheckVideosTarget(){ // 双重检验,确保加载成功 var target_page = window.document.getElementsByClassName('vui_button--active-blue')[0].textContent if(target_page == saved_target_page) return 1 var main_target = checkElement(window.document, 'class', "video-list row")[0] var video_target = checkElement(main_target, 'class', "bili-video-card__wrap __scale-wrap")[0] var video_target_href = video_target.children[0].attributes['href'].nodeValue if(saved_video_target_href == video_target_href) return 1 var video_later = checkElement(video_target, 'class', 'bili-watch-later') if(video_later == null) return 1 return 0 } /**** * 关注按钮相关函数 *****/ // 增加按钮到搜索栏末尾 function addFollowLi(){ var ul = document.getElementsByClassName("vui_tabs--nav vui_tabs--nav-pl0")[0] const li = ul.getElementsByClassName("vui_tabs--nav-item")[0] var follow_li= li.cloneNode(true) follow_li.getElementsByClassName("vui_tabs--nav-text")[0].innerText = "关注" follow_li.attributes['class'].nodeValue = "vui_tabs--nav-item" follow_li.id = 'follow_btn' follow_li.onclick = function(){clickFollowLi(follow_li)} ul.appendChild(follow_li) } // 选择搜索关注内容,关注的元素内容修改 function clickFollowLi(follow_li){ // 更改活跃显示 var active_li = document.getElementsByClassName("vui_tabs--nav-item-active")[0] active_li.attributes['class'].nodeValue = "vui_tabs--nav-item" follow_li.attributes['class'].nodeValue = "vui_tabs--nav-item vui_tabs--nav-item-active" fixBannerTarget() // 开始搜索并取代原内容 run_search(5, 5, document, '', '', 0, 0, 0, 0) } function endButton(btn){ console.log(btn) btn.style.display = 'block' btn.textContent = "结束" btn.disabled = true } /**** * 元素处理函数 *****/ // 得到关注页面,以及各up主的搜索页面 function addChildIframe(src){ var e_parent_iframe = document.body iframe = document.createElement('iframe') iframe.src = src iframe.style.width = '500px' iframe.style.height = '500px' e_parent_iframe.appendChild(iframe, e_parent_iframe) iframe.id = 'child-iframe' dm = iframe.contentDocument } // 筛选未隐藏的视频 function selectNotHideElement(list){ var result = new Array() for( var i = 0; i < list.length; ++i){ // 这里使用函数,所以不需要nodeValue if(list[i].parentElement.parentElement.getAttribute('class').indexOf("to_hide_xs") == -1){ result.push(list[i]) } } return result } function clickNextButtonTarget(btn){ btn.style.display = 'none' init() } function fixBannerTarget(){ // 删去细化筛选栏,综合/视频/番剧/用户栏;会固定按照关注顺序依次显示 if(checkElement(document, 'class', "search-header") != null){ var strategy_banner = document.getElementsByClassName("search-header")[0].children[3] strategy_banner.style.display = "none" } // 删去选页栏,只留下一页;滚动显示,不保留全部内容 // TODO:也可以预处理多花些事件,获取所有视频列表后,排序显示,可选页 if(checkElement(document, 'class', "vui_pagenation--btns") != null){ var page_btns = document.getElementsByClassName("vui_pagenation--btns")[0] for(var i = 0; i < page_btns.children.length - 1; ++i){ strategy_banner.style.display = "none" page_btns.children[i].style.display = "none" } btn_next_target = page_btns.children[page_btns.children.length - 1] btn_next_target.style.display = 'none' btn_next_target.onclick = function(){clickNextButtonTarget(btn_next_target)} } } /**** * 等待相关函数 ****/ // 检查所需元素是否已加载成功 function checkElement(element, method, text){ if(element == null) return null var result = null switch(method){ case 'class': result = element.getElementsByClassName(text) break case 'tag': result = element.getElementsByTagName(text) break case 'id': result = element.getElementById(text) break default: result = element.getElementsByClassName(text) break } // console.log(result) if(result != null && result != undefined && result.length != 0){ return result }else{ return null } } /**** * 一些小函数 ****/ // 正则匹配 function regGroup(patt, text){ var matched_str = text.match(patt) var result = RegExp.$1 return result } // 保存过去信息:主页面翻页时 function saveTargrtInfo(up_i, page_i, source_i){ saved = 1 saved_up_i = up_i saved_page_i = page_i saved_source_i = source_i saved_target_page = window.document.getElementsByClassName('vui_button--active-blue')[0].textContent saved_video_target_href = videos_target[0].children[0].attributes['href'].nodeValue } // 保存过去信息:子页面翻页时 function saveSrcInfo(){ saved_video_src_href = videos_src[0].getElementsByClassName('title')[0].attributes['href'].nodeValue }