GUI插件完成设置窗口

This commit is contained in:
John Smith 2024-03-16 22:58:06 +08:00
parent abbbbb1154
commit c285ba20cc
8 changed files with 379 additions and 181 deletions

View File

@ -1,5 +1,137 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import configparser
import logging
import os import os
from typing import *
import pubsub.pub as pub
logger = logging.getLogger('native-ui.' + __name__)
BASE_PATH = os.path.realpath(os.getcwd()) BASE_PATH = os.path.realpath(os.getcwd())
LOG_PATH = os.path.join(BASE_PATH, 'log') LOG_PATH = os.path.join(BASE_PATH, 'log')
DATA_PATH = os.path.join(BASE_PATH, 'data')
SAVE_CONFIG_PATH = os.path.join(DATA_PATH, 'config.ini')
CONFIG_PATH_LIST = [
SAVE_CONFIG_PATH,
os.path.join(DATA_PATH, 'config.example.ini')
]
_config: Optional['AppConfig'] = None
def init():
if reload():
return
logger.warning('Using default config')
set_config(AppConfig())
def reload():
config_path = ''
for path in CONFIG_PATH_LIST:
if os.path.exists(path):
config_path = path
break
if config_path == '':
return False
config = AppConfig()
if not config.load(config_path):
return False
set_config(config)
return True
def get_config():
return _config
def set_config(new_config: 'AppConfig'):
global _config
old_config = _config
_config = new_config
if old_config is not None and new_config is not old_config:
pub.sendMessage('config_change', new_config=new_config, old_config=old_config)
class AppConfig:
def __init__(self):
self.room_opacity = 100
self.chat_url_params = self._get_default_url_params()
self.paid_url_params = self._get_default_url_params()
@staticmethod
def _get_default_url_params():
return {
'minGiftPrice': '0',
'showGiftName': 'true',
'maxNumber': '200',
}
def is_url_params_changed(self, other: 'AppConfig'):
return self.chat_url_params != other.chat_url_params or self.paid_url_params != other.paid_url_params
def load(self, path):
try:
config = configparser.ConfigParser()
config.read(path, 'utf-8-sig')
self._load_ui_config(config)
self._load_url_params(config)
except Exception: # noqa
logger.exception('Failed to load config:')
return False
return True
def save(self, path):
try:
config = configparser.ConfigParser()
self._save_ui_config(config)
self._save_url_params(config)
tmp_path = path + '.tmp'
with open(tmp_path, 'w', encoding='utf-8-sig') as f:
config.write(f)
os.replace(tmp_path, path)
except Exception: # noqa
logger.exception('Failed to save config:')
return False
return True
def _load_ui_config(self, config: configparser.ConfigParser):
ui_section = config['ui']
self.room_opacity = ui_section.getint('room_opacity', self.room_opacity)
def _save_ui_config(self, config: configparser.ConfigParser):
config['ui'] = {
'room_opacity': str(self.room_opacity),
}
def _load_url_params(self, config: configparser.ConfigParser):
self.chat_url_params = self._section_to_url_params(config['chat_url_params'])
self.paid_url_params = self._section_to_url_params(config['paid_url_params'])
@staticmethod
def _section_to_url_params(section: configparser.SectionProxy):
params = {}
for line in section.values():
key, _, value = line.partition('=')
params[key.strip()] = value.strip()
return params
def _save_url_params(self, config: configparser.ConfigParser):
config['chat_url_params'] = self._url_params_to_section(self.chat_url_params)
config['paid_url_params'] = self._url_params_to_section(self.paid_url_params)
@staticmethod
def _url_params_to_section(url_params: dict):
return {
str(index): f'{key} = {value}'
for index, (key, value) in enumerate(url_params.items(), 1)
}

View File

