美文网首页
UP主小助手 使用说明

UP主小助手 使用说明

作者: 请叫我雯子小姐的小爷 | 来源:发表于2020-05-12 17:26 被阅读0次

最新版软件已经发布

示例图如下,有兴趣的小伙伴可以查看这个视频:
软件介绍视频:https://www.bilibili.com/video/BV1Jp4y1C73Y/
软件介绍视频(快闪版): https://www.bilibili.com/video/BV11A41187Ye/

软件下载

V1.21版紧急发布:4月28日晚,B站视频接口做了调整,v1.2版本仅能显示最新10个视频的数据,v1.21版本现在已经发布,此次更新为增量更新,只需下载补丁复制到程序所在的文件夹中进行替换即可

补丁下载:蓝奏云下载
完整版下载:蓝奏云下载

正式版v1.2:

  • 1、优化了评论管理模块的展示效果
  • 2、增加了弹幕管理模块
  • 3、增加了版本管理文件

正式版v1.1:

修复了v1.0版本中的一些bug

  • 1、修复了自2020-04-10晚开始的评论接口数据异常而导致的软件频繁提示重启问题;
  • 2、更改了软件重启机制,非主进程停止工作时不>会影响软件的运行;

正式版v1.0:[点击进入](https://www.toodo.fun/funs/softwares/?vod=%E5%93%94%E5%93%A9%E5%93%94%E5%93%A9UP%E4%B8%BB%E5%8A%A9%E6%89%8B(%E6%AD%A3%E5%BC%8F%E7%89%88v1.0)


半成品预览版:点击进入

程序源码

Github:https://github.com/MR5356/bilibili-up-helper


[图片上传失败...(image-9fc112-1589275555223)]


<span style="color:red">注意:以下为旧版应用信息,不适用上面的新版软件</span>


介绍视频:https://www.bilibili.com/video/BV1m7411o7k5/

软件下载

此软件为百度网盘分享
链接:https://pan.baidu.com/s/1ICc1D6mV0vELQrNANrnlqA
提取码:jssa

使用

首先,下载后将软件解压,并修改软件目录中的config.toml(可使用记事本打开修改):

[global]
refresh = 60 #刷新间隔(s)

[user]
cookies = true # 自动保存cookies,方便以后登录获取信息
account = """
username=你的账号;password=你的密码;
"""

然后双击运行软件即可,第一次登录会获取登录cookies并保存,可能较慢(3-5秒),此后运行将会优先使用cookies,打开就比较快了。

帮助与Bug 反馈

请扫描页面下方二维码,关注微信公众号后留言即可,我会在看到后第一时间给予回复。

支持此项目

由于本人实为理科生,艺术细胞不明显,导致界面并不符合各位的审美,如有好的UI方案或建议,可关注微信公众号后给我留言。万分感谢。

下面是源码(不要问我为什么不用GitHub~~~)

程序入口:main.py

import sys
import function
from PyQt5 import QtWidgets


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    ui = function.fun_main()
    ui.show()
    sys.exit(app.exec_())

软件UI:window.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'window.ui'
#
# Created by: PyQt5 UI code generator 5.13.2
#
# WARNING! All changes made in this file will be lost!


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(400, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.widget_main = QtWidgets.QWidget(self.centralwidget)
        self.widget_main.setAutoFillBackground(False)
        self.widget_main.setStyleSheet("QWidget#widget_main{border-image:url(:/images/2233.png);border:1px solid blank;border-radius:10px;}")
        self.widget_main.setObjectName("widget_main")
        self.level = QtWidgets.QLabel(self.widget_main)
        self.level.setGeometry(QtCore.QRect(170, 100, 81, 21))
        self.level.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.level.setText("")
        self.level.setObjectName("level")
        self.name_9 = QtWidgets.QLabel(self.widget_main)
        self.name_9.setGeometry(QtCore.QRect(260, 120, 61, 21))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.name_9.setFont(font)
        self.name_9.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.name_9.setObjectName("name_9")
        self.pushButton_min = QtWidgets.QPushButton(self.widget_main)
        self.pushButton_min.setGeometry(QtCore.QRect(330, 10, 21, 21))
        self.pushButton_min.setStyleSheet("QPushButton{background:Transparent;border-radius:5px;border:0px solid grey;}QPushButton:hover{background:CornflowerBlue;}")
        self.pushButton_min.setText("")
        self.pushButton_min.setObjectName("pushButton_min")
        self.name_4 = QtWidgets.QLabel(self.widget_main)
        self.name_4.setGeometry(QtCore.QRect(110, 120, 51, 21))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.name_4.setFont(font)
        self.name_4.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.name_4.setObjectName("name_4")
        self.pushButton_top = QtWidgets.QPushButton(self.widget_main)
        self.pushButton_top.setGeometry(QtCore.QRect(310, 10, 21, 21))
        self.pushButton_top.setStyleSheet("QPushButton{background:Transparent;border-radius:5px;border:0px solid grey;}QPushButton:hover{background:CornflowerBlue;}")
        self.pushButton_top.setText("")
        self.pushButton_top.setObjectName("pushButton_top")
        self.name_2 = QtWidgets.QLabel(self.widget_main)
        self.name_2.setGeometry(QtCore.QRect(260, 80, 41, 21))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.name_2.setFont(font)
        self.name_2.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.name_2.setObjectName("name_2")
        self.nameaaaa = QtWidgets.QLabel(self.widget_main)
        self.nameaaaa.setGeometry(QtCore.QRect(110, 40, 41, 21))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.nameaaaa.setFont(font)
        self.nameaaaa.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.nameaaaa.setObjectName("nameaaaa")
        self.video_info = QtWidgets.QTableView(self.widget_main)
        self.video_info.setGeometry(QtCore.QRect(10, 160, 361, 391))
        self.video_info.setStyleSheet("QTableView{background:Transparent;border-radius:8px;border:0px solid grey;padding:2px 4px}QTbaleView:hover{background:GhostWhite;}QHeaderView::section{background:Transparent;}")
        self.video_info.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.video_info.setShowGrid(False)
        self.video_info.setObjectName("video_info")
        self.sex = QtWidgets.QLabel(self.widget_main)
        self.sex.setGeometry(QtCore.QRect(300, 80, 71, 21))
        self.sex.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.sex.setText("")
        self.sex.setObjectName("sex")
        self.name = QtWidgets.QLabel(self.widget_main)
        self.name.setGeometry(QtCore.QRect(150, 40, 221, 21))
        self.name.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.name.setText("")
        self.name.setObjectName("name")
        self.likes = QtWidgets.QLabel(self.widget_main)
        self.likes.setGeometry(QtCore.QRect(320, 120, 51, 21))
        self.likes.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.likes.setText("")
        self.likes.setObjectName("likes")
        self.name_8 = QtWidgets.QLabel(self.widget_main)
        self.name_8.setGeometry(QtCore.QRect(260, 140, 61, 21))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.name_8.setFont(font)
        self.name_8.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.name_8.setObjectName("name_8")
        self.name_7 = QtWidgets.QLabel(self.widget_main)
        self.name_7.setGeometry(QtCore.QRect(110, 100, 61, 21))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.name_7.setFont(font)
        self.name_7.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.name_7.setObjectName("name_7")
        self.name_6 = QtWidgets.QLabel(self.widget_main)
        self.name_6.setGeometry(QtCore.QRect(110, 140, 61, 21))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.name_6.setFont(font)
        self.name_6.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.name_6.setObjectName("name_6")
        self.face = QtWidgets.QLabel(self.widget_main)
        self.face.setGeometry(QtCore.QRect(10, 40, 91, 91))
        self.face.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.face.setText("")
        self.face.setAlignment(QtCore.Qt.AlignCenter)
        self.face.setObjectName("face")
        self.sign = QtWidgets.QLabel(self.widget_main)
        self.sign.setGeometry(QtCore.QRect(150, 60, 221, 21))
        self.sign.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.sign.setText("")
        self.sign.setObjectName("sign")
        self.name_3 = QtWidgets.QLabel(self.widget_main)
        self.name_3.setGeometry(QtCore.QRect(110, 60, 41, 21))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.name_3.setFont(font)
        self.name_3.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.name_3.setObjectName("name_3")
        self.follower = QtWidgets.QLabel(self.widget_main)
        self.follower.setGeometry(QtCore.QRect(160, 120, 71, 21))
        self.follower.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.follower.setText("")
        self.follower.setObjectName("follower")
        self.pushButton_close = QtWidgets.QPushButton(self.widget_main)
        self.pushButton_close.setGeometry(QtCore.QRect(350, 10, 21, 21))
        self.pushButton_close.setStyleSheet("QPushButton{background:Transparent;border-radius:5px;border:0px solid grey;}QPushButton:hover{background:CornflowerBlue;}")
        self.pushButton_close.setText("")
        self.pushButton_close.setObjectName("pushButton_close")
        self.arc_v = QtWidgets.QLabel(self.widget_main)
        self.arc_v.setGeometry(QtCore.QRect(170, 140, 81, 21))
        self.arc_v.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.arc_v.setText("")
        self.arc_v.setObjectName("arc_v")
        self.art_v = QtWidgets.QLabel(self.widget_main)
        self.art_v.setGeometry(QtCore.QRect(320, 140, 51, 21))
        self.art_v.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.art_v.setText("")
        self.art_v.setObjectName("art_v")
        self.pushButton_help = QtWidgets.QPushButton(self.widget_main)
        self.pushButton_help.setGeometry(QtCore.QRect(250, 10, 41, 23))
        self.pushButton_help.setStyleSheet("QPushButton{background:Transparent;border-radius:5px;border:0px solid grey;}QPushButton:hover{background:CornflowerBlue;}")
        self.pushButton_help.setObjectName("pushButton_help")
        self.count = QtWidgets.QLabel(self.widget_main)
        self.count.setGeometry(QtCore.QRect(10, 10, 181, 21))
        font = QtGui.QFont()
        font.setBold(False)
        font.setWeight(50)
        self.count.setFont(font)
        self.count.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.count.setText("")
        self.count.setObjectName("count")
        self.nameaaaa_2 = QtWidgets.QLabel(self.widget_main)
        self.nameaaaa_2.setGeometry(QtCore.QRect(260, 100, 61, 21))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.nameaaaa_2.setFont(font)
        self.nameaaaa_2.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.nameaaaa_2.setObjectName("nameaaaa_2")
        self.ban = QtWidgets.QLabel(self.widget_main)
        self.ban.setGeometry(QtCore.QRect(320, 100, 51, 21))
        self.ban.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.ban.setText("")
        self.ban.setObjectName("ban")
        self.name_10 = QtWidgets.QLabel(self.widget_main)
        self.name_10.setGeometry(QtCore.QRect(10, 140, 41, 21))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.name_10.setFont(font)
        self.name_10.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.name_10.setObjectName("name_10")
        self.name_11 = QtWidgets.QLabel(self.widget_main)
        self.name_11.setGeometry(QtCore.QRect(110, 80, 31, 21))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.name_11.setFont(font)
        self.name_11.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.name_11.setObjectName("name_11")
        self.coins = QtWidgets.QLabel(self.widget_main)
        self.coins.setGeometry(QtCore.QRect(50, 140, 61, 21))
        self.coins.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.coins.setText("")
        self.coins.setObjectName("coins")
        self.birthday = QtWidgets.QLabel(self.widget_main)
        self.birthday.setGeometry(QtCore.QRect(150, 80, 91, 21))
        self.birthday.setStyleSheet("QLabel{background:Transparent;border-radius:5px;border:0px solid grey;}")
        self.birthday.setText("")
        self.birthday.setObjectName("birthday")
        self.pushButton_home = QtWidgets.QPushButton(self.widget_main)
        self.pushButton_home.setGeometry(QtCore.QRect(200, 10, 51, 23))
        self.pushButton_home.setStyleSheet("QPushButton{background:Transparent;border-radius:5px;border:0px solid grey;}QPushButton:hover{background:CornflowerBlue;}")
        self.pushButton_home.setObjectName("pushButton_home")
        self.gridLayout.addWidget(self.widget_main, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 400, 23))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "UP主小助手"))
        self.name_9.setText(_translate("MainWindow", "收到的赞:"))
        self.name_4.setText(_translate("MainWindow", "粉丝数:"))
        self.name_2.setText(_translate("MainWindow", "性别:"))
        self.nameaaaa.setText(_translate("MainWindow", "昵称:"))
        self.name_8.setText(_translate("MainWindow", "文章查看:"))
        self.name_7.setText(_translate("MainWindow", "会员等级:"))
        self.name_6.setText(_translate("MainWindow", "视频播放:"))
        self.name_3.setText(_translate("MainWindow", "签名:"))
        self.pushButton_help.setText(_translate("MainWindow", "帮助"))
        self.nameaaaa_2.setText(_translate("MainWindow", "账号状态:"))
        self.name_10.setText(_translate("MainWindow", "硬币:"))
        self.name_11.setText(_translate("MainWindow", "生日:"))
        self.pushButton_home.setText(_translate("MainWindow", "个人主页"))
