dltest 发表于 2022-10-16 23:39

[原码]虎牙直播收看器。任意直播源播放,不定期更新时,请看置顶贴

本帖最后由 dltest 于 2022-10-16 23:47 编辑

1输入虎牙房间ID号,不是网址中的号.
2点解析
3如果主播在线,默认播放地址为蓝光4M. 或者可以自己选择其它CDN及清晰度
4 播放
5.全屏快捷键 F11 ,或Esc键退出全屏
6 URL栏可以直播输入其它直播源地址,直接进行播放
7 代码编写环境 win7x64python3.8

获取房间ID



本软件运行中截图


打包后的下载,如下。因本代码调用三方程序VLC所以同时打包了该程序约139M,测试环境win7x64
下载:https://wwz.lanzoub.com/i0n8F0e0biqf 密码:52pj




代码如下


# -*- coding:utf-8 -*-
# @FileName:huya_live_read.py
# @ Author   :dltest@52pojie
import json
import tkinter as tk
import tkinter.font as tkFont
from tkinter import *
from tkinter import ttk
import requests
import re
import os, platform
# 设置VLC库路径,需在import vlc之前
# os.environ['PYTHON_VLC_MODULE_PATH'] = "./vlc-3.0.6"
import vlc
class Player:
    '''
      args:设置 options
    '''

    def __init__(self, *args):
      if args:
            instance = vlc.Instance(*args)
            self.media = instance.media_player_new()
      else:
            self.media = vlc.MediaPlayer()

    # 设置待播放的url地址或本地文件路径,每次调用都会重新加载资源
    def set_uri(self, uri):
      self.media.set_mrl(uri)

    # 播放 成功返回0,失败返回-1
    def play(self, path=None):
      if path:
            self.set_uri(path)
            return self.media.play()
      else:
            return self.media.play()

    # 暂停
    def pause(self):
      self.media.pause()

    # 恢复
    def resume(self):
      self.media.set_pause(0)

    # 停止
    def stop(self):
      self.media.stop()

    # 释放资源
    def release(self):
      return self.media.release()

    # 是否正在播放
    def is_playing(self):
      return self.media.is_playing()

    # 已播放时间,返回毫秒值
    def get_time(self):
      return self.media.get_time()

    # 拖动指定的毫秒值处播放。成功返回0,失败返回-1 (需要注意,只有当前多媒体格式或流媒体协议支持才会生效)
    def set_time(self, ms):
      return self.media.get_time()

    # 音视频总长度,返回毫秒值
    def get_length(self):
      return self.media.get_length()

    # 获取当前音量(0~100)
    def get_volume(self):
      return self.media.audio_get_volume()

    # 设置音量(0~100)
    def set_volume(self, volume):
      return self.media.audio_set_volume(volume)

    # 返回当前状态:正在播放;暂停中;其他
    def get_state(self):
      state = self.media.get_state()
      if state == vlc.State.Playing:
            return 1
      elif state == vlc.State.Paused:
            return 0
      else:
            return -1

    # 当前播放进度情况。返回0.0~1.0之间的浮点数
    def get_position(self):
      return self.media.get_position()

    # 拖动当前进度,传入0.0~1.0之间的浮点数(需要注意,只有当前多媒体格式或流媒体协议支持才会生效)
    def set_position(self, float_val):
      return self.media.set_position(float_val)

    # 获取当前文件播放速率
    def get_rate(self):
      return self.media.get_rate()

    # 设置播放速率(如:1.2,表示加速1.2倍播放)
    def set_rate(self, rate):
      return self.media.set_rate(rate)

    # 设置宽高比率(如"16:9","4:3")
    def set_ratio(self, ratio):
      self.media.video_set_scale(0)# 必须设置为0,否则无法修改屏幕宽高
      self.media.video_set_aspect_ratio(ratio)

    # 设置窗口句柄
    def set_window(self, wm_id):
      if platform.system() == 'Windows':
            self.media.set_hwnd(wm_id)
      else:
            self.media.set_xwindow(wm_id)

    # 注册监听器
    def add_callback(self, event_type, callback):
      self.media.event_manager().event_attach(event_type, callback)

    # 移除监听器
    def remove_callback(self, event_type, callback):
      self.media.event_manager().event_detach(event_type, callback)

