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

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

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

问题

  1. import pylrc
  2. import sys
  3. import time
  4. import vlc
  5. import pathlib
  6. import signal
  7. import argparse
  8. import tkinter
  9. # 检查用户是否指定了.lrc文件
  10. if (len(sys.argv) != 2):
  11. exit(0)
  12. parser = argparse.ArgumentParser()
  13. parser.add_argument('input_lrc', help='')
  14. args = parser.parse_args()
  15. # 使用pylrc解析.lrc文件
  16. fp = open(args.input_lrc,'r')
  17. lrc_string = ''.join(fp.readlines())
  18. fp.close()
  19. window = tkinter.Tk()
  20. window.title("Scores")
  21. window.geometry("800x1000")
  22. # 创建文本小部件
  23. sample_text = tkinter.Entry(window)
  24. sample_text.pack()
  25. subs = pylrc.parse(lrc_string)
  26. # 生成.mp3文件名
  27. filename = args.input_lrc.split('\\')[-1].split('.')[0]
  28. mp3_file = filename + '.mp3'
  29. def SongFinished(event):
  30. global song_has_finished
  31. print("Event reports - finished")
  32. song_has_finished = True
  33. # 显示光标
  34. sys.stdout.write("\033[?25h")
  35. song_has_finished = False
  36. # 准备VLC
  37. instance = vlc.Instance()
  38. player = instance.media_player_new()
  39. media = instance.media_new_path(mp3_file)
  40. player.set_media(media)
  41. events = player.event_manager()
  42. events.event_attach(vlc.EventType.MediaPlayerEndReached, SongFinished)
  43. # 处理Ctrl-C
  44. def sigint_handler(signum, frame):
  45. player.stop()
  46. # 显示光标
  47. sys.stdout.write("\033[?25h")
  48. exit(0)
  49. signal.signal(signal.SIGINT, sigint_handler)
  50. # 开始播放歌曲
  51. print('Playing "' + subs.title + '" by "' + subs.artist + '"')
  52. player.play()
  53. # 隐藏光标
  54. sys.stdout.write("\033[?25l")
  55. line = 0
  56. num_lines = len(subs)
  57. line_printed = False
  58. # 等待歌曲播放完成
  59. while song_has_finished == False:
  60. sec = player.get_time() / 1000
  61. # 是否应该显示下一句歌词?
  62. if line+1 == num_lines or sec < subs
    .time:
  63. # 确保我们只显示歌词一次
  64. if line_printed == False:
  65. print("\r" + subs
    .text.rstrip() + " " * (60 - len(subs
    .text)), end='', flush=True)
  66. sample_text.insert(0, "\r" + subs
    .text.rstrip() + " " * (60 - len(subs
    .text)))
  67. line_printed = True
  68. else:
  69. line += 1
  70. line_printed = False
  71. # 尝试稍微减少CPU使用率...
  72. time.sleep(0.1)
  73. window.mainloop()
