mirror of
https://github.com/rembo10/headphones.git
synced 2026-05-21 19:07:44 +01:00
Added librarysync, added bitrate and location to db and album template
This commit is contained in:
+5
-3
@@ -173,17 +173,19 @@ table#album_table td#have { vertical-align: middle; }
|
||||
|
||||
img.albumArt { float: left; padding-right: 5px; }
|
||||
div#albumheader { padding-top: 48px; height: 200px; }
|
||||
div#track_wrapper { padding-top: 20px; text-align: center; font-size: 16px; }
|
||||
div#track_wrapper { margin-left: -50px; padding-top: 20px; font-size: 16px; width: 100%; }
|
||||
|
||||
table#track_table th#number { text-align: right; min-width: 20px; }
|
||||
table#track_table th#name { text-align: center; min-width: 350px; }
|
||||
table#track_table th#duration { width: 175px; text-align: center; min-width: 100px; }
|
||||
table#track_table th#have { width: 175px; text-align: center; min-width: 100px; }
|
||||
table#track_table th#location { text-align: center; min-width: 200px; }
|
||||
table#track_table th#bitrate { text-align: center; min-width: 75px; }
|
||||
|
||||
table#track_table td#number { vertical-align: middle; text-align: right; }
|
||||
table#track_table td#name { vertical-align: middle; text-align: center; }
|
||||
table#track_table td#duration { vertical-align: middle; text-align: center; }
|
||||
table#track_table td#have { vertical-align: middle; text-align: center; }
|
||||
table#track_table td#location { vertical-align: middle; text-align: center; font-size: 11px; }
|
||||
table#track_table td#location { vertical-align: middle; text-align: center; }
|
||||
|
||||
table#history_table { background-color: white; width: 100%; }
|
||||
|
||||
|
||||
@@ -51,20 +51,24 @@
|
||||
<th id="number">#</th>
|
||||
<th id="name">Track Title</th>
|
||||
<th id="duration">Duration</th>
|
||||
<th id="location"></th>
|
||||
<th id="location">Local File</th>
|
||||
<th id="bitrate">Bit Rate</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%
|
||||
i = 0
|
||||
%>
|
||||
%for track in tracks:
|
||||
<%
|
||||
i += 1
|
||||
if track['Location']:
|
||||
grade = 'A'
|
||||
location = track['Location']
|
||||
else:
|
||||
grade = 'Z'
|
||||
location = ''
|
||||
|
||||
if track['BitRate']:
|
||||
bitrate = str(track['BitRate']/1000) + ' kbps'
|
||||
else:
|
||||
bitrate = ''
|
||||
|
||||
try:
|
||||
trackduration = helpers.convert_milliseconds(track['TrackDuration'])
|
||||
@@ -72,10 +76,11 @@
|
||||
trackduration = 'n/a'
|
||||
%>
|
||||
<tr class="grade${grade}">
|
||||
<td id="number">${i}</td>
|
||||
<td id="number">${track['TrackNumber']}</td>
|
||||
<td id="name">${track['TrackTitle']}</td>
|
||||
<td id="duration">${trackduration}</td>
|
||||
<td id="location">${track['Location']}</td>
|
||||
<td id="location">${location}</td>
|
||||
<td id="bitrate">${bitrate}</td>
|
||||
</tr>
|
||||
%endfor
|
||||
</tbody>
|
||||
|
||||
@@ -51,33 +51,36 @@
|
||||
<th id="number">#</th>
|
||||
<th id="name">Track Title</th>
|
||||
<th id="duration">Duration</th>
|
||||
<th id="have"></th>
|
||||
<th id="location">Local File</th>
|
||||
<th id="bitrate">Bit Rate</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%
|
||||
i = 0
|
||||
%>
|
||||
%for track in tracks:
|
||||
<%
|
||||
i += 1
|
||||
have = myDB.select('SELECT TrackTitle from have WHERE ArtistName like ? AND AlbumTitle like ? AND TrackTitle like ?', [track['ArtistName'], track['AlbumTitle'], track['TrackTitle']])
|
||||
if len(have):
|
||||
if track['Location']:
|
||||
grade = 'A'
|
||||
check = '<img src="images/checkmark.png" alt="checkmark">'
|
||||
location = track['Location']
|
||||
else:
|
||||
grade = 'Z'
|
||||
check = ''
|
||||
location = ''
|
||||
|
||||
if track['BitRate']:
|
||||
bitrate = str(track['BitRate']/1000) + ' kbps'
|
||||
else:
|
||||
bitrate = ''
|
||||
|
||||
try:
|
||||
trackduration = helpers.convert_milliseconds(track['TrackDuration'])
|
||||
except:
|
||||
trackduration = 'n/a'
|
||||
%>
|
||||
<tr class="grade${grade}">
|
||||
<td id="number">${i}</td>
|
||||
<td id="number">${track['TrackNumber']}</td>
|
||||
<td id="name">${track['TrackTitle']}</td>
|
||||
<td id="duration">${trackduration}</td>
|
||||
<td id="have">${check}</td>
|
||||
<td id="location">${location}</td>
|
||||
<td id="bitrate">${bitrate}</td>
|
||||
</tr>
|
||||
%endfor
|
||||
</tbody>
|
||||
|
||||
@@ -11,7 +11,7 @@ from lib.configobj import ConfigObj
|
||||
|
||||
import cherrypy
|
||||
|
||||
from headphones import updater, searcher, importer, versioncheck, logger, postprocessor, version, sab
|
||||
from headphones import updater, searcher, importer, versioncheck, logger, postprocessor, version, sab, librarysync
|
||||
from headphones.common import *
|
||||
|
||||
FULL_PATH = None
|
||||
@@ -439,7 +439,7 @@ def dbcheck():
|
||||
c=conn.cursor()
|
||||
c.execute('CREATE TABLE IF NOT EXISTS artists (ArtistID TEXT UNIQUE, ArtistName TEXT, ArtistSortName TEXT, DateAdded TEXT, Status TEXT, IncludeExtras INTEGER, LatestAlbum TEXT, ReleaseDate TEXT, AlbumID TEXT, HaveTracks INTEGER, TotalTracks INTEGER)')
|
||||
c.execute('CREATE TABLE IF NOT EXISTS albums (ArtistID TEXT, ArtistName TEXT, AlbumTitle TEXT, AlbumASIN TEXT, ReleaseDate TEXT, DateAdded TEXT, AlbumID TEXT UNIQUE, Status TEXT, Type TEXT)')
|
||||
c.execute('CREATE TABLE IF NOT EXISTS tracks (ArtistID TEXT, ArtistName TEXT, AlbumTitle TEXT, AlbumASIN TEXT, AlbumID TEXT, TrackTitle TEXT, TrackDuration, TrackID TEXT, TrackNumber INTEGER, Location TEXT)')
|
||||
c.execute('CREATE TABLE IF NOT EXISTS tracks (ArtistID TEXT, ArtistName TEXT, AlbumTitle TEXT, AlbumASIN TEXT, AlbumID TEXT, TrackTitle TEXT, TrackDuration, TrackID TEXT, TrackNumber INTEGER, Location TEXT, BitRate INTEGER)')
|
||||
c.execute('CREATE TABLE IF NOT EXISTS snatched (AlbumID TEXT, Title TEXT, Size INTEGER, URL TEXT, DateAdded TEXT, Status TEXT, FolderName TEXT)')
|
||||
c.execute('CREATE TABLE IF NOT EXISTS have (ArtistName TEXT, AlbumTitle TEXT, TrackNumber TEXT, TrackTitle TEXT, TrackLength TEXT, BitRate TEXT, Genre TEXT, Date TEXT, TrackID TEXT)')
|
||||
c.execute('CREATE TABLE IF NOT EXISTS lastfmcloud (ArtistName TEXT, ArtistID TEXT, Count INTEGER)')
|
||||
@@ -494,7 +494,12 @@ def dbcheck():
|
||||
try:
|
||||
c.execute('SELECT Location from tracks')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE tracks ADD COLUMN Location TEXT')
|
||||
c.execute('ALTER TABLE tracks ADD COLUMN Location TEXT')
|
||||
|
||||
try:
|
||||
c.execute('SELECT BitRate from tracks')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE tracks ADD COLUMN BitRate INTEGER')
|
||||
|
||||
conn.commit()
|
||||
c.close()
|
||||
|
||||
+32
-1
@@ -143,4 +143,35 @@ def extract_logline(s):
|
||||
message = match.group("message")
|
||||
return (timestamp, level, thread, message)
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
||||
def extract_song_data(s):
|
||||
|
||||
#headphones default format
|
||||
music_dir = headphones.MUSIC_DIR
|
||||
folder_format = headphones.FOLDER_FORMAT
|
||||
file_format = headphones.FILE_FORMAT
|
||||
|
||||
full_format = os.path.join(headphones.MUSIC_DIR)
|
||||
pattern = re.compile(r'(?P<name>.*?)\s\-\s(?P<album>.*?)\s\[(?P<year>.*?)\]', re.VERBOSE)
|
||||
match = pattern.match(s)
|
||||
|
||||
if match:
|
||||
name = match.group("name")
|
||||
album = match.group("album")
|
||||
year = match.group("year")
|
||||
return (name, album, year)
|
||||
else:
|
||||
logger.info("Couldn't parse " + s + " into a valid default format")
|
||||
|
||||
#newzbin default format
|
||||
pattern = re.compile(r'(?P<name>.*?)\s\-\s(?P<album>.*?)\s\((?P<year>\d+?\))', re.VERBOSE)
|
||||
match = pattern.match(s)
|
||||
if match:
|
||||
name = match.group("name")
|
||||
album = match.group("album")
|
||||
year = match.group("year")
|
||||
return (name, album, year)
|
||||
else:
|
||||
logger.info("Couldn't parse " + s + " into a valid Newbin format")
|
||||
return (name, album, year)
|
||||
@@ -0,0 +1,160 @@
|
||||
import os
|
||||
import glob
|
||||
|
||||
from lib.beets.mediafile import MediaFile
|
||||
|
||||
import headphones
|
||||
from headphones import db, logger
|
||||
|
||||
def LibraryScan():
|
||||
|
||||
if not headphones.MUSIC_DIR:
|
||||
return
|
||||
|
||||
unmatched_files = []
|
||||
new_artists = []
|
||||
|
||||
myDB = db.DBConnection()
|
||||
|
||||
for r,d,f in os.walk(headphones.MUSIC_DIR):
|
||||
for files in f:
|
||||
# MEDIA_FORMATS = music file extensions, e.g. mp3, flac, etc
|
||||
if any(files.endswith('.' + x) for x in headphones.MEDIA_FORMATS):
|
||||
|
||||
file = unicode(os.path.join(r, files), "utf-8")
|
||||
print repr(file)
|
||||
# Try to read the metadata
|
||||
try:
|
||||
f = MediaFile(file)
|
||||
except:
|
||||
logger.error('Cannot read file: ' + file)
|
||||
continue
|
||||
|
||||
# Try to match on metadata first,
|
||||
if f.mb_trackid:
|
||||
print 'has track id:' + repr(f.mb_trackid)
|
||||
# Wondering if theres a better way to do this -> do one thing if the row exists,
|
||||
# do something else if it doesn't
|
||||
track = myDB.action('SELECT TrackID from tracks WHERE TrackID=?', [f.mb_trackid]).fetchone()
|
||||
|
||||
if not track:
|
||||
if f.albumartist:
|
||||
new_artists.append(f.albumartist)
|
||||
elif f.artist:
|
||||
new_artists.append(f.artist)
|
||||
else:
|
||||
unmatched_files.append(file)
|
||||
|
||||
else:
|
||||
myDB.action('UPDATE tracks SET Location=?, BitRate=? WHERE TrackID=?', [file, f.bitrate, track['TrackID']])
|
||||
continue
|
||||
|
||||
elif f.albumartist and f.album and f.title:
|
||||
|
||||
track = myDB.action('SELECT TrackID from tracks WHERE ArtistName LIKE ? AND AlbumTitle LIKE ? AND TrackTitle LIKE ?', [f.albumartist, f.album, f.title]).fetchone()
|
||||
|
||||
if not track:
|
||||
new_artists.append(f.albumartist)
|
||||
|
||||
else:
|
||||
myDB.action('UPDATE tracks SET Location=?, BitRate=? WHERE TrackID=?', [file, f.bitrate, track['TrackID']])
|
||||
|
||||
elif f.artist and f.album and f.title:
|
||||
|
||||
track = myDB.action('SELECT TrackID from tracks WHERE ArtistName LIKE ? AND AlbumTitle LIKE ? AND TrackTitle LIKE ?', [f.artist, f.album, f.title]).fetchone()
|
||||
|
||||
if not track:
|
||||
new_artists.append(file)
|
||||
else:
|
||||
myDB.action('UPDATE tracks SET Location=?, BitRate=? WHERE TrackID=?', [file, f.bitrate, track['TrackID']])
|
||||
|
||||
else:
|
||||
continue
|
||||
|
||||
# Try to parse the unmatched files based on the folder & file formats in the config
|
||||
for file in unmatched_files:
|
||||
# Will do later
|
||||
pass
|
||||
|
||||
# Now check empty file paths to see if we can find a match based on their folder format
|
||||
tracks = myDB.select('SELECT * from tracks WHERE Location=NULL')
|
||||
for track in tracks:
|
||||
release = myDB.action('SELECT * from albums WHERE AlbumID=?', [track['AlbumID']]).fetchone()
|
||||
|
||||
try:
|
||||
year = release['ReleaseDate'][:4]
|
||||
except TypeError:
|
||||
year = ''
|
||||
|
||||
artist = release['ArtistName'].replace('/', '_')
|
||||
album = release['AlbumTitle'].replace('/', '_')
|
||||
|
||||
if release['ArtistName'].startswith('The '):
|
||||
sortname = release['ArtistName'][4:]
|
||||
else:
|
||||
sortname = release['ArtistName']
|
||||
|
||||
if sortname.isdigit():
|
||||
firstchar = '0-9'
|
||||
else:
|
||||
firstchar = sortname[0]
|
||||
|
||||
|
||||
albumvalues = { 'artist': artist,
|
||||
'album': album,
|
||||
'year': year,
|
||||
'first': firstchar,
|
||||
}
|
||||
|
||||
|
||||
folder = helpers.replace_all(headphones.FOLDER_FORMAT, albumvalues)
|
||||
folder = folder.replace('./', '_/').replace(':','_').replace('?','_')
|
||||
|
||||
if folder.endswith('.'):
|
||||
folder = folder.replace(folder[len(folder)-1], '_')
|
||||
|
||||
if not track['TrackNumber']:
|
||||
tracknumber = ''
|
||||
else:
|
||||
tracknumber = '%02d' % track['TrackNumber']
|
||||
|
||||
trackvalues = { 'tracknumber': tracknumber,
|
||||
'title': track['TrackTitle'],
|
||||
'artist': release['ArtistName'],
|
||||
'album': release['AlbumTitle'],
|
||||
'year': year
|
||||
}
|
||||
|
||||
new_file_name = helpers.replace_all(headphones.FILE_FORMAT, trackvalues).replace('/','_') + '.*'
|
||||
|
||||
new_file_name = new_file_name.replace('?','_').replace(':', '_')
|
||||
|
||||
full_path_to_file = os.path.join(headphones.MUSIC_DIR, folder, new_file_name)
|
||||
|
||||
print 'Full path to file is: ' + repr(full_path_to_file)
|
||||
|
||||
if glob.glob(full_path_to_file):
|
||||
myDB.action('UPDATE tracks SET Location=? WHERE TrackID=?', [full_path_to_file, track['TrackID']])
|
||||
|
||||
# Try to insert the appropriate track id so we don't have to keep doing this
|
||||
try:
|
||||
f = MediaFile(full_path_to_file)
|
||||
f.mb_trackid = track['TrackID']
|
||||
myDB.action('UPDATE tracks SET BitRate=? WHERE TrackID=?', [f.bitrate, track['TrackID']])
|
||||
f.save()
|
||||
except:
|
||||
logger.error('Error embedding track id into: %s' % full_path_to_file)
|
||||
|
||||
# Lastly, clean up any old paths that don't exist
|
||||
tracks = myDB.select('SELECT Location, TrackID from tracks WHERE Location IS NOT NULL')
|
||||
for track in tracks:
|
||||
if not os.path.isfile(track['Location']):
|
||||
myDB.action('UPDATE tracks SET Location=? WHERE TrackID=?', [None, track['TrackID']])
|
||||
|
||||
# Clean up the new artist list
|
||||
unique_artists = {}.fromkeys(new_artists).keys()
|
||||
current_artists = myDB.action('SELECT ArtistName from artists').fetchall()
|
||||
|
||||
artist_list = [f for f in unique_artists if f not in current_artists]
|
||||
|
||||
logger.info('Found %i artists to import: ' % len(artist_list))
|
||||
Reference in New Issue
Block a user