我想使用Tkinter创建用户界面,根据需要显示歌曲的定时歌词。

huangapple go评论74阅读模式
英文:

I want to create UI using Tkinter where timed lyrics of a song are shown according to their time as needed

问题

import pylrc
import sys
import time
import vlc
import pathlib
import signal
import argparse
import tkinter

# 检查用户是否指定了.lrc文件
if (len(sys.argv) != 2):
  exit(0)

parser = argparse.ArgumentParser()
parser.add_argument('input_lrc', help='')
args = parser.parse_args()

# 使用pylrc解析.lrc文件
fp = open(args.input_lrc,'r') 
lrc_string = ''.join(fp.readlines())
fp.close()

window = tkinter.Tk()
window.title("Scores")
window.geometry("800x1000")

# 创建文本小部件
sample_text = tkinter.Entry(window)
sample_text.pack()

subs = pylrc.parse(lrc_string)

# 生成.mp3文件名
filename = args.input_lrc.split('\\')[-1].split('.')[0]
mp3_file = filename + '.mp3'

def SongFinished(event):
    global song_has_finished
    print("Event reports - finished")
    song_has_finished = True
    # 显示光标
    sys.stdout.write("\033[?25h")

song_has_finished = False

# 准备VLC
instance = vlc.Instance()
player = instance.media_player_new()
media = instance.media_new_path(mp3_file)
player.set_media(media)
events = player.event_manager()
events.event_attach(vlc.EventType.MediaPlayerEndReached, SongFinished)

# 处理Ctrl-C
def sigint_handler(signum, frame):
    player.stop()
    # 显示光标
    sys.stdout.write("\033[?25h")
    exit(0)

signal.signal(signal.SIGINT, sigint_handler)

# 开始播放歌曲
print('Playing "' + subs.title + '" by "' + subs.artist + '"')
player.play()

# 隐藏光标
sys.stdout.write("\033[?25l")

line = 0
num_lines = len(subs)
line_printed = False

# 等待歌曲播放完成
while song_has_finished == False:
    sec = player.get_time() / 1000

    # 是否应该显示下一句歌词?
    if line+1 == num_lines or sec < subs
