// ==UserScript==
// @name 人生只若如初见
// @namespace http://tampermonkey.net/
// @version 1.6.5
// @description 让TA们重新走进你的生活。
// @author boynextdesk
// @match https://t.bilibili.com/*
// @icon none
// @grant none
// @license GPL V3.0
// ==/UserScript==
// https://greasyfork.org/zh-CN/scripts/447357-%E4%BA%BA%E7%94%9F%E5%8F%AA%E8%8B%A5%E5%A6%82%E5%88%9D%E8%A7%81
(async function() {
'use strict';
// todo: [] live room simulation
// todo: [] generate pseudo-stream time schedule
// todo: [] more ways to show livers' pseudo-existence
// 人话:不仅在动态侧边栏,也在首页导航栏和live.bilibili.com下的页面显示(可行性存疑
const COOKIE_CONFIG_LIVER_NUMBER = "FAKE_STREAMER_LIVER_TOTAL_NUMBER"
const COOKIE_LIVER_LIST = "FAKE_STREAMER_LIST"
const COOKIE_LIVER_CONFIG_PREFIX = "FAKE_STREAMER_"
const COOKIE_WAY_BACK_DAY = "FAKE_STREAMER_WAY_BACK_DAY"
const COOKIE_WAY_BACK_HOUR = "FAKE_STREAMER_WAY_BACK_HOUR"
const COOKIE_WAY_BACK_MINUTE = "FAKE_STREAMER_WAY_BACK_MINUTE"
const COOKIE_SHOW_MORE = "FAKE_STREAMER_SHOW_REAL_TIME"
const SPLIT_WORD = "!"
const FIRST_TITLE_DEFAULT_FONT_SIZE = "18px"
const SECOND_TITLE_DEFAULT_PADDING_SIZE = "5px"
const DATE_SELECTOR_ID = "fake-streamer-way-back-selector"
const DATE_SELECTOR_CONFIRM_BTN_ID = "fake-streamer-way-back-confirm-button"
const SECTION_ID = "fake-streamer-settings-section"
const LEFT_STREAMER_ITEM_ID = "fake-streamer-dyn-item"
const STREAMER_SPECIFIC_WAY_BACK_ID = "fake-streamer-way-back"
let date_selector_count = 0
let left_streamer_item_count = 0
let date_selector_confirm_btn_count = 0
function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
function log_sep() {
console.log("---------------------------")
}
// easier to code yet not very elegant
Number.prototype.toLeadZeroString = function (len) {
let result = String(this)
if(result.length >= len){
return result
}
len = len - result.length
for(let i = 0 ; i < len ; i++){
result = "0" + result
}
return result
}
// www.runoob.com
function setCookie(cname,cvalue,exdays=365000){
const d = new Date();
d.setTime(d.getTime()+(exdays*24*60*60*1000));
const expires = "expires=" + d.toUTCString()
document.cookie = cname+"="+cvalue+"; "+expires;
}
function getCookie(cname){
const name = cname + "=";
const ca = document.cookie.split(';');
for(let i=0; i<ca.length; i++) {
const c = ca[i].trim();
if (c.indexOf(name)===0) { return c.substring(name.length,c.length); }
}
return "";
}
function gen_liver_storage_id(liverBase64){
return COOKIE_LIVER_CONFIG_PREFIX + liverBase64
}
function gen_date_selector_id(){
return DATE_SELECTOR_ID + "-" + date_selector_count++
}
function gen_date2dateSelectorValue(date){
return `${date.getFullYear().toLeadZeroString(4)}-${(date.getMonth() + 1).toLeadZeroString(2)}-${date.getDate().toLeadZeroString(2)}T${date.getHours().toLeadZeroString(2)}:${date.getMinutes().toLeadZeroString(2)}`
}
function gen_dateSelectorValue2date(dateSelectorValue){
dateSelectorValue = dateSelectorValue.split('T')
if(dateSelectorValue.length < 2){
console.log("invalid value")
return
}
let date = dateSelectorValue[0].split('-')
let time = dateSelectorValue[1].split(':')
if(date.length < 3 || time.length < 2){
console.log("invalid value")
return
}
let dateObj = new Date()
dateObj.setFullYear(Number(date[0]), Number(date[1]) - 1, Number(date[2]))
dateObj.setHours(Number(time[0]), Number(time[1]))
return dateObj
}
function gen_left_streamer_item_id(){
return LEFT_STREAMER_ITEM_ID + "-" + left_streamer_item_count++
}
function gen_left_streamer_item_id_manual(num){
return LEFT_STREAMER_ITEM_ID + "-" + num
}
function gen_streamer_specific_way_back_id(streamer_id){
return STREAMER_SPECIFIC_WAY_BACK_ID + "-" + streamer_id
}
function gen_date_selector_confirm_btn_id(){
return DATE_SELECTOR_CONFIRM_BTN_ID + "-" + date_selector_confirm_btn_count++
}
function get_show_more_state() {
return getCookie(COOKIE_SHOW_MORE) === ""
}
function set_show_more_state(new_state){
if(!!new_state)
setCookie(COOKIE_SHOW_MORE, "true")
else
setCookie(COOKIE_SHOW_MORE, "")
}
function add_left_section_streamer(inputLiverName, inputLiveTitle, inputLiveUrl, inputLiverAvatarAttr, startTime = null, endTime = null) {
// create new item
let liveBody = document.getElementsByClassName("bili-dyn-live-users__body")[0]
if (liveBody == null) {
console.log("No live-body found")
return
}
const liveNewItemRawStringNewVersion = "<div class=\"bili-dyn-live-users__item\">" +
" <div class=\"bili-dyn-live-users__item__left\">" +
" <div class=\"bili-dyn-live-users__item__face-container\">" +
" <div class=\"bili-dyn-live-users__item__face\">" +
" <div class=\"bili-awesome-img\"></div>" +
" </div>" +
" </div>" +
" <div class=\"bili-dyn-live-users__item__living\"><span>直播中</span></div>" +
" </div>" +
" <div class=\"bili-dyn-live-users__item__right\">" +
" <div class=\"bili-dyn-live-users__item__uname bili-ellipsis\"></div>" +
" <div class=\"bili-dyn-live-users__item__title bili-ellipsis\"></div>" +
" </div>" +
"</div>"
const liveNewItemRawStringOldVersion = "<div class=\"bili-dyn-live-users__item\">" +
" <div class=\"bili-dyn-live-users__item__left\">" +
" <div class=\"bili-dyn-live-users__item__face-container\">" +
" <div class=\"bili-dyn-live-users__item__face\">" +
" <div class=\"bili-awesome-img\"></div>" +
" </div>" +
" </div>" +
" </div>" +
" <div class=\"bili-dyn-live-users__item__right\">" +
" <div class=\"bili-dyn-live-users__item__uname bili-ellipsis\"></div>" +
" <div class=\"bili-dyn-live-users__item__title bili-ellipsis\"></div>" +
" </div>" +
"</div>"
let liveNewItemParent = document.createElement("div")
if(document.getElementsByClassName("bili-dyn-live-users__item__living").length == 0){
liveNewItemParent.innerHTML = liveNewItemRawStringOldVersion
}
else{
liveNewItemParent.innerHTML = liveNewItemRawStringNewVersion
}
let liveNewItem = liveNewItemParent.firstChild
liveBody.appendChild(liveNewItem)
liveNewItem = liveBody.getElementsByClassName("bili-dyn-live-users__item")
liveNewItem = liveNewItem[liveNewItem.length - 1]
liveNewItem.setAttribute("id", gen_left_streamer_item_id())
// modify new item - image
let liveNewItemAvatar = liveNewItem.firstElementChild.firstElementChild.firstElementChild.firstElementChild
liveNewItemAvatar.setAttribute("style", "background-image: url(\"" + inputLiverAvatarAttr + "\");")
// modify new item - nickname
let liveNewItemNickname = liveNewItem.lastChild.firstElementChild
let newNicknameNode = document.createTextNode(inputLiverName)
liveNewItemNickname.appendChild(newNicknameNode)
// modify new item - title
let liveNewItemTitle = liveNewItem.lastChild.lastElementChild
let newTitleNode = document.createTextNode(inputLiveTitle)
liveNewItemTitle.appendChild(newTitleNode)
// update livers' number
let liveTitle = document.getElementsByClassName("bili-dyn-live-users__title")
if (liveTitle.length == 0) {
console.log("No title found")
return
}
liveTitle = liveTitle[0]
let liveTitleOldNode = liveTitle.lastChild.firstChild;
if(liveTitleOldNode){
let livingNum = liveTitleOldNode.nodeValue.slice(1, -1)
livingNum = Number(livingNum) + 1
let liveTitleNewNode = document.createTextNode("(" + String(livingNum) + ")")
liveTitle.lastChild.replaceChild(liveTitleNewNode, liveTitleOldNode)
}else{
console.debug("新版取消了正在直播的计数")
}
// register event
liveNewItem.addEventListener("click", function () {
if(endTime == null || startTime == null){
window.open(inputLiveUrl)
return
}
let nowTime = new Date()
if(nowTime >= endTime){
alert("主播正在觅食~")
return
}
let offset = parseInt(nowTime - startTime) / 1000.0
let isArgExisting = inputLiveUrl.includes('?')
if(isArgExisting){
let url = inputLiveUrl + "&t=" + offset
window.open(url)
return
}
window.open(inputLiveUrl + "?t=" + offset)
})
}
// register new settings to user_face to control its visibility
function add_new_setting(click_listener, title = null, item = null) {
let dyn_item = item
if (dyn_item == null){
return
}
dyn_item.setAttribute("style", "display: none;")
// register show listener
let face_status = 0
let face = document.getElementsByClassName("bili-dyn-my-info__face")
if(face.length == 0){
face = document.getElementsByClassName("avatar")
}
if(face.length == 0){
console.log("获取用户头像组件失败!")
return
}
face = face[0]
face.addEventListener("mouseenter", function () {
face_status = 1 - face_status
if(face_status){
dyn_item.setAttribute("style", "display: flex;")
}else{
dyn_item.setAttribute("style", "display: none;")
}
})
// register click listener
dyn_item.addEventListener("click", click_listener)
return dyn_item
}
function create_setting_panel_item(panel, inputLiverName, inputLiveTitle, inputLiverAvatarAttr, buttonListener) {
// append child
const liveNewItemRawString = "<div class=\"bili-dyn-live-users__item\">" +
" <div class=\"bili-dyn-live-users__item__left\">" +
" <div class=\"bili-dyn-live-users__item__face-container\">" +
" <div class=\"bili-dyn-live-users__item__face\">" +
" <div class=\"bili-awesome-img\"></div>" +
" </div>" +
" </div>" +
" </div>" +
" <div class=\"bili-dyn-live-users__item__right\">" +
" <div class=\"bili-dyn-live-users__item__uname\"></div>" +
" <div class=\"bili-dyn-live-users__item__title\"></div>" +
" </div>" +
" <button class = \"bili-dyn-live-users__item__reset\">" +
" 重置" +
" </button>" +
"</div>"
let liveNewItem = document.createElement("div")
liveNewItem.innerHTML = liveNewItemRawString
panel.appendChild(liveNewItem.firstChild)
liveNewItem = document.getElementsByClassName("bili-dyn-live-users__item")
liveNewItem = liveNewItem[liveNewItem.length - 1]
// modify new item - image
let liveNewItemAvatar = liveNewItem.firstElementChild.firstElementChild.firstElementChild.firstElementChild
liveNewItemAvatar.setAttribute("style", "background-image: url(\"" + inputLiverAvatarAttr + "\");")
// modify new item - nickname
let liveNewItemNickname = liveNewItem.children.item(1).firstElementChild
let newNicknameNode = document.createTextNode(inputLiverName)
liveNewItemNickname.appendChild(newNicknameNode)
// modify new item - title
let liveNewItemTitle = liveNewItem.children.item(1).lastElementChild
let newTitleNode = document.createTextNode(inputLiveTitle)
liveNewItemTitle.appendChild(newTitleNode)
// modify new item - button
let liveNewItemBtn = liveNewItem.lastElementChild
liveNewItemBtn.addEventListener('click', buttonListener)
return liveNewItem
}
function create_panel() {
// create new banner panel
let banners = document.getElementsByClassName("bili-dyn-banner")
let refChild = document.getElementsByClassName("sticky")
let right = document.getElementsByClassName("right")[0]
let banner = banners[banners.length - 1]
let panel_section = document.createElement("section")
panel_section.setAttribute("id", SECTION_ID)
refChild = refChild[refChild.length - 1]
banner = banner.cloneNode(false)
panel_section.appendChild(banner)
right.insertBefore(panel_section, refChild)
// padding
banner.setAttribute("style", "padding: 12px 16px 16px;")
if(get_show_more_state()){
// title
let panel_title = document.getElementsByClassName("bili-dyn-banner__title")
if(panel_title.length == 0){
panel_title = document.getElementsByClassName("bili-dyn-live-users__title")
}
if(panel_title.length == 0){
console.log("获取面板标题控件失败")
return
}
console.log(panel_title)
panel_title = panel_title[0]
let panel_title_node = document.createTextNode("插件设置")
panel_title = panel_title.cloneNode(false)
panel_title.appendChild(panel_title_node)
banner.appendChild(panel_title)
// config 0: input file
let config0_text_node = document.createTextNode("导入json配置文件")
let config0_title_div = document.createElement("div")
config0_title_div.style.setProperty("font-size", FIRST_TITLE_DEFAULT_FONT_SIZE)
config0_title_div.appendChild(config0_text_node)
banner.appendChild(config0_title_div)
let config0_chooser = document.createElement("input")
config0_chooser.setAttribute("type", "file")
config0_chooser.setAttribute("id", "configFileInput")
config0_chooser.setAttribute("accept", ".json")
banner.appendChild(config0_chooser)
config0_chooser.addEventListener("change", function () {
if(this.files.length === 0){
console.log("没有导入文件")
return
}
if(!window.localStorage){
alert("导入失败:浏览器不支持localStorage")
return
}
const reader = new FileReader()
reader.onerror = function () {
alert("导入失败:文件读取失败")
}
reader.onloadend = function () {
let rawData = reader.result
let rawJson = JSON.parse(rawData)
// read liver's name
let liver_name = rawJson.liver_name
if(liver_name == null){
alert("导入失败:缺少主播名称")
return
}
console.log(liver_name)
let liver_name_base64 = window.btoa(window.encodeURI(liver_name))
// storage it into list
let liver_list = window.localStorage[COOKIE_LIVER_LIST]
if (liver_list == null){
window.localStorage[COOKIE_LIVER_LIST] = liver_name_base64
}else{
let livers = liver_list.split(SPLIT_WORD)
for(let i = 0 ; i < livers.length ; i++)
{
if (livers[i] === liver_name_base64)
{
alert("导入失败:已经导入过")
return
}
}
liver_list += SPLIT_WORD + liver_name_base64
window.localStorage[COOKIE_LIVER_LIST] = liver_list
if (window.localStorage[COOKIE_LIVER_LIST] == null){
alert("导入失败:localStorage大小限制为4M,大小可能已经超出限制")
return
}
}
// storage it into localStorage
let storage_id = gen_liver_storage_id(liver_name_base64)
window.localStorage[storage_id] = rawData
alert("导入完成")
update_panel()
}
reader.readAsText(this.files[0])
})
// config 1: reset
let reset_title_node = document.createTextNode("删除所有数据")
let reset_title_div = document.createElement("div")
reset_title_div.appendChild(reset_title_node)
reset_title_div.style.setProperty("font-size", FIRST_TITLE_DEFAULT_FONT_SIZE)
banner.appendChild(reset_title_div)
let div1 = document.createElement("div")
let btn_reset = document.createElement("button")
btn_reset.appendChild(document.createTextNode("重置"))
div1.appendChild(btn_reset)
banner.appendChild(div1)
btn_reset.addEventListener("click", function () {
let yes = confirm("确定全部清除吗?")
if(!yes)
return
setCookie(COOKIE_CONFIG_LIVER_NUMBER, 0)
setCookie(COOKIE_WAY_BACK_DAY, "")
setCookie(COOKIE_WAY_BACK_HOUR, "")
let liver_list = window.localStorage[COOKIE_LIVER_LIST]
if(liver_list != null){
let livers = liver_list.split(SPLIT_WORD)
for(let i = 0 ; i < livers.length; i++)
{
let liver_name_storage_id = gen_liver_storage_id(livers[i])
window.localStorage.removeItem(liver_name_storage_id)
}
window.localStorage.removeItem(COOKIE_LIVER_LIST)
alert("清除完毕")
update_panel()
return
}
alert("清除失败:列表为null")
})
// config 2: way back time
let way_back_node = document.createTextNode("全局设置时空倒流时间")
let way_back_div = document.createElement("div")
let way_back_day = getCookie(COOKIE_WAY_BACK_DAY)
let way_back_hour = getCookie(COOKIE_WAY_BACK_HOUR)
let way_back_minute = getCookie(COOKIE_WAY_BACK_MINUTE)
way_back_div.appendChild(way_back_node)
way_back_div.style.setProperty("font-size", FIRST_TITLE_DEFAULT_FONT_SIZE)
banner.appendChild(way_back_div)
way_back_node = document.createTextNode("注:如果为某个主播单独进行设置,则会覆盖掉全局设置")
banner.appendChild(way_back_node)
// one-step setting
let way_back_all = document.createElement("div")
let way_back_all_id = gen_date_selector_id()
let way_back_all_btn_id = gen_date_selector_confirm_btn_id()
let way_back_time_now = new Date()
if(way_back_minute !== ""){
way_back_time_now.setMinutes(way_back_time_now.getMinutes() - Number(way_back_minute))
}
if(way_back_hour !== ""){
way_back_time_now.setHours(way_back_time_now.getHours() - Number(way_back_hour))
}
if(way_back_day !== ""){
way_back_time_now.setDate(way_back_time_now.getDate() - Number(way_back_day))
}
let way_back_selector_default_value = gen_date2dateSelectorValue(way_back_time_now)
if(get_show_more_state()){
way_back_all.innerHTML = "<p>你要回到哪一刻?</p>" +
"<input id='"+ way_back_all_id + "' type='datetime-local' value='" + way_back_selector_default_value +"' />" +
"<button id='"+ way_back_all_btn_id +"'>确认更改到这个日期</button>"
banner.appendChild(way_back_all)
let way_back_datetime_input = document.getElementById(way_back_all_id)
let way_back_datetime_input_confirm_btn = document.getElementById(way_back_all_btn_id)
way_back_datetime_input.onchange = function () {
way_back_time_now = gen_dateSelectorValue2date(this.value)
}
way_back_datetime_input_confirm_btn.addEventListener("click", function () {
let std_date = way_back_time_now
let time_now = new Date()
let diff_s = Math.floor((time_now - std_date) / 1000)
let diff_minutes = Math.floor(diff_s % 3600 / 60)
let diff_hours = Math.floor(diff_s % (3600 * 24) / 3600)
let diff_days = Math.floor(diff_s / (3600 * 24))
console.log(`way_back_datetime_input: ${diff_days} d ${diff_hours} h ${diff_minutes} min BACK`)
setCookie(COOKIE_WAY_BACK_DAY, diff_days)
setCookie(COOKIE_WAY_BACK_HOUR, diff_hours)
setCookie(COOKIE_WAY_BACK_MINUTE, diff_minutes)
alert("更新完毕")
update_panel()
})
}
// day
if(way_back_day !== "") {
let way_back_day_ele = document.createElement("div")
way_back_day_ele.appendChild(document.createTextNode("当前时空倒流天数: " + way_back_day))
way_back_day_ele.style.setProperty("padding-left", SECOND_TITLE_DEFAULT_PADDING_SIZE)
banner.appendChild(way_back_day_ele)
}
let div_day = document.createElement("div")
let btn_way_back_day = document.createElement("button")
btn_way_back_day.appendChild(document.createTextNode("单独设置天数"))
div_day.appendChild(btn_way_back_day)
banner.appendChild(div_day)
btn_way_back_day.addEventListener('click', function () {
let day = prompt("请设置时间倒流天数")
if(day != null){
day = Number(day)
setCookie(COOKIE_WAY_BACK_DAY, day)
alert("设置成功")
update_panel()
// if vue...
}
})
// hour
if(way_back_hour !== "") {
let way_back_hour_ele = document.createElement("div")
way_back_hour_ele.appendChild(document.createTextNode("当前时空倒流小时数: "+ way_back_hour))
way_back_hour_ele.style.setProperty("padding-left", SECOND_TITLE_DEFAULT_PADDING_SIZE)
banner.appendChild(way_back_hour_ele)
}
let div_hour = document.createElement("div")
let btn_way_back_hour = document.createElement("button")
btn_way_back_hour.appendChild(document.createTextNode("单独设置小时"))
div_hour.appendChild(btn_way_back_hour)
banner.appendChild(div_hour)
btn_way_back_hour.addEventListener('click', function () {
let hour = prompt("请设置时间倒流小时数")
if(hour != null){
hour = Number(hour)
setCookie(COOKIE_WAY_BACK_HOUR, hour)
alert("设置成功")
update_panel()
}
})
// minutes
if(way_back_minute !== "") {
let way_back_minute_ele = document.createElement("div")
way_back_minute_ele.appendChild(document.createTextNode("当前时空倒流分钟数: "+ way_back_minute))
way_back_minute_ele.style.setProperty("padding-left", SECOND_TITLE_DEFAULT_PADDING_SIZE)
banner.appendChild(way_back_minute_ele)
}
let div_minute = document.createElement("div")
let btn_way_back_minute = document.createElement("button")
btn_way_back_minute.appendChild(document.createTextNode("单独设置分钟"))
div_minute.appendChild(btn_way_back_minute)
banner.appendChild(div_minute)
btn_way_back_minute.addEventListener('click', function () {
let minute = prompt("请设置时间倒流分钟数")
if(minute != null){
minute = Number(minute)
setCookie(COOKIE_WAY_BACK_MINUTE, minute)
alert("设置成功")
update_panel()
}
})
// config 3: list
let list_title_node = document.createTextNode("已导入的主播")
let list_title_div = document.createElement("div")
list_title_div.appendChild(list_title_node)
list_title_div.style.setProperty("font-size", FIRST_TITLE_DEFAULT_FONT_SIZE)
banner.appendChild(list_title_div)
let live_list = window.localStorage[COOKIE_LIVER_LIST]
if (live_list == null){
return panel_section
}
let livers = live_list.split('!')
for(let i = 0 ; i < livers.length ; i++)
{
let liver_storage_id = livers[i]
let rawData = window.localStorage[gen_liver_storage_id(liver_storage_id)]
if(rawData == null){
continue
}
let rawJson = JSON.parse(rawData)
let newItem = create_setting_panel_item(panel_section,
rawJson.liver_name, rawJson.extra_info, rawJson.liver_avatar_url,
function () {
let yes = confirm(`确定清除 ${rawJson.liver_name} 的配置信息吗?`)
if(!yes)
return
window.localStorage.removeItem(liver_storage_id)
window.localStorage.removeItem(gen_streamer_specific_way_back_id(livers[i]))
let live_list_now = window.localStorage[COOKIE_LIVER_LIST]
if (live_list_now != null){
let livers_now = live_list_now.split(SPLIT_WORD)
let livers_after = ""
for(let j = 0 ; j < livers_now.length ; j++)
{
if(livers_now[j] === liver_storage_id){
continue
}
if(j === 0){
livers_after = livers_now[j]
}else{
livers_after += SPLIT_WORD + livers_now[j]
}
}
window.localStorage[COOKIE_LIVER_LIST] = livers_after
}
alert("清除完成")
update_panel()
})
banner.appendChild(newItem)
// new: independent rollback time
if(get_show_more_state()){
let specific_way_back_id = gen_streamer_specific_way_back_id(livers[i])
let specific_time_back = window.localStorage[specific_way_back_id]
let specific_way_back_value = way_back_selector_default_value
if(!!specific_time_back){
specific_way_back_value = specific_time_back
}
let specific_way_back_ele = document.createElement("div")
let specific_way_back_ele_id = gen_date_selector_id()
let specific_way_back_btn_id = gen_date_selector_confirm_btn_id()
specific_way_back_ele.innerHTML =
"<input id='"+ specific_way_back_ele_id + "' type='datetime-local' value='" + specific_way_back_value +"' />" +
"<button id='"+ specific_way_back_btn_id +"'>确认更改到这个日期</button>"
banner.appendChild(specific_way_back_ele)
let specific_selector = document.getElementById(specific_way_back_ele_id)
let specific_btn = document.getElementById(specific_way_back_btn_id)
specific_btn.addEventListener("click", function () {
window.localStorage[specific_way_back_id] = specific_selector.value
alert("设置完成")
update_panel()
})
banner.appendChild(specific_way_back_ele)
}
}
}
return panel_section
}
function update_left_section() {
let liver_list = window.localStorage[COOKIE_LIVER_LIST]
if (liver_list == null){
return null
}
let livers = liver_list.split(SPLIT_WORD)
let gen_info_bundle = new Map()
let time_now = new Date()
for(let i = 0 ; i < livers.length ; i++)
{
let rawData = window.localStorage[gen_liver_storage_id(livers[i])]
if(rawData == null){
continue
}
let rawJson = JSON.parse(rawData)
let ava_url = rawJson.liver_avatar_url
let way_back_video = null
let way_back_time_start = null
let way_back_time_end = null
let back_day = getCookie(COOKIE_WAY_BACK_DAY)
let back_hour = getCookie(COOKIE_WAY_BACK_HOUR)
let back_minute = getCookie(COOKIE_WAY_BACK_MINUTE)
let nearest_next_video = null
let nearest_time = null
let nearest_real_time = null
let fake_liver_name = rawJson.liver_name
// specific way back
let specific_way_back_id = gen_streamer_specific_way_back_id(livers[i])
let specific_time_back = window.localStorage[specific_way_back_id]
if(!!specific_time_back){
specific_time_back = gen_dateSelectorValue2date(specific_time_back)
let diff = time_now - specific_time_back
let diff_s = Math.floor((time_now - specific_time_back) / 1000)
let diff_minutes = Math.floor(diff_s % 3600 / 60)
let diff_hours = Math.floor(diff_s % (3600 * 24) / 3600)
let diff_days = Math.floor(diff_s / (3600 * 24))
back_day = diff_days
back_hour = diff_hours
back_minute = diff_minutes
}
// way back day
if(back_day === ""){
back_day = 0
}else{
back_day = Number(back_day)
}
// way back hour
if(back_hour === ""){
back_hour = 0
}else{
back_hour = Number(back_hour)
}
// way back minute
if(back_minute === ""){
back_minute = 0
}else{
back_minute = Number(back_minute)
}
for(let j = 0 ; j < rawJson.video_list.length ; j++){
let publish_year = rawJson.video_list[j].video_publish_year
let publish_month = rawJson.video_list[j].video_publish_month
let publish_day = rawJson.video_list[j].video_publish_day
let publish_hour = rawJson.video_list[j].video_publish_hour
let video_length = rawJson.video_list[j].video_length
video_length = video_length.split(':')
// setFullYear这个月份设置...
// real start / end
let real_live_start_time = new Date()
real_live_start_time.setFullYear(Number(publish_year), Number(publish_month) - 1, Number(publish_day))
real_live_start_time.setHours(Number(publish_hour), 0, 0)
let real_live_end_time = new Date()
real_live_end_time.setFullYear(Number(publish_year), Number(publish_month) - 1, Number(publish_day))
if (video_length.length >= 3){
real_live_end_time.setHours(Number(publish_hour) + Number(video_length[0]), Number(video_length[1]), Number(video_length[2]))
}else{
real_live_end_time.setHours(Number(publish_hour), Number(video_length[0]), Number(video_length[1]))
}
// start time
let live_start_time = new Date()
live_start_time.setFullYear(Number(publish_year), Number(publish_month) - 1, Number(publish_day) + back_day)
live_start_time.setHours(Number(publish_hour) + back_hour, back_minute, 0)
// end time
let live_end_time = new Date()
live_end_time.setFullYear(Number(publish_year), Number(publish_month) - 1, Number(publish_day) + back_day)
if (video_length.length >= 3){
live_end_time.setHours(Number(publish_hour) + Number(video_length[0]) + back_hour, Number(video_length[1]) + back_minute, Number(video_length[2]))
}else{
live_end_time.setHours(Number(publish_hour) + back_hour, Number(video_length[0]) + back_minute, Number(video_length[1]))
}
// time now
if(time_now < live_start_time){
if(nearest_time == null || live_start_time < nearest_time){
nearest_next_video = rawJson.video_list[j]
nearest_time = live_start_time
nearest_real_time = real_live_start_time
}
continue
}
if(time_now >= live_start_time && time_now <= live_end_time){
let desc = []
desc[0] = ` ${fake_liver_name} 正在直播: ${rawJson.video_list[j].video_title}`
if(get_show_more_state()){
desc[1] = `直播开始时间: ${live_start_time}`
desc[2] = `[原始时间 ${real_live_start_time}]`
desc[3] = `页面加载时间: ${time_now}`
desc[4] = `[原始时间 ${new Date(time_now.getTime() - live_start_time.getTime() + real_live_start_time.getTime())}]`
desc[5] = `直播结束时间: ${live_end_time}`
desc[6] = `[原始时间 ${real_live_end_time}]`
}else{
desc[1] = `直播开始时间: ${live_start_time}`
desc[2] = `页面加载时间: ${time_now}`
desc[3] = `直播结束时间: ${live_end_time}`
}
log_sep()
for(let k = 0 ; k < desc.length ; k++)
console.log(desc[k])
log_sep()
gen_info_bundle.set(fake_liver_name, desc)
way_back_video = rawJson.video_list[j]
way_back_time_start = live_start_time
way_back_time_end = live_end_time
break
}
}
if (way_back_video == null){
let desc = []
desc[0] = `${fake_liver_name} 未直播`
if(nearest_next_video != null && nearest_time != null){
desc[1] = `${fake_liver_name} 的下一次直播消息: `
desc[2] = `标题: ${nearest_next_video.video_title}`
if(get_show_more_state()){
desc[3] = `直播开始时间: ${nearest_time}`
desc[4] = `[原始时间 ${nearest_real_time}]`
}else{
desc[3] = `直播开始时间: ${nearest_time}`
}
}else{
desc[1] = `${fake_liver_name} 的所有直播已经推送完毕`
}
log_sep()
for(let k = 0 ; k < desc.length ; k++)
console.log(desc[k])
log_sep()
gen_info_bundle.set(fake_liver_name, desc)
continue
}
let fake_live_title = way_back_video.video_title
let fake_live_url = way_back_video.video_url
add_left_section_streamer(fake_liver_name, fake_live_title, "https://" + fake_live_url, ava_url, way_back_time_start, way_back_time_end)
}
return gen_info_bundle
}
function add_live_info_into_panel(panel, info){
let banner = panel.firstElementChild
if(banner == null || info == null ||info.keys() == null){
console.log("参数错误")
return
}
// title
let title = document.createElement("div")
let title_text = document.createTextNode("直播相关信息")
title.style.setProperty("font-size", FIRST_TITLE_DEFAULT_FONT_SIZE)
title.appendChild(title_text)
banner.appendChild(title)
// extra settings
let show_more_btn = document.createElement("button")
show_more_btn.appendChild(document.createTextNode("显示/隐藏更多信息"))
show_more_btn.addEventListener("click", function () {
if(get_show_more_state()){
set_show_more_state(true)
}else{
set_show_more_state(false)
}
update_panel()
})
banner.appendChild(show_more_btn)
// blank
banner.appendChild(document.createElement("p"))
// info
let keys = info.keys()
for(let key = keys.next().value ; key != null ; key = keys.next().value){
// sub title
let sub_title = document.createElement("div")
let sub_title_node = document.createTextNode(key)
sub_title.appendChild(sub_title_node)
sub_title.style.setProperty("color", "rgb(251, 114, 153)")
banner.appendChild(sub_title)
// info
let desc = info.get(key)
if(desc.length == null){
console.log("参数错误")
return
}
for(let j = 0 ; j < desc.length ; j++){
let info_ele = document.createElement("p")
let info_node = document.createTextNode(desc[j])
info_ele.appendChild(info_node)
banner.appendChild(info_ele)
}
// blank
banner.appendChild(document.createElement("p"))
}
return panel
}
// 实际上我觉得可以把每个按钮监听器另外封装,然后把这个更新面板的函数做成每个监听器后面的一个钩子(然而还是懒
function update_panel() {
// remove old panel
let panel_sections = document.getElementsByClassName("right")[0]
let old_panel = document.getElementById(SECTION_ID)
if(!panel_sections || !old_panel){
console.log("panel not found")
return
}
panel_sections.removeChild(old_panel)
// remove old dyn items
let dyn_body = document.getElementsByClassName("bili-dyn-live-users__body")[0]
if(!dyn_body){
console.log("dyn body not found")
return
}
for(let i = 0 ; i < left_streamer_item_count ; i++){
let old_item = document.getElementById(gen_left_streamer_item_id_manual(i))
if(!old_item){
break
}
dyn_body.removeChild(old_item)
}
left_streamer_item_count = 0
// create new panel
let new_panel = create_panel()
add_new_setting(null, null, new_panel)
let live_info = update_left_section()
add_live_info_into_panel(new_panel, live_info)
new_panel.setAttribute("style", "display: flex;")
}
let page_loaded = false
function sleep_and_check(){
sleep(300).then( async () => {
page_loaded = document.getElementsByClassName("bili-dyn-live-users__body")[0] != null
if(page_loaded)
sleep_and_exec()
else
sleep_and_check()
})
}
function sleep_and_exec(){
sleep(50).then( async () => {
let panel = create_panel()
add_new_setting(null, null, panel)
let live_info = update_left_section()
add_live_info_into_panel(panel, live_info)
})
}
// main
sleep_and_check()
})();