mirror of
https://github.com/rembo10/headphones.git
synced 2026-04-01 02:29:26 +01:00
Merge branch 'release-selection' into develop
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<%inherit file="base.html" />
|
||||
<%!
|
||||
<%!
|
||||
from headphones import db, helpers
|
||||
myDB = db.DBConnection()
|
||||
%>
|
||||
@@ -16,7 +16,31 @@
|
||||
%else:
|
||||
<a id="menu_link_retry" href="#" onclick="doAjaxCall('queueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}&new=False', $(this),true);" data-success="Retrying the same version of '${album['AlbumTitle']}'">Retry Download</a>
|
||||
<a id="menu_link_new" href="#" onclick="doAjaxCall('queueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}&new=True', $(this),true);" data-success="Looking for a new version of '${album['AlbumTitle']}'">Try New Version</a>
|
||||
%endif
|
||||
%endif
|
||||
<a class="menu_link_edit" id="album_chooser" href="#">Choose Alternate Version</a>
|
||||
<div id="dialog" title="Choose an Alternate Release" style="display:none" class="configtable">
|
||||
<div class="links">
|
||||
<%
|
||||
alternate_albums = myDB.select("SELECT * from allalbums WHERE AlbumID=?", [album['AlbumID']])
|
||||
%>
|
||||
%if not alternate_albums:
|
||||
<p>No alternate versions found. Try refreshing the artist</p>
|
||||
%else:
|
||||
%for alternate_album in alternate_albums:
|
||||
<%
|
||||
track_count = len(myDB.select("SELECT * from alltracks WHERE ReleaseID=?", [alternate_album['ReleaseID']]))
|
||||
have_track_count = len(myDB.select("SELECT * from alltracks WHERE ReleaseID=? AND Location IS NOT NULL", [alternate_album['ReleaseID']]))
|
||||
if alternate_album['AlbumID'] == alternate_album['ReleaseID']:
|
||||
alternate_album_name = "Headphones Default Release [" + have_track_count + "/" track_count + " tracks]"
|
||||
else:
|
||||
alternate_album_name = alternate_album['AlbumTitle'] + " (" + alternate_album['ReleaseCountry'] + ", " + alternate_album['ReleaseFormat'] + ") [" + have_track_count + "/" track_count + " tracks]"
|
||||
|
||||
%>
|
||||
<a href="#" onclick="doAjaxCall('switchAlbum?AlbumID=${album['AlbumID']}&ReleaseID=${alternate_album['ReleaseID']}', $(this), 'table');" data-success="Switched release to: ${alternate_album_name}">${alternate_album_name}</a><br>
|
||||
%endfor
|
||||
%endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="artistPage?ArtistID=${album['ArtistID']}" class="back">« Back to ${album['ArtistName']}</a>
|
||||
@@ -82,7 +106,7 @@
|
||||
trackduration = 'n/a'
|
||||
|
||||
if not track['Format']:
|
||||
format = 'Unknown'
|
||||
format = ''
|
||||
else:
|
||||
format = track['Format']
|
||||
%>
|
||||
@@ -144,6 +168,10 @@
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#album_chooser').click(function() {
|
||||
$('#dialog').dialog();
|
||||
return false;
|
||||
});
|
||||
getAlbumInfo();
|
||||
getAlbumArt();
|
||||
initActions();
|
||||
|
||||
@@ -257,7 +257,7 @@ function doAjaxCall(url,elem,reload,form) {
|
||||
var dataError = $(elem).data('error');
|
||||
if (typeof dataError === "undefined") {
|
||||
// Standard Message when variable is not set
|
||||
var dataError = "There was a error";
|
||||
var dataError = "There was an error";
|
||||
}
|
||||
// Get Success & Error message from inline data, else use standard message
|
||||
var succesMsg = $("<div class='msg'><span class='ui-icon ui-icon-check'></span>" + dataSucces + "</div>");
|
||||
|
||||
@@ -719,10 +719,12 @@ def dbcheck():
|
||||
conn=sqlite3.connect(DB_FILE)
|
||||
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, LastUpdated TEXT, ArtworkURL TEXT, ThumbURL TEXT)')
|
||||
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, ArtworkURL TEXT, ThumbURL 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, CleanName TEXT, Format TEXT)')
|
||||
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, ArtworkURL TEXT, ThumbURL TEXT, ReleaseID TEXT, ReleaseCountry TEXT, ReleaseFormat TEXT)') # ReleaseFormat here means CD,Digital,Vinyl, etc. If using the default Headphones hybrid release, ReleaseID will equal AlbumID (AlbumID is releasegroup id)
|
||||
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, CleanName TEXT, Format TEXT, ReleaseID TEXT)') # Format here means mp3, flac, etc.
|
||||
c.execute('CREATE TABLE IF NOT EXISTS allalbums (ArtistID TEXT, ArtistName TEXT, AlbumTitle TEXT, AlbumASIN TEXT, ReleaseDate TEXT, AlbumID TEXT, Type TEXT, ReleaseID TEXT, ReleaseCountry TEXT, ReleaseFormat TEXT)')
|
||||
c.execute('CREATE TABLE IF NOT EXISTS alltracks (ArtistID TEXT, ArtistName TEXT, AlbumTitle TEXT, AlbumASIN TEXT, AlbumID TEXT, TrackTitle TEXT, TrackDuration, TrackID TEXT, TrackNumber INTEGER, Location TEXT, BitRate INTEGER, CleanName TEXT, Format TEXT, ReleaseID TEXT)')
|
||||
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, Location TEXT, CleanName TEXT, Format 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, Location TEXT, CleanName TEXT, Format TEXT, Matched TEXT)') # Matched is a temporary value used to see if there was a match found in alltracks
|
||||
c.execute('CREATE TABLE IF NOT EXISTS lastfmcloud (ArtistName TEXT, ArtistID TEXT, Count INTEGER)')
|
||||
c.execute('CREATE TABLE IF NOT EXISTS descriptions (ArtistID TEXT, ReleaseGroupID TEXT, ReleaseID TEXT, Summary TEXT, Content TEXT, LastUpdated TEXT)')
|
||||
c.execute('CREATE TABLE IF NOT EXISTS blacklist (ArtistID TEXT UNIQUE)')
|
||||
@@ -846,6 +848,31 @@ def dbcheck():
|
||||
c.execute('SELECT LastUpdated from descriptions')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE descriptions ADD COLUMN LastUpdated TEXT DEFAULT NULL')
|
||||
|
||||
try:
|
||||
c.execute('SELECT ReleaseID from albums')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE albums ADD COLUMN ReleaseID TEXT DEFAULT NULL')
|
||||
|
||||
try:
|
||||
c.execute('SELECT ReleaseFormat from albums')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE albums ADD COLUMN ReleaseFormat TEXT DEFAULT NULL')
|
||||
|
||||
try:
|
||||
c.execute('SELECT ReleaseCountry from albums')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE albums ADD COLUMN ReleaseCountry TEXT DEFAULT NULL')
|
||||
|
||||
try:
|
||||
c.execute('SELECT ReleaseID from tracks')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE tracks ADD COLUMN ReleaseID TEXT DEFAULT NULL')
|
||||
|
||||
try:
|
||||
c.execute('SELECT Matched from have')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE have ADD COLUMN Matched TEXT DEFAULT NULL')
|
||||
|
||||
conn.commit()
|
||||
c.close()
|
||||
|
||||
82
headphones/albumswitcher.py
Normal file
82
headphones/albumswitcher.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# This file is part of Headphones.
|
||||
#
|
||||
# Headphones is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Headphones is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Headphones. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import headphones
|
||||
from headphones import db, logger
|
||||
|
||||
def switch(AlbumID, ReleaseID):
|
||||
'''
|
||||
Takes the contents from allalbums & alltracks (based on ReleaseID) and switches them into
|
||||
the albums & tracks table.
|
||||
'''
|
||||
myDB = db.DBConnection()
|
||||
oldalbumdata = myDB.action('SELECT * from albums WHERE AlbumID=?', [AlbumID]).fetchone()
|
||||
newalbumdata = myDB.action('SELECT * from allalbums WHERE ReleaseID=?', [ReleaseID]).fetchone()
|
||||
newtrackdata = myDB.action('SELECT * from alltracks WHERE ReleaseID=?', [ReleaseID]).fetchall()
|
||||
myDB.action('DELETE from tracks WHERE AlbumID=?', [AlbumID])
|
||||
|
||||
controlValueDict = {"AlbumID": AlbumID}
|
||||
|
||||
newValueDict = {"ArtistID": newalbumdata['ArtistID'],
|
||||
"ArtistName": newalbumdata['ArtistName'],
|
||||
"AlbumTitle": newalbumdata['AlbumTitle'],
|
||||
"ReleaseID": newalbumdata['ReleaseID'],
|
||||
"AlbumASIN": newalbumdata['AlbumASIN'],
|
||||
"ReleaseDate": newalbumdata['ReleaseDate'],
|
||||
"Type": newalbumdata['Type'],
|
||||
"ReleaseCountry": newalbumdata['ReleaseCountry'],
|
||||
"ReleaseFormat": newalbumdata['ReleaseFormat']
|
||||
}
|
||||
|
||||
myDB.upsert("albums", newValueDict, controlValueDict)
|
||||
|
||||
for track in newtrackdata:
|
||||
|
||||
controlValueDict = {"TrackID": track['TrackID'],
|
||||
"AlbumID": AlbumID}
|
||||
|
||||
newValueDict = {"ArtistID": track['ArtistID'],
|
||||
"ArtistName": track['ArtistName'],
|
||||
"AlbumTitle": track['AlbumTitle'],
|
||||
"AlbumASIN": track['AlbumASIN'],
|
||||
"ReleaseID": track['ReleaseID'],
|
||||
"TrackTitle": track['TrackTitle'],
|
||||
"TrackDuration": track['TrackDuration'],
|
||||
"TrackNumber": track['TrackNumber'],
|
||||
"CleanName": track['CleanName'],
|
||||
"Location": track['Location'],
|
||||
"Format": track['Format'],
|
||||
"BitRate": track['BitRate']
|
||||
}
|
||||
|
||||
myDB.upsert("tracks", newValueDict, controlValueDict)
|
||||
|
||||
# Mark albums as downloaded if they have at least 80% (by default, configurable) of the album
|
||||
total_track_count = len(newtrackdata)
|
||||
have_track_count = len(myDB.select('SELECT * from tracks WHERE AlbumID=? AND Location IS NOT NULL', [AlbumID]))
|
||||
|
||||
if oldalbumdata['Status'] == 'Skipped' and ((have_track_count/float(total_track_count)) >= (headphones.ALBUM_COMPLETION_PCT/100.0)):
|
||||
myDB.action('UPDATE albums SET Status=? WHERE AlbumID=?', ['Downloaded', AlbumID])
|
||||
|
||||
# Update have track counts on index
|
||||
totaltracks = len(myDB.select('SELECT TrackTitle from tracks WHERE ArtistID=?', [newalbumdata['ArtistID']]))
|
||||
havetracks = len(myDB.select('SELECT TrackTitle from tracks WHERE ArtistID=? AND Location IS NOT NULL', [newalbumdata['ArtistID']])) + len(myDB.select('SELECT TrackTitle from have WHERE ArtistName like ?', [newalbumdata['ArtistID']]))
|
||||
|
||||
controlValueDict = {"ArtistID": newalbumdata['ArtistID']}
|
||||
|
||||
newValueDict = { "TotalTracks": totaltracks,
|
||||
"HaveTracks": havetracks}
|
||||
|
||||
myDB.upsert("artists", newValueDict, controlValueDict)
|
||||
@@ -153,68 +153,132 @@ def addArtisttoDB(artistid, extrasonly=False):
|
||||
|
||||
for rg in artist['releasegroups']:
|
||||
|
||||
logger.info("Now adding/updating: " + rg['title'])
|
||||
|
||||
rgid = rg['id']
|
||||
|
||||
# check if the album already exists
|
||||
rg_exists = myDB.action("SELECT * from albums WHERE AlbumID=?", [rg['id']]).fetchone()
|
||||
|
||||
try:
|
||||
release_dict = mb.getReleaseGroup(rgid)
|
||||
releaselist = mb.getReleaseGroup(rgid)
|
||||
except Exception, e:
|
||||
logger.info('Unable to get release information for %s - there may not be any official releases in this release group' % rg['title'])
|
||||
continue
|
||||
|
||||
if not release_dict:
|
||||
if not releaselist:
|
||||
continue
|
||||
|
||||
logger.info(u"Now adding/updating album: " + rg['title'])
|
||||
|
||||
# This will be used later to build a hybrid release
|
||||
fullreleaselist = []
|
||||
|
||||
for release in releaselist:
|
||||
# What we're doing here now is first updating the allalbums & alltracks table to the most
|
||||
# current info, then moving the appropriate release into the album table and its associated
|
||||
# tracks into the tracks table
|
||||
|
||||
releaseid = release['id']
|
||||
|
||||
try:
|
||||
releasedict = mb.getRelease(releaseid, include_artist_info=False)
|
||||
except Exception, e:
|
||||
logger.info('Unable to get release information for %s: %s' % (release['id'], e))
|
||||
continue
|
||||
|
||||
if not releasedict:
|
||||
continue
|
||||
|
||||
controlValueDict = {"AlbumID": rg['id']}
|
||||
controlValueDict = {"ReleaseID": release['id']}
|
||||
|
||||
newValueDict = {"ArtistID": artistid,
|
||||
"ArtistName": artist['artist_name'],
|
||||
"AlbumTitle": rg['title'],
|
||||
"AlbumID": rg['id'],
|
||||
"AlbumASIN": releasedict['asin'],
|
||||
"ReleaseDate": releasedict['date'],
|
||||
"Type": rg['type'],
|
||||
"ReleaseCountry": releasedict['country'],
|
||||
"ReleaseFormat": releasedict['format']
|
||||
}
|
||||
|
||||
myDB.upsert("allalbums", newValueDict, controlValueDict)
|
||||
|
||||
# Build the dictionary for the fullreleaselist
|
||||
newValueDict['ReleaseID'] = release['id']
|
||||
newValueDict['Tracks'] = releasedict['tracks']
|
||||
fullreleaselist.append(newValueDict)
|
||||
|
||||
for track in releasedict['tracks']:
|
||||
|
||||
cleanname = helpers.cleanName(artist['artist_name'] + ' ' + rg['title'] + ' ' + track['title'])
|
||||
|
||||
controlValueDict = {"TrackID": track['id'],
|
||||
"ReleaseID": release['id']}
|
||||
|
||||
newValueDict = {"ArtistID": artistid,
|
||||
"ArtistName": artist['artist_name'],
|
||||
"AlbumTitle": rg['title'],
|
||||
"AlbumASIN": releasedict['asin'],
|
||||
"AlbumID": rg['id'],
|
||||
"TrackTitle": track['title'],
|
||||
"TrackDuration": track['duration'],
|
||||
"TrackNumber": track['number'],
|
||||
"CleanName": cleanname
|
||||
}
|
||||
|
||||
match = myDB.action('SELECT Location, BitRate, Format from have WHERE CleanName=?', [cleanname]).fetchone()
|
||||
|
||||
if not match:
|
||||
match = myDB.action('SELECT Location, BitRate, Format from have WHERE ArtistName LIKE ? AND AlbumTitle LIKE ? AND TrackTitle LIKE ?', [artist['artist_name'], rg['title'], track['title']]).fetchone()
|
||||
if not match:
|
||||
match = myDB.action('SELECT Location, BitRate, Format from have WHERE TrackID=?', [track['id']]).fetchone()
|
||||
if match:
|
||||
newValueDict['Location'] = match['Location']
|
||||
newValueDict['BitRate'] = match['BitRate']
|
||||
newValueDict['Format'] = match['Format']
|
||||
myDB.action('UPDATE tracks SET Matched="True" WHERE Location=?', match['Location'])
|
||||
|
||||
myDB.upsert("alltracks", newValueDict, controlValueDict)
|
||||
|
||||
# Basically just do the same thing again for the hybrid release
|
||||
hybridrelease = getHybridRelease(fullreleaselist)
|
||||
|
||||
# Use the ReleaseGroupID as the ReleaseID for the hybrid release to differentiate it
|
||||
# We can then use the condition WHERE ReleaseID == ReleaseGroupID to select it
|
||||
# The hybrid won't have a country or a format
|
||||
controlValueDict = {"ReleaseID": rg['id']}
|
||||
|
||||
newValueDict = {"ArtistID": artistid,
|
||||
"ArtistName": artist['artist_name'],
|
||||
"AlbumTitle": rg['title'],
|
||||
"AlbumASIN": release_dict['asin'],
|
||||
"ReleaseDate": release_dict['releasedate'],
|
||||
"AlbumID": rg['id'],
|
||||
"AlbumASIN": hybridrelease['AlbumASIN'],
|
||||
"ReleaseDate": hybridrelease['ReleaseDate'],
|
||||
"Type": rg['type']
|
||||
}
|
||||
}
|
||||
|
||||
myDB.upsert("allalbums", newValueDict, controlValueDict)
|
||||
|
||||
# Only change the status & add DateAdded if the album is not already in the database
|
||||
if not rg_exists:
|
||||
for track in hybridrelease['Tracks']:
|
||||
|
||||
newValueDict['DateAdded']= helpers.today()
|
||||
|
||||
if headphones.AUTOWANT_ALL:
|
||||
newValueDict['Status'] = "Wanted"
|
||||
elif release_dict['releasedate'] > helpers.today() and headphones.AUTOWANT_UPCOMING:
|
||||
newValueDict['Status'] = "Wanted"
|
||||
else:
|
||||
newValueDict['Status'] = "Skipped"
|
||||
|
||||
myDB.upsert("albums", newValueDict, controlValueDict)
|
||||
|
||||
# This is used to see how many tracks you have from an album - to mark it as downloaded. Default is 80%, can be set in config as ALBUM_COMPLETION_PCT
|
||||
total_track_count = len(release_dict['tracks'])
|
||||
|
||||
for track in release_dict['tracks']:
|
||||
|
||||
cleanname = helpers.cleanName(artist['artist_name'] + ' ' + rg['title'] + ' ' + track['title'])
|
||||
|
||||
controlValueDict = {"TrackID": track['id'],
|
||||
"AlbumID": rg['id']}
|
||||
|
||||
controlValueDict = {"TrackID": track['id'],
|
||||
"ReleaseID": rg['id']}
|
||||
|
||||
newValueDict = {"ArtistID": artistid,
|
||||
"ArtistName": artist['artist_name'],
|
||||
"AlbumTitle": rg['title'],
|
||||
"AlbumASIN": release_dict['asin'],
|
||||
"TrackTitle": track['title'],
|
||||
"TrackDuration": track['duration'],
|
||||
"TrackNumber": track['number'],
|
||||
"CleanName": cleanname
|
||||
newValueDict = {"ArtistID": artistid,
|
||||
"ArtistName": artist['artist_name'],
|
||||
"AlbumTitle": rg['title'],
|
||||
"AlbumASIN": hybridrelease['AlbumASIN'],
|
||||
"AlbumID": rg['id'],
|
||||
"TrackTitle": track['title'],
|
||||
"TrackDuration": track['duration'],
|
||||
"TrackNumber": track['number'],
|
||||
"CleanName": cleanname
|
||||
}
|
||||
|
||||
|
||||
match = myDB.action('SELECT Location, BitRate, Format from have WHERE CleanName=?', [cleanname]).fetchone()
|
||||
|
||||
|
||||
if not match:
|
||||
match = myDB.action('SELECT Location, BitRate, Format from have WHERE ArtistName LIKE ? AND AlbumTitle LIKE ? AND TrackTitle LIKE ?', [artist['artist_name'], rg['title'], track['title']]).fetchone()
|
||||
if not match:
|
||||
@@ -223,8 +287,89 @@ def addArtisttoDB(artistid, extrasonly=False):
|
||||
newValueDict['Location'] = match['Location']
|
||||
newValueDict['BitRate'] = match['BitRate']
|
||||
newValueDict['Format'] = match['Format']
|
||||
myDB.action('DELETE from have WHERE Location=?', [match['Location']])
|
||||
myDB.action('UPDATE tracks SET Matched="True" WHERE Location=?', match['Location'])
|
||||
|
||||
myDB.upsert("alltracks", newValueDict, controlValueDict)
|
||||
|
||||
# Delete matched tracks from the have table
|
||||
myDB.action('DELETE from have WHERE Matched="True"')
|
||||
|
||||
# If there's no release in the main albums tables, add the default (hybrid)
|
||||
# If there is a release, check the ReleaseID against the AlbumID to see if they differ (user updated)
|
||||
if not rg_exists:
|
||||
releaseid = rg['id']
|
||||
elif rg_exists and not rg_exists['ReleaseID']:
|
||||
# Need to do some importing here - to transition the old format of using the release group
|
||||
# only to using releasegroup & releaseid. These are the albums that are missing a ReleaseID
|
||||
# so we'll need to move over the locations, bitrates & formats from the tracks table to the new
|
||||
# alltracks table. Thankfully we can just use TrackIDs since they span releases/releasegroups
|
||||
logger.info("Copying current track information to alternate releases")
|
||||
tracks = myDB.action('SELECT * from tracks WHERE AlbumID=?', [rg['id']]).fetchall()
|
||||
for track in tracks:
|
||||
if track['Location']:
|
||||
controlValueDict = {"TrackID": track['TrackID']}
|
||||
newValueDict = {"Location": track['Location'],
|
||||
"BitRate": track['BitRate'],
|
||||
"Format": track['Format'],
|
||||
}
|
||||
myDB.upsert("alltracks", newValueDict, controlValueDict)
|
||||
releaseid = rg['id']
|
||||
else:
|
||||
releaseid = rg_exists['ReleaseID']
|
||||
|
||||
album = myDB.action('SELECT * from allalbums WHERE ReleaseID=?', [releaseid]).fetchone()
|
||||
|
||||
controlValueDict = {"AlbumID": rg['id']}
|
||||
|
||||
newValueDict = {"ArtistID": album['ArtistID'],
|
||||
"ArtistName": album['ArtistName'],
|
||||
"AlbumTitle": album['AlbumTitle'],
|
||||
"ReleaseID": album['ReleaseID'],
|
||||
"AlbumASIN": album['AlbumASIN'],
|
||||
"ReleaseDate": album['ReleaseDate'],
|
||||
"Type": album['Type'],
|
||||
"ReleaseCountry": album['ReleaseCountry'],
|
||||
"ReleaseFormat": album['ReleaseFormat']
|
||||
}
|
||||
|
||||
if not rg_exists:
|
||||
|
||||
newValueDict['DateAdded']= helpers.today()
|
||||
|
||||
if headphones.AUTOWANT_ALL:
|
||||
newValueDict['Status'] = "Wanted"
|
||||
elif album['ReleaseDate'] > helpers.today() and headphones.AUTOWANT_UPCOMING:
|
||||
newValueDict['Status'] = "Wanted"
|
||||
else:
|
||||
newValueDict['Status'] = "Skipped"
|
||||
|
||||
myDB.upsert("albums", newValueDict, controlValueDict)
|
||||
|
||||
myDB.action('DELETE from tracks WHERE AlbumID=?', [rg['id']])
|
||||
tracks = myDB.action('SELECT * from alltracks WHERE ReleaseID=?', [releaseid]).fetchall()
|
||||
|
||||
# This is used to see how many tracks you have from an album - to mark it as downloaded. Default is 80%, can be set in config as ALBUM_COMPLETION_PCT
|
||||
total_track_count = len(tracks)
|
||||
|
||||
for track in tracks:
|
||||
|
||||
controlValueDict = {"TrackID": track['TrackID'],
|
||||
"AlbumID": rg['id']}
|
||||
|
||||
newValueDict = {"ArtistID": track['ArtistID'],
|
||||
"ArtistName": track['ArtistName'],
|
||||
"AlbumTitle": track['AlbumTitle'],
|
||||
"AlbumASIN": track['AlbumASIN'],
|
||||
"ReleaseID": track['ReleaseID'],
|
||||
"TrackTitle": track['TrackTitle'],
|
||||
"TrackDuration": track['TrackDuration'],
|
||||
"TrackNumber": track['TrackNumber'],
|
||||
"CleanName": track['CleanName'],
|
||||
"Location": track['Location'],
|
||||
"Format": track['Format'],
|
||||
"BitRate": track['BitRate']
|
||||
}
|
||||
|
||||
myDB.upsert("tracks", newValueDict, controlValueDict)
|
||||
|
||||
# Mark albums as downloaded if they have at least 80% (by default, configurable) of the album
|
||||
@@ -237,7 +382,7 @@ def addArtisttoDB(artistid, extrasonly=False):
|
||||
if ((have_track_count/float(total_track_count)) >= (headphones.ALBUM_COMPLETION_PCT/100.0)):
|
||||
myDB.action('UPDATE albums SET Status=? WHERE AlbumID=?', ['Downloaded', rg['id']])
|
||||
|
||||
logger.debug(u"Updating album cache for " + rg['title'])
|
||||
logger.info(u"Seeing if we need album art for " + rg['title'])
|
||||
cache.getThumb(AlbumID=rg['id'])
|
||||
|
||||
latestalbum = myDB.action('SELECT AlbumTitle, ReleaseDate, AlbumID from albums WHERE ArtistID=? order by ReleaseDate DESC', [artistid]).fetchone()
|
||||
@@ -262,7 +407,7 @@ def addArtisttoDB(artistid, extrasonly=False):
|
||||
|
||||
myDB.upsert("artists", newValueDict, controlValueDict)
|
||||
|
||||
logger.debug(u"Updating cache for: " + artist['artist_name'])
|
||||
logger.info(u"Seeing if we need album art for: " + artist['artist_name'])
|
||||
cache.getThumb(ArtistID=artistid)
|
||||
|
||||
logger.info(u"Updating complete for: " + artist['artist_name'])
|
||||
@@ -412,3 +557,76 @@ def updateFormat():
|
||||
newValueDict = {"Format": f.format}
|
||||
myDB.upsert("have", newValueDict, controlValueDict)
|
||||
logger.info('Finished finding media format for %s files' % len(havetracks))
|
||||
|
||||
def getHybridRelease(fullreleaselist):
|
||||
"""
|
||||
Returns a dictionary of best group of tracks from the list of releases & earliest release date
|
||||
"""
|
||||
sortable_release_list = []
|
||||
|
||||
for release in fullreleaselist:
|
||||
|
||||
formats = {
|
||||
'2xVinyl': '2',
|
||||
'Vinyl': '2',
|
||||
'CD': '0',
|
||||
'Cassette': '3',
|
||||
'2xCD': '1',
|
||||
'Digital Media': '0'
|
||||
}
|
||||
|
||||
countries = {
|
||||
'US': '0',
|
||||
'GB': '1',
|
||||
'JP': '2',
|
||||
}
|
||||
|
||||
try:
|
||||
format = int(formats[release['Format']])
|
||||
except:
|
||||
format = 3
|
||||
|
||||
try:
|
||||
country = int(countries[release['Country']])
|
||||
except:
|
||||
country = 3
|
||||
|
||||
release_dict = {
|
||||
'hasasin': bool(release['AlbumASIN']),
|
||||
'asin': release['AlbumASIN'],
|
||||
'trackscount': len(release['Tracks']),
|
||||
'releaseid': release['ReleaseID'],
|
||||
'releasedate': release['ReleaseDate'],
|
||||
'format': format,
|
||||
'country': country,
|
||||
'tracks': release['Tracks']
|
||||
}
|
||||
|
||||
sortable_release_list.append(release_dict)
|
||||
|
||||
#necessary to make dates that miss the month and/or day show up after full dates
|
||||
def getSortableReleaseDate(releaseDate):
|
||||
if releaseDate == None:
|
||||
return 'None';#change this value to change the sorting behaviour of none, returning 'None' will put it at the top
|
||||
#which was normal behaviour for pre-ngs versions
|
||||
if releaseDate.count('-') == 2:
|
||||
return releaseDate
|
||||
elif releaseDate.count('-') == 1:
|
||||
return releaseDate + '32'
|
||||
else:
|
||||
return releaseDate + '13-32'
|
||||
|
||||
sortable_release_list.sort(key=lambda x:getSortableReleaseDate(x['releasedate']))
|
||||
|
||||
average_tracks = sum(x['trackscount'] for x in sortable_release_list) / float(len(sortable_release_list))
|
||||
for item in sortable_release_list:
|
||||
item['trackscount_delta'] = abs(average_tracks - item['trackscount'])
|
||||
|
||||
a = helpers.multikeysort(sortable_release_list, ['-hasasin', 'country', 'format', 'trackscount_delta'])
|
||||
|
||||
release_dict = {'ReleaseDate' : sortable_release_list[0]['releasedate'],
|
||||
'Tracks' : a[0]['tracks'],
|
||||
'AlbumASIN' : a[0]['asin']
|
||||
}
|
||||
|
||||
return release_dict
|
||||
|
||||
188
headphones/mb.py
188
headphones/mb.py
@@ -124,9 +124,9 @@ def findArtist(name, limit=1):
|
||||
else:
|
||||
artistlist.append({
|
||||
'name': unicode(result['sort-name']),
|
||||
'uniquename': uniquename,
|
||||
'id': unicode(result['id']),
|
||||
'url': unicode("http://musicbrainz.org/artist/" + result['id']),#probably needs to be changed
|
||||
'uniquename': uniquename,
|
||||
'id': unicode(result['id']),
|
||||
'url': unicode("http://musicbrainz.org/artist/" + result['id']),#probably needs to be changed
|
||||
'score': int(result['ext:score'])
|
||||
})
|
||||
return artistlist
|
||||
@@ -158,10 +158,10 @@ def findRelease(name, limit=1):
|
||||
'uniquename': unicode(result['artist-credit'][0]['artist']['name']),
|
||||
'title': unicode(result['title']),
|
||||
'id': unicode(result['artist-credit'][0]['artist']['id']),
|
||||
'albumid': unicode(result['id']),
|
||||
'url': unicode("http://musicbrainz.org/artist/" + result['artist-credit'][0]['artist']['id']),#probably needs to be changed
|
||||
'albumurl': unicode("http://musicbrainz.org/release/" + result['id']),#probably needs to be changed
|
||||
'score': int(result['ext:score'])
|
||||
'albumid': unicode(result['id']),
|
||||
'url': unicode("http://musicbrainz.org/artist/" + result['artist-credit'][0]['artist']['id']),#probably needs to be changed
|
||||
'albumurl': unicode("http://musicbrainz.org/release/" + result['id']),#probably needs to be changed
|
||||
'score': int(result['ext:score'])
|
||||
})
|
||||
return releaselistngs
|
||||
|
||||
@@ -215,8 +215,7 @@ def getArtist(artistid, extrasonly=False):
|
||||
# if 'end' in artist['life-span']:
|
||||
# artist_dict['artist_enddate'] = unicode(artist['life-span']['end'])
|
||||
|
||||
|
||||
|
||||
|
||||
releasegroups = []
|
||||
|
||||
if not extrasonly:
|
||||
@@ -224,10 +223,10 @@ def getArtist(artistid, extrasonly=False):
|
||||
if rg['type'] != 'Album': #only add releases without a secondary type
|
||||
continue
|
||||
releasegroups.append({
|
||||
'title': unicode(rg['title']),
|
||||
'id': unicode(rg['id']),
|
||||
'url': u"http://musicbrainz.org/release-group/" + rg['id'],
|
||||
'type': unicode(rg['type'])
|
||||
'title': unicode(rg['title']),
|
||||
'id': unicode(rg['id']),
|
||||
'url': u"http://musicbrainz.org/release-group/" + rg['id'],
|
||||
'type': unicode(rg['type'])
|
||||
})
|
||||
|
||||
# See if we need to grab extras
|
||||
@@ -255,18 +254,18 @@ def getArtist(artistid, extrasonly=False):
|
||||
for rg in artist['release-group-list']:
|
||||
releasegroups.append({
|
||||
'title': unicode(rg['title']),
|
||||
'id': unicode(rg['id']),
|
||||
'url': u"http://musicbrainz.org/release-group/" + rg['id'],
|
||||
'type': unicode(rg['type'])
|
||||
'id': unicode(rg['id']),
|
||||
'url': u"http://musicbrainz.org/release-group/" + rg['id'],
|
||||
'type': unicode(rg['type'])
|
||||
})
|
||||
|
||||
artist_dict['releasegroups'] = releasegroups
|
||||
|
||||
return artist_dict
|
||||
|
||||
|
||||
def getReleaseGroup(rgid):
|
||||
"""
|
||||
Returns a dictionary of the best stuff from a release group
|
||||
Returns a list of releases in a release group
|
||||
"""
|
||||
with mb_lock:
|
||||
|
||||
@@ -284,113 +283,10 @@ def getReleaseGroup(rgid):
|
||||
|
||||
if not releaseGroup:
|
||||
return False
|
||||
|
||||
|
||||
time.sleep(sleepytime)
|
||||
|
||||
# I think for now we have to make separate queries for each release, in order
|
||||
# to get more detailed release info (ASIN, track count, etc.)
|
||||
for release in releaseGroup['release-list']:
|
||||
releaseResult = None
|
||||
|
||||
try:
|
||||
releaseResult = musicbrainzngs.get_release_by_id(release['id'],["recordings","media"])['release']
|
||||
except WebServiceError, e:
|
||||
logger.warn('Attempt to retrieve release information for %s from MusicBrainz failed (%s)' % (releaseResult.title, str(e)))
|
||||
time.sleep(5)
|
||||
|
||||
if not releaseResult:
|
||||
continue
|
||||
|
||||
if releaseGroup['type'] == 'live' and releaseResult['status'] != 'Official':
|
||||
logger.debug('%s is not an official live album. Skipping' % releaseResult.name)
|
||||
continue
|
||||
|
||||
time.sleep(sleepytime)
|
||||
|
||||
formats = {
|
||||
'2xVinyl': '2',
|
||||
'Vinyl': '2',
|
||||
'CD': '0',
|
||||
'Cassette': '3',
|
||||
'2xCD': '1',
|
||||
'Digital Media': '0'
|
||||
}
|
||||
|
||||
countries = {
|
||||
'US': '0',
|
||||
|
||||
'GB': '1',
|
||||
'JP': '2',
|
||||
}
|
||||
try:
|
||||
format = int(formats[releaseResult['medium-list'][0]['format']])
|
||||
except:
|
||||
format = 3
|
||||
|
||||
try:
|
||||
country = int(countries[releaseResult['country']])
|
||||
except:
|
||||
country = 3
|
||||
totalTracks = 0
|
||||
tracks = []
|
||||
for medium in releaseResult['medium-list']:
|
||||
for track in medium['track-list']:
|
||||
tracks.append({
|
||||
'number': totalTracks + 1,
|
||||
'title': unicode(track['recording']['title']),
|
||||
'id': unicode(track['recording']['id']),
|
||||
'url': u"http://musicbrainz.org/track/" + track['recording']['id'],
|
||||
'duration': int(track['recording']['length'] if 'length' in track['recording'] else track['length'] if 'length' in track else 0)
|
||||
})
|
||||
totalTracks += 1
|
||||
|
||||
release_dict = {
|
||||
'hasasin': bool(releaseResult.get('asin')),
|
||||
'asin': unicode(releaseResult.get('asin')) if 'asin' in releaseResult else None,
|
||||
'trackscount': totalTracks,
|
||||
'releaseid': unicode(releaseResult.get('id')),
|
||||
'releasedate': unicode(releaseResult.get('date')) if 'date' in releaseResult else None,
|
||||
'format': format,
|
||||
'country': country
|
||||
}
|
||||
release_dict['tracks'] = tracks
|
||||
releaselist.append(release_dict)
|
||||
#necessary to make dates that miss the month and/or day show up after full dates
|
||||
def getSortableReleaseDate(releaseDate):
|
||||
if releaseDate == None:
|
||||
return 'None';#change this value to change the sorting behaviour of none, returning 'None' will put it at the top
|
||||
#which was normal behaviour for pre-ngs versions
|
||||
if releaseDate.count('-') == 2:
|
||||
return releaseDate
|
||||
elif releaseDate.count('-') == 1:
|
||||
return releaseDate + '32'
|
||||
else:
|
||||
return releaseDate + '13-32'
|
||||
|
||||
releaselist.sort(key=lambda x:getSortableReleaseDate(x['releasedate']))
|
||||
|
||||
|
||||
average_tracks = sum(x['trackscount'] for x in releaselist) / float(len(releaselist))
|
||||
for item in releaselist:
|
||||
item['trackscount_delta'] = abs(average_tracks - item['trackscount'])
|
||||
a = multikeysort(releaselist, ['-hasasin', 'country', 'format', 'trackscount_delta'])
|
||||
|
||||
release_dict = {'releaseid' :a[0]['releaseid'],
|
||||
'releasedate' : releaselist[0]['releasedate'],
|
||||
'trackcount' : a[0]['trackscount'],
|
||||
'tracks' : a[0]['tracks'],
|
||||
'asin' : a[0]['asin'],
|
||||
'releaselist' : releaselist,
|
||||
'artist_name' : unicode(releaseGroup['artist-credit'][0]['artist']['name']),
|
||||
'artist_id' : unicode(releaseGroup['artist-credit'][0]['artist']['id']),
|
||||
'title' : unicode(releaseGroup['title']),
|
||||
'type' : unicode(releaseGroup['type'])
|
||||
}
|
||||
|
||||
return release_dict
|
||||
else:
|
||||
return releaseGroup['release-list']
|
||||
|
||||
def getRelease(releaseid):
|
||||
def getRelease(releaseid, include_artist_info=True):
|
||||
"""
|
||||
Deep release search to get track info
|
||||
"""
|
||||
@@ -402,7 +298,10 @@ def getRelease(releaseid):
|
||||
q, sleepytime = startmb()
|
||||
|
||||
try:
|
||||
results = musicbrainzngs.get_release_by_id(releaseid,["artists","release-groups","media","recordings"]).get('release')
|
||||
if include_artist_info:
|
||||
results = musicbrainzngs.get_release_by_id(releaseid,["artists","release-groups","media","recordings"]).get('release')
|
||||
else:
|
||||
results = musicbrainzngs.get_release_by_id(releaseid,["media","recordings"]).get('release')
|
||||
except WebServiceError, e:
|
||||
logger.warn('Attempt to retrieve information from MusicBrainz for release "%s" failed (%s)' % (releaseid, str(e)))
|
||||
time.sleep(5)
|
||||
@@ -416,28 +315,39 @@ def getRelease(releaseid):
|
||||
release['id'] = unicode(results['id'])
|
||||
release['asin'] = unicode(results['asin']) if 'asin' in results else None
|
||||
release['date'] = unicode(results['date'])
|
||||
try:
|
||||
release['format'] = unicode(results['medium-list'][0]['format'])
|
||||
except:
|
||||
release['format'] = u'Unknown'
|
||||
|
||||
try:
|
||||
release['country'] = unicode(results['country'])
|
||||
except:
|
||||
release['country'] = u'Unknown'
|
||||
|
||||
|
||||
if 'release-group' in results:
|
||||
release['rgid'] = unicode(results['release-group']['id'])
|
||||
release['rg_title'] = unicode(results['release-group']['title'])
|
||||
release['rg_type'] = unicode(results['release-group']['type'])
|
||||
else:
|
||||
logger.warn("Release " + releaseid + "had no ReleaseGroup associated")
|
||||
if include_artist_info:
|
||||
|
||||
if 'release-group' in results:
|
||||
release['rgid'] = unicode(results['release-group']['id'])
|
||||
release['rg_title'] = unicode(results['release-group']['title'])
|
||||
release['rg_type'] = unicode(results['release-group']['type'])
|
||||
else:
|
||||
logger.warn("Release " + releaseid + "had no ReleaseGroup associated")
|
||||
|
||||
release['artist_name'] = unicode(results['artist-credit'][0]['artist']['name'])
|
||||
release['artist_id'] = unicode(results['artist-credit'][0]['artist']['id'])
|
||||
release['artist_name'] = unicode(results['artist-credit'][0]['artist']['name'])
|
||||
release['artist_id'] = unicode(results['artist-credit'][0]['artist']['id'])
|
||||
|
||||
|
||||
totalTracks = 0
|
||||
totalTracks = 1
|
||||
tracks = []
|
||||
for medium in results['medium-list']:
|
||||
for track in medium['track-list']:
|
||||
tracks.append({
|
||||
'number': totalTracks + 1,
|
||||
'title': unicode(track['recording']['title']),
|
||||
'number': totalTracks,
|
||||
'title': unicode(track['recording']['title']),
|
||||
'id': unicode(track['recording']['id']),
|
||||
'url': u"http://musicbrainz.org/track/" + track['recording']['id'],
|
||||
'duration': int(track['length']) if 'length' in track else 0
|
||||
'url': u"http://musicbrainz.org/track/" + track['recording']['id'],
|
||||
'duration': int(track['length']) if 'length' in track else 0
|
||||
})
|
||||
totalTracks += 1
|
||||
|
||||
|
||||
@@ -211,6 +211,15 @@ class WebInterface(object):
|
||||
else:
|
||||
raise cherrypy.HTTPRedirect("home")
|
||||
deleteAlbum.exposed = True
|
||||
|
||||
def switchAlbum(self, AlbumID, ReleaseID):
|
||||
'''
|
||||
Take the values from allalbums/alltracks (based on the ReleaseID) and swap it into the album & track tables
|
||||
'''
|
||||
from headphones import albumswitcher
|
||||
albumswitcher.switch(AlbumID, ReleaseID)
|
||||
raise cherrypy.HTTPRedirect("albumPage?AlbumID=%s" % AlbumID)
|
||||
switchAlbum.exposed = True
|
||||
|
||||
def upcoming(self):
|
||||
myDB = db.DBConnection()
|
||||
|
||||
Reference in New Issue
Block a user