UP主小助手 使用说明

2020-05-12  本文已影响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:

正式版v1.1:

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


正式版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=你的密码;
"""

上一篇 下一篇

猜你喜欢

热点阅读