initial commit
This commit is contained in:
parent
aca646d087
commit
b17a59c735
54
app.py
Normal file
54
app.py
Normal file
@ -0,0 +1,54 @@
|
||||
import sys
|
||||
from tracemalloc import Frame
|
||||
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QColor
|
||||
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QMainWindow, QFrame
|
||||
from widgets import OutlinedLabel
|
||||
|
||||
|
||||
class Lyric(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setLayout(QVBoxLayout())
|
||||
self.lyrics = []
|
||||
self.label_now = QLabel()
|
||||
self.label_now.setObjectName("label_now")
|
||||
self.label_now.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
self.label_next = QLabel()
|
||||
self.label_next.setObjectName("label_next")
|
||||
self.label_next.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
self.label_now.setStyleSheet("font-size: 30px; color: pink;")
|
||||
self.label_next.setStyleSheet("font-size: 30px;")
|
||||
self.layout().addWidget(self.label_now)
|
||||
self.layout().addWidget(self.label_next)
|
||||
self.setStyleSheet("background-color: rgba(255, 255, 255, 0);")
|
||||
self.label_now.setText("asdasd")
|
||||
self.label_next.setText("asdasd")
|
||||
|
||||
def set_lyrics(self, lyrics):
|
||||
self.label_now.setText(lyrics[0])
|
||||
self.label_next.setText(lyrics[1])
|
||||
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.lyrics = Lyric()
|
||||
self.frame = QFrame()
|
||||
self.setCentralWidget(self.frame)
|
||||
# self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, True)
|
||||
self.setWindowFlag(Qt.WindowType.FramelessWindowHint, True)
|
||||
self.setWindowFlag(Qt.WindowType.WindowStaysOnTopHint, True)
|
||||
self.frame.setLayout(QVBoxLayout())
|
||||
self.frame.layout().addWidget(self.lyrics)
|
||||
self.frame.setStyleSheet("background-color: rgba(255, 255, 255, 50);")
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
window = Lyric()
|
||||
window.show()
|
||||
sys.exit(app.exec())
|
1
credits.lrc
Normal file
1
credits.lrc
Normal file
File diff suppressed because one or more lines are too long
BIN
credits.mp3
Normal file
BIN
credits.mp3
Normal file
Binary file not shown.
16
fakeplayer.py
Normal file
16
fakeplayer.py
Normal file
@ -0,0 +1,16 @@
|
||||
class FakePlayer:
|
||||
def __init__(self):
|
||||
self.curr_pos = 0.0
|
||||
|
||||
def seek(self, pos):
|
||||
self.curr_pos = float(pos)
|
||||
|
||||
def add(self, num):
|
||||
self.curr_pos += num
|
||||
|
||||
def play(self):
|
||||
...
|
||||
|
||||
def stop(self):
|
||||
...
|
||||
|
1
lrc.lrc
Normal file
1
lrc.lrc
Normal file
@ -0,0 +1 @@
|
||||
[00:00.000] 作词 : 後藤正文[00:01.000] 作曲 : 後藤正文/山田貴洋[00:02.000] 编曲 : 三井律郎[01:16.022] 君を待った[01:17.476] 僕は待った[01:19.170] 途切れない明日も過ぎて行って[01:22.161] 立ち止まって振り返って[01:25.318] とめどない今日を嘆き合った[01:28.189][01:28.514] 記憶だって 永遠になんて[01:31.541] 残らないものとおもい知って[01:34.575] 僕はずっと掻きむしって[01:37.718] 心の隅っこで泣いた[01:39.976][01:40.032] そしてどうかなくさないでよって[01:43.884] 高架下、過ぎる日々を[01:46.837] 後悔してんだよって そう言い逃したあの日[01:54.171][02:05.529] 繋ぎ合った時もあった[02:08.720] ほどけない感情持ち寄って[02:11.753] それが僕のすべてだった[02:14.817] それもたった今 失くしたんだ[02:17.930][02:17.998] 形だって 時が経って[02:21.012] 変わりゆくものとおもい知って[02:24.094] 僕はずっと掻きむしって[02:27.232] 塞がれた今日を恨んだ[02:29.518][02:29.553] そしてどうかなくさないでよって[02:33.381] 高架下、過ぎる日々を[02:36.376] 後悔してんだよって そう言い逃したあの日[02:43.652][03:26.096] 君を待った[03:27.668] 僕は待った[03:29.181] 途切れない明日も過ぎて行って[03:32.291] 僕は今日も掻きむしって[03:35.462] 忘れない傷をつけているんだよ[03:43.207] 君じゃないとさ
|
35
lyric_parse.py
Normal file
35
lyric_parse.py
Normal file
@ -0,0 +1,35 @@
|
||||
from re import match
|
||||
|
||||
|
||||
def split_lyric(lyric_str):
|
||||
lyrics = []
|
||||
temp_str = ''
|
||||
for index in range(len(lyric_str)):
|
||||
if lyric_str[index] == '[' and lyric_str[(index - 1) if index > 0 else index] != ']':
|
||||
lyrics.append(temp_str)
|
||||
temp_str = ''
|
||||
temp_str += lyric_str[index] if lyric_str[index] != '\n' else ''
|
||||
lyrics.append(temp_str)
|
||||
return lyrics[1:]
|
||||
|
||||
|
||||
def parse_lyric(lyric_str):
|
||||
total = {}
|
||||
lyrics = split_lyric(lyric_str)
|
||||
for lyric in lyrics:
|
||||
if not match(r'^(\[[a-zA-Z])', lyric):
|
||||
temp = lyric.replace('[', '').split(']')
|
||||
timestamps = temp[:-1]
|
||||
lyric = temp[-1].strip()
|
||||
for ts in timestamps:
|
||||
total[ts] = lyric
|
||||
sort = {}
|
||||
for k in sorted(total.keys()):
|
||||
sort[k] = total[k]
|
||||
return sort
|
||||
|
||||
if __name__ == '__main__':
|
||||
with open('y.lrc', encoding='utf-8') as f:
|
||||
for k, v in parse_lyric(f.read()).items():
|
||||
print(k, v)
|
||||
|
66
play.py
Normal file
66
play.py
Normal file
@ -0,0 +1,66 @@
|
||||
from just_playback import Playback
|
||||
from time import sleep, time
|
||||
from lyric_parse import parse_lyric
|
||||
from threading import Thread
|
||||
from datetime import datetime
|
||||
from wcwidth import wcswidth
|
||||
|
||||
|
||||
music = 'music.mp3'
|
||||
lyric = 'lrc.lrc'
|
||||
|
||||
|
||||
player = Playback(music)
|
||||
|
||||
|
||||
def time_convert(raw):
|
||||
if isinstance(raw, float):
|
||||
minutes = int(raw // 60)
|
||||
seconds = int(raw % 60)
|
||||
microsec = raw % 1
|
||||
return datetime.strptime(f'{minutes}:{seconds}.{("%.6f" % microsec)[2:]}', '%M:%S.%f')
|
||||
elif isinstance(raw, str):
|
||||
return datetime.strptime(raw, '%M:%S.%f')
|
||||
else:
|
||||
return datetime.strptime('00', '%S')
|
||||
|
||||
|
||||
def print_lyric(player, lyrics):
|
||||
global stopped
|
||||
lyrics['59:59.999999'] = ''
|
||||
index = 1
|
||||
times = list(lyrics.keys())
|
||||
previous_lrc = ''
|
||||
while index < len(lyrics) and not stopped:
|
||||
if index < (len(lyrics) - 1) and time_convert(times[index]) < time_convert(player.curr_pos):
|
||||
index += 1
|
||||
continue
|
||||
if index >= 1 and time_convert(times[index - 1]) > time_convert(player.curr_pos):
|
||||
index -= 1
|
||||
continue
|
||||
if previous_lrc != lyrics[times[index - 1]]:
|
||||
previous_lrc = lyrics[times[index - 1]]
|
||||
print('\r' + previous_lrc + '.' * ((40 - wcswidth(previous_lrc)) if 40 > len(previous_lrc) else 0), end='')
|
||||
sleep(0.01)
|
||||
|
||||
|
||||
if True:
|
||||
stopped = False
|
||||
player.play()
|
||||
player.current_time = 80
|
||||
|
||||
with open(lyric, encoding='utf-8') as f:
|
||||
lyrics = parse_lyric(f.read())
|
||||
Thread(target=print_lyric, args=(player, lyrics)).start()
|
||||
|
||||
try:
|
||||
while True:
|
||||
#print_lyric(player, lyrics)
|
||||
#print(player.current_time)
|
||||
r = input()
|
||||
delta = r.count('k') * 5 - (len(r) - r.count('k')) * 5
|
||||
player.seek(player.curr_pos + delta)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
stopped = True
|
||||
player.stop()
|
74
play_ui.py
Normal file
74
play_ui.py
Normal file
@ -0,0 +1,74 @@
|
||||
from just_playback import Playback
|
||||
from time import sleep, time
|
||||
from lyric_parse import parse_lyric
|
||||
from threading import Thread
|
||||
from datetime import datetime
|
||||
from wcwidth import wcswidth
|
||||
from app import MainWindow, QApplication
|
||||
|
||||
|
||||
music = 'credits.mp3'
|
||||
lyric = 'credits.lrc'
|
||||
|
||||
|
||||
player = Playback(music)
|
||||
|
||||
|
||||
def time_convert(raw):
|
||||
if isinstance(raw, float):
|
||||
minutes = int(raw // 60)
|
||||
seconds = int(raw % 60)
|
||||
microsec = raw % 1
|
||||
return datetime.strptime(f'{minutes}:{seconds}.{("%.6f" % microsec)[2:]}', '%M:%S.%f')
|
||||
elif isinstance(raw, str):
|
||||
return datetime.strptime(raw, '%M:%S.%f')
|
||||
else:
|
||||
return datetime.strptime('00', '%S')
|
||||
|
||||
|
||||
def display_lyric(player, lyrics, app):
|
||||
global stopped
|
||||
lyrics['59:59.999999'] = ''
|
||||
index = 1
|
||||
times = list(lyrics.keys())
|
||||
previous_lrc = ''
|
||||
while index < len(lyrics) and not stopped:
|
||||
if index < (len(lyrics) - 1) and time_convert(times[index]) < time_convert(player.curr_pos):
|
||||
index += 1
|
||||
continue
|
||||
if index >= 1 and time_convert(times[index - 1]) > time_convert(player.curr_pos):
|
||||
index -= 1
|
||||
continue
|
||||
if previous_lrc != lyrics[times[index - 1]]:
|
||||
previous_lrc = lyrics[times[index - 1]]
|
||||
app.lyrics.set_lyrics([previous_lrc, lyrics[times[index]]])
|
||||
sleep(0.01)
|
||||
|
||||
|
||||
def catch():
|
||||
global player
|
||||
try:
|
||||
while True:
|
||||
#print_lyric(player, lyrics)
|
||||
#print(player.current_time)
|
||||
r = input()
|
||||
delta = r.count('k') * 5 - (len(r) - r.count('k')) * 5
|
||||
player.seek(player.curr_pos + delta)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
|
||||
if True:
|
||||
stopped = False
|
||||
player.play()
|
||||
player.current_time = 80
|
||||
app = QApplication()
|
||||
window = MainWindow()
|
||||
window.show()
|
||||
with open(lyric, encoding='utf-8') as f:
|
||||
lyrics = parse_lyric(f.read())
|
||||
Thread(target=display_lyric, args=(player, lyrics, window)).start()
|
||||
Thread(target=catch).start()
|
||||
app.exec()
|
||||
stopped = True
|
||||
player.stop()
|
27
widgets.py
Normal file
27
widgets.py
Normal file
@ -0,0 +1,27 @@
|
||||
from PySide6.QtWidgets import QLabel
|
||||
from PySide6.QtGui import QPainter, QColor
|
||||
from PySide6.QtCore import Qt
|
||||
|
||||
|
||||
class OutlinedLabel(QLabel):
|
||||
def __init__(self, text='', outline_color=QColor(0, 0, 0), outline_width=2, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.setText(text)
|
||||
self.outline_color = outline_color
|
||||
self.outline_width = outline_width
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QPainter(self)
|
||||
painter.setFont(self.font())
|
||||
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
|
||||
|
||||
# 绘制描边
|
||||
painter.setPen(self.outline_color)
|
||||
for dx in range(-self.outline_width, self.outline_width + 1):
|
||||
for dy in range(-self.outline_width, self.outline_width + 1):
|
||||
if abs(dx) + abs(dy) <= self.outline_width:
|
||||
painter.drawText(self.rect().adjusted(dx, dy, dx, dy), Qt.AlignmentFlag.AlignCenter, self.text())
|
||||
|
||||
# 绘制文本
|
||||
painter.setPen(self.palette().windowText().color())
|
||||
painter.drawText(self.rect(), Qt.AlignmentFlag.AlignCenter, self.text())
|
Loading…
Reference in New Issue
Block a user