class App:
    def __init__(self, root):
      self.editdate = '2022/10/17'
      self.root =root

      self.initUI(root)
      self.initData()
      self.player = Player()
      self.create_video_view(self.GLineEdit_621.winfo_id())
      self.root.bind("<F11>",self.changescreen)
      self.root.bind("<Escape>",self.exitfullscreen)

    def initData(self):
      self.GLineEdit_621.insert(0,'请输入直播间的ID')
      self.vol =50
      self.flag= True
      self.headers = {'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148'}
      self.api_url = 'https://mp.huya.com/cache.php?m=Live&do=profileRoom&roomid='

    def initUI(self,root):
      #setting title
      root.title(f"虎牙直播收看器 {self.editdate}dltest@52pojie")
      #setting window size
      width=1244
      height=744
      screenwidth = root.winfo_screenwidth()
      screenheight = root.winfo_screenheight()
      alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
      root.geometry(alignstr)
      # root.resizable(width=False, height=False)


      self.GLineEdit_621=tk.Entry(root)
      self.GLineEdit_621["borderwidth"] = "1px"
      ft = tkFont.Font(family='Times',size=10)
      self.GLineEdit_621["font"] = ft
      self.GLineEdit_621["fg"] = "#333333"
      self.GLineEdit_621["bg"] = "#393d49"
      self.GLineEdit_621["justify"] = "center"
      self.GLineEdit_621["text"] = "ve"
      self.w =1243
      self.h =705
      self.GLineEdit_621.place(x=0,y=0,width=self.w,height=self.h)
      self.GLineEdit_621.bind('<Double-Button-1>',self.changescreen)

      self.GListBox_294=ttk.Combobox(root)
      ft = tkFont.Font(family='Times',size=10)
      self.GListBox_294["font"] = ft
      self.GListBox_294["justify"] = "center"
      self.GListBox_294.place(x=600,y=710,width=103,height=30)
      self.GListBox_294.bind("<<ComboboxSelected>>", self.choose)

      self.GLabel_149=tk.Label(root)
      ft = tkFont.Font(family='Times',size=10)
      self.GLabel_149["font"] = ft
      self.GLabel_149["fg"] = "#333333"
      self.GLabel_149["justify"] = "center"
      self.GLabel_149["text"] = "直播间ID:"
      self.GLabel_149.place(x=10,y=710,width=67,height=30)

      self.GLineEdit_15=tk.Entry(root)
      self.GLineEdit_15["borderwidth"] = "1px"
      ft = tkFont.Font(family='Times',size=10)
      self.GLineEdit_15["font"] = ft
      self.GLineEdit_15["fg"] = "#333333"
      self.GLineEdit_15["justify"] = "center"
      self.GLineEdit_15["text"] = "room_id"
      self.GLineEdit_15["relief"] = "groove"
      self.GLineEdit_15.place(x=80,y=710,width=83,height=30)

      self.GButton_246=tk.Button(root)
      self.GButton_246["bg"] = "#f0f0f0"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_246["font"] = ft
      self.GButton_246["fg"] = "#000000"
      self.GButton_246["justify"] = "center"
      self.GButton_246["text"] = "解析"
      self.GButton_246["relief"] = "groove"
      self.GButton_246.place(x=170,y=710,width=67,height=30)
      self.GButton_246["command"] = self.GButton_246_command

      self.GLabel_158=tk.Label(root)
      ft = tkFont.Font(family='Times',size=10)
      self.GLabel_158["font"] = ft
      self.GLabel_158["fg"] = "#333333"
      self.GLabel_158["justify"] = "center"
      self.GLabel_158["text"] = "选择清晰度:"
      self.GLabel_158.place(x=530,y=710,width=78,height=30)

      self.GLineEdit_316=tk.Entry(root)
      self.GLineEdit_316["borderwidth"] = "1px"
      ft = tkFont.Font(family='Times',size=10)
      self.GLineEdit_316["font"] = ft
      self.GLineEdit_316["fg"] = "#333333"
      self.GLineEdit_316["justify"] = "center"
      self.GLineEdit_316["text"] = "real_url"
      self.GLineEdit_316["relief"] = "groove"
      self.GLineEdit_316.place(x=450,y=710,width=80,height=30)

      self.GButton_701=tk.Button(root)
      self.GButton_701["bg"] = "#f0f0f0"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_701["font"] = ft
      self.GButton_701["fg"] = "#000000"
      self.GButton_701["justify"] = "center"
      self.GButton_701["text"] = "►播 放"
      self.GButton_701["relief"] = "groove"
      self.GButton_701.place(x=710,y=710,width=66,height=30)
      self.GButton_701["command"] = self.GButton_701_command

      self.GButton_132=tk.Button(root)
      self.GButton_132["bg"] = "#f0f0f0"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_132["font"] = ft
      self.GButton_132["fg"] = "#000000"
      self.GButton_132["justify"] = "center"
      self.GButton_132["text"] = "▍▍暂停"
      self.GButton_132["relief"] = "groove"
      self.GButton_132.place(x=780,y=710,width=66,height=30)
      self.GButton_132["command"] = self.GButton_132_command

      self.GButton_492=tk.Button(root)
      self.GButton_492["bg"] = "#f0f0f0"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_492["font"] = ft
      self.GButton_492["fg"] = "#000000"
      self.GButton_492["justify"] = "center"
      self.GButton_492["text"] = "⬛ 停止"
      self.GButton_492["relief"] = "groove"
      self.GButton_492.place(x=850,y=710,width=66,height=30)
      self.GButton_492["command"] = self.GButton_492_command

      self.GButton_813=tk.Button(root)
      self.GButton_813["bg"] = "#f0f0f0"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_813["font"] = ft
      self.GButton_813["fg"] = "#000000"
      self.GButton_813["justify"] = "center"
      self.GButton_813["text"] = "音量 +"
      self.GButton_813["relief"] = "groove"
      self.GButton_813.place(x=940,y=710,width=66,height=30)
      self.GButton_813["command"] = self.GButton_813_command

      self.GButton_229=tk.Button(root)
      self.GButton_229["bg"] = "#f0f0f0"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_229["font"] = ft
      self.GButton_229["fg"] = "#000000"
      self.GButton_229["justify"] = "center"
      self.GButton_229["text"] = "音量 -"
      self.GButton_229["relief"] = "groove"
      self.GButton_229.place(x=1010,y=710,width=66,height=30)
      self.GButton_229["command"] = self.GButton_229_command

      self.GButton_316=tk.Button(root)
      self.GButton_316["bg"] = "#f0f0f0"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_316["font"] = ft
      self.GButton_316["fg"] = "#000000"
      self.GButton_316["justify"] = "center"
      self.GButton_316["text"] = "静 音"
      self.GButton_316["relief"] = "groove"
      self.GButton_316.place(x=1080,y=710,width=66,height=30)
      self.GButton_316["command"] = self.GButton_316_command

      self.GButton_275=tk.Button(root)
      self.GButton_275["bg"] = "#f0f0f0"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_275["font"] = ft
      self.GButton_275["fg"] = "#000000"
      self.GButton_275["justify"] = "center"
      self.GButton_275["text"] = "F11全屏"
      self.GButton_275["relief"] = "groove"
      self.GButton_275.place(x=1180,y=710,width=59,height=30)
      self.GButton_275["command"] = self.GButton_275_command

      self.GLineEdit_754=tk.Entry(root)
      self.GLineEdit_754["borderwidth"] = "1px"
      ft = tkFont.Font(family='Times',size=10)
      self.GLineEdit_754["font"] = ft
      self.GLineEdit_754["fg"] = "#333333"
      self.GLineEdit_754["justify"] = "center"
      self.GLineEdit_754["text"] = "zhubo_name"
      self.GLineEdit_754.place(x=290,y=710,width=153,height=30)

      self.GLabel_143=tk.Label(root)
      ft = tkFont.Font(family='Times',size=10)
      self.GLabel_143["font"] = ft
      self.GLabel_143["fg"] = "#333333"
      self.GLabel_143["justify"] = "center"
      self.GLabel_143["text"] = "主播名:"
      self.GLabel_143.place(x=240,y=710,width=57,height=30)

    def create_video_view(self,wid):
      self.player.set_window(wid)

    def choose(self,event):
      url = self.GListBox_294.get()
      self.GLineEdit_316.delete(0,'end')
      self.GLineEdit_316.insert(0,url.split('::'))

    #解析
    def GButton_246_command(self):
      self.GLineEdit_316.delete(0,'end')
      room_id = self.GLineEdit_15.get()
      if not room_id:
            return
      try:
            html = requests.get(self.api_url + room_id, headers=self.headers)
            data = json.loads(html.text)['data']
            nick = data['profileInfo']['nick']
            room_name = data['liveData']['roomName']
            liveStatus = data['liveStatus']
            print(f'{nick} {room_name} {liveStatus}')
      except:
            print('Room id is invalid!')
            self.GLineEdit_754.delete(0,'end')
            self.GLineEdit_754.insert(0,'房号错误!')
            return
      if liveStatus == "OFF":
            self.GLineEdit_754.delete(0,'end')
            self.GLineEdit_754.insert(0,f'未开播 {nick}')
            return f'{room_name} {nick} is offline'
      elif liveStatus == "REPLAY":
            self.GLineEdit_754.delete(0,'end')
            self.GLineEdit_754.insert(0,f'未开播 {nick}')
            return f'{room_name} {nick} is REPLAY'

      else:
            self.GLineEdit_754.delete(0,'end')
            self.GLineEdit_754.insert(0,f'【{nick}】{room_name}')
            stream_dict = data['stream']
            flv = stream_dict['flv']# type: dict
            cdn = flv['multiLine']# type: List
            rate = flv['rateArray']# type: List
            supportable_resolution = {'原画': '', }
            for b in rate:
                supportable_resolution] = b['iBitRate']
            sort_dict = {}
            listbox = []
            for resolution, bitrate in supportable_resolution.items():
                url_list = []
                for i in cdn:
                  url = i['url'].replace('http://', 'https://')
                  url = url.replace(
                        'imgplus.flv', f'imgplus_{bitrate}.flv')
                  url_list.append(url)
                sort_dict = url_list
            for resolution, url_list in sort_dict.items():
                count=0
                for i in url_list:
                  count += 1
                  listbox.append(f'【{resolution}】{count}::{i}')
      self.GListBox_294["values"] = listbox
      for i in listbox:
            if i.startswith('【蓝光4M】'):
                # self.GListBox_294.current(1)
                self.GListBox_294.set(i)
                self.GLineEdit_316.delete(0,'end')
                self.GLineEdit_316.insert(0,i.split('::'))
                break
      else:
            self.GListBox_294.current(1)
            self.GLineEdit_316.delete(0,'end')
            self.GLineEdit_316.insert(0,i.split('::'))


    def GButton_701_command(self): #►播 放
      url = self.GLineEdit_316.get().strip()
      if not url:
            return
      if self.player.get_state() == 0:
            self.player.resume()
      elif self.player.get_state() == 1:
            pass# 播放新资源
            self.player.play(url)
      else:
            self.player.play(url)


    #暂停
    def GButton_132_command(self):
      self.player.pause()

    #停止
    def GButton_492_command(self):
      self.player.stop()

    #音量加
    def GButton_813_command(self):
      vol = self.player.get_volume()
      self.player.set_volume(vol+5)

    #音量减
    def GButton_229_command(self):
      vol = self.player.get_volume()
      self.player.set_volume(vol-5)

    #静音
    def GButton_316_command(self):
      vol = self.player.get_volume()
      if vol == 0:
            self.player.set_volume(self.vol)
      else:
            self.vol = self.player.get_volume()
            self.player.set_volume(0)

    #全屏
    def GButton_275_command(self):
      ifself.flag:
            self.root.attributes('-fullscreen',True)
            self.w, self.h = self.root.winfo_screenwidth(), self.root.winfo_screenheight()
            self.GLineEdit_621.place(x=0,y=0,width=self.w,height=self.h)
            self.GButton_492.place_forget()
            self.GLabel_149.place_forget()
            self.GLineEdit_15.place_forget()
            self.GButton_246.place_forget()
            self.GLabel_143.place_forget()
            self.GLineEdit_754.place_forget()
            self.GLineEdit_316.place_forget()
            self.GLabel_158.place_forget()
            self.GListBox_294.place_forget()
            self.GButton_701.place_forget()
            self.GButton_132.place_forget()
            self.GButton_492.place_forget()
            self.GButton_813.place_forget()
            self.GButton_229.place_forget()
            self.GButton_316.place_forget()
            self.GButton_275.place_forget()

      else:
            self.root.attributes('-fullscreen',False)
            # self.GLineEdit_621.place(x=0,y=0,width=self.w,height=self.h)
            self.GLineEdit_621.place(x=0,y=0,width=1243,height=705)
            self.GLabel_149.place(x=10,y=710,width=67,height=30)
            self.GLineEdit_15.place(x=80,y=710,width=83,height=30)
            self.GButton_246.place(x=170,y=710,width=67,height=30)
            self.GLabel_143.place(x=240,y=710,width=57,height=30)
            self.GLineEdit_754.place(x=290,y=710,width=153,height=30)
            self.GLineEdit_316.place(x=450,y=710,width=80,height=30)
            self.GLabel_158.place(x=530,y=710,width=78,height=30)
            self.GListBox_294.place(x=600,y=710,width=103,height=30)
            self.GButton_701.place(x=710,y=710,width=66,height=30)
            self.GButton_132.place(x=780,y=710,width=66,height=30)
            self.GButton_492.place(x=850,y=710,width=66,height=30)
            self.GButton_813.place(x=940,y=710,width=66,height=30)
            self.GButton_229.place(x=1010,y=710,width=66,height=30)
            self.GButton_316.place(x=1080,y=710,width=66,height=30)
            self.GButton_275.place(x=1180,y=710,width=59,height=30)

      self.flag = not self.flag



    def changescreen(self,event):
      self.GButton_275_command()

    def exitfullscreen(self,event):
      self.flag = True
      self.root.attributes('-fullscreen',False)
      self.GLineEdit_621.place(x=0,y=0,width=1243,height=705)
      self.GLabel_149.place(x=10,y=710,width=67,height=30)
      self.GLineEdit_15.place(x=80,y=710,width=83,height=30)
      self.GButton_246.place(x=170,y=710,width=67,height=30)
      self.GLabel_143.place(x=240,y=710,width=57,height=30)
      self.GLineEdit_754.place(x=290,y=710,width=153,height=30)
      self.GLineEdit_316.place(x=450,y=710,width=80,height=30)
      self.GLabel_158.place(x=530,y=710,width=78,height=30)
      self.GListBox_294.place(x=600,y=710,width=103,height=30)
      self.GButton_701.place(x=710,y=710,width=66,height=30)
      self.GButton_132.place(x=780,y=710,width=66,height=30)
      self.GButton_492.place(x=850,y=710,width=66,height=30)
      self.GButton_813.place(x=940,y=710,width=66,height=30)
      self.GButton_229.place(x=1010,y=710,width=66,height=30)
      self.GButton_316.place(x=1080,y=710,width=66,height=30)
      self.GButton_275.place(x=1180,y=710,width=59,height=30)