.time:
# 确保我们只显示歌词一次 if line_printed == False: print("\r" + subs
.text.rstrip() + " " * (60 - len(subs
.text)), end='', flush=True)
sample_text.insert(0, "\r" + subs
.text.rstrip() + " " * (60 - len(subs
.text)))
line_printed = True else: line += 1 line_printed = False # 尝试稍微减少CPU使用率... time.sleep(0.1) window.mainloop()
英文:
import pylrc
import sys
import time
import vlc
import pathlib
import signal
import argparse
import tkinter
# Check that the user has specified the .lrc file
if (len(sys.argv) != 2):
exit(0)
parser = argparse.ArgumentParser()
parser.add_argument(&#39;input_lrc&#39;, help=&#39;&#39;)
args = parser.parse_args()
# Parse the .lrc file using pylrc
fp = open(args.input_lrc,&#39;r&#39;) 
lrc_string = &#39;&#39;.join(fp.readlines())
fp.close()
window = tkinter.Tk()
window.title(&quot;Scores&quot;)
window.geometry(&quot;800x1000&quot;)
# Creating our text widget.
sample_text = tkinter.Entry(window)
sample_text.pack()
subs = pylrc.parse(lrc_string)
# Generate the .mp3 filename
# an alternative is https://stackoverflow.com/questions/678236/how-to-get-the-filename-without-the-extension-from-a-path-in-python
# filename = pathlib.PurePosixPath(sys.argv[1]).stem
filename = args.input_lrc.split(&#39;\\&#39;)[-1].split(&#39;.&#39;)[0]
mp3_file = filename + &#39;.mp3&#39;
def SongFinished(event):
global song_has_finished
print(&quot;Event reports - finished&quot;)
song_has_finished = True
# Show the cursor
sys.stdout.write(&quot;\033[?25h&quot;)
song_has_finished = False
# Prepare VLC
instance = vlc.Instance()
player = instance.media_player_new()
media = instance.media_new_path(mp3_file) #Your audio file here
player.set_media(media)
events = player.event_manager()
events.event_attach(vlc.EventType.MediaPlayerEndReached, SongFinished)
# handle ctrl-c
def sigint_handler(signum, frame):
player.stop()
# Show cursor
sys.stdout.write(&quot;\033[?25h&quot;)
exit(0)
signal.signal(signal.SIGINT, sigint_handler)
# Start playing the song
print(&#39;Playing &quot;&#39; + subs.title + &#39;&quot; by &quot;&#39; + subs.artist + &#39;&quot;&#39;)
player.play()
# Hide the cursor
sys.stdout.write(&quot;\033[?25l&quot;)
line = 0
num_lines = len(subs)
line_printed = False
# wait for the song to finish
while song_has_finished == False:
sec = player.get_time() / 1000
# should we show the next lyrics?
if line+1 == num_lines or sec &lt; subs
.time: # make sure that we only show the lyric once if line_printed == False: print(&quot;\r&quot; + subs
.text.rstrip() + &quot; &quot; * (60 - len(subs
.text)), end=&#39;&#39;, flush=True) sample_text.insert(0,&quot;\r&quot; + subs
.text.rstrip() + &quot; &quot; * (60 - len(subs
.text))) # Creating the function to set the text # with the help of button line_printed = True else: line += 1 line_printed = False # try to reduce the CPU usage a bit... time.sleep(0.1) window.mainloop()

So as shown above I have created an textbox to show the lyrics. The timed lyric have been created and saved as lrc. It works when the tkinter interface is not in use and shows the output as needed in cmd.

I have shifted the position of the mainloop and the windows to get different output. The output I need is the printing of the timed lyric according to time in the tkinter interface without no user intervention. (Press of a button etc)

答案1

得分: 0

也许类似这样(我无法测试,因为我手边没有任何LRC文件) - 这个想法是window.after()安排Tk每0.1秒调用一次歌词函数。

我还趁机简化了你的参数解析等等,使用finally:来清理播放器,而不是使用sigint处理程序。

import argparse
import pathlib
import sys
import tkinter

import pylrc
import vlc

parser = argparse.ArgumentParser()
parser.add_argument("input_lrc", required=True)
args = parser.parse_args()
lrc_path = pathlib.Path(args.input_lrc)
mp3_path = lrc_path.with_suffix(".mp3")
subs = pylrc.parse(lrc_path.read_text())

window = tkinter.Tk()
window.title("Scores")
window.geometry("800x1000")

sample_text = tkinter.Entry(window)
sample_text.pack()

# 准备VLC
instance = vlc.Instance()
player = instance.media_player_new()
media = instance.media_new_path(str(mp3_path))
player.set_media(media)
events = player.event_manager()
events.event_attach(vlc.EventType.MediaPlayerEndReached, lambda: window.destroy())

# 开始播放歌曲
print('Playing "' + subs.title + '" by "' + subs.artist + '"')
player.play()

last_time_printed = 0

def update_lyrics():
    global last_time_printed
    sec = player.get_time() / 1000
    next_lyric = next((s for s in subs if last_time_printed <= s.time < sec), None)
    if next_lyric and last_time_printed < next_lyric.time:
        sample_text.insert(0, "\r" + next_lyric.text.ljust(60))
        last_time_printed = next_lyric.time
    window.after(100, update_lyrics)  # 安排下一次调用

try:
    sys.stdout.write("\033[?25l")  # 隐藏光标
    window.after(100, update_lyrics)  # 安排第一次更新调用
    window.mainloop()
finally:
    sys.stdout.write("\033[?25h")  # 显示光标
    player.stop()
英文:

Maybe something like this (I can't test this since I don't have any LRC files at hand) – the idea is that window.after() schedules Tk to call the lyric function every 0.1 seconds.

I also took the liberty of simplifying your argument parsing and so on, and using finally: to clean up the player instead of a sigint handler.

import argparse
import pathlib
import sys
import tkinter
import pylrc
import vlc
parser = argparse.ArgumentParser()
parser.add_argument(&quot;input_lrc&quot;, required=True)
args = parser.parse_args()
lrc_path = pathlib.Path(args.input_lrc)
mp3_path = lrc_path.with_suffix(&quot;.mp3&quot;)
subs = pylrc.parse(lrc_path.read_text())
window = tkinter.Tk()
window.title(&quot;Scores&quot;)
window.geometry(&quot;800x1000&quot;)
sample_text = tkinter.Entry(window)
sample_text.pack()
# Prepare VLC
instance = vlc.Instance()
player = instance.media_player_new()
media = instance.media_new_path(str(mp3_path))
player.set_media(media)
events = player.event_manager()
events.event_attach(vlc.EventType.MediaPlayerEndReached, lambda: window.destroy())
# Start playing the song
print(&#39;Playing &quot;&#39; + subs.title + &#39;&quot; by &quot;&#39; + subs.artist + &#39;&quot;&#39;)
player.play()
last_time_printed = 0
def update_lyrics():
global last_time_printed
sec = player.get_time() / 1000
next_lyric = next((s for s in subs if last_time_printed &lt;= s.time &lt; sec), None)
if next_lyric and last_time_printed &lt; next_lyric.time:
sample_text.insert(0, &quot;\r&quot; + next_lyric.text.ljust(60))
last_time_printed = next_lyric.time
window.after(100, update_lyrics)  # Schedule next call
try:
sys.stdout.write(&quot;\033[?25l&quot;)  # Hide cursor
window.after(100, update_lyrics)  # Schedule first update call
window.mainloop()
finally:
sys.stdout.write(&quot;\033[?25h&quot;)  # Show cursor
player.stop()

huangapple
  • 本文由 发表于 2023年6月19日 18:21:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76505697.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定