From 2202043121e3e6f7f4cfdc36b393f9e7c41f89c9 Mon Sep 17 00:00:00 2001 From: Damon Lu <59256766+WhatDamon@users.noreply.github.com> Date: Sat, 24 Feb 2024 00:07:33 +0800 Subject: [PATCH] Settings Update --- .gitignore | 2 ++ README.md | 2 +- i18n/en_US.py | 4 ++- i18n/zh_CN.py | 4 ++- lib/cfg.py | 52 ++++++++++++++++++++++++++++ lib/work.py | 12 ++++--- pages/settingsPage.py | 80 +++++++++++++++++++++++++++++++++++-------- player.py | 17 +++++++-- 8 files changed, 148 insertions(+), 25 deletions(-) create mode 100644 lib/cfg.py diff --git a/.gitignore b/.gitignore index 97a2b06..9040504 100644 --- a/.gitignore +++ b/.gitignore @@ -157,3 +157,5 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +config.json \ No newline at end of file diff --git a/README.md b/README.md index 8888e7b..dda39d5 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ pip install winsdk - [ ] 进阶逻辑 - [ ] 进阶播放方式选择 (目前就只支持一个单曲循环) - [ ] 将主界面迁移至 `pages` 中 -- [ ] 设置 (施工中, 目前还需要研究 JSON 读写, 重写 `i18n/lang.py` 的部分功能才能实现自定义语言) +- [ ] 设置 (施工中, `i18n/lang.py` 的部分功能需要重构才能实现自定义语言) - [ ] 区间播放 (即 AB 点) - [ ] 系统托盘 (预计使用 `pystray` 实现, 如果实现了就可以让 `Windows-Toasts` 退役了) - [ ] 界面自动取色 (可能使用 __OpenCV__ 实现, 或者自己算) diff --git a/i18n/en_US.py b/i18n/en_US.py index 1ab9772..f423cd1 100644 --- a/i18n/en_US.py +++ b/i18n/en_US.py @@ -112,7 +112,7 @@ sets = { "settings": "Settings", - "note": "The spacebar can also be used here to control the play and pause of the music.", + "note": "The spacebar can also be used here to control the play and pause of the music.\nMost settings will take effect after restarting the software", "pleaseSelect": "Please select...", "construction": "Under Construction", "language": "Languages", @@ -142,6 +142,8 @@ "webAPIInfo": "Deployment scenarios from https://github.com/Kevin0z0/Python_NetEaseMusicAPI must be used to ensure compatibility!", "systemIntegration": "System integration", "enableSMTC": "Enable SMTC (incomplete)", + "dangerous": "Dangerous", + "delConfigAndClose": "Delete the configuration and close the software", "feedback": "Feedback", "bugReport": "Report a BUG", "shareIdeas": "Share new feature ideas", diff --git a/i18n/zh_CN.py b/i18n/zh_CN.py index 475f91a..4d02dd5 100644 --- a/i18n/zh_CN.py +++ b/i18n/zh_CN.py @@ -112,7 +112,7 @@ sets = { "settings": "设置", - "note": "这里也可以用空格键来控制音乐的播放与暂停哟~", + "note": "这里也可以用空格键来控制音乐的播放与暂停哟~\n大部分设置将在重启后生效", "pleaseSelect": "请选择...", "construction": "正在施工", "language": "语言", @@ -142,6 +142,8 @@ "webAPIInfo": "必须使用 https://github.com/Kevin0z0/Python_NetEaseMusicAPI 的部署方案以保证兼容性!", "systemIntegration": "系统集成", "enableSMTC": "启用 SMTC (未完成)", + "dangerous": "高危选项", + "delConfigAndClose": "删除配置并关闭软件", "feedback": "反馈", "bugReport": "报告 BUG", "shareIdeas": "分享新功能想法", diff --git a/lib/cfg.py b/lib/cfg.py new file mode 100644 index 0000000..e5ee8b6 --- /dev/null +++ b/lib/cfg.py @@ -0,0 +1,52 @@ +import json, os +from lib import log_init +log_init.logging.info("Basic libs imported at cfg.py") + +cfgData = None +defaultJSON = """{ + "language": "sys", + "appearances": [ + { + "mode": "sys", + "schemes": "blue" + } + ], + "play": [ + { + "immediatelyPlay": false, + "defaultPlayInLoop": false, + "defaultVolume": 100 + } + ], + "lyrics": [ + { + "lyricsDefaultVisible": true + } + ], + "online": [ + { + "onlineAPI": "https://music.dsb.ink/api/" + } + ] +} +""" + +def loadConfig(): + global cfgData, defaultJSON + if not os.path.exists('config.json'): + log_init.logging.info("No config.json found, creating a new one") + f = open('config.json', 'w') + f.write(defaultJSON) + f.close() + log_init.logging.info("config.json created") + with open('config.json', 'r') as f: + cfgData = json.load(f) + f.close() + log_init.logging.info("config.json loaded to cfgData") + +def saveConfig(): + global cfgData + with open('config.json', 'w') as f: + json.dump(cfgData, f, indent = 4) + f.close() + log_init.logging.info("Config saved") \ No newline at end of file diff --git a/lib/work.py b/lib/work.py index b2bb5e4..a7ec9fd 100644 --- a/lib/work.py +++ b/lib/work.py @@ -1,6 +1,6 @@ import flet as ft import tinytag, time, base64, requests, json -from lib import log_init +from lib import log_init, cfg log_init.logging.info("Basic libs imported at work.py") @@ -21,6 +21,10 @@ audioArtistText = None audioState = None +apiUrl = cfg.cfgData["online"][0]["onlineAPI"] +if apiUrl[-1] != '/': + apiUrl += '/' + log_init.logging.info("Variable initialization complete at work.py") def secondConvert(sec): @@ -67,8 +71,8 @@ def audioInfoUpdate(audioFile): log_init.logging.info("Set audio info") def audioFromUrlInfo(audioID): # 网站音频信息更新 - global audioTitleText, audioArtistText, audioAlbumText, audioInfo, audioCoverBase64, audioCover_src, audioUrl, currentLength - response = requests.get('https://music.dsb.ink/api/song/detail?id=' + audioID) # 请求音频信息 + global audioTitleText, audioArtistText, audioAlbumText, audioInfo, audioCoverBase64, audioCover_src, audioUrl, currentLength, apiUrl + response = requests.get(apiUrl + 'song/detail?id=' + audioID) # 请求音频信息 audioIdInfo = response.text try: # 尝试读取 ID_json = json.loads(audioIdInfo) @@ -298,7 +302,7 @@ def stateSet(e): playAudio = ft.Audio( autoplay = False, - volume = 1, + volume = cfg.cfgData["play"][0]["defaultVolume"] / 100, balance = 0, on_duration_changed = lambda e: log_init.logging.info("Duration changed:" + e.data), on_state_changed = stateSet, diff --git a/pages/settingsPage.py b/pages/settingsPage.py index c91884c..57555cc 100644 --- a/pages/settingsPage.py +++ b/pages/settingsPage.py @@ -1,10 +1,8 @@ import flet as ft -from lib import log_init - +from lib import log_init, cfg log_init.logging.info("Basic libs imported at settingsPage.py") import i18n - log_init.logging.info("Languages imported at settingsPage.py") appBar = ft.AppBar(title = ft.Row(controls = [ft.Icon(ft.icons.SETTINGS_OUTLINED), ft.Text(value = i18n.lang.sets["settings"])])) @@ -108,9 +106,34 @@ disabled = True ) -playImmediatelyAfterLoaded_switch = ft.Switch(label = i18n.lang.sets["immediatelyPlay"]) -defaultPlayInLoop_switch = ft.Switch(label = i18n.lang.sets["defaultLoop"]) -defaultVolume_slider = ft.Slider(min = 0, max = 100, divisions = 100, label = "{value}", value = 100) +def playImmediatelyAfterLoadedWrite(e): + if playImmediatelyAfterLoaded_switch.value == True: + cfg.cfgData["play"][0]["immediatelyPlay"] = True + log_init.logging.info("Set immediatelyPlay at play as True") + else: + cfg.cfgData["play"][0]["immediatelyPlay"] = False + log_init.logging.info("Set immediatelyPlay at play as False") + cfg.saveConfig() + +playImmediatelyAfterLoaded_switch = ft.Switch(label = i18n.lang.sets["immediatelyPlay"], value = cfg.cfgData["play"][0]["immediatelyPlay"], on_change = playImmediatelyAfterLoadedWrite) + +def defaultPlayInLoopWrite(e): + if defaultPlayInLoop_switch.value == True: + cfg.cfgData["play"][0]["defaultPlayInLoop"] = True + log_init.logging.info("Set defaultPlayInLoop at play as True") + else: + cfg.cfgData["play"][0]["defaultPlayInLoop"] = False + log_init.logging.info("Set defaultPlayInLoop at play as False") + cfg.saveConfig() + +defaultPlayInLoop_switch = ft.Switch(label = i18n.lang.sets["defaultLoop"], value = cfg.cfgData["play"][0]["defaultPlayInLoop"], on_change = defaultPlayInLoopWrite) + +def defaultVolumeWrite(e): + cfg.cfgData["play"][0]["defaultVolume"] = defaultVolume_slider.value + log_init.logging.info("Set defaultVolume at play as " + onlineAPI_tf.value) + cfg.saveConfig() + +defaultVolume_slider = ft.Slider(min = 0, max = 100, divisions = 100, label = "{value}", value = cfg.cfgData["play"][0]["defaultVolume"], on_change_end = defaultVolumeWrite) playSetCard = ft.Card( content = ft.Container( @@ -124,11 +147,22 @@ ), padding = 15 ), - elevation = 0.5, - disabled = True + elevation = 0.5 ) -lyricsDefaultVisible_switch = ft.Switch(label = i18n.lang.sets["lyricsDefaultVis"], value = True) +def lyricsDefaultVisibleWrite(e): + if lyricsDefaultVisible_switch.value == True: + cfg.cfgData["lyrics"][0]["lyricsDefaultVisible"] = True + log_init.logging.info("Set lyricsDefaultVisible at lyrics as True") + else: + cfg.cfgData["lyrics"][0]["lyricsDefaultVisible"] = False + log_init.logging.info("Set lyricsDefaultVisible at lyrics as False") + cfg.saveConfig() + +lyricsDefaultVisible_switch = ft.Switch(label = i18n.lang.sets["lyricsDefaultVis"], on_change = lyricsDefaultVisibleWrite, value = cfg.cfgData["lyrics"][0]["lyricsDefaultVisible"]) + +if cfg.cfgData["lyrics"][0]["lyricsDefaultVisible"] == True: + lyricsDefaultVisible_switch.value = True lyricsSetCard = ft.Card( content = ft.Container( @@ -139,11 +173,15 @@ ), padding = 15 ), - elevation = 0.5, - disabled = True + elevation = 0.5 ) -onlineAPI_tf = ft.TextField(label = i18n.lang.sets["inputAPI"], value = "https://music.dsb.ink/api/") +def onlineAPIWrite(e): + cfg.cfgData["online"][0]["onlineAPI"] = onlineAPI_tf.value + log_init.logging.info("Set onlineAPI at online as " + onlineAPI_tf.value) + cfg.saveConfig() + +onlineAPI_tf = ft.TextField(label = i18n.lang.sets["inputAPI"], value = cfg.cfgData["online"][0]["onlineAPI"], on_change = onlineAPIWrite) onlineSetCard = ft.Card( content = ft.Container( @@ -155,8 +193,7 @@ ), padding = 15 ), - elevation = 0.5, - disabled = True + elevation = 0.5 ) smtcEnable_switch = ft.Switch(label = i18n.lang.sets["enableSMTC"], value = False) @@ -174,6 +211,19 @@ disabled = True ) +advanceSetCard = ft.Card( + content = ft.Container( + content = ft.Column(controls = [ + ft.Row(controls = [ft.Icon(ft.icons.DANGEROUS_OUTLINED), ft.Text(value = i18n.lang.sets["dangerous"], size = 18)]), + ft.ElevatedButton(text = i18n.lang.sets["delConfigAndClose"], icon = ft.icons.DELETE_FOREVER_OUTLINED, bgcolor = ft.colors.RED, color = ft.colors.WHITE, elevation = 0, disabled = True, ) + ] + ), + padding = 15 + ), + elevation = 0.5, + disabled = True +) + feedbackSetCard = ft.Card( content = ft.Container( content = ft.Column(controls = [ @@ -192,4 +242,4 @@ elevation = 0.5 ) -settings_pageView = ft.View("/settings", controls = [appBar, constructionNotice, settingsNotice, languageSetCard, appearancesSetCard, playSetCard, lyricsSetCard, onlineSetCard, systemSetCard, feedbackSetCard], scroll = ft.ScrollMode.AUTO) \ No newline at end of file +settings_pageView = ft.View("/settings", controls = [appBar, constructionNotice, settingsNotice, languageSetCard, appearancesSetCard, playSetCard, lyricsSetCard, onlineSetCard, systemSetCard, advanceSetCard, feedbackSetCard], scroll = ft.ScrollMode.AUTO) \ No newline at end of file diff --git a/player.py b/player.py index b0472e6..6f65ed0 100644 --- a/player.py +++ b/player.py @@ -1,11 +1,13 @@ import flet as ft import platform, os -from lib import work, log_init, update, platform_check +from lib import cfg +cfg.loadConfig() + +from lib import work, log_init, update, platform_check log_init.logging.info("Basic libs imported at player.py") from i18n import lang - log_init.logging.info("Languages imported at player.py") ver = "2.0.0_pre2" @@ -158,6 +160,10 @@ def readSong(audioPathTemp): page.update() log_init.logging.info("Page updated") log_init.logging.info("File picked") + if cfg.cfgData["play"][0]["immediatelyPlay"] == True: + if work.audioState == True: + playOrPauseMusic(0) + playOrPauseMusic(0) def pickFolderResult(e: ft.FilePickerResultEvent): allowed_extensions = ['mp3'] @@ -749,7 +755,7 @@ def viewPop(e): on_click = openVolumePanel ) - volume_silder = ft.Slider(min = 0, max = 100, divisions = 100, label = "{value}", value = 100, on_change = volumeChange) + volume_silder = ft.Slider(min = 0, max = 100, divisions = 100, label = "{value}", value = cfg.cfgData["play"][0]["defaultVolume"], on_change = volumeChange) volume_panel = ft.Card( content = volume_silder, @@ -857,6 +863,11 @@ def viewPop(e): page.on_view_pop = viewPop log_init.logging.info("Window initialization complete") + if cfg.cfgData["lyrics"][0]["lyricsDefaultVisible"] == False: + lyricShow(0) + if cfg.cfgData["play"][0]["defaultPlayInLoop"] == True: + enableOrDisableRepeat(0) + if __name__ == '__main__': log_init.logging.info("Program start") platform_check.detectOS()