if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)
    root.mainloop()






dltest 发表于 2022-10-24 23:07

本次更新:

[*]重写UI
[*]可以自由缩放播放器大小
[*]加载虎牙分类菜单,方便快速找到喜欢的主播
[*]解析出来的主播,可以加入关注/收藏,点右侧列表快速加载
[*]其它


原功能仍保留

[*]可以自己输入房间号,进行解析、观看
[*]可以输入自定义直播间地址,观看


提醒

[*]返回选择类别或收藏界面,要先停止直播收看


程序目前尚存问题
1部份直播无法正常播放,例 娱乐天地/一起看 这个类型的直播基本都无法播放,语音类的无法正常显示等
2鼠标滚轮快捷调节音量,有时会失灵

打包好的exe文件下载(含vlc三方控件)
下载:https://wwz.lanzoub.com/iXbyS0ei3uja 密码:52pj





代码如下

# -*- coding:utf-8 -*-
# @FileName:huya_live_read.py
# @ Author   :dltest@52pojie
import json
import tkinter as tk
import tkinter.font as tkFont
from tkinter import *
from tkinter import ttk
import requests
import re
import os, platform
# 设置VLC库路径,需在import vlc之前
os.environ['PYTHON_VLC_MODULE_PATH'] = "./vlc-3.0.9.2-win64"
import vlc
from lxml import etree