英文:
  1. import pylrc
  2. import sys
  3. import time
  4. import vlc
  5. import pathlib
  6. import signal
  7. import argparse
  8. import tkinter
  9. # Check that the user has specified the .lrc file
  10. if (len(sys.argv) != 2):
  11. exit(0)
  12. parser = argparse.ArgumentParser()
  13. parser.add_argument(&#39;input_lrc&#39;, help=&#39;&#39;)
  14. args = parser.parse_args()
  15. # Parse the .lrc file using pylrc
  16. fp = open(args.input_lrc,&#39;r&#39;)
  17. lrc_string = &#39;&#39;.join(fp.readlines())
  18. fp.close()
  19. window = tkinter.Tk()
  20. window.title(&quot;Scores&quot;)
  21. window.geometry(&quot;800x1000&quot;)
  22. # Creating our text widget.
  23. sample_text = tkinter.Entry(window)
  24. sample_text.pack()
  25. subs = pylrc.parse(lrc_string)
  26. # Generate the .mp3 filename
  27. # an alternative is https://stackoverflow.com/questions/678236/how-to-get-the-filename-without-the-extension-from-a-path-in-python
  28. # filename = pathlib.PurePosixPath(sys.argv[1]).stem
  29. filename = args.input_lrc.split(&#39;\\&#39;)[-1].split(&#39;.&#39;)[0]
  30. mp3_file = filename + &#39;.mp3&#39;
  31. def SongFinished(event):
  32. global song_has_finished
  33. print(&quot;Event reports - finished&quot;)
  34. song_has_finished = True
  35. # Show the cursor
  36. sys.stdout.write(&quot;\033[?25h&quot;)
  37. song_has_finished = False
  38. # Prepare VLC
  39. instance = vlc.Instance()
  40. player = instance.media_player_new()
  41. media = instance.media_new_path(mp3_file) #Your audio file here
  42. player.set_media(media)
  43. events = player.event_manager()
  44. events.event_attach(vlc.EventType.MediaPlayerEndReached, SongFinished)
  45. # handle ctrl-c
  46. def sigint_handler(signum, frame):
  47. player.stop()
  48. # Show cursor
  49. sys.stdout.write(&quot;\033[?25h&quot;)
  50. exit(0)
  51. signal.signal(signal.SIGINT, sigint_handler)
  52. # Start playing the song
  53. print(&#39;Playing &quot;&#39; + subs.title + &#39;&quot; by &quot;&#39; + subs.artist + &#39;&quot;&#39;)
  54. player.play()
  55. # Hide the cursor
  56. sys.stdout.write(&quot;\033[?25l&quot;)
  57. line = 0
  58. num_lines = len(subs)
  59. line_printed = False
  60. # wait for the song to finish
  61. while song_has_finished == False:
  62. sec = player.get_time() / 1000
  63. # should we show the next lyrics?
  64. if line+1 == num_lines or sec &lt; subs
    .time:
  65. # make sure that we only show the lyric once
  66. if line_printed == False:
  67. print(&quot;\r&quot; + subs
    .text.rstrip() + &quot; &quot; * (60 - len(subs
    .text)), end=&#39;&#39;, flush=True)
  68. sample_text.insert(0,&quot;\r&quot; + subs
    .text.rstrip() + &quot; &quot; * (60 - len(subs
    .text)))
  69. # Creating the function to set the text
  70. # with the help of button
  71. line_printed = True
  72. else:
  73. line += 1
  74. line_printed = False
  75. # try to reduce the CPU usage a bit...
  76. time.sleep(0.1)
  77. 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处理程序。

  1. import argparse
  2. import pathlib
  3. import sys
  4. import tkinter
  5. import pylrc
  6. import vlc
  7. parser = argparse.ArgumentParser()
  8. parser.add_argument("input_lrc", required=True)
  9. args = parser.parse_args()
  10. lrc_path = pathlib.Path(args.input_lrc)
  11. mp3_path = lrc_path.with_suffix(".mp3")
  12. subs = pylrc.parse(lrc_path.read_text())
  13. window = tkinter.Tk()
  14. window.title("Scores")
  15. window.geometry("800x1000")
  16. sample_text = tkinter.Entry(window)
  17. sample_text.pack()
  18. # 准备VLC
  19. instance = vlc.Instance()
  20. player = instance.media_player_new()
  21. media = instance.media_new_path(str(mp3_path))
  22. player.set_media(media)
  23. events = player.event_manager()
  24. events.event_attach(vlc.EventType.MediaPlayerEndReached, lambda: window.destroy())
  25. # 开始播放歌曲
  26. print('Playing "' + subs.title + '" by "' + subs.artist + '"')
  27. player.play()
  28. last_time_printed = 0
  29. def update_lyrics():
  30. global last_time_printed
  31. sec = player.get_time() / 1000
  32. next_lyric = next((s for s in subs if last_time_printed <= s.time < sec), None)
  33. if next_lyric and last_time_printed < next_lyric.time:
  34. sample_text.insert(0, "\r" + next_lyric.text.ljust(60))
  35. last_time_printed = next_lyric.time
  36. window.after(100, update_lyrics) # 安排下一次调用
  37. try:
  38. sys.stdout.write("\033[?25l") # 隐藏光标
  39. window.after(100, update_lyrics) # 安排第一次更新调用
  40. window.mainloop()
  41. finally:
  42. sys.stdout.write("\033[?25h") # 显示光标
  43. 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.

  1. import argparse
  2. import pathlib
  3. import sys
  4. import tkinter
  5. import pylrc
  6. import vlc
  7. parser = argparse.ArgumentParser()
  8. parser.add_argument(&quot;input_lrc&quot;, required=True)
  9. args = parser.parse_args()
  10. lrc_path = pathlib.Path(args.input_lrc)
  11. mp3_path = lrc_path.with_suffix(&quot;.mp3&quot;)
  12. subs = pylrc.parse(lrc_path.read_text())
  13. window = tkinter.Tk()
  14. window.title(&quot;Scores&quot;)
  15. window.geometry(&quot;800x1000&quot;)
  16. sample_text = tkinter.Entry(window)
  17. sample_text.pack()
  18. # Prepare VLC
  19. instance = vlc.Instance()
  20. player = instance.media_player_new()
  21. media = instance.media_new_path(str(mp3_path))
  22. player.set_media(media)
  23. events = player.event_manager()
  24. events.event_attach(vlc.EventType.MediaPlayerEndReached, lambda: window.destroy())
  25. # Start playing the song
  26. print(&#39;Playing &quot;&#39; + subs.title + &#39;&quot; by &quot;&#39; + subs.artist + &#39;&quot;&#39;)
  27. player.play()
  28. last_time_printed = 0
  29. def update_lyrics():
  30. global last_time_printed
  31. sec = player.get_time() / 1000
  32. next_lyric = next((s for s in subs if last_time_printed &lt;= s.time &lt; sec), None)
  33. if next_lyric and last_time_printed &lt; next_lyric.time:
  34. sample_text.insert(0, &quot;\r&quot; + next_lyric.text.ljust(60))
  35. last_time_printed = next_lyric.time
  36. window.after(100, update_lyrics) # Schedule next call
  37. try:
  38. sys.stdout.write(&quot;\033[?25l&quot;) # Hide cursor
  39. window.after(100, update_lyrics) # Schedule first update call
  40. window.mainloop()
  41. finally:
  42. sys.stdout.write(&quot;\033[?25h&quot;) # Show cursor
  43. 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:

确定