Greasy Fork is available in English.

b站直播间房管辅助直播 bilibili 哔哩哔哩

try to take over the world!

Od 14.02.2021.. Pogledajte najnovija verzija.

// ==UserScript==
// @name         b站直播间房管辅助直播 bilibili 哔哩哔哩
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  try to take over the world!
// @author       You
// @match        *://live.bilibili.com/*
// @exclude      *://live.bilibili.com/p/*
// @grant        none
// ==/UserScript==

(function() {
    const hour = '1'

    function zfill(num, n) {
        return (Array(n).join(0) + num).slice(-n);
    }
    class BasicAction{
        static fontButtonOver(){this.style.color = '#23ade5'}
        static fontButtonOut(){this.style.color = '#333'}

    }
    class FileUtils{
        static saveFile(filename,data){
            var urlObject = window.URL 
            var export_blob = new Blob([data],{type:'text/csv'});
            var save_link = document.createElement('a')
            save_link.href = urlObject.createObjectURL(export_blob);
            save_link.download = filename;
            save_link.click()
        } 
    }
    
    class Ajax{
        static post(url,data={},head={},callback=()=>{},credentials=true){
            const xhr = new XMLHttpRequest()
            xhr.open('POST',url)
            let urlData = new Array()
            for(let d in data){urlData.push(d+'='+data[d])}
            const urlParams = urlData.join('&')

            for(let h in head){xhr.setRequestHeader(h,head[h])}
            xhr.withCredentials = credentials
            xhr.send(urlParams)
            xhr.onreadystatechange = function(){
                callback(xhr)
            }
        }
    }
    class Dialog{
        static wholeScreen(child,height= '200px',width='200px',top='0px',left='0px'){
            const background = document.createElement('div')
            background.style = 'top:0px;left:0px;z-index:9999;position: fixed; background-color: rgba(0, 0, 0, 0.5); display: flex; flex-flow: column nowrap; justify-content: start; align-items: center; height: 100%; width: 100%;'
            background.onclick = function(){
                this.parentElement.removeChild(this)
            }
            let dialog = child
            if(!child){
                dialog = document.createElement('div')                        
                dialog.style.backgroundColor = 'white'
                dialog.style.borderRadius = '5px'
                dialog.style.height = height
                dialog.style.width = width           
                dialog.style.top = top
                dialog.style.left = left
            }    


            
            dialog.onclick = function (e){
                e.stopPropagation()
            }
            background.appendChild(dialog)
            document.body.appendChild(background)
            return {background,dialog}
        }
    }
    class AdminConsole{
        constructor(){
            this.injectStyle()
            this.initConsole()
        }
        injectStyle(){
            let style = ''
            style += '.mana-fontbutton{cursor: pointer;margin-left: 4px;}'
            style += '.mana-logbox { top: 200px; position: relative; display: flex; flex-flow: column nowrap; justify-content: start; align-items: center; padding: 20px 20px 20px 20px; background-color: white; border-radius: 5px; overflow: auto; width: 300px; height: 600px; }'
            style += '.mana-logline{ border-bottom: 1px solid #e5e5e5; margin: 3px 0px 3px 0px; }'

            const styleDOM = document.createElement('style')
            styleDOM.innerHTML = style            
            styleDOM.setAttribute('mana-style','')
            document.body.appendChild(styleDOM)
        }
        initConsole(){
            const injectConsole = () =>{
                const menu = document.getElementsByClassName('admin-drop-ctnr')[0]
                if(menu){
                    const openLog = document.createElement('p')
                    openLog.className = 'drop-menu-item ts-dot-4'
                    openLog.innerText = '一键禁言记录'
                    openLog.style = 'white-space: nowrap;font-size: 12px;color: #333;line-height: 19px;margin: 0 0 8px;'
                    openLog.onmouseover = BasicAction.fontButtonOver
                    openLog.onmouseout = BasicAction.fontButtonOut
                    openLog.onclick = this.openLog
                    menu.appendChild(openLog)
                    return
                }
                requestAnimationFrame(injectConsole)
            }
            injectConsole()
        }
        openLog = () => {
            let logFile = new Array()
            for(let key in localStorage){
                if(key.startsWith('blockLog-')){
                    logFile.push(key)
                }
            }
            logFile.sort()
            if(logFile.length > 0){
                let box = document.createElement('div')
                box.className = 'mana-logbox'
                for(let file of logFile){
                    const line = document.createElement('div')
                    const title = document.createElement('span')
                    title.innerText = file
                    line.setAttribute('log',file)
                    line.className = 'mana-logline'
                    title.style.minWidth = '200px'
                    title.style.display = 'inline-block'
                    line.appendChild(title)

                    const del = document.createElement('span')
                    del.innerText = '删除'
                    del.onclick = this.deleteLog
                    del.onmouseover = BasicAction.fontButtonOver
                    del.onmouseout = BasicAction.fontButtonOut      
                    del.className = 'mana-fontbutton' 
                                 
                    
                    const dowl = document.createElement('span') 
                    dowl.innerText = '下载'
                    dowl.onclick = this.downloadLog
                    dowl.onmouseover = BasicAction.fontButtonOver
                    dowl.onmouseout = BasicAction.fontButtonOut
                    dowl.className = 'mana-fontbutton'

                    line.appendChild(del)
                    line.appendChild(dowl)
                    box.appendChild(line)
                    
                }
                const d = Dialog.wholeScreen(box)

            }
        }
        downloadLog(e){
            try{
                const logName = e.target.parentElement.getAttribute('log')
                const log = localStorage.getItem(logName)
                FileUtils.saveFile(logName+'.csv',log)
            }catch(e){console.log('导出日志异常')}
        }
        deleteLog(e){
            try{
                const logName = e.target.parentElement.getAttribute('log')
                if(confirm(`是否要删除日志: ${logName} ?`)){
                    localStorage.removeItem(logName)
                    const container = e.target.parentElement.parentElement
                    for(let line of container.children){
                        if(line.getAttribute('log') === logName){
                            container.removeChild(line)
                        }
                    }
                }

            }catch(e){console.log('删除日志异常')}
        }

    }
    
    class Blocker{
        constructor(){
            this.bindMutation()
        }
        bindMutation(){
            const observation = (mutations,observer) =>{
                for(let mutation of mutations){
                    if(mutation.addedNodes.length > 0){
                        for(let node of mutation.addedNodes){
                            if(node.hasAttribute('data-uid')){
                                const deleteButton = document.createElement('span')
                                deleteButton.innerText = '禁言'
                                deleteButton.className = 'v-middle'
                                deleteButton.onclick = this.addBlockUser
                                deleteButton.style = 'color:#23ade5;cursor:pointer;line-height:20px'
                                node.insertBefore(deleteButton,node.children[0])

                            }
                        }
                    }
                }
            }
            this.chatList =  document.getElementById('chat-items')
            const config = {childList:true}
            const observer = new MutationObserver(observation)
            observer.observe(this.chatList,config)
        }
        removeBlockUser  (dom,data,logTitle,uid,uname)  {
            const head = {
                'accept': 'application/json, text/plain, */*',
                'content-type': 'application/x-www-form-urlencoded'
            }
            Ajax.post('//api.live.bilibili.com/banned_service/v1/Silent/del_room_block_user',data,head,(xhr)=>{
                        if(xhr.readyState == 4 && xhr.status == 200 ){
                            const res = JSON.parse(xhr.responseText)
                            if(res.code == 0){
                                let log = window.localStorage.getItem(logTitle) || ''
                                const date = new Date()
                                log += `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()},${uid},${uname},撤销禁言\n`                                        
                                window.localStorage.setItem(logTitle,log)

                                dom.innerText = '禁言'
                                dom.onclick = this.addBlockUser
                            }
                        }
                    })
        }
        addBlockUser = (e) =>{
            const container = e.target.parentElement
            const uid = container.getAttribute('data-uid')
            const uname = container.getAttribute('data-uname')
            const danmaku = container.getAttribute('data-danmaku')
            const date = new Date()
            const block_uid = uid || '1'
            const logTitle = `blockLog-${date.getFullYear()}-${zfill(date.getMonth()+1,2)}-${zfill(date.getDate(),2)}`
            
            const cookie = new WebCookie()
            const data = {
                roomid:cookie.roomid || '1',
                block_uid,
                hour,
                csrf_token: cookie.bili_jct || '1',
                csrf: cookie.bili_jct || '1',
                visit_id:""
            }
            const head = {
                'accept': 'application/json, text/plain, */*',
                'content-type': 'application/x-www-form-urlencoded'
            }
            Ajax.post('//api.live.bilibili.com/banned_service/v2/Silent/add_block_user',data,head,(xhr)=>{
                if(xhr.readyState == 4 && xhr.status == 200 ){
                    const res = JSON.parse(xhr.responseText)
                    if(res.code == 0){
                        const id = res.data.id
                        let log = window.localStorage.getItem(logTitle) || ''
                        log += `${zfill(date.getHours(),2)}:${zfill(date.getMinutes(),2)}:${zfill(date.getSeconds(),2)},${uid},${uname},${danmaku}\n`
                        window.localStorage.setItem(logTitle,log)
                        const button = container.children[0]
                        button.innerText = '撤销'
                        const data = {
                            id,
                            roomid:cookie.roomid || '1',
                            csrf_token: cookie.bili_jct || '1',
                            csrf: cookie.bili_jct || '1',
                            visit_id:""
                        }
                        button.onclick = () =>{
                            this.removeBlockUser.call(this,button,data,logTitle,uid,uname)
                        }
                    }
                }
            })
        }
    }

    class WebCookie{
        constructor(){
            const cookies = {}
            for(let cookie of document.cookie.split(';')){
                const [k,v] = cookie.trim().split('=')
                cookies[k] = v
            }
            cookies ['roomid'] = document.location.pathname.substr(1).split('?')[0]
            return cookies
        }
    }

    const adminConsole = new AdminConsole()
    const blocker = new Blocker()
    
})();