class Player:
    '''
      args:设置 options
    '''

    def __init__(self, *args):
      if args:
            instance = vlc.Instance(*args)
            self.media = instance.media_player_new()
      else:
            self.media = vlc.MediaPlayer()

    # 设置待播放的url地址或本地文件路径,每次调用都会重新加载资源
    def set_uri(self, uri):
      self.media.set_mrl(uri)

    # 播放 成功返回0,失败返回-1
    def play(self, path=None):
      if path:
            self.set_uri(path)
            return self.media.play()
      else:
            return self.media.play()

    # 暂停
    def pause(self):
      self.media.pause()

    # 恢复
    def resume(self):
      self.media.set_pause(0)

    # 停止
    def stop(self):
      self.media.stop()

    # 释放资源
    def release(self):
      return self.media.release()

    # 是否正在播放
    def is_playing(self):
      return self.media.is_playing()

    # 已播放时间,返回毫秒值
    def get_time(self):
      return self.media.get_time()

    # 拖动指定的毫秒值处播放。成功返回0,失败返回-1 (需要注意,只有当前多媒体格式或流媒体协议支持才会生效)
    def set_time(self, ms):
      return self.media.get_time()

    # 音视频总长度,返回毫秒值
    def get_length(self):
      return self.media.get_length()

    # 获取当前音量(0~100)
    def get_volume(self):
      return self.media.audio_get_volume()

    # 设置音量(0~100)
    def set_volume(self, volume):
      return self.media.audio_set_volume(volume)

    # 返回当前状态:正在播放;暂停中;其他
    def get_state(self):
      state = self.media.get_state()
      if state == vlc.State.Playing:
            return 1
      elif state == vlc.State.Paused:
            return 0
      else:
            return -1

    # 当前播放进度情况。返回0.0~1.0之间的浮点数
    def get_position(self):
      return self.media.get_position()

    # 拖动当前进度,传入0.0~1.0之间的浮点数(需要注意,只有当前多媒体格式或流媒体协议支持才会生效)
    def set_position(self, float_val):
      return self.media.set_position(float_val)

    # 获取当前文件播放速率
    def get_rate(self):
      return self.media.get_rate()

    # 设置播放速率(如:1.2,表示加速1.2倍播放)
    def set_rate(self, rate):
      return self.media.set_rate(rate)

    # 设置宽高比率(如"16:9","4:3")
    def set_ratio(self, ratio):
      self.media.video_set_scale(0)# 必须设置为0,否则无法修改屏幕宽高
      self.media.video_set_aspect_ratio(ratio)

    # 设置窗口句柄
    def set_window(self, wm_id):
      if platform.system() == 'Windows':
            self.media.set_hwnd(wm_id)
      else:
            self.media.set_xwindow(wm_id)

    # 注册监听器
    def add_callback(self, event_type, callback):
      self.media.event_manager().event_attach(event_type, callback)

    # 移除监听器
    def remove_callback(self, event_type, callback):
      self.media.event_manager().event_detach(event_type, callback)