@ -0,0 +1,47 @@
# 如果要修改配置可以复制此文件并重命名为“config.ini”再修改
[ui]
# 房间窗口不透明度
room_opacity = 100
# 评论栏浏览器URL中的参数
[chat_url_params]
# --- 这些参数不可改变 ---
# 通过服务器转发消息
# 1 = relayMessagesByServer = true
# --- 这些参数可以在UI中设置 ---
# 自动翻译弹幕到日语
1 = autoTranslate = false
# 标注打赏用户名读音
2 = giftUsernamePronunciation =
# 最低显示打赏价格(元)
3 = minGiftPrice = 0
# 屏蔽礼物弹幕
4 = blockGiftDanmaku = true
# --- 其他的参数自己发挥 ---
# 显示礼物名
5 = showGiftName = true
# 最大弹幕数
6 = maxNumber = 200
# 付费消息浏览器URL中的参数
[paid_url_params]
# --- 这些参数不可改变 ---
# 通过服务器转发消息
# 1 = relayMessagesByServer = true
# 显示弹幕
# 2 = showDanmaku = false
# --- 这些参数可以在UI中设置 ---
1 = autoTranslate = false
2 = giftUsernamePronunciation =
3 = minGiftPrice = 0
4 = blockGiftDanmaku = true
# --- 其他的参数自己发挥 ---
5 = showGiftName = true
6 = maxNumber = 200

View File

@ -443,7 +443,7 @@
<object class="notebookpage" expanded="true"> <object class="notebookpage" expanded="true">
<property name="bitmap"></property> <property name="bitmap"></property>
<property name="label">付费消息</property> <property name="label">付费消息</property>
<property name="select">0</property> <property name="select">1</property>
<object class="wxPanel" expanded="true"> <object class="wxPanel" expanded="true">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
@ -824,7 +824,7 @@
<object class="notebookpage" expanded="true"> <object class="notebookpage" expanded="true">
<property name="bitmap"></property> <property name="bitmap"></property>
<property name="label">统计</property> <property name="label">统计</property>
<property name="select">1</property> <property name="select">0</property>
<object class="wxPanel" expanded="true"> <object class="wxPanel" expanded="true">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
@ -1134,7 +1134,7 @@
<property name="name">RoomConfigDialogBase</property> <property name="name">RoomConfigDialogBase</property>
<property name="pos"></property> <property name="pos"></property>
<property name="size">-1,-1</property> <property name="size">-1,-1</property>
<property name="style">wxDEFAULT_DIALOG_STYLE</property> <property name="style">wxDEFAULT_DIALOG_STYLE|wxDIALOG_NO_PARENT</property>
<property name="subclass">; ; forward_declare</property> <property name="subclass">; ; forward_declare</property>
<property name="title">房间设置</property> <property name="title">房间设置</property>
<property name="tooltip"></property> <property name="tooltip"></property>
@ -1288,7 +1288,7 @@
<property name="pos"></property> <property name="pos"></property>
<property name="resize">Resizable</property> <property name="resize">Resizable</property>
<property name="show">1</property> <property name="show">1</property>
<property name="size">-1,-1</property> <property name="size">200,-1</property>
<property name="style">wxSL_HORIZONTAL</property> <property name="style">wxSL_HORIZONTAL</property>
<property name="subclass">; ; forward_declare</property> <property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property> <property name="toolbar_pane">0</property>
@ -1301,6 +1301,7 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></property> <property name="window_style"></property>
<event name="OnSlider">_on_opacity_slider_change</event>
</object> </object>
</object> </object>
<object class="sizeritem" expanded="true"> <object class="sizeritem" expanded="true">
@ -1472,7 +1473,7 @@
<property name="minimize_button">0</property> <property name="minimize_button">0</property>
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="moveable">1</property> <property name="moveable">1</property>
<property name="name">auto_translate_label1</property> <property name="name">gift_pron_label</property>
<property name="pane_border">1</property> <property name="pane_border">1</property>
<property name="pane_position"></property> <property name="pane_position"></property>
<property name="pane_size"></property> <property name="pane_size"></property>
@ -1503,9 +1504,9 @@
<property name="permission">none</property> <property name="permission">none</property>
<object class="sizeritem" expanded="true"> <object class="sizeritem" expanded="true">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALL</property> <property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property> <property name="proportion">1</property>
<object class="wxRadioButton" expanded="true"> <object class="wxChoice" expanded="true">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -1519,6 +1520,7 @@
<property name="caption"></property> <property name="caption"></property>
<property name="caption_visible">1</property> <property name="caption_visible">1</property>
<property name="center_pane">0</property> <property name="center_pane">0</property>
<property name="choices">&quot;不显示&quot; &quot;拼音&quot; &quot;日文假名&quot;</property>
<property name="close_button">1</property> <property name="close_button">1</property>
<property name="context_help"></property> <property name="context_help"></property>
<property name="context_menu">1</property> <property name="context_menu">1</property>
@ -1534,7 +1536,6 @@
<property name="gripper">0</property> <property name="gripper">0</property>
<property name="hidden">0</property> <property name="hidden">0</property>
<property name="id">wxID_ANY</property> <property name="id">wxID_ANY</property>
<property name="label">不显示</property>
<property name="max_size"></property> <property name="max_size"></property>
<property name="maximize_button">0</property> <property name="maximize_button">0</property>
<property name="maximum_size"></property> <property name="maximum_size"></property>
@ -1542,72 +1543,7 @@
<property name="minimize_button">0</property> <property name="minimize_button">0</property>
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="moveable">1</property> <property name="moveable">1</property>
<property name="name">gift_pron_none_radio</property> <property name="name">gift_pron_choice</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxRB_GROUP</property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value">1</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxRadioButton" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">拼音</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">gift_pron_pinyin_radio</property>
<property name="pane_border">1</property> <property name="pane_border">1</property>
<property name="pane_position"></property> <property name="pane_position"></property>
<property name="pane_size"></property> <property name="pane_size"></property>
@ -1615,6 +1551,7 @@
<property name="pin_button">1</property> <property name="pin_button">1</property>
<property name="pos"></property> <property name="pos"></property>
<property name="resize">Resizable</property> <property name="resize">Resizable</property>
<property name="selection">0</property>
<property name="show">1</property> <property name="show">1</property>
<property name="size"></property> <property name="size"></property>
<property name="style"></property> <property name="style"></property>
@ -1625,72 +1562,6 @@
<property name="validator_style">wxFILTER_NONE</property> <property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property> <property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property> <property name="validator_variable"></property>
<property name="value">0</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxRadioButton" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">日文假名</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">gift_pron_kana_radio</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value">0</property>
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></property> <property name="window_style"></property>
@ -2079,6 +1950,7 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></property> <property name="window_style"></property>
<event name="OnButtonClick">_on_ok</event>
</object> </object>
</object> </object>
<object class="sizeritem" expanded="true"> <object class="sizeritem" expanded="true">
@ -2153,6 +2025,7 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></property> <property name="window_style"></property>
<event name="OnButtonClick">_on_cancel</event>
</object> </object>
</object> </object>
</object> </object>