import resources_rc

程序逻辑:function.py

import requests
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtGui import QImage, QPixmap, QStandardItem, QStandardItemModel, QIcon, QPalette, QBrush
from PyQt5.QtWidgets import QMessageBox, QTableView, QHeaderView, QAbstractItemView
from window import Ui_MainWindow
import qtawesome
import time
import resources_rc
import api_v2


class fun_main(Ui_MainWindow, QtWidgets.QMainWindow):
    def __init__(self):
        super(fun_main, self).__init__()
        self.main_thread()
        self.isTop = 0
        self.setupUi(self)
        self.set_icon()
        self.set_location()
        self.signal_on_button()
        self.setWindowOpacity(0.9)  # 设置窗口透明度
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)  ##主窗口透明
        self.setWindowFlag(QtCore.Qt.FramelessWindowHint)  ##隐藏边框
        self.setWindowFlag(QtCore.Qt.WindowStaysOnTopHint)  ##窗口始终置顶
        self.setWindowIcon(QIcon(':/images/logo.ico'))



    def set_icon(self):
        self.pushButton_close.setIcon(qtawesome.icon('fa.close', color='blank'))
        self.pushButton_min.setIcon(qtawesome.icon('fa.window-minimize', color='blank'))
        self.pushButton_top.setIcon(qtawesome.icon('fa.thumb-tack', color='blank'))

    def set_location(self):  # 屏幕右上角
        desktop = QtWidgets.QApplication.desktop()
        x = (desktop.width() - self.width())
        y = (desktop.height() - self.height())-10
        self.move(x, y)

    def signal_on_button(self):
        # 主界面转换按钮
        self.pushButton_close.clicked.connect(self.close_win)
        self.pushButton_min.clicked.connect(self.showMinimized)
        self.pushButton_top.clicked.connect(self.window_Top)
        self.pushButton_help.clicked.connect(lambda: self.open_browser("https://www.toodo.fun/funs/learn/files/article.php?id=58&title=UP%E4%B8%BB%E5%B0%8F%E5%8A%A9%E6%89%8B%20%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E"))
        self.pushButton_home.clicked.connect(lambda: self.open_browser(f"https://space.bilibili.com/{self.msm['mid']}"))
        self.video_info.clicked.connect(self.video_clicked)


    def close_win(self):
        res = QMessageBox.question(self, '是否关闭小助手', '是否确认退出小助手', QMessageBox.Yes | QMessageBox.No,
                                   QMessageBox.No)
        if res == QMessageBox.Yes:
            self.close()
        else:
            pass

    def window_Top(self):
        QMessageBox.information(self, '小助手提示', '当前UP主小助手仅支持置顶模式')

    def open_browser(self, url):
        QtGui.QDesktopServices.openUrl(QtCore.QUrl(url))

    def main_thread(self):
        try:
            self.main_Thread.stop()
            print("已经停止")
        except:
            pass
        try:
            # mid = self.mid.text()
            self.main_Thread = Main_Thread()
            self.main_Thread.display_signal.connect(self.change_UI)
            self.main_Thread.start()
        except:
            QMessageBox.information(self, '小助手提示', '程序运行异常,请确定网络连接是否正常,然后尝试重启客户端,如问题还未解决,请点击帮助按钮留言')

    def change_UI(self, msm):
        self.msm = msm
        if msm.get('error') == 1:
            res = QMessageBox.question(self, '小助手提示', '配置文件"config.toml"不存在或者配置不正确,如有疑问请查看帮助', QMessageBox.Yes | QMessageBox.No,
                                       QMessageBox.No)
            if res == QMessageBox.Yes:
                self.open_browser(
                    "https://www.toodo.fun/funs/learn/files/article.php?id=58&title=UP%E4%B8%BB%E5%B0%8F%E5%8A%A9%E6%89%8B%20%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E")
                self.close()
            else:
                self.open_browser(
                    "https://www.toodo.fun/funs/learn/files/article.php?id=58&title=UP%E4%B8%BB%E5%B0%8F%E5%8A%A9%E6%89%8B%20%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E")
                self.close()
            return
        self.name.setText(msm['nickname'])
        self.sex.setText(msm['sex'])
        try:
            img = QImage.fromData(requests.get(msm['face']).content)
        except:
            img = QImage.fromData(requests.get("http://bpic.588ku.com/element_pic/01/47/72/305743feac8f672.jpg").content)
        self.face.setPixmap(QPixmap.fromImage(img))
        self.face.setScaledContents(True)
        self.sign.setText(str(msm['sign']))
        self.level.setText(f"{msm['level']}({msm['experience']['current']}/{msm['experience']['next']})")
        self.arc_v.setText(str(msm['arc_view']))
        self.art_v.setText(str(msm['art_view']))
        self.likes.setText(str(msm['likes']))
        self.follower.setText(str(msm['follower']))
        self.count.setText(time.strftime("%Y-%m-%d", time.localtime(time.time())) + " 已刷新"+str(msm['count'])+"次,等待" + str(msm['refresh']) + "秒" )
        self.coins.setText(str(msm['coins']))
        if msm['ban'] == 0:
            self.ban.setText("正常")
        else:
            self.ban.setText("封禁")
        self.birthday.setText(time.strftime("%Y-%m-%d", time.localtime(msm['birthday'])))
        self.model = QStandardItemModel(len(msm['videos']), 4)
        self.model.clear()
        self.model.setHorizontalHeaderLabels(['发布时间', '视频标题', '评论', '播放次数'])
        for row in range(len(msm['videos'])):
            for column in range(4):
                item = QStandardItem(str(msm['videos'][row][column]))
                self.model.setItem(row, column, item)
        self.video_info.setModel(self.model)
        self.video_info.setEditTriggers(QTableView.NoEditTriggers)
        self.video_info.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.video_info.setSelectionMode(QAbstractItemView.SingleSelection)
        self.video_info.horizontalHeader().setVisible(False)
        self.video_info.verticalHeader().setVisible(False)


    def video_clicked(self):
        num = self.video_info.currentIndex().row()
        self.open_browser(f"https://www.bilibili.com/video/av{self.msm['videos'][num][4]}/")


