Skip to content

Commit

Permalink
Add status bar, lyrics display, .lrc file parser
Browse files Browse the repository at this point in the history
Status bar is for lyrics displaying
There are still improvement
  • Loading branch information
ManHinnn0509 committed Nov 29, 2021
1 parent 6dc56d9 commit ef7008d
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 1 deletion.
174 changes: 174 additions & 0 deletions lyricsdisplay.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
from mp3player import MP3Player

class LyricsDisplay:
def __init__(self, mp3Player: MP3Player, dirPath: str, mp3Name: str) -> None:
self.mp3Player = mp3Player
self.master = mp3Player.master

self.dirPath = dirPath
self.mp3Name = mp3Name

self.songName = mp3Name[:-4]

self.filePath = f'{dirPath}/{self.songName}.lrc'
self.lrcContent = self.__readLRC()

self.lyricsDict = None
if (self.lrcContent != None):
parser = LRC_Parser(self.lrcContent)
self.lyricsDict = parser.lrcDict

def displayLyrics(self):
sec = self.mp3Player.timeSlider.posTime
if (sec == -1):
sec = 0

lyrics = self.lyricsDict.get(sec, None)
if (lyrics != None):
self.mp3Player.statusBar.updateText(lyrics)

def hasLyrics(self):
if (self.lrcContent == None):
# print('self.lrcContent == None')
return False

if (self.lyricsDict == None):
# print('self.lyricsDict == None')
return False

if (len(self.lyricsDict) == 0):
# print('len(self.lyricsDict) == 0')
return False

return True

def __readLRC(self, encoding='UTF-8'):
try:
with open(self.filePath, 'r', encoding=encoding) as f:
return f.read()
except:
return None

"""
Just a simple class I created.
This class is for converting the .lrc file content into a dict() like this:
{
"31":"She's got a smile it seems to me",
"35":"Reminds me of childhood memories",
"38":"Where everything",
"40":"Was as fresh as the bright blue sky",
"46":"Now and then when I see her face",
"50":"She takes me away to that special place",
"53":"And if I'd stare too long",
"55":"I'd probably break down and cry",
"61":"Oh, oh, oh",
"64":"Sweet child o' mine",
"69":"Oh, oh, oh, oh",
"71":"Sweet love of mine",
"92":"She's got eyes of the bluest skies",
"96":"As if they thought of rain",
"100":"I hate to look into those eyes",
"103":"And see an ounce of pain",
"107":"Her hair reminds me of a warm safe place",
"111":"Where as a child I'd hide",
"115":"And pray for the thunder",
"117":"And the rain",
"119":"To quietly pass me by",
"123":"Oh, oh, oh",
"125":"Sweet child o' mine",
"130":"Oh, oh, oh, oh",
"133":"Sweet love of mine",
"138":"Oh, oh, oh, oh",
"140":"Sweet child o' mine",
"146":"Oh, oh, oh, oh",
"149":"Sweet love of mine",
"222":"Oh, oh, oh, oh",
"223":"Oh oh sweet love of mine",
"224":"Where do we go now?",
"225":"Where do we go?",
"229":"(Where do we go now?)",
"233":"Oh where do we go now? (Where do we go?)",
"235":"Where do we go? (Sweet child)",
"237":"Oh where do we go now?",
"240":"Ay ay ay ay (where do we go now, where do we go)",
"245":"Oh where do we go now?",
"247":"Where do we go?",
"250":"Oh, where do we go now?",
"255":"Oh, where do we go?",
"258":"Oh where do we go now?",
"262":"Where do we go?",
"265":"Oh, where do we go now?",
"269":"No, no, no, no, no, no",
"271":"Sweet child",
"273":"Sweet child of mine"
}
Uses second as KEY and the lyrics as VALUE
"""
class LRC_Parser:

def __init__(self, lrcContent: str) -> None:
self.lrcContent = lrcContent
self.lrcLines = [i for i in lrcContent.split('\n') if (i != '\n' or i != '')]

self.offset = self.__getOffset()
self.lrcDict = self.__processContent()