View File

@ -64,7 +64,7 @@ class RoomFrameBase ( wx.Frame ):
self.paid_panel.SetSizer( bSizer4 ) self.paid_panel.SetSizer( bSizer4 )
self.paid_panel.Layout() self.paid_panel.Layout()
bSizer4.Fit( self.paid_panel ) bSizer4.Fit( self.paid_panel )
self.console_notebook.AddPage( self.paid_panel, u"付费消息", False ) self.console_notebook.AddPage( self.paid_panel, u"付费消息", True )
self.super_chat_panel = wx.Panel( self.console_notebook, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) self.super_chat_panel = wx.Panel( self.console_notebook, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
bSizer5 = wx.BoxSizer( wx.VERTICAL ) bSizer5 = wx.BoxSizer( wx.VERTICAL )
@ -115,7 +115,7 @@ class RoomFrameBase ( wx.Frame ):
self.statistics_panel.SetSizer( bSizer7 ) self.statistics_panel.SetSizer( bSizer7 )
self.statistics_panel.Layout() self.statistics_panel.Layout()
bSizer7.Fit( self.statistics_panel ) bSizer7.Fit( self.statistics_panel )
self.console_notebook.AddPage( self.statistics_panel, u"统计", True ) self.console_notebook.AddPage( self.statistics_panel, u"统计", False )
bSizer1.Add( self.console_notebook, 1, wx.EXPAND, 5 ) bSizer1.Add( self.console_notebook, 1, wx.EXPAND, 5 )
@ -160,7 +160,7 @@ class RoomFrameBase ( wx.Frame ):
class RoomConfigDialogBase ( wx.Dialog ): class RoomConfigDialogBase ( wx.Dialog ):
def __init__( self, parent ): def __init__( self, parent ):
wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"房间设置", pos = wx.DefaultPosition, size = wx.Size( -1,-1 ), style = wx.DEFAULT_DIALOG_STYLE ) wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"房间设置", pos = wx.DefaultPosition, size = wx.Size( -1,-1 ), style = wx.DEFAULT_DIALOG_STYLE|wx.DIALOG_NO_PARENT )
self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
@ -177,7 +177,7 @@ class RoomConfigDialogBase ( wx.Dialog ):
fgSizer1.Add( self.opacity_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 ) fgSizer1.Add( self.opacity_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 )
self.opacity_slider = wx.Slider( sbSizer1.GetStaticBox(), wx.ID_ANY, 100, 10, 100, wx.DefaultPosition, wx.Size( -1,-1 ), wx.SL_HORIZONTAL ) self.opacity_slider = wx.Slider( sbSizer1.GetStaticBox(), wx.ID_ANY, 100, 10, 100, wx.DefaultPosition, wx.Size( 200,-1 ), wx.SL_HORIZONTAL )
fgSizer1.Add( self.opacity_slider, 1, wx.ALL|wx.EXPAND, 5 ) fgSizer1.Add( self.opacity_slider, 1, wx.ALL|wx.EXPAND, 5 )
self.auto_translate_label = wx.StaticText( sbSizer1.GetStaticBox(), wx.ID_ANY, u"自动翻译弹幕到日语", wx.DefaultPosition, wx.DefaultSize, 0 ) self.auto_translate_label = wx.StaticText( sbSizer1.GetStaticBox(), wx.ID_ANY, u"自动翻译弹幕到日语", wx.DefaultPosition, wx.DefaultSize, 0 )
@ -188,22 +188,17 @@ class RoomConfigDialogBase ( wx.Dialog ):
self.auto_translate_check = wx.CheckBox( sbSizer1.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) self.auto_translate_check = wx.CheckBox( sbSizer1.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
fgSizer1.Add( self.auto_translate_check, 1, wx.ALL|wx.EXPAND, 5 ) fgSizer1.Add( self.auto_translate_check, 1, wx.ALL|wx.EXPAND, 5 )
self.auto_translate_label1 = wx.StaticText( sbSizer1.GetStaticBox(), wx.ID_ANY, u"标注打赏用户名读音", wx.DefaultPosition, wx.DefaultSize, 0 ) self.gift_pron_label = wx.StaticText( sbSizer1.GetStaticBox(), wx.ID_ANY, u"标注打赏用户名读音", wx.DefaultPosition, wx.DefaultSize, 0 )
self.auto_translate_label1.Wrap( -1 ) self.gift_pron_label.Wrap( -1 )
fgSizer1.Add( self.auto_translate_label1, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 ) fgSizer1.Add( self.gift_pron_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 )
bSizer2 = wx.BoxSizer( wx.HORIZONTAL ) bSizer2 = wx.BoxSizer( wx.HORIZONTAL )
self.gift_pron_none_radio = wx.RadioButton( sbSizer1.GetStaticBox(), wx.ID_ANY, u"不显示", wx.DefaultPosition, wx.DefaultSize, wx.RB_GROUP ) gift_pron_choiceChoices = [ u"不显示", u"拼音", u"日文假名" ]
self.gift_pron_none_radio.SetValue( True ) self.gift_pron_choice = wx.Choice( sbSizer1.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, gift_pron_choiceChoices, 0 )
bSizer2.Add( self.gift_pron_none_radio, 0, wx.ALL, 5 ) self.gift_pron_choice.SetSelection( 0 )
bSizer2.Add( self.gift_pron_choice, 1, wx.ALL|wx.EXPAND, 5 )
self.gift_pron_pinyin_radio = wx.RadioButton( sbSizer1.GetStaticBox(), wx.ID_ANY, u"拼音", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer2.Add( self.gift_pron_pinyin_radio, 0, wx.ALL, 5 )
self.gift_pron_kana_radio = wx.RadioButton( sbSizer1.GetStaticBox(), wx.ID_ANY, u"日文假名", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer2.Add( self.gift_pron_kana_radio, 0, wx.ALL, 5 )
fgSizer1.Add( bSizer2, 1, wx.ALL|wx.EXPAND, 5 ) fgSizer1.Add( bSizer2, 1, wx.ALL|wx.EXPAND, 5 )
@ -250,12 +245,12 @@ class RoomConfigDialogBase ( wx.Dialog ):
bSizer3.Add( ( 0, 0), 1, wx.EXPAND, 5 ) bSizer3.Add( ( 0, 0), 1, wx.EXPAND, 5 )
self.ok_button = wx.Button( self, wx.ID_ANY, u"确定", wx.DefaultPosition, wx.DefaultSize, 0 ) self.ok_button = wx.Button( self, wx.ID_OK, u"确定", wx.DefaultPosition, wx.DefaultSize, 0 )
self.ok_button.SetDefault() self.ok_button.SetDefault()
bSizer3.Add( self.ok_button, 0, wx.ALL, 5 ) bSizer3.Add( self.ok_button, 0, wx.ALL, 5 )
self.cancel_button = wx.Button( self, wx.ID_ANY, u"取消", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cancel_button = wx.Button( self, wx.ID_CANCEL, u"取消", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer3.Add( self.cancel_button, 0, wx.ALL, 5 ) bSizer3.Add( self.cancel_button, 0, wx.ALL, 5 )
@ -268,7 +263,23 @@ class RoomConfigDialogBase ( wx.Dialog ):
self.Centre( wx.BOTH ) self.Centre( wx.BOTH )
# Connect Events
self.opacity_slider.Bind( wx.EVT_SLIDER, self._on_opacity_slider_change )
self.ok_button.Bind( wx.EVT_BUTTON, self._on_ok )
self.cancel_button.Bind( wx.EVT_BUTTON, self._on_cancel )
def __del__( self ): def __del__( self ):
pass pass
# Virtual event handlers, override them in your derived class
def _on_opacity_slider_change( self, event ):
event.Skip()
def _on_ok( self, event ):
event.Skip()
def _on_cancel( self, event ):
event.Skip()

View File

@ -29,6 +29,7 @@ async def init():
init_signal_handlers() init_signal_handlers()
init_logging() init_logging()
config.init()
await blcsdk.init() await blcsdk.init()
if not blcsdk.is_sdk_version_compatible(): if not blcsdk.is_sdk_version_compatible():

View File

@ -7,6 +7,7 @@ import wxasync
import blcsdk.models as sdk_models import blcsdk.models as sdk_models
import listener import listener
import ui.room_config_dialog
import ui.room_frame import ui.room_frame
logger = logging.getLogger('native-ui.' + __name__) logger = logging.getLogger('native-ui.' + __name__)
@ -25,12 +26,14 @@ class App(wxasync.WxAsyncApp):
self.SetExitOnFrameDelete(False) self.SetExitOnFrameDelete(False)
self._key_room_frame_dict: Dict[sdk_models.RoomKey, ui.room_frame.RoomFrame] = {} self._key_room_frame_dict: Dict[sdk_models.RoomKey, ui.room_frame.RoomFrame] = {}
self._room_config_dialog: Optional[ui.room_config_dialog.RoomConfigDialog] = None
def OnInit(self): def OnInit(self):
pub.subscribe(self._on_add_room, 'add_room') pub.subscribe(self._on_add_room, 'add_room')
pub.subscribe(self._on_del_room, 'del_room') pub.subscribe(self._on_del_room, 'del_room')
pub.subscribe(self._on_room_frame_close, 'room_frame_close') pub.subscribe(self._on_room_frame_close, 'room_frame_close')
pub.subscribe(self._on_open_admin_ui, 'open_admin_ui') pub.subscribe(self._on_open_admin_ui, 'open_admin_ui')
pub.subscribe(self._on_open_room_config_dialog, 'open_room_config_dialog')
return True return True
def _on_add_room(self, room_key: sdk_models.RoomKey): def _on_add_room(self, room_key: sdk_models.RoomKey):
@ -51,3 +54,8 @@ class App(wxasync.WxAsyncApp):
def _on_open_admin_ui(self): def _on_open_admin_ui(self):
for room in listener.iter_rooms(): for room in listener.iter_rooms():
self._on_add_room(room.room_key) self._on_add_room(room.room_key)
def _on_open_room_config_dialog(self):
if self._room_config_dialog is None or self._room_config_dialog.IsBeingDeleted():
self._room_config_dialog = ui.room_config_dialog.RoomConfigDialog(None)
self._room_config_dialog.Show()

View File

@ -0,0 +1,96 @@
# -*- coding: utf-8 -*-
import copy
import logging
from typing import *
import pubsub.pub as pub
import wx
import config
import designer.ui_base
logger = logging.getLogger('native-ui.' + __name__)
class RoomConfigDialog(designer.ui_base.RoomConfigDialogBase):
_GIFT_PRON_CHOICES = ('', 'pinyin', 'kana')
def __init__(self, parent):
super().__init__(parent)
self._new_cfg_cache: Optional[config.AppConfig] = None
def TransferDataToWindow(self):
cfg = config.get_config()
url_params: dict = cfg.chat_url_params
self.opacity_slider.SetValue(cfg.room_opacity)
self.auto_translate_check.SetValue(self._to_bool(url_params.get('autoTranslate', 'false')))
try:
gift_pron_index = self._GIFT_PRON_CHOICES.index(url_params.get('giftUsernamePronunciation', ''))
except ValueError:
gift_pron_index = 0
self.gift_pron_choice.SetSelection(gift_pron_index)
self.min_gift_price_edit.SetValue(url_params.get('minGiftPrice', '0'))
self.block_gift_danmaku_check.SetValue(self._to_bool(url_params.get('blockGiftDanmaku', 'true')))
return super().TransferDataToWindow()
def _on_ok(self, event):
try:
self._new_cfg_cache = self._create_config_from_window()
except Exception as e:
logger.exception('_create_config_from_window failed:')
wx.MessageBox(str(e), '应用设置失败', wx.OK | wx.ICON_ERROR | wx.CENTRE, self)
return
if (
self._new_cfg_cache.is_url_params_changed(config.get_config())
and wx.MessageBox(
'修改部分设置需要刷新浏览器,是否继续?', '提示', wx.YES_NO | wx.CENTRE, self
) != wx.YES
):
return
super()._on_ok(event)
def _create_config_from_window(self):
cfg = copy.deepcopy(config.get_config())
cfg.room_opacity = self.opacity_slider.GetValue()
url_params = {
'autoTranslate': self._bool_to_str(self.auto_translate_check.GetValue()),
'giftUsernamePronunciation': self._GIFT_PRON_CHOICES[self.gift_pron_choice.GetSelection()],
'minGiftPrice': self.min_gift_price_edit.GetValue(),
'blockGiftDanmaku': self._bool_to_str(self.block_gift_danmaku_check.GetValue()),
}
cfg.chat_url_params.update(url_params)
cfg.paid_url_params.update(url_params)
return cfg
def TransferDataFromWindow(self):
if self._new_cfg_cache is None:
logger.warning('_new_cfg_cache is None')
return False
config.set_config(self._new_cfg_cache)
wx.CallAfter(self._new_cfg_cache.save, config.SAVE_CONFIG_PATH)
return super().TransferDataFromWindow()
def _on_cancel(self, event):
pub.sendMessage('room_config_dialog_cancel')
super()._on_cancel(event)
@staticmethod
def _to_bool(value):
if isinstance(value, str):
return value.lower() not in ('false', 'no', 'off', '0', '')
return bool(value)
@staticmethod
def _bool_to_str(value):
return 'true' if value else 'false'
def _on_opacity_slider_change(self, event):
pub.sendMessage('preview_room_opacity', room_opacity=self.opacity_slider.GetValue())

View File

@ -10,6 +10,7 @@ import xlsxwriter.exceptions
import blcsdk import blcsdk
import blcsdk.models as sdk_models import blcsdk.models as sdk_models
import config
import designer.ui_base import designer.ui_base
import listener import listener
@ -25,10 +26,7 @@ class RoomFrame(designer.ui_base.RoomFrameBase):
room_str = str(room.room_id) if room is not None else str(self._room_key) room_str = str(room.room_id) if room is not None else str(self._room_key)
self.SetTitle(f'blivechat - 房间 {room_str}') self.SetTitle(f'blivechat - 房间 {room_str}')
room_params = {'minGiftPrice': 0, 'showGiftName': 'true'} self._apply_config(True)
self.chat_web_view.LoadURL(self._get_room_url(room_params))
room_params['showDanmaku'] = 'false'
self.paid_web_view.LoadURL(self._get_room_url(room_params))
self.super_chat_list.AppendColumn('时间', width=50) self.super_chat_list.AppendColumn('时间', width=50)
self.super_chat_list.AppendColumn('用户名', width=120) self.super_chat_list.AppendColumn('用户名', width=120)
@ -53,6 +51,9 @@ class RoomFrame(designer.ui_base.RoomFrameBase):
for index in room.uid_paid_user_dict: for index in room.uid_paid_user_dict:
self._on_uid_paid_user_dict_change(room, room.uid_paid_user_dict, index, True) self._on_uid_paid_user_dict_change(room, room.uid_paid_user_dict, index, True)
pub.subscribe(self._on_preview_room_opacity, 'preview_room_opacity')
pub.subscribe(self._on_room_config_dialog_cancel, 'room_config_dialog_cancel')
pub.subscribe(self._on_config_change, 'config_change')
pub.subscribe(self._on_super_chats_change, 'room_data_change.super_chats') pub.subscribe(self._on_super_chats_change, 'room_data_change.super_chats')
pub.subscribe(self._on_gifts_change, 'room_data_change.gifts') pub.subscribe(self._on_gifts_change, 'room_data_change.gifts')
pub.subscribe(self._on_uid_paid_user_dict_change, 'room_data_change.uid_paid_user_dict') pub.subscribe(self._on_uid_paid_user_dict_change, 'room_data_change.uid_paid_user_dict')
@ -60,22 +61,8 @@ class RoomFrame(designer.ui_base.RoomFrameBase):
pub.subscribe(self._on_simple_statistics_change, 'room_data_change.interact_uids') pub.subscribe(self._on_simple_statistics_change, 'room_data_change.interact_uids')
pub.subscribe(self._on_simple_statistics_change, 'room_data_change.total_paid_price') pub.subscribe(self._on_simple_statistics_change, 'room_data_change.total_paid_price')
def _get_room_url(self, params: dict):
params = params.copy()
params['roomKeyType'] = self._room_key.type.value
params['relayMessagesByServer'] = 'true'
query = '&'.join(
f'{urllib.parse.quote_plus(key)}={urllib.parse.quote_plus(str(value))}'
for key, value in params.items()
)
blc_port = blcsdk.get_blc_port()
encoded_room_key_value = urllib.parse.quote_plus(str(self._room_key.value))
url = f'http://localhost:{blc_port}/room/{encoded_room_key_value}?{query}'
return url
# #
# UI事件 # 本窗口UI事件
# #
def _on_close(self, event): def _on_close(self, event):
@ -83,9 +70,7 @@ class RoomFrame(designer.ui_base.RoomFrameBase):
super()._on_close(event) super()._on_close(event)
def _on_config_button_click(self, event): def _on_config_button_click(self, event):
# TODO WIP pub.sendMessage('open_room_config_dialog')
dialog = designer.ui_base.RoomConfigDialogBase(self)
dialog.Show()
def _on_stay_on_top_button_toggle(self, event: wx.CommandEvent): def _on_stay_on_top_button_toggle(self, event: wx.CommandEvent):
style = self.GetWindowStyle() style = self.GetWindowStyle()
@ -161,6 +146,51 @@ class RoomFrame(designer.ui_base.RoomFrameBase):
for row in range(row_num): for row in range(row_num):
yield [list_ctrl.GetItemText(row, col) for col in range(col_num)] yield [list_ctrl.GetItemText(row, col) for col in range(col_num)]
#
# 配置事件
#
def _on_preview_room_opacity(self, room_opacity):
self._set_opacity(room_opacity)
def _set_opacity(self, opacity):
opacity = min(max(opacity, 10), 100)
alpha = round(opacity * wx.IMAGE_ALPHA_OPAQUE / 100)
return self.SetTransparent(alpha)
def _on_room_config_dialog_cancel(self):
cfg = config.get_config()
self._set_opacity(cfg.room_opacity)
def _on_config_change(self, new_config: config.AppConfig, old_config: config.AppConfig):
self._apply_config(new_config.is_url_params_changed(old_config))
def _apply_config(self, reload_web_views):
cfg = config.get_config()
self._set_opacity(cfg.room_opacity)
if reload_web_views:
self.chat_web_view.LoadURL(self._get_room_url(cfg.chat_url_params))
self.paid_web_view.LoadURL(self._get_room_url(cfg.paid_url_params, {'showDanmaku': 'false'}))
def _get_room_url(self, params: dict, override_params: Optional[dict] = None):
if override_params is None:
override_params = {}
params = {
**params,
'roomKeyType': self._room_key.type.value,
'relayMessagesByServer': 'true',
**override_params,
}
query = '&'.join(
f'{urllib.parse.quote_plus(key)}={urllib.parse.quote_plus(str(value))}'
for key, value in params.items()
)
blc_port = blcsdk.get_blc_port()
encoded_room_key_value = urllib.parse.quote_plus(str(self._room_key.value))
url = f'http://localhost:{blc_port}/room/{encoded_room_key_value}?{query}'
return url
# #
# 模型事件 # 模型事件
# #