Skip to content

Cover Image and Encoding bug fixes #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Pipfile
Pipfile.lock
64 changes: 52 additions & 12 deletions Serato-Now-Playing/SeratoNowPlaying.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
from time import sleep, time
import os
import sys
from eyed3.id3.tag import Tag
import mimetypes

# define global variables
ini = paused = 0
Expand Down Expand Up @@ -60,6 +62,7 @@ def __init__(self, cparser, cfile):
self.libpath = config.get('Settings', 'libpath')
self.url = config.get('Settings', 'url')
self.file = config.get('Settings', 'file')
self.cover = is_bool(config.get('Settings', 'cover'))
self.interval = config.get('Settings', 'interval')
self.delay = config.get('Settings', 'delay')
self.multi = is_bool(config.get('Settings', 'multi'))
Expand All @@ -80,11 +83,12 @@ def __init__(self, cparser, cfile):
except configparser.NoOptionError:
pass

def put(self, local, libpath, url, file, interval, delay, multi, quote, a_pref, a_suff, s_pref, s_suff, notif):
def put(self, local, libpath, url, file, interval, delay, multi, quote, a_pref, a_suff, s_pref, s_suff, notif, cover):
self.cparser.set('Settings', 'local', local)
self.cparser.set('Settings', 'libpath', libpath)
self.cparser.set('Settings', 'url', url)
self.cparser.set('Settings', 'file', file)
self.cparser.set('Settings', 'cover', cover)
self.cparser.set('Settings', 'interval', interval)
self.cparser.set('Settings', 'delay', delay)
self.cparser.set('Settings', 'multi', str(multi))
Expand Down Expand Up @@ -115,6 +119,7 @@ def __init__(self, conf, conffile, icn):
self.layoutH0a = QHBoxLayout()
self.layoutH1 = QHBoxLayout()
self.layoutH2 = QHBoxLayout()
self.layoutH8 = QHBoxLayout()
self.layoutH3 = QHBoxLayout()
self.layoutH4 = QHBoxLayout()
self.layoutH5 = QHBoxLayout()
Expand Down Expand Up @@ -237,6 +242,17 @@ def __init__(self, conf, conffile, icn):
self.multiDesc.setStyleSheet('color: grey')
self.layoutH2.addWidget(self.multiDesc)
self.layoutV.addLayout(self.layoutH2)
# cover
self.coverLabel = QLabel('Cover File')
self.coverLabel.setFont(self.fBold)
self.layoutV.addWidget(self.coverLabel)
self.coverCbox = QCheckBox()
self.coverCbox.setMaximumWidth(25)
self.layoutH8.addWidget(self.coverCbox)
self.coverDesc = QLabel('Write a cover image to the same folder as track information.')
self.coverDesc.setStyleSheet('color: grey')
self.layoutH8.addWidget(self.coverDesc)
self.layoutV.addLayout(self.layoutH8)
# quotes
self.quoteLabel = QLabel('Song Quote Indicator')
self.quoteLabel.setFont(self.fBold)
Expand Down Expand Up @@ -323,6 +339,7 @@ def upd_win(self):
self.intervalEdit.setText(str(c.interval))
self.delayEdit.setText(str(c.delay))
self.multiCbox.setChecked(c.multi)
self.coverCbox.setChecked(c.cover)
self.quoteCbox.setChecked(c.quote)
self.a_prefixEdit.setText(c.a_pref)
self.a_suffixEdit.setText(c.a_suff)
Expand All @@ -339,6 +356,7 @@ def upd_conf(self):
interval = self.intervalEdit.text()
delay = self.delayEdit.text()
multi = str(self.multiCbox.isChecked())
cover = str(self.coverCbox.isChecked())
quote = str(self.quoteCbox.isChecked())
a_pref = self.a_prefixEdit.text().replace(" ", "|_0")
a_suff = self.a_suffixEdit.text().replace(" ", "|_0")
Expand All @@ -347,7 +365,7 @@ def upd_conf(self):
notif = str(self.notifCbox.isChecked())

c = ConfigFile(self.conf, self.conffile)
c.put(local, libpath, url, file, interval, delay, multi, quote, a_pref, a_suff, s_pref, s_suff, notif)
c.put(local, libpath, url, file, interval, delay, multi, quote, a_pref, a_suff, s_pref, s_suff, notif, cover)

# radio button action
def on_radiobutton_select(self, b):
Expand Down Expand Up @@ -581,7 +599,7 @@ def gettrack(c, t): # get last played track
sera_dir = conf.libpath
hist_dir = os.path.abspath(os.path.join(sera_dir, "History"))
sess_dir = os.path.abspath(os.path.join(hist_dir, "Sessions"))
tdat = getlasttrack(sess_dir)
tdat = getlasttrack(sess_dir, conf)
if tdat is False:
return False
else: # remotely derived
Expand Down Expand Up @@ -657,7 +675,7 @@ def getsessfile(directory, showlast=True):
return file


def getlasttrack(s): # function to parse out last track from binary session file
def getlasttrack(s, conf): # function to parse out last track from binary session file
# get latest session file
sess = getsessfile(s)
if sess is False:
Expand All @@ -670,10 +688,10 @@ def getlasttrack(s): # function to parse out last track from binary session fil
with open(sess, "rb") as f:
raw = f.read()

# decode and split out last track of session file
binstr = raw.decode('latin').rsplit('oent') # split tracks
byt = binstr[-1] # last track chunk
# print(byt)
index = raw.rfind(b'\x6f\x65\x6e\x74')
bytr = raw[index:] # last track chunk
byt = bytr.decode('latin')

# determine if playing
if (byt.find('\x00\x00\x00-') > 0 or # ejected or is
byt.find('\x00\x00\x00\x003') > 0): # loaded, but not played
Expand Down Expand Up @@ -701,16 +719,38 @@ def getlasttrack(s): # function to parse out last track from binary session fil
if ay == -1:
ay = byt.find('\x00\x00\x00\x00\x0f')

# parse song file
if(conf.cover == 1):
mx = byt.find('\x00\x00\x00\x02') # field start

if mx > 0:
my = byt.find('\x00\x00\x00\x06') # field end

if mx > 0:
bin_mp3 = bytr[mx + 4:my]
bin_mp3 = bin_mp3[4:-2]
str_mp3 = bin_mp3.decode('utf-16-be')
tag = Tag()
tag.parse(str_mp3)
dir_name = os.path.dirname(os.path.abspath(conf.file))
if len(tag.images) > 0:
extension = mimetypes.guess_extension(tag.images[0].mime_type)
f = open(os.path.join(dir_name, 'cover'+extension), 'wb')
f.write(tag.images[0].image_data)
f.close()

# cleanup and return
if ax > 0:
bin_artist = byt[ax + 4:ay].replace('\x00', '')
str_artist = bin_artist[2:]
bin_artist = bytr[ax + 4:ay]
bin_artist = bin_artist[5:-1]
str_artist = bin_artist.decode('utf-16-be')
else:
str_artist = '.'

if sx > 0:
bin_song = byt[sx + 4:sy].replace('\x00', '')
str_song = bin_song[2:]
bin_song = bytr[sx + 4:sy]
bin_song = bin_song[5:-1]
str_song = bin_song.decode('utf-16-be')
else:
str_song = '.'

Expand Down
2 changes: 1 addition & 1 deletion Serato-Now-Playing/bin/config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ a_suff =
s_pref =
s_suff =
notif = False

cover = False
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
PyQT5
polling2
lxml
requests
eyed3