class App:
    def __init__(self, root):
      self.root =root
      self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'}
      self.editdate = '2022/10/24'
      self.init_ui(root)
      self.player = Player()
      self.create_video_view(self.frame_video.winfo_id())
      self.root.bind("<F11>",self.changescreen)
      self.root.bind("<Escape>",self.exitfullscreen)
      self.root.bind("<MouseWheel>",self.change_vol)
      self.flag= True
      self.choose_active(None)
      self.count = 0
      self.zhubo_list = self.getzhubolist()
      if not self.zhubo_list or len(self.zhubo_list) < 1:
            return
      self.anchor_list =[]
      self.settvlist(self.zhubo_list)

    def init_ui(self,root):
      #setting title
      root.title(f"虎牙直播收看器 {self.editdate}dltest@52pojie")
      #setting window size
      width=578
      height=380
      screenwidth = root.winfo_screenwidth()
      screenheight = root.winfo_screenheight()
      alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
      root.geometry(alignstr)

      root.grid_rowconfigure(0,weight=1,minsize=40) # row为1,缩放比为1
      root.grid_columnconfigure(0,weight=1,minsize=40) # column为0,缩放比为1

      self.frame_main=tk.Frame(root, relief='groove' )
      self.frame_main.grid(row=0,column=0,sticky=NSEW)

      self.frame_video=tk.Frame(root, relief='groove' )
      self.frame_video['bg'] = "#ccc"
      self.frame_video.grid(row=0,column=0,sticky=NSEW)

      self.frame_main.tkraise()

      self.frame_buttom=tk.Frame(root, relief='groove')
      # self.frame_buttom['bg'] = "#ffffff"
      self.frame_buttom.grid(row=1,column=0,sticky=NSEW,padx=0, pady=0 ) # 跨2列

      self.GButton_274=tk.Button(self.frame_buttom)
      self.GButton_274["bg"] = "#efefef"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_274["font"] = ft
      self.GButton_274["fg"] = "#000000"
      self.GButton_274["justify"] = "center"
      self.GButton_274["text"] = "►"
      self.GButton_274["relief"] = "groove"
      # self.GButton_274.place(x=0,y=0,width=30,height=30)
      self.GButton_274.grid(row=0,column=0,sticky=NSEW,padx=5, pady=1 )
      self.GButton_274["command"] = self.GButton_274_command

      self.GButton_751=tk.Button(self.frame_buttom)
      self.GButton_751["bg"] = "#efefef"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_751["font"] = ft
      self.GButton_751["fg"] = "#000000"
      self.GButton_751["justify"] = "center"
      self.GButton_751["text"] = "▍▍"
      self.GButton_751["relief"] = "groove"
      self.GButton_751.grid(row=0,column=1,sticky=NSEW,padx=1, pady=1 )
      self.GButton_751["command"] = self.GButton_751_command

      self.GButton_159=tk.Button(self.frame_buttom)
      self.GButton_159["bg"] = "#efefef"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_159["font"] = ft
      self.GButton_159["fg"] = "#000000"
      self.GButton_159["justify"] = "center"
      self.GButton_159["text"] = "⬛"
      self.GButton_159["relief"] = "groove"
      self.GButton_159.grid(row=0,column=2,sticky=NSEW,padx=5, pady=1 )
      self.GButton_159["command"] = self.GButton_159_command

      self.GButton_991=tk.Button(self.frame_buttom)
      self.GButton_991["bg"] = "#efefef"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_991["font"] = ft
      self.GButton_991["fg"] = "#000000"
      self.GButton_991["justify"] = "center"
      self.GButton_991["text"] = "静音"
      self.GButton_991["relief"] = "groove"
      self.GButton_991.grid(row=0,column=3,sticky=NSEW,padx=5, pady=1 )
      self.GButton_991["command"] = self.GButton_991_command

      self.scint = IntVar()
      self.scint.set(50)
      self.GButton_79=tk.Scale(self.frame_buttom,from_=0,to=100,showvalue=False,tickinterval = 0,variable = self.scint,
                                 activebackground='#00ced1',orient=HORIZONTAL)
      self.GButton_79["bg"] = "#efefef"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_79["font"] = ft
      self.GButton_79["fg"] = "#000000"
      # self.GButton_79["justify"] = "center"
      # self.GButton_79["text"] = "音量控制"
      self.GButton_79["relief"] = "groove"
      self.GButton_79.grid(row=0,column=4,sticky=NSEW,padx=1, pady=1 )
      self.GButton_79["command"] = self.GButton_79_command

      self.GButton_39=tk.Button(self.frame_buttom)
      self.GButton_39["bg"] = "#efefef"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_39["font"] = ft
      self.GButton_39["fg"] = "#000000"
      self.GButton_39["justify"] = "center"
      self.GButton_39["text"] = "F11全屏"
      self.GButton_39["relief"] = "groove"
      self.GButton_39.grid(row=0,column=5,sticky=NSEW,padx=15, pady=1 )
      self.GButton_39["command"] = self.GButton_39_command

      #####################################################################################
      value = [('全部', '/g'), ('网游竞技', '/g_ol'), ('单机热游', '/g_pc'), ('娱乐天地', '/g_yl'), ('手游休闲', '/g_sy')]
      self.GLineEdit_678 = ttk.Combobox(self.frame_main, state='readonly')
      ft = tkFont.Font(family='Times',size=10)
      self.GLineEdit_678["font"] = ft
      self.GLineEdit_678["value"] = value
      self.GLineEdit_678.place(x=40,y=0,width=253,height=30)
      self.GLineEdit_678.bind("<<ComboboxSelected>>", self.choose_active)
      self.GLineEdit_678.current(0)


      self.GLabel_397=tk.Label(self.frame_main)
      ft = tkFont.Font(family='Times',size=10)
      self.GLabel_397["font"] = ft
      self.GLabel_397["fg"] = "#333333"
      self.GLabel_397["justify"] = "center"
      self.GLabel_397["text"] = "分 类"
      self.GLabel_397.place(x=0,y=0,width=30,height=30)

      self.GLabel_268=tk.Label(self.frame_main)
      ft = tkFont.Font(family='Times',size=10)
      self.GLabel_268["font"] = ft
      self.GLabel_268["fg"] = "#333333"
      self.GLabel_268["justify"] = "center"
      self.GLabel_268["text"] = "列 表"
      self.GLabel_268.place(x=0,y=40,width=30,height=30)

      self.GLineEdit_803=ttk.Combobox(self.frame_main, state='readonly')
      ft = tkFont.Font(family='Times',size=10)
      self.GLineEdit_803["font"] = ft
      self.GLineEdit_803.place(x=40,y=40,width=252,height=30)
      self.GLineEdit_803.bind("<<ComboboxSelected>>", self.choose_game)

      self.GLabel_354=tk.Label(self.frame_main)
      ft = tkFont.Font(family='Times',size=10)
      self.GLabel_354["font"] = ft
      self.GLabel_354["fg"] = "#333333"
      self.GLabel_354["justify"] = "center"
      self.GLabel_354["text"] = "在 播 "
      self.GLabel_354.place(x=0,y=80,width=30,height=30)

      self.GLineEdit_178=ttk.Combobox(self.frame_main, state='readonly')
      ft = tkFont.Font(family='Times',size=10)
      self.GLineEdit_178["font"] = ft
      self.GLineEdit_178.place(x=40,y=80,width=253,height=30)
      self.GLineEdit_178.bind("<<ComboboxSelected>>", self.choose_anchor)

      self.GButton_112=tk.Button(self.frame_main)
      self.GButton_112["bg"] = "#efefef"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_112["font"] = ft
      self.GButton_112["fg"] = "#000000"
      self.GButton_112["relief"] = "groove"
      self.GButton_112["justify"] = "center"
      self.GButton_112["text"] = "解析"
      self.GButton_112.place(x=50,y=160,width=96,height=30)
      self.GButton_112["command"] = self.GButton_112_command

      self.GButton_706=tk.Button(self.frame_main)
      self.GButton_706["bg"] = "#efefef"
      ft = tkFont.Font(family='Times',size=10)
      self.GButton_706["font"] = ft
      self.GButton_706["fg"] = "#000000"
      self.GButton_706["justify"] = "center"
      self.GButton_706["text"] = "加入关注"
      self.GButton_706.place(x=170,y=160,width=98,height=30)
      self.GButton_706["command"] = self.GButton_706_command



      self.GLineEdit_945=tk.Entry(self.frame_main)
      self.GLineEdit_945["borderwidth"] = "1px"
      ft = tkFont.Font(family='Times',size=10)
      self.GLineEdit_945["font"] = ft
      self.GLineEdit_945["fg"] = "#333333"
      self.GLineEdit_945["justify"] = "center"
      self.GLineEdit_945["text"] = "id"
      self.GLineEdit_945.place(x=40,y=120,width=253,height=30)

      self.GLabel_608=tk.Label(self.frame_main)
      ft = tkFont.Font(family='Times',size=10)
      self.GLabel_608["font"] = ft
      self.GLabel_608["fg"] = "#333333"
      self.GLabel_608["justify"] = "center"
      self.GLabel_608["text"] = "房间ID"
      self.GLabel_608.place(x=0,y=120,width=41,height=30)

      self.GLabel_538=tk.Label(self.frame_main)
      ft = tkFont.Font(family='Times',size=10)
      self.GLabel_538["font"] = ft
      self.GLabel_538["fg"] = "#333333"
      self.GLabel_538["justify"] = "center"
      self.GLabel_538["text"] = "主播名"
      self.GLabel_538.place(x=0,y=200,width=40,height=32)

      self.GLabel_803=tk.Label(self.frame_main)
      self.GLabel_803["bg"] = "#ffffff"
      ft = tkFont.Font(family='Times',size=10)
      self.GLabel_803["font"] = ft
      self.GLabel_803["fg"] = "#333333"
      self.GLabel_803["justify"] = "center"
      self.GLabel_803.place(x=40,y=200,width=252,height=31)

      self.GLabel_953=tk.Label(self.frame_main)
      ft = tkFont.Font(family='Times',size=10)
      self.GLabel_953["font"] = ft
      self.GLabel_953["fg"] = "#333333"
      self.GLabel_953["justify"] = "center"
      self.GLabel_953["text"] = "房间名"
      self.GLabel_953.place(x=0,y=240,width=42,height=30)

      self.GLabel_201=tk.Label(self.frame_main)
      self.GLabel_201["bg"] = "#ffffff"
      ft = tkFont.Font(family='Times',size=10)
      self.GLabel_201["font"] = ft
      self.GLabel_201["fg"] = "#333333"
      self.GLabel_201["justify"] = "center"
      self.GLabel_201.place(x=40,y=240,width=253,height=30)

      self.GLabel_913=tk.Label(self.frame_main)
      ft = tkFont.Font(family='Times',size=10)
      self.GLabel_913["font"] = ft
      self.GLabel_913["fg"] = "#333333"
      self.GLabel_913["justify"] = "center"
      self.GLabel_913["text"] = "清晰度"
      self.GLabel_913.place(x=0,y=280,width=36,height=30)

      self.GLineEdit_440=ttk.Combobox(self.frame_main, state='readonly')
      ft = tkFont.Font(family='Times',size=10)
      self.GLineEdit_440["font"] = ft
      self.GLineEdit_440.place(x=40,y=280,width=254,height=30)
      self.GLineEdit_440.bind("<<ComboboxSelected>>", self.chooseCDN)

      self.GLabel_708=tk.Label(self.frame_main)
      ft = tkFont.Font(family='Times',size=10)
      self.GLabel_708["font"] = ft
      self.GLabel_708["fg"] = "#333333"
      self.GLabel_708["justify"] = "center"
      self.GLabel_708["text"] = "地址"
      self.GLabel_708.place(x=0,y=320,width=35,height=30)

      self.GLineEdit_795=tk.Entry(self.frame_main)
      self.GLineEdit_795["borderwidth"] = "1px"
      ft = tkFont.Font(family='Times',size=10)
      self.GLineEdit_795["font"] = ft
      self.GLineEdit_795["fg"] = "#333333"
      self.GLineEdit_795["justify"] = "center"
      self.GLineEdit_795["text"] = "address"
      self.GLineEdit_795.place(x=40,y=320,width=253,height=30)

      self.GLineEdit_136=tk.Entry(self.frame_main)
      self.GLineEdit_136["borderwidth"] = "1px"
      ft = tkFont.Font(family='Times',size=10)
      self.GLineEdit_136["font"] = ft
      self.GLineEdit_136["fg"] = "#333333"
      self.GLineEdit_136["justify"] = "center"
      self.GLineEdit_136["text"] = "关注列表"
      self.GLineEdit_136.place(x=300,y=0,width=293,height=352)
      yscroll = Scrollbar(self.GLineEdit_136, orient=VERTICAL)
      yscroll.pack(side=RIGHT, fill=Y)
      titles = ('房号', '主播', '操作')
      self.tvList =ttk.Treeview(self.GLineEdit_136, columns=titles, style='Treeview', show='headings', height=21,
                                        yscrollcommand=yscroll.set)
      self.tvList.pack()
      for i in range(len(titles)):
            self.tvList.heading(column=titles, text=titles, anchor=CENTER) # 定义表头
            self.tvList.column(titles, minwidth=20, anchor=CENTER ,stretch=True) # 定义列
      self.tvList.column(titles, width=80, anchor=CENTER)
      self.tvList.column(titles, width=120, anchor='w')
      self.tvList.column(titles, width=75, anchor=CENTER)
      yscroll.config(command=self.tvList.yview)
      self.tvList.bind("<ButtonRelease-1>", self.tvList_leftButtonRelease)

    def tvList_leftButtonRelease(self,event):
      if str(event.widget) == ".!frame.!entry3.!treeview":# 左键释放的是否为表格
            items = event.widget.selection()
            try:
                item = self.tvList.item(items)['values']
                id = item
                name = item
                self.GLineEdit_945.delete(0,'end')
                self.GLineEdit_945.insert(0,id)
                self.GLabel_803['text'] = name
                self.GButton_112_command()
            except:
                pass
            row = self.tvList.identify_row(event.y)# 点击的行
            column = self.tvList.identify_column(event.x)# 点击的列
            col = int(str(column).replace('#', ''))# 列号
            item = self.tvList.item(row)['values']
            if item:
                if col == 3:
                  # print("删除操作")
                  value = f'{item}={item}'
                  self.zhubo_list.remove(value)
                  self.tvList.delete(row)
                  self.save_list(self.zhubo_list)
    def save_list(self,zhubo_list):
         with open('HYZBconfig.ini', 'w', encoding='utf-8') as writer:
            for item in zhubo_list:
                writer.writelines(item)
                writer.writelines('\n')

    def getzhubolist(self):
      try:
            file = open("HYZBconfig.ini", "rb")
            l1 = []
            while 1:
                line = file.readline().strip()
                data = line.decode('utf-8', 'ignore') #ignore"的作用就是有异常就越过
                if len(data)>0 and len(data.split('='))>1 :
                  l1.append(data)
                if not line:
                  break
            return l1
      except:
            with open('HYZBconfig.ini', 'w', encoding='utf-8') as writer:
                writer.writelines('关注列表')
                writer.writelines('\n')
            return []

    #关注
    def GButton_706_command(self):
      roomid = self.GLineEdit_945.get().strip()
      anchor = self.GLabel_803.cget("text")
      self.tvList.insert('','end',values=((roomid,anchor,'删除')))
      self.zhubo_list.append((f'{roomid}={anchor}'))
      with open('HYZBconfig.ini', 'a+', encoding='utf-8') as writer:
            writer.writelines(f'{roomid}={anchor}')
            writer.writelines('\n')

    def settvlist(self,zhubo_list):
      if len(zhubo_list) < 1:
            return
      for zhubo in zhubo_list:
            self.count +=1
            li = zhubo.split('=')
            li.append('删除')
            self.tvList.insert('','end',values=(li))

    def GButton_274_command(self):
      url = self.GLineEdit_795.get().strip()
      if not url:
            return
      if self.player.get_state() == 0:
            self.player.resume()
      elif self.player.get_state() == 1:
            self.player.play(url)
      else:
            self.player.play(url)
      self.frame_video.tkraise()
    #停止
    def GButton_159_command(self):
      self.player.stop()
      self.frame_main.tkraise()
    #暂停
    def GButton_751_command(self):
      self.player.pause()
    #静音
    def GButton_991_command(self):
      vol = self.player.get_volume()
      if vol == 0:
            self.player.set_volume(self.vol)
      else:
            self.vol = self.player.get_volume()
            self.player.set_volume(0)
    #调音
    def GButton_79_command(self,value):
      self.player.set_volume(int(value))
      # self.scint

    #全屏
    def GButton_39_command(self):
      ifself.flag:
            self.root.attributes('-fullscreen',True)
            # self.frame_video.tkraise()
            self.frame_buttom.grid_forget()
      else:
            self.root.attributes('-fullscreen',False)
            self.frame_buttom.grid(row=1,column=0,sticky=NSEW,padx=0, pady=0 )
      self.flag = not self.flag

    def change_vol(self,evt):
      vol = self.player.get_volume()
      if evt.delta == 120:
            if vol < 100:
                vol += 5
      else:
            if vol > 0:
                vol -= 5
      self.player.set_volume(vol)
      self.scint.set(vol)
      print(vol)





    def changescreen(self,event):
      self.GButton_39_command()
    def exitfullscreen(self,event):
      self.flag = True
      self.root.attributes('-fullscreen',False)
      self.frame_buttom.grid(row=1,column=0,sticky=NSEW,padx=0, pady=0 )

    def create_video_view(self,wid):
      self.player.set_window(wid)

    def choose_active(self,event):
      url = 'https://www.huya.com/'
      text = self.GLineEdit_678.get()
      url += text.split('/')
      self.set_game_list(url)
    def set_game_list(self,url):
      # url = 'https://www.huya.com/g'
      req = requests.get(url, headers=self.headers).content.decode('utf8', 'ignore')
      html_etree = etree.HTML(req)
      game_list =html_etree.xpath('//*[@id="js-game-list"]/li')
      value =[]
      for idx,row in enumerate(game_list):
            idx +=1
            game = row.attrib['title']
            url =self.get_row_text(row,'./a','href')
            value.append((game,url))
      self.GLineEdit_803["values"] = value
      self.GLineEdit_803.current(0)
      self.choose_game(None)
    def choose_game(self,event):
      url = 'http'
      text = self.GLineEdit_803.get()
      url += text.split('http')
      self.set_live_list(url)
    def set_live_list(self,url):
      req = requests.get(url, headers=self.headers).content.decode('utf8', 'ignore')
      html_etree = etree.HTML(req)
      live_list =html_etree.xpath('//*[@id="js-live-list"]/li')
      value =[]
      for idx,row in enumerate(live_list):
            idx +=1
            nick =   self.get_row_text(row,'.//*[@class="nick"]')
            title =   self.get_row_text(row,'.//*[@class="title"]')
            #人气
            js_num = self.get_row_text(row,'.//i[@class="js-num"]')
            tag_recommend =self.get_row_text(row,'.//*[@class="tag tag-recommend"]')
            #英雄
            pos2_content =   self.get_row_text(row,'.//*[@class="tag-pos2-content"]')
            url_anchor =self.get_row_text(row,'.//a','href')
            value.append((nick,title,js_num,tag_recommend,pos2_content,url_anchor))
      self.GLineEdit_178["values"] = value
      self.GLineEdit_178.current(0)
      self.choose_anchor(None)

    def choose_anchor(self,event):
      url = 'http'
      text = self.GLineEdit_178.get()
      url += text.split('http')
      req = requests.get(url, headers=self.headers).content.decode('utf8', 'ignore')
      html_etree = etree.HTML(req)
      host_rid =self.get_row_text(html_etree,'//span[@class="host-rid"]/em')
      self.GLineEdit_945.delete(0,'end')
      self.GLineEdit_945.insert(0,host_rid)

    def get_row_text(self,str_html,str_analysis,str_attrib='0'):
      table_element = str_html.xpath(str_analysis)
      if len(table_element) > 0:
            if str_attrib == '0':
                return table_element.text
            else:
                return table_element.attrib
      else:
            return ' '

    #解析
    def GButton_112_command(self):
      self.GLineEdit_795.delete(0,'end')
      room_id = self.GLineEdit_945.get().strip()
      if not room_id:
            return
      try:
            api_url = 'https://mp.huya.com/cache.php?m=Live&do=profileRoom&roomid='
            html = requests.get(api_url + room_id, headers=self.headers)
            data = json.loads(html.text)['data']
            nick = data['profileInfo']['nick']
            room_name = data['liveData']['roomName']
            liveStatus = data['liveStatus']
      except:
            self.GLabel_803['text']='房号错误!'
            return
      if liveStatus == "OFF":
            self.GLabel_803['text']=f'未开播 {nick}'
            return f'{room_name} {nick} is offline'
      elif liveStatus == "REPLAY":
            self.GLabel_803['text']=f'未开播 {nick}'
            return f'{room_name} {nick} is REPLAY'
      else:
            self.GLabel_803['text']=f'{nick}'
            self.GLabel_201['text']=f'{room_name}'
            stream_dict = data['stream']
            flv = stream_dict['flv']# type: dict
            cdn = flv['multiLine']# type: List
            bitRateInfo = json.loads(data['liveData']['bitRateInfo'])
            bitRateInfo.append(({'sDisplayName': '原画', 'iBitRate': -1, 'iCodecType': 0, 'iCompatibleFlag': 0, 'iHEVCBitRate': -1}))
            listbox = []
            for item in bitRateInfo:
                count=0
                for i in cdn:
                  count += 1
                  url = i['url'].replace('http://', 'https://')
                  if item["iBitRate"] >= 0:
                      url = url.replace('imgplus.flv', f'imgplus_{item["iBitRate"]}.flv')
                  listbox.append(f'【{item["sDisplayName"]}-线路{count}】::{url}')

      self.GLineEdit_440["values"] = listbox
      for i in listbox:
            if i.startswith('【蓝光4M】'):
                # self.GListBox_294.current(1)
                self.GLineEdit_440.set(i)
                self.GLineEdit_795.delete(0,'end')
                self.GLineEdit_795.insert(0,i.split('::'))
                break
      else:
            self.GLineEdit_440.current(1)
            self.GLineEdit_795.delete(0,'end')
            self.GLineEdit_795.insert(0,i.split('::'))

    def chooseCDN(self,event):
      url = self.GLineEdit_440.get()
      self.GLineEdit_795.delete(0,'end')
      self.GLineEdit_795.insert(0,url.split('::'))