def __getOffset(self):
try:
for line in self.lrcLines:
if (line.startswith('[offset:')):
line = line.replace(' ', '')
offsetMS = line[8:-1]
return float(int(offsetMS) / 1000)
except:
pass

return 0

def __processContent(self):
d = {}
for line in self.lrcLines:
lrcTime, lyrics = self.__processLine(line)

secs = self.__convertTime(lrcTime)
if (secs != None):
d[secs] = lyrics

return d

def __processLine(self, line: str):
"""
Splits out the time & lyrics
"""

parts = line.split(']')

time = parts.pop(0)
time = time[1::] # Removes the '[' character

# The rest of the itesm in parts are just the lyrics
# Form them back like how we splitted it
lyrics = ']'.join(parts)
lyrics = lyrics.strip()

return time, lyrics

def __convertTime(self, lyricsTime: str, returnFloat=False):
parts = lyricsTime.split(":")

try:
mins = parts[0]
secs = parts[-1]

result = float(secs)
result += int(mins) * 60
result += self.offset

if not (returnFloat):
# result = int(result)
result = round(result)

return result
except:
return None
24 changes: 23 additions & 1 deletion mp3player.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
class MP3Player:

def __init__(self, dirPath: str) -> None:

from songlist import SongList
from controlmenu import ControlMenu
from timeslider import TimeSlider
from statusbar import StatusBar

master = Tk()
self.master = master
Expand All @@ -39,8 +41,12 @@ def __init__(self, dirPath: str) -> None:
self.playedAnySongs = False

self.job = None

# --- Widgets

statusBar = StatusBar(mp3Player=self)
self.statusBar = statusBar

songList = SongList(mp3Player=self)
self.songList = songList

Expand All @@ -50,6 +56,8 @@ def __init__(self, dirPath: str) -> None:
timeSlider = TimeSlider(mp3Player=self)
self.timeSlider = timeSlider

self.lyricsDisplay = None

def playSong(self, resetPos=True):
self.playedAnySongs = True

Expand All @@ -72,6 +80,8 @@ def playSong(self, resetPos=True):
# Resets the counting
if (resetPos):
self.timeSlider.changePosition(resetPos=True)
# Clears the previous lyrics lines
self.statusBar.updateText('')

# Loop inf. times if pass in -1
loop = -1 if (self.loopEnabled) else 0
Expand All @@ -86,6 +96,12 @@ def playSong(self, resetPos=True):
self.isPlaying = True
# Reset the button's text since it's playing now
self.controlMenu.pauseResumeButton.config(text='Pause')

if (resetPos):
from lyricsdisplay import LyricsDisplay
self.lyricsDisplay = LyricsDisplay(
mp3Player=self, dirPath=MP3_FOLDER_PATH, mp3Name=selectedSong
)

self.__countPosition()

Expand All @@ -95,8 +111,14 @@ def playSong(self, resetPos=True):

def __countPosition(self):
self.job = self.master.after(1000, self.__countPosition)

self.timeSlider.changePosition(counting=True, setPos=True)

# Always keep this part under the changePosition() call
if (self.lyricsDisplay != None):
if (self.lyricsDisplay.hasLyrics()):
self.lyricsDisplay.displayLyrics()

# For init.
def __getMP3(self):
return [i for i in os.listdir(self.dirPath) if (i.endswith('.mp3'))]
Expand Down
27 changes: 27 additions & 0 deletions statusbar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import tkinter as tk
from tkinter import *

from mp3player import MP3Player

class StatusBar:

def __init__(self, mp3Player: MP3Player) -> None:
self.mp3Player = mp3Player
self.master = mp3Player.master

text = StringVar()
text.set('')
self.text = text

statusBar = Label(
self.master,
textvariable=self.text,
relief=SUNKEN,
anchor='w'
)
self.statusBar = statusBar

self.statusBar.pack(side=BOTTOM, fill=X)

def updateText(self, newText: str):
self.text.set(newText)

0 comments on commit ef7008d

Please sign in to comment.