class Main_Thread(QThread):
    display_signal = pyqtSignal(dict)
    def __init__(self):
        super().__init__()
        self.flag = 1

    def run(self):
        num = 0
        while self.flag == 1:
            try:
                msms = api_v2.main()
                num += 1
                msms['count'] = num
                self.display_signal.emit(msms)
                st = int(msms['refresh'])
                time.sleep(st)
            except:
                msms = {"error": 1, "mid": 0}
                self.display_signal.emit(msms)
                time.sleep(1e5)

    def stop(self):
        self.flag = 0

api接口:api_v2.py(登录逻辑借鉴Bilibili-Tookit)

# -*- coding: utf-8 -*-
import base64
import chardet
import hashlib
import requests
import rsa
import sys
import time
import toml
import random
from urllib import parse


class Bilibili:
    app_key = "1d8b6e7d45233436"

    def __init__(self, https=True):
        self._session = requests.Session()
        self._session.headers.update({'User-Agent': "Mozilla/5.0 BiliDroid/5.51.1 (bbcallen@gmail.com)"})
        self.get_cookies = lambda: self._session.cookies.get_dict(domain=".bilibili.com")
        self.get_csrf = lambda: self.get_cookies().get("bili_jct", "")
        self.get_sid = lambda: self.get_cookies().get("sid", "")
        self.get_uid = lambda: self.get_cookies().get("DedeUserID", "")
        self.access_token = ""
        self.refresh_token = ""
        self.username = ""
        self.password = ""
        self.info = {
            'ban': False,
            'coins': 0,
            'experience': {
                'current': 0,
                'next': 0,
            },
            'face': "",
            'level': 0,
            'nickname': "",
            'mid': "",
            'sign': "",
            'follower': 0,
            'following': 0,
            'birthday': 0,
            'sex': "",
            'arc_view': 0,
            'art_view': 0,
            'likes': 0,
            'videos': [],
        }
        self.protocol = "https" if https else "http"

    def _log(self, message):
        log = f"[{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))}][{self.username if self.username else '#' + self.get_uid() if self.get_uid() else ''}] {message}"
        print(log)

    def _requests(self, method, url, decode_level=2, retry=10, timeout=15, **kwargs):
        if method in ["get", "post"]:
            for _ in range(retry + 1):
                try:
                    response = getattr(self._session, method)(url, timeout=timeout, **kwargs)
                    return response.json() if decode_level == 2 else response.content if decode_level == 1 else response
                except:
                    pass
        return None

    # 验证码识别
    def _solve_captcha(self, image):
        url = "https://bili.dev:2233/captcha"
        payload = {'image': base64.b64encode(image).decode("utf-8")}
        response = self._requests("post", url, json=payload)
        return response['message'] if response and response.get("code") == 0 else None

    @staticmethod
    def calc_sign(param):
        salt = "560c52ccd288fed045859ed18bffd973"
        sign_hash = hashlib.md5()
        sign_hash.update(f"{param}{salt}".encode())
        return sign_hash.hexdigest()

    # 登录
    def login(self, **kwargs):
        def by_cookie():
            url = f"{self.protocol}://api.bilibili.com/x/space/myinfo"
            headers = {'Host': "api.bilibili.com"}
            response = self._requests("get", url, headers=headers)
            if response and response.get("code") != -101:
                return True
            else:
                return False

        def by_token(force_refresh=False):
            if not force_refresh:
                param = f"access_key={self.access_token}&appkey={Bilibili.app_key}&ts={int(time.time())}"
                print(param)
                url = f"{self.protocol}://passport.bilibili.com/api/v2/oauth2/info?{param}&sign={self.calc_sign(param)}"
                response = self._requests("get", url)
                if response and response.get("code") == 0:
                    self._session.cookies.set('DedeUserID', str(response['data']['mid']), domain=".bilibili.com")
                    param = f"access_key={self.access_token}&appkey={Bilibili.app_key}&gourl={self.protocol}%3A%2F%2Faccount.bilibili.com%2Faccount%2Fhome&ts={int(time.time())}"
                    url = f"{self.protocol}://passport.bilibili.com/api/login/sso?{param}&sign={self.calc_sign(param)}"
                    self._requests("get", url, decode_level=0)
                    if all(key in self.get_cookies() for key in
                           ["bili_jct", "DedeUserID", "DedeUserID__ckMd5", "sid", "SESSDATA"]):
                        return True
                    else:
                        pass
            url = f"{self.protocol}://passport.bilibili.com/api/v2/oauth2/refresh_token"
            param = f"access_key={self.access_token}&appkey={Bilibili.app_key}&refresh_token={self.refresh_token}&ts={int(time.time())}"
            payload = f"{param}&sign={self.calc_sign(param)}"
            headers = {'Content-type': "application/x-www-form-urlencoded"}
            response = self._requests("post", url, data=payload, headers=headers)
            if response and response.get("code") == 0:
                for cookie in response['data']['cookie_info']['cookies']:
                    self._session.cookies.set(cookie['name'], cookie['value'], domain=".bilibili.com")
                self.access_token = response['data']['token_info']['access_token']
                self.refresh_token = response['data']['token_info']['refresh_token']
                return True
            else:
                self.access_token = ""
                self.refresh_token = ""
                return False

        def by_password():
            def get_key():
                url = f"{self.protocol}://passport.bilibili.com/api/oauth2/getKey"
                payload = {
                    'appkey': Bilibili.app_key,
                    'sign': self.calc_sign(f"appkey={Bilibili.app_key}"),
                }
                while True:
                    response = self._requests("post", url, data=payload)
                    if response and response.get("code") == 0:
                        return {
                            'key_hash': response['data']['hash'],
                            'pub_key': rsa.PublicKey.load_pkcs1_openssl_pem(response['data']['key'].encode()),
                        }
                    else:
                        time.sleep(1)

            while True:
                key = get_key()
                key_hash, pub_key = key['key_hash'], key['pub_key']
                url = f"{self.protocol}://passport.bilibili.com/api/v2/oauth2/login"
                param = f"appkey={Bilibili.app_key}&password={parse.quote_plus(base64.b64encode(rsa.encrypt(f'{key_hash}{self.password}'.encode(), pub_key)))}&username={parse.quote_plus(self.username)}"
                payload = f"{param}&sign={self.calc_sign(param)}"
                headers = {'Content-type': "application/x-www-form-urlencoded"}
                response = self._requests("post", url, data=payload, headers=headers)
                while True:
                    if response and response.get("code") is not None:
                        if response['code'] == -105:
                            url = f"{self.protocol}://passport.bilibili.com/captcha"
                            headers = {'Host': "passport.bilibili.com"}
                            response = self._requests("get", url, headers=headers, decode_level=1)
                            captcha = self._solve_captcha(response)
                            if captcha:
                                key = get_key()
                                key_hash, pub_key = key['key_hash'], key['pub_key']
                                url = f"{self.protocol}://passport.bilibili.com/api/v2/oauth2/login"
                                param = f"appkey={Bilibili.app_key}&captcha={captcha}&password={parse.quote_plus(base64.b64encode(rsa.encrypt(f'{key_hash}{self.password}'.encode(), pub_key)))}&username={parse.quote_plus(self.username)}"
                                payload = f"{param}&sign={self.calc_sign(param)}"
                                headers = {'Content-type': "application/x-www-form-urlencoded"}
                                response = self._requests("post", url, data=payload, headers=headers)
                            else:
                                time.sleep(10)

                        elif response['code'] == -449:
                            time.sleep(1)
                            response = self._requests("post", url, data=payload, headers=headers)
                        elif response['code'] == 0 and response['data']['status'] == 0:
                            for cookie in response['data']['cookie_info']['cookies']:
                                self._session.cookies.set(cookie['name'], cookie['value'], domain=".bilibili.com")
                            self.access_token = response['data']['token_info']['access_token']
                            self.refresh_token = response['data']['token_info']['refresh_token']
                            return True
                        else:
                            return False
                    else:
                        time.sleep(60)

        self._session.cookies.clear()
        for name in ["bili_jct", "DedeUserID", "DedeUserID__ckMd5", "sid", "SESSDATA"]:
            value = kwargs.get(name)
            if value:
                self._session.cookies.set(name, value, domain=".bilibili.com")
        self.access_token = kwargs.get("access_token", "")
        self.refresh_token = kwargs.get("refresh_token", "")
        self.username = kwargs.get("username", "")
        self.password = kwargs.get("password", "")
        force_refresh_token = kwargs.get("force_refresh_token", False)
        if (not force_refresh_token or not self.access_token or not self.refresh_token) and all(
                key in self.get_cookies() for key in
                ["bili_jct", "DedeUserID", "DedeUserID__ckMd5", "sid", "SESSDATA"]) and by_cookie():
            return True
        elif self.access_token and self.refresh_token and by_token(force_refresh_token):
            return True
        elif self.username and self.password and by_password():
            return True
        else:
            self._session.cookies.clear()
            return False

    # 获取用户信息
    def get_user_info(self):
        url = f"{self.protocol}://api.bilibili.com/x/space/myinfo?jsonp=jsonp"
        headers = {
            'Host': "api.bilibili.com",
            'Referer': f"https://space.bilibili.com/{self.get_uid()}/",
        }
        response = self._requests("get", url, headers=headers)
        if response and response.get("code") == 0:
            self.info['ban'] = bool(response['data']['silence'])
            self.info['coins'] = response['data']['coins']
            self.info['experience']['current'] = response['data']['level_exp']['current_exp']
            self.info['experience']['next'] = response['data']['level_exp']['next_exp']
            self.info['face'] = response['data']['face']
            self.info['level'] = response['data']['level']
            self.info['nickname'] = response['data']['name']
            self.info['sign'] = response['data']['sign']
            self.info['mid'] = self.get_uid()
            self.info['follower'] = response['data']['follower']
            self.info['following'] = response['data']['following']
            self.info['birthday'] = response['data']['birthday']
            self.info['sex'] = response['data']["sex"]
        else:
            return False
        up_views = self._requests("get",f"https://api.bilibili.com/x/space/upstat?mid={self.get_uid()}",headers=headers)
        if up_views and up_views.get("code") == 0:
            arc_view = up_views["data"]["archive"]["view"]
            art_view = up_views["data"]["article"]["view"]
            likes = up_views["data"]["likes"]
        else:
            arc_view, art_view, likes = "unknow", "unknow", "unknow"
        self.info['arc_view'] = arc_view
        self.info['art_view'] = art_view
        self.info['likes'] = likes
        video_info = self._requests("get", f"https://api.bilibili.com/x/space/arc/search?mid={self.get_uid()}&ps=30&pn=1", headers=headers)
        # print(video_info)
        if video_info["code"] == 0:
            count = video_info["data"]["page"]["count"]
            videos = []
            for i in video_info["data"]["list"]["vlist"]:
                aid = i["aid"]
                title = i["title"]
                created_time = time.strftime("%Y-%m-%d", time.localtime(i["created"]))
                comment = i["comment"]
                play = i["play"]
                videos.append([created_time, title, comment, play, aid])
            if count > 30:
                if count % 30 == 0:
                    pn = int(count / 30)
                else:
                    pn = int(count / 30) + 1
                for i in range(2, pn + 1):
                    video_info = self._requests("get",
                        f"https://api.bilibili.com/x/space/arc/search?mid={self.get_uid()}&ps=30&pn={i}", headers=headers)
                    if video_info["code"] == 0:
                        count = video_info["data"]["page"]["count"]
                        for i in video_info["data"]["list"]["vlist"]:
                            aid = i["aid"]
                            title = i["title"]
                            created_time = time.strftime("%Y-%m-%d", time.localtime(i["created"]))
                            comment = i["comment"]
                            play = i["play"]
                            videos.append([created_time, title, comment, play, aid])
        else:
            videos = []
        self.info['videos'] = videos
        return True