if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)
    root.mainloop()

simgo2231 发表于 2024-2-6 10:18

大佬 出现了这个问题 能帮忙看看、?
Traceback (most recent call last):
File "huya_live_read2.py", line 677, in <module>
File "huya_live_read2.py", line 140, in __init__
File "huya_live_read2.py", line 557, in choose_active
File "huya_live_read2.py", line 571, in set_game_list
File "huya_live_read2.py", line 576, in choose_game
File "huya_live_read2.py", line 591, in set_live_list
File "huya_live_read2.py", line 613, in get_row_text
File "src\lxml\etree.pyx", line 2494, in lxml.etree._Attrib.__getitem__
KeyError: 'href'

青春小韭菜 发表于 2022-10-16 23:48

6呀我先试试是看

花葬 发表于 2022-10-16 23:50

刚刚去测试了下,显示房间号错误。不知道我是不是个例。
当然,我输入的是房间号

zdmboot 发表于 2022-10-17 02:11

好东西,值得点赞......

feng_129 发表于 2022-10-17 02:30

流畅,清晰度不错。要是有自定义缩放就更好了~

candleliu 发表于 2022-10-17 06:10

支持原创,膜拜的大佬{:1_919:}

我还行 发表于 2022-10-17 07:21

感觉不错 下来试试看 感谢分享

lx0720 发表于 2022-10-17 07:21

要是有自定义缩放就更好了~

l441669899 发表于 2022-10-17 08:06

感谢楼主分享!

duanxiaopeng 发表于 2022-10-17 08:33

厉害,感谢楼主分享
页: [1] 2 3 4 5 6 7
查看完整版本: [原码]虎牙直播收看器。任意直播源播放,不定期更新时,请看置顶贴