def detect_charset(file, fallback="utf-8"):
    with open(file, "rb") as f:
        detector = chardet.UniversalDetector()
        for line in f.readlines():
            detector.feed(line)
            if detector.done:
                return detector.result['encoding']
    return fallback


def run_app(arg):
    app = Bilibili()
    config, account = arg['config'], arg['account']
    if app.login(force_refresh_token=True, **account):
        if app.get_user_info():
            return [{
                'username': app.username,
                'password': app.password,
                'access_token': app.access_token,
                'refresh_token': app.refresh_token,
                'cookie': app.get_cookies(),
            }], app.info


def main():
    config_file = sys.argv[1] if len(sys.argv) > 1 else "config.toml"
    try:
        with open(config_file, "r", encoding=detect_charset(config_file)) as f:
            config = toml.load(f)
    except:
        print(f"无法加载{config_file}")
        return
    accounts = []
    for line in config['user']['account'].splitlines():
        try:
            if line[0] == "#":
                continue
            pairs = {}
            for pair in line.strip(";").split(";"):
                if len(pair.split("=")) == 2:
                    key, value = pair.split("=")
                    pairs[key] = value
            password = all(key in pairs for key in ["username", "password"])
            token = all(key in pairs for key in ["access_token", "refresh_token"])
            cookie = all(key in pairs for key in ["bili_jct", "DedeUserID", "DedeUserID__ckMd5", "sid", "SESSDATA"])
            if password or token or cookie:
                accounts.append(pairs)
        except:
            pass
    config['user'].pop("account")
    if not accounts:
        return
    # 主程序
    result, user_info = run_app({"config": config, "account": accounts[0]})
    if config['user']['cookies']:
        with open(config_file, "r+", encoding=detect_charset(config_file)) as f:
            content = f.read()
            before = content.split("account")[0]
            after = content.split("account")[-1].split("\"\"\"")[-1]
            f.seek(0)
            f.truncate()
            f.write(before)
            f.write("account = \"\"\"\n")
            for credential in result:
                new_line = False
                for key, value in credential.items():
                    if value:
                        if key == "cookie":
                            f.write(f"{';'.join(f'{key}={value}' for key, value in value.items())};")
                        else:
                            f.write(f"{key}={value};")
                        new_line = True
                if new_line:
                    f.write("\n")
            f.write("\"\"\"")
            f.write(after)
    refresh = config['global']['refresh']
    refresh = int(refresh) + random.randint(-10, 10)
    user_info['refresh'] = refresh
    return user_info


if __name__ == "__main__":
    a = main()
    print(a)

程序图片资源:resources.qrc logo.ico 2233.png

<!DOCTYPE RCC><RCC version="1.0">

<qresource prefix="/images">

<file alias="logo.ico">images/logo.ico</file>
<file alias="2233.png">images/2233.png</file>

</qresource>

</RCC>

程序配置文件:config.toml

[global]
refresh = 60 #刷新间隔(s)

[user]
cookies = true # 自动保存cookies,方便以后登录获取信息
account = """
username=你的账号;password=你的密码;
"""

相关文章

  • UP主小助手 使用说明

    最新版软件已经发布 示例图如下,有兴趣的小伙伴可以查看这个视频:软件介绍视频:https://www.bilibi...

  • 手机扫描答题卡教程

    答题卡扫描助手小程序使用说明 2使用说明及操作步骤 2.1创建考试 打开软件后点击绿色➕按钮添加考试。 2.2 创...

  • 翻译小助手使用说明

    本软件不得用于商业用途,仅做学习交流。 软件下载地址Github 摘要 本文旨在简明扼要的介绍“翻译小助手”的使用...

  • 公众号小程序管理-物流助手功能使用说明

    物流助手功能使用说明 物流助手是什么? 物流助手是微信官方提供的免费物流接口工具,帮助有物流需求的开发者快速高效对...

  • up主

    最近开始逛b站啦。---因为想学美妆的原因 是一种缘分吧 我打开的第一个视频就是我越来越喜欢的up主的视频。 虽然...

  • up主

    总有些时间,很自由却又不适合学习,也不想看视频也不想虚度,那就多些毫无文采的笔耕不辍吧。——前记 说到up主,有些...

  • 介绍

    这是b站up主:cg学习笔记,关于worldmachine教学视频的学习笔记。 这个up主是一位全能up主,有更多...

  • 无题

    还觉得每天的更文无东西可写吗?那你就关注投稿小助手吧,投稿小助手每天发布征稿信息,即使不投稿,你也可以找到更文的主...

  • 小姜,我爱的辣个男人他肿么啦(T ^ T)

    前几天刷B站的时候,看到喜欢的UP主更新了,就很开心地点进去看了。我姑且把这个UP主称作“小姜”吧,不知道是出于什...

  • 关于up主

    关注小翔哥很早了,我记得第一次看到他的视频的时候,他才刚开始做视频,那个时候好像是日更吧,想着这个人好厉害每天更新...

网友评论

      本文标题:UP主小助手 使用说明

      本文链接:https://www.haomeiwen.com/subject/jycinhtx.html