mirror of
https://github.com/rembo10/headphones.git
synced 2026-07-22 00:44:00 +01:00
Release v0.5.5
This commit is contained in:
+20
-1
@@ -1,5 +1,24 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v0.5.5
|
||||||
|
Released 04 May 2015
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
* Added: force ID3v2.3 during post processing (#2121)
|
||||||
|
* Added: MusicBrainz authentication (#2125)
|
||||||
|
* Added: Email notifications (addresses #1045)
|
||||||
|
* Fixed: Kickass url updated to kickass.to (#2119)
|
||||||
|
* Fixed: Piratebay returning 0 bytes for all files
|
||||||
|
* Fixed: Albums stopped automatically refreshing when adding an artist
|
||||||
|
* Fixed: Min/max sizes for target bitrate
|
||||||
|
* Fixed: Don't filter any results if looking for a specific download
|
||||||
|
* Fixed: Sort by size in the specific download table
|
||||||
|
* Fixed: Deal with beets recommendation.none correctly
|
||||||
|
* Improved: Close dialog window automatically when choosing a specific download
|
||||||
|
* Improved: Move some repetitive log messages to debug level
|
||||||
|
|
||||||
|
The full list of commits can be found [here](https://github.com/rembo10/headphones/compare/v0.5.4...v0.5.5).
|
||||||
|
|
||||||
## v0.5.4
|
## v0.5.4
|
||||||
Released 05 February 2015
|
Released 05 February 2015
|
||||||
|
|
||||||
@@ -155,4 +174,4 @@ The full list of commits can be found [here](https://github.com/rembo10/headphon
|
|||||||
## v0.1
|
## v0.1
|
||||||
Released 05 August 2013
|
Released 05 August 2013
|
||||||
|
|
||||||
The full list of commits can be found [here](https://github.com/rembo10/headphones/compare/2156e1341405d07c5bcfbe994f6b354b32d94cda...v0.1).
|
The full list of commits can be found [here](https://github.com/rembo10/headphones/compare/2156e1341405d07c5bcfbe994f6b354b32d94cda...v0.1).
|
||||||
|
|||||||
@@ -337,6 +337,21 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jQuery.extend( jQuery.fn.dataTableExt.oSort, {
|
||||||
|
"title-numeric-pre": function ( a ) {
|
||||||
|
var x = a.match(/title="*(-?[0-9\.]+)/)[1];
|
||||||
|
return parseFloat( x );
|
||||||
|
},
|
||||||
|
|
||||||
|
"title-numeric-asc": function ( a, b ) {
|
||||||
|
return ((a < b) ? -1 : ((a > b) ? 1 : 0));
|
||||||
|
},
|
||||||
|
|
||||||
|
"title-numeric-desc": function ( a, b ) {
|
||||||
|
return ((a < b) ? 1 : ((a > b) ? -1 : 0));
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
getAlbumInfo();
|
getAlbumInfo();
|
||||||
initThisPage();
|
initThisPage();
|
||||||
|
|||||||
@@ -786,6 +786,10 @@
|
|||||||
Embed lyrics
|
Embed lyrics
|
||||||
<input type="checkbox" name="embed_lyrics" value="1" ${config['embed_lyrics']}>
|
<input type="checkbox" name="embed_lyrics" value="1" ${config['embed_lyrics']}>
|
||||||
</label>
|
</label>
|
||||||
|
<label title="Use ID3v2.3 instead of ID3v2.4">
|
||||||
|
Tag using ID3v2.3
|
||||||
|
<input type="checkbox" name="idtag" value="1" ${config['idtag']}>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>
|
<label>
|
||||||
@@ -1104,6 +1108,39 @@
|
|||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<h3>Email</h3>
|
||||||
|
<div class="row checkbox">
|
||||||
|
<input type="checkbox" name="email_enabled" id="email" value="1" ${config['email_enabled']} /><label>Enable Email Notifications</label>
|
||||||
|
</div>
|
||||||
|
<div id="email_options">
|
||||||
|
<div class="row">
|
||||||
|
<label>From</label><input type="text" name="email_from" value="${config['email_from']}" size="254">
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<label>To</label><input type="text" name="email_to" value="${config['email_to']}" size="254">
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<label>SMTP Server</label><input type="text" name="email_smtp_server" value="${config['email_smtp_server']}" size="254">
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<label>SMTP User</label><input type="text" name="email_smtp_user" value="${config['email_smtp_user']}" size="254">
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<label>SMTP Password</label><input type="password" name="email_smtp_password" value="${config['email_smtp_password']}" size="50">
|
||||||
|
</div>
|
||||||
|
<div class="row checkbox">
|
||||||
|
<input type="text" class="override-float" name="email_smtp_port" value="${config['email_smtp_port']}" size="4"><label>SMTP Port</label>
|
||||||
|
</div>
|
||||||
|
<div class="row checkbox">
|
||||||
|
<input type="checkbox" name="email_tls" value="1" ${config['email_tls']} /><label>TLS</label>
|
||||||
|
</div>
|
||||||
|
<div class="row checkbox">
|
||||||
|
<input type="checkbox" name="email_onsnatch" value="1" ${config['email_onsnatch']} /><label>Notify on snatch?</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -1416,6 +1453,17 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Port</label><input type="text" name="customport" value="${config['customport']}" size="8">
|
<label>Port</label><input type="text" name="customport" value="${config['customport']}" size="8">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row checkbox">
|
||||||
|
<input type="checkbox" name="customauth" id="customauth" value="1" ${config['customauth']} /><label>Requires Authentication</label>
|
||||||
|
</div>
|
||||||
|
<div id="customauth_options">
|
||||||
|
<div class="row">
|
||||||
|
<label>Username</label><input type="text" class="customuser" name="customuser" value="${config['customuser']}" size="20">
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<label>Password</label><input type="password" class="custompass" name="custompass" value="${config['custompass']}" size="15"><br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Sleep Interval</label><input type="text" name="customsleep" value="${config['customsleep']}" size="4">
|
<label>Sleep Interval</label><input type="text" name="customsleep" value="${config['customsleep']}" size="4">
|
||||||
</div>
|
</div>
|
||||||
@@ -1526,6 +1574,25 @@
|
|||||||
$('#api_key').val(data);
|
$('#api_key').val(data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
if ($("#customauth").is(":checked"))
|
||||||
|
{
|
||||||
|
$("#customauth_options").show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$("#customauth_options").hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#customauth").click(function(){
|
||||||
|
if ($("#customauth").is(":checked"))
|
||||||
|
{
|
||||||
|
$("#customauth_options").slideDown();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$("#customauth_options").slideUp();
|
||||||
|
}
|
||||||
|
});
|
||||||
if ($("#enable_https").is(":checked"))
|
if ($("#enable_https").is(":checked"))
|
||||||
{
|
{
|
||||||
$("#https_options").show();
|
$("#https_options").show();
|
||||||
@@ -1866,6 +1933,26 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if ($("#email").is(":checked"))
|
||||||
|
{
|
||||||
|
$("#email_options").show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$("#email_options").hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#email").click(function(){
|
||||||
|
if ($("#email").is(":checked"))
|
||||||
|
{
|
||||||
|
$("#email_options").slideDown();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$("#email_options").slideUp();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if ($("#songkick").is(":checked"))
|
if ($("#songkick").is(":checked"))
|
||||||
{
|
{
|
||||||
$("#songkickoptions").show();
|
$("#songkickoptions").show();
|
||||||
@@ -2074,6 +2161,7 @@
|
|||||||
initConfigCheckbox("#use_whatcd");
|
initConfigCheckbox("#use_whatcd");
|
||||||
initConfigCheckbox("#api_enabled");
|
initConfigCheckbox("#api_enabled");
|
||||||
initConfigCheckbox("#enable_https");
|
initConfigCheckbox("#enable_https");
|
||||||
|
initConfigCheckbox("#customauth");
|
||||||
|
|
||||||
|
|
||||||
$('#twitterStep1').click(function () {
|
$('#twitterStep1').click(function () {
|
||||||
|
|||||||
@@ -44,9 +44,12 @@ _CONFIG_DEFINITIONS = {
|
|||||||
'CUE_SPLIT': (int, 'General', 1),
|
'CUE_SPLIT': (int, 'General', 1),
|
||||||
'CUE_SPLIT_FLAC_PATH': (str, 'General', ''),
|
'CUE_SPLIT_FLAC_PATH': (str, 'General', ''),
|
||||||
'CUE_SPLIT_SHNTOOL_PATH': (str, 'General', ''),
|
'CUE_SPLIT_SHNTOOL_PATH': (str, 'General', ''),
|
||||||
|
'CUSTOMAUTH': (int, 'General', 0),
|
||||||
'CUSTOMHOST': (str, 'General', 'localhost'),
|
'CUSTOMHOST': (str, 'General', 'localhost'),
|
||||||
|
'CUSTOMPASS': (str, 'General', ''),
|
||||||
'CUSTOMPORT': (int, 'General', 5000),
|
'CUSTOMPORT': (int, 'General', 5000),
|
||||||
'CUSTOMSLEEP': (int, 'General', 1),
|
'CUSTOMSLEEP': (int, 'General', 1),
|
||||||
|
'CUSTOMUSER': (str, 'General', ''),
|
||||||
'DELETE_LOSSLESS_FILES': (int, 'General', 1),
|
'DELETE_LOSSLESS_FILES': (int, 'General', 1),
|
||||||
'DESTINATION_DIR': (str, 'General', ''),
|
'DESTINATION_DIR': (str, 'General', ''),
|
||||||
'DETECT_BITRATE': (int, 'General', 0),
|
'DETECT_BITRATE': (int, 'General', 0),
|
||||||
@@ -54,6 +57,15 @@ _CONFIG_DEFINITIONS = {
|
|||||||
'DOWNLOAD_SCAN_INTERVAL': (int, 'General', 5),
|
'DOWNLOAD_SCAN_INTERVAL': (int, 'General', 5),
|
||||||
'DOWNLOAD_TORRENT_DIR': (str, 'General', ''),
|
'DOWNLOAD_TORRENT_DIR': (str, 'General', ''),
|
||||||
'DO_NOT_OVERRIDE_GIT_BRANCH': (int, 'General', 0),
|
'DO_NOT_OVERRIDE_GIT_BRANCH': (int, 'General', 0),
|
||||||
|
'EMAIL_ENABLED': (int, 'Email', 0),
|
||||||
|
'EMAIL_FROM': (str, 'Email', ''),
|
||||||
|
'EMAIL_TO': (str, 'Email', ''),
|
||||||
|
'EMAIL_SMTP_SERVER': (str, 'Email', ''),
|
||||||
|
'EMAIL_SMTP_USER': (str, 'Email', ''),
|
||||||
|
'EMAIL_SMTP_PASSWORD': (str, 'Email', ''),
|
||||||
|
'EMAIL_SMTP_PORT': (int, 'Email', 25),
|
||||||
|
'EMAIL_TLS': (int, 'Email', 0),
|
||||||
|
'EMAIL_ONSNATCH': (int, 'Email', 0),
|
||||||
'EMBED_ALBUM_ART': (int, 'General', 0),
|
'EMBED_ALBUM_ART': (int, 'General', 0),
|
||||||
'EMBED_LYRICS': (int, 'General', 0),
|
'EMBED_LYRICS': (int, 'General', 0),
|
||||||
'ENABLE_HTTPS': (int, 'General', 0),
|
'ENABLE_HTTPS': (int, 'General', 0),
|
||||||
@@ -92,6 +104,7 @@ _CONFIG_DEFINITIONS = {
|
|||||||
'HTTP_PROXY': (int, 'General', 0),
|
'HTTP_PROXY': (int, 'General', 0),
|
||||||
'HTTP_ROOT': (str, 'General', '/'),
|
'HTTP_ROOT': (str, 'General', '/'),
|
||||||
'HTTP_USERNAME': (str, 'General', ''),
|
'HTTP_USERNAME': (str, 'General', ''),
|
||||||
|
'IDTAG': (int, 'Beets', 0),
|
||||||
'IGNORED_WORDS': (str, 'General', ''),
|
'IGNORED_WORDS': (str, 'General', ''),
|
||||||
'IGNORED_FOLDERS': (list, 'Advanced', []),
|
'IGNORED_FOLDERS': (list, 'Advanced', []),
|
||||||
'IGNORED_FILES': (list, 'Advanced', []),
|
'IGNORED_FILES': (list, 'Advanced', []),
|
||||||
|
|||||||
@@ -173,15 +173,15 @@ def piratesize(size):
|
|||||||
factor = float(split[0])
|
factor = float(split[0])
|
||||||
unit = split[1].upper()
|
unit = split[1].upper()
|
||||||
|
|
||||||
if unit == 'MiB':
|
if unit == 'MIB':
|
||||||
size = factor * 1048576
|
size = factor * 1048576
|
||||||
elif unit == 'MB':
|
elif unit == 'MB':
|
||||||
size = factor * 1000000
|
size = factor * 1000000
|
||||||
elif unit == 'GiB':
|
elif unit == 'GIB':
|
||||||
size = factor * 1073741824
|
size = factor * 1073741824
|
||||||
elif unit == 'GB':
|
elif unit == 'GB':
|
||||||
size = factor * 1000000000
|
size = factor * 1000000000
|
||||||
elif unit == 'KiB':
|
elif unit == 'KIB':
|
||||||
size = factor * 1024
|
size = factor * 1024
|
||||||
elif unit == 'KB':
|
elif unit == 'KB':
|
||||||
size = factor * 1000
|
size = factor * 1000
|
||||||
|
|||||||
+9
-3
@@ -47,6 +47,8 @@ def startmb():
|
|||||||
elif headphones.CONFIG.MIRROR == "custom":
|
elif headphones.CONFIG.MIRROR == "custom":
|
||||||
mbhost = headphones.CONFIG.CUSTOMHOST
|
mbhost = headphones.CONFIG.CUSTOMHOST
|
||||||
mbport = int(headphones.CONFIG.CUSTOMPORT)
|
mbport = int(headphones.CONFIG.CUSTOMPORT)
|
||||||
|
mbuser = headphones.CONFIG.CUSTOMUSER
|
||||||
|
mbpass = headphones.CONFIG.CUSTOMPASS
|
||||||
sleepytime = int(headphones.CONFIG.CUSTOMSLEEP)
|
sleepytime = int(headphones.CONFIG.CUSTOMSLEEP)
|
||||||
elif headphones.CONFIG.MIRROR == "headphones":
|
elif headphones.CONFIG.MIRROR == "headphones":
|
||||||
mbhost = "144.76.94.239"
|
mbhost = "144.76.94.239"
|
||||||
@@ -69,12 +71,16 @@ def startmb():
|
|||||||
mb_lock.minimum_delta = sleepytime
|
mb_lock.minimum_delta = sleepytime
|
||||||
|
|
||||||
# Add headphones credentials
|
# Add headphones credentials
|
||||||
if headphones.CONFIG.MIRROR == "headphones":
|
if headphones.CONFIG.MIRROR == "headphones" or headphones.CONFIG.CUSTOMAUTH:
|
||||||
if not mbuser and mbpass:
|
if not mbuser or not mbpass:
|
||||||
logger.warn("No username or password set for VIP server")
|
logger.warn("No username or password set for MusicBrainz server")
|
||||||
else:
|
else:
|
||||||
musicbrainzngs.hpauth(mbuser, mbpass)
|
musicbrainzngs.hpauth(mbuser, mbpass)
|
||||||
|
|
||||||
|
# Let us know if we disable custom authentication
|
||||||
|
if not headphones.CONFIG.CUSTOMAUTH and headphones.CONFIG.MIRROR == "custom":
|
||||||
|
musicbrainzngs.disable_hpauth()
|
||||||
|
|
||||||
logger.debug('Using the following server values: MBHost: %s, MBPort: %i, Sleep Interval: %i', mbhost, mbport, sleepytime)
|
logger.debug('Using the following server values: MBHost: %s, MBPort: %i, Sleep Interval: %i', mbhost, mbport, sleepytime)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -34,6 +34,11 @@ import json
|
|||||||
import oauth2 as oauth
|
import oauth2 as oauth
|
||||||
import pythontwitter as twitter
|
import pythontwitter as twitter
|
||||||
|
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
import smtplib
|
||||||
|
import email.utils
|
||||||
|
|
||||||
|
|
||||||
class GROWL(object):
|
class GROWL(object):
|
||||||
"""
|
"""
|
||||||
Growl notifications, for OS X.
|
Growl notifications, for OS X.
|
||||||
@@ -827,3 +832,31 @@ class SubSonicNotifier(object):
|
|||||||
# Invoke request
|
# Invoke request
|
||||||
request.request_response(self.host + "musicFolderSettings.view?scanNow",
|
request.request_response(self.host + "musicFolderSettings.view?scanNow",
|
||||||
auth=(self.username, self.password))
|
auth=(self.username, self.password))
|
||||||
|
|
||||||
|
class Email(object):
|
||||||
|
|
||||||
|
def notify(self, subject, message):
|
||||||
|
|
||||||
|
message = MIMEText(message, 'plain', "utf-8")
|
||||||
|
message['Subject'] = subject
|
||||||
|
message['From'] = email.utils.formataddr(('Headphones', headphones.CONFIG.EMAIL_FROM))
|
||||||
|
message['To'] = headphones.CONFIG.EMAIL_TO
|
||||||
|
|
||||||
|
try:
|
||||||
|
mailserver = smtplib.SMTP(headphones.CONFIG.EMAIL_SMTP_SERVER, headphones.CONFIG.EMAIL_SMTP_PORT)
|
||||||
|
|
||||||
|
if (headphones.CONFIG.EMAIL_TLS):
|
||||||
|
mailserver.starttls()
|
||||||
|
|
||||||
|
mailserver.ehlo()
|
||||||
|
|
||||||
|
if headphones.CONFIG.EMAIL_SMTP_USER:
|
||||||
|
mailserver.login(headphones.CONFIG.EMAIL_SMTP_USER, headphones.CONFIG.EMAIL_SMTP_PASSWORD)
|
||||||
|
|
||||||
|
mailserver.sendmail(headphones.CONFIG.EMAIL_FROM, headphones.CONFIG.EMAIL_TO, message.as_string())
|
||||||
|
mailserver.quit()
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception, e:
|
||||||
|
logger.warn('Error sending Email: %s' % e)
|
||||||
|
return False
|
||||||
@@ -23,6 +23,7 @@ import itertools
|
|||||||
import headphones
|
import headphones
|
||||||
|
|
||||||
from beets import autotag
|
from beets import autotag
|
||||||
|
from beets import config as beetsconfig
|
||||||
from beets.mediafile import MediaFile, FileTypeError, UnreadableFileError
|
from beets.mediafile import MediaFile, FileTypeError, UnreadableFileError
|
||||||
from beetsplug import lyrics as beetslyrics
|
from beetsplug import lyrics as beetslyrics
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ postprocessor_lock = threading.Lock()
|
|||||||
|
|
||||||
|
|
||||||
def checkFolder():
|
def checkFolder():
|
||||||
logger.info("Checking download folder for completed downloads (only snatched ones).")
|
logger.debug("Checking download folder for completed downloads (only snatched ones).")
|
||||||
|
|
||||||
with postprocessor_lock:
|
with postprocessor_lock:
|
||||||
myDB = db.DBConnection()
|
myDB = db.DBConnection()
|
||||||
@@ -56,7 +57,7 @@ def checkFolder():
|
|||||||
else:
|
else:
|
||||||
logger.info("No folder name found for " + album['Title'])
|
logger.info("No folder name found for " + album['Title'])
|
||||||
|
|
||||||
logger.info("Checking download folder finished.")
|
logger.debug("Checking download folder finished.")
|
||||||
|
|
||||||
def verify(albumid, albumpath, Kind=None, forced=False):
|
def verify(albumid, albumpath, Kind=None, forced=False):
|
||||||
|
|
||||||
@@ -513,6 +514,12 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list,
|
|||||||
mpc = notifiers.MPC()
|
mpc = notifiers.MPC()
|
||||||
mpc.notify()
|
mpc.notify()
|
||||||
|
|
||||||
|
if headphones.CONFIG.EMAIL_ENABLED:
|
||||||
|
logger.info(u"Sending Email notification")
|
||||||
|
email = notifiers.Email()
|
||||||
|
subject = release['ArtistName'] + ' - ' + release['AlbumTitle']
|
||||||
|
email.notify(subject, "Download and Postprocessing completed")
|
||||||
|
|
||||||
|
|
||||||
def embedAlbumArt(artwork, downloaded_track_list):
|
def embedAlbumArt(artwork, downloaded_track_list):
|
||||||
logger.info('Embedding album art')
|
logger.info('Embedding album art')
|
||||||
@@ -858,7 +865,7 @@ def correctMetadata(albumid, release, downloaded_track_list):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Error getting recommendation: %s. Not writing metadata', e)
|
logger.error('Error getting recommendation: %s. Not writing metadata', e)
|
||||||
return
|
return
|
||||||
if str(rec) == 'recommendation.none':
|
if str(rec) == 'Recommendation.none':
|
||||||
logger.warn('No accurate album match found for %s, %s - not writing metadata', release['ArtistName'], release['AlbumTitle'])
|
logger.warn('No accurate album match found for %s, %s - not writing metadata', release['ArtistName'], release['AlbumTitle'])
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -873,6 +880,14 @@ def correctMetadata(albumid, release, downloaded_track_list):
|
|||||||
# TODO: Handle extra_items & extra_tracks
|
# TODO: Handle extra_items & extra_tracks
|
||||||
|
|
||||||
autotag.apply_metadata(info, mapping)
|
autotag.apply_metadata(info, mapping)
|
||||||
|
|
||||||
|
# Set ID3 tag version
|
||||||
|
if headphones.CONFIG.IDTAG:
|
||||||
|
beetsconfig['id3v23'] = True
|
||||||
|
logger.debug("Using ID3v2.3")
|
||||||
|
else:
|
||||||
|
beetsconfig['id3v23'] = False
|
||||||
|
logger.debug("Using ID3v2.4")
|
||||||
|
|
||||||
for item in items:
|
for item in items:
|
||||||
try:
|
try:
|
||||||
@@ -1053,6 +1068,8 @@ def renameUnprocessedFolder(path, tag):
|
|||||||
|
|
||||||
def forcePostProcess(dir=None, expand_subfolders=True, album_dir=None):
|
def forcePostProcess(dir=None, expand_subfolders=True, album_dir=None):
|
||||||
|
|
||||||
|
logger.info('Force checking download folder for completed downloads')
|
||||||
|
|
||||||
ignored = 0
|
ignored = 0
|
||||||
|
|
||||||
if album_dir:
|
if album_dir:
|
||||||
|
|||||||
+16
-12
@@ -225,7 +225,7 @@ def do_sorted_search(album, new, losslessOnly, choose_specific_download=False):
|
|||||||
myDB = db.DBConnection()
|
myDB = db.DBConnection()
|
||||||
albumlength = myDB.select('SELECT sum(TrackDuration) from tracks WHERE AlbumID=?', [album['AlbumID']])[0][0]
|
albumlength = myDB.select('SELECT sum(TrackDuration) from tracks WHERE AlbumID=?', [album['AlbumID']])[0][0]
|
||||||
|
|
||||||
if headphones.CONFIG.PREFER_TORRENTS == 0:
|
if headphones.CONFIG.PREFER_TORRENTS == 0 and not choose_specific_download:
|
||||||
|
|
||||||
if NZB_PROVIDERS and NZB_DOWNLOADERS:
|
if NZB_PROVIDERS and NZB_DOWNLOADERS:
|
||||||
results = searchNZB(album, new, losslessOnly, albumlength)
|
results = searchNZB(album, new, losslessOnly, albumlength)
|
||||||
@@ -233,7 +233,7 @@ def do_sorted_search(album, new, losslessOnly, choose_specific_download=False):
|
|||||||
if not results and TORRENT_PROVIDERS:
|
if not results and TORRENT_PROVIDERS:
|
||||||
results = searchTorrent(album, new, losslessOnly, albumlength)
|
results = searchTorrent(album, new, losslessOnly, albumlength)
|
||||||
|
|
||||||
elif headphones.CONFIG.PREFER_TORRENTS == 1:
|
elif headphones.CONFIG.PREFER_TORRENTS == 1 and not choose_specific_download:
|
||||||
|
|
||||||
if TORRENT_PROVIDERS:
|
if TORRENT_PROVIDERS:
|
||||||
results = searchTorrent(album, new, losslessOnly, albumlength)
|
results = searchTorrent(album, new, losslessOnly, albumlength)
|
||||||
@@ -247,10 +247,10 @@ def do_sorted_search(album, new, losslessOnly, choose_specific_download=False):
|
|||||||
torrent_results = None
|
torrent_results = None
|
||||||
|
|
||||||
if NZB_PROVIDERS and NZB_DOWNLOADERS:
|
if NZB_PROVIDERS and NZB_DOWNLOADERS:
|
||||||
nzb_results = searchNZB(album, new, losslessOnly, albumlength)
|
nzb_results = searchNZB(album, new, losslessOnly, albumlength, choose_specific_download)
|
||||||
|
|
||||||
if TORRENT_PROVIDERS:
|
if TORRENT_PROVIDERS:
|
||||||
torrent_results = searchTorrent(album, new, losslessOnly, albumlength)
|
torrent_results = searchTorrent(album, new, losslessOnly, albumlength, choose_specific_download)
|
||||||
|
|
||||||
if not nzb_results:
|
if not nzb_results:
|
||||||
nzb_results = []
|
nzb_results = []
|
||||||
@@ -306,9 +306,9 @@ def more_filtering(results, album, albumlength, new):
|
|||||||
targetsize = albumlength / 1000 * int(headphones.CONFIG.PREFERRED_BITRATE) * 128
|
targetsize = albumlength / 1000 * int(headphones.CONFIG.PREFERRED_BITRATE) * 128
|
||||||
logger.info('Target size: %s' % helpers.bytes_to_mb(targetsize))
|
logger.info('Target size: %s' % helpers.bytes_to_mb(targetsize))
|
||||||
if headphones.CONFIG.PREFERRED_BITRATE_LOW_BUFFER:
|
if headphones.CONFIG.PREFERRED_BITRATE_LOW_BUFFER:
|
||||||
low_size_limit = targetsize - (targetsize * int(headphones.CONFIG.PREFERRED_BITRATE_LOW_BUFFER) / 100)
|
low_size_limit = targetsize * int(headphones.CONFIG.PREFERRED_BITRATE_LOW_BUFFER) / 100
|
||||||
if headphones.CONFIG.PREFERRED_BITRATE_HIGH_BUFFER:
|
if headphones.CONFIG.PREFERRED_BITRATE_HIGH_BUFFER:
|
||||||
high_size_limit = targetsize + (targetsize * int(headphones.CONFIG.PREFERRED_BITRATE_HIGH_BUFFER) / 100)
|
high_size_limit = targetsize * int(headphones.CONFIG.PREFERRED_BITRATE_HIGH_BUFFER) / 100
|
||||||
if headphones.CONFIG.PREFERRED_BITRATE_ALLOW_LOSSLESS:
|
if headphones.CONFIG.PREFERRED_BITRATE_ALLOW_LOSSLESS:
|
||||||
allow_lossless = True
|
allow_lossless = True
|
||||||
|
|
||||||
@@ -429,7 +429,7 @@ def get_year_from_release_date(release_date):
|
|||||||
return year
|
return year
|
||||||
|
|
||||||
|
|
||||||
def searchNZB(album, new=False, losslessOnly=False, albumlength=None):
|
def searchNZB(album, new=False, losslessOnly=False, albumlength=None, choose_specific_download=False):
|
||||||
reldate = album['ReleaseDate']
|
reldate = album['ReleaseDate']
|
||||||
year = get_year_from_release_date(reldate)
|
year = get_year_from_release_date(reldate)
|
||||||
|
|
||||||
@@ -691,7 +691,7 @@ def searchNZB(album, new=False, losslessOnly=False, albumlength=None):
|
|||||||
results = [result for result in resultlist if verifyresult(result[0], artistterm, term, losslessOnly)]
|
results = [result for result in resultlist if verifyresult(result[0], artistterm, term, losslessOnly)]
|
||||||
|
|
||||||
# Additional filtering for size etc
|
# Additional filtering for size etc
|
||||||
if results:
|
if results and not choose_specific_download:
|
||||||
results = more_filtering(results, album, albumlength, new)
|
results = more_filtering(results, album, albumlength, new)
|
||||||
|
|
||||||
return results
|
return results
|
||||||
@@ -946,7 +946,11 @@ def send_to_downloader(data, bestqual, album):
|
|||||||
b2msg = 'From ' + provider + '<br></br>' + name
|
b2msg = 'From ' + provider + '<br></br>' + name
|
||||||
boxcar = notifiers.BOXCAR()
|
boxcar = notifiers.BOXCAR()
|
||||||
boxcar.notify('Headphones snatched: ' + title, b2msg, rgid)
|
boxcar.notify('Headphones snatched: ' + title, b2msg, rgid)
|
||||||
|
if headphones.CONFIG.EMAIL_ENABLED and headphones.CONFIG.EMAIL_ONSNATCH:
|
||||||
|
logger.info(u"Sending Email notification")
|
||||||
|
email = notifiers.Email()
|
||||||
|
message = 'Snatched from ' + provider + '. ' + name
|
||||||
|
email.notify(title, message)
|
||||||
|
|
||||||
def verifyresult(title, artistterm, term, lossless):
|
def verifyresult(title, artistterm, term, lossless):
|
||||||
|
|
||||||
@@ -1014,7 +1018,7 @@ def verifyresult(title, artistterm, term, lossless):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def searchTorrent(album, new=False, losslessOnly=False, albumlength=None):
|
def searchTorrent(album, new=False, losslessOnly=False, albumlength=None, choose_specific_download=False):
|
||||||
global gazelle # persistent what.cd api object to reduce number of login attempts
|
global gazelle # persistent what.cd api object to reduce number of login attempts
|
||||||
|
|
||||||
# rutracker login
|
# rutracker login
|
||||||
@@ -1092,7 +1096,7 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None):
|
|||||||
if headphones.CONFIG.KAT_PROXY_URL:
|
if headphones.CONFIG.KAT_PROXY_URL:
|
||||||
providerurl = fix_url(set_proxy(headphones.CONFIG.KAT_PROXY_URL))
|
providerurl = fix_url(set_proxy(headphones.CONFIG.KAT_PROXY_URL))
|
||||||
else:
|
else:
|
||||||
providerurl = fix_url("https://kickass.so")
|
providerurl = fix_url("https://kickass.to")
|
||||||
|
|
||||||
# Build URL
|
# Build URL
|
||||||
providerurl = providerurl + "/usearch/" + ka_term
|
providerurl = providerurl + "/usearch/" + ka_term
|
||||||
@@ -1521,7 +1525,7 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None):
|
|||||||
results = [result for result in resultlist if verifyresult(result[0], artistterm, term, losslessOnly)]
|
results = [result for result in resultlist if verifyresult(result[0], artistterm, term, losslessOnly)]
|
||||||
|
|
||||||
# Additional filtering for size etc
|
# Additional filtering for size etc
|
||||||
if results:
|
if results and not choose_specific_download:
|
||||||
results = more_filtering(results, album, albumlength, new)
|
results = more_filtering(results, album, albumlength, new)
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|||||||
+19
-2
@@ -374,6 +374,9 @@ class WebInterface(object):
|
|||||||
myDB = db.DBConnection()
|
myDB = db.DBConnection()
|
||||||
album = myDB.action('SELECT * from albums WHERE AlbumID=?', [AlbumID]).fetchone()
|
album = myDB.action('SELECT * from albums WHERE AlbumID=?', [AlbumID]).fetchone()
|
||||||
searcher.send_to_downloader(data, bestqual, album)
|
searcher.send_to_downloader(data, bestqual, album)
|
||||||
|
return json.dumps({'result':'success'})
|
||||||
|
else:
|
||||||
|
return json.dumps({'result':'failure'})
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
def unqueueAlbum(self, AlbumID, ArtistID):
|
def unqueueAlbum(self, AlbumID, ArtistID):
|
||||||
@@ -877,6 +880,7 @@ class WebInterface(object):
|
|||||||
cherrypy.response.headers['Content-type'] = 'application/json'
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
return json_albums
|
return json_albums
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
def getArtistjson(self, ArtistID, **kwargs):
|
def getArtistjson(self, ArtistID, **kwargs):
|
||||||
myDB = db.DBConnection()
|
myDB = db.DBConnection()
|
||||||
artist = myDB.action('SELECT * FROM artists WHERE ArtistID=?', [ArtistID]).fetchone()
|
artist = myDB.action('SELECT * FROM artists WHERE ArtistID=?', [ArtistID]).fetchone()
|
||||||
@@ -1142,6 +1146,9 @@ class WebInterface(object):
|
|||||||
"customhost": headphones.CONFIG.CUSTOMHOST,
|
"customhost": headphones.CONFIG.CUSTOMHOST,
|
||||||
"customport": headphones.CONFIG.CUSTOMPORT,
|
"customport": headphones.CONFIG.CUSTOMPORT,
|
||||||
"customsleep": headphones.CONFIG.CUSTOMSLEEP,
|
"customsleep": headphones.CONFIG.CUSTOMSLEEP,
|
||||||
|
"customauth": checked(headphones.CONFIG.CUSTOMAUTH),
|
||||||
|
"customuser": headphones.CONFIG.CUSTOMUSER,
|
||||||
|
"custompass": headphones.CONFIG.CUSTOMPASS,
|
||||||
"hpuser": headphones.CONFIG.HPUSER,
|
"hpuser": headphones.CONFIG.HPUSER,
|
||||||
"hppass": headphones.CONFIG.HPPASS,
|
"hppass": headphones.CONFIG.HPPASS,
|
||||||
"songkick_enabled": checked(headphones.CONFIG.SONGKICK_ENABLED),
|
"songkick_enabled": checked(headphones.CONFIG.SONGKICK_ENABLED),
|
||||||
@@ -1151,7 +1158,17 @@ class WebInterface(object):
|
|||||||
"cache_sizemb": headphones.CONFIG.CACHE_SIZEMB,
|
"cache_sizemb": headphones.CONFIG.CACHE_SIZEMB,
|
||||||
"file_permissions": headphones.CONFIG.FILE_PERMISSIONS,
|
"file_permissions": headphones.CONFIG.FILE_PERMISSIONS,
|
||||||
"folder_permissions": headphones.CONFIG.FOLDER_PERMISSIONS,
|
"folder_permissions": headphones.CONFIG.FOLDER_PERMISSIONS,
|
||||||
"mpc_enabled": checked(headphones.CONFIG.MPC_ENABLED)
|
"mpc_enabled": checked(headphones.CONFIG.MPC_ENABLED),
|
||||||
|
"email_enabled": checked(headphones.CONFIG.EMAIL_ENABLED),
|
||||||
|
"email_from": headphones.CONFIG.EMAIL_FROM,
|
||||||
|
"email_to": headphones.CONFIG.EMAIL_TO,
|
||||||
|
"email_smtp_server": headphones.CONFIG.EMAIL_SMTP_SERVER,
|
||||||
|
"email_smtp_user": headphones.CONFIG.EMAIL_SMTP_USER,
|
||||||
|
"email_smtp_password": headphones.CONFIG.EMAIL_SMTP_PASSWORD,
|
||||||
|
"email_smtp_port": int(headphones.CONFIG.EMAIL_SMTP_PORT),
|
||||||
|
"email_tls": checked(headphones.CONFIG.EMAIL_TLS),
|
||||||
|
"email_onsnatch": checked(headphones.CONFIG.EMAIL_ONSNATCH),
|
||||||
|
"idtag": checked(headphones.CONFIG.IDTAG)
|
||||||
}
|
}
|
||||||
|
|
||||||
# Need to convert EXTRAS to a dictionary we can pass to the config:
|
# Need to convert EXTRAS to a dictionary we can pass to the config:
|
||||||
@@ -1196,7 +1213,7 @@ class WebInterface(object):
|
|||||||
"nma_enabled", "nma_onsnatch", "pushalot_enabled", "pushalot_onsnatch", "synoindex_enabled", "pushover_enabled",
|
"nma_enabled", "nma_onsnatch", "pushalot_enabled", "pushalot_onsnatch", "synoindex_enabled", "pushover_enabled",
|
||||||
"pushover_onsnatch", "pushbullet_enabled", "pushbullet_onsnatch", "subsonic_enabled", "twitter_enabled", "twitter_onsnatch",
|
"pushover_onsnatch", "pushbullet_enabled", "pushbullet_onsnatch", "subsonic_enabled", "twitter_enabled", "twitter_onsnatch",
|
||||||
"osx_notify_enabled", "osx_notify_onsnatch", "boxcar_enabled", "boxcar_onsnatch", "songkick_enabled", "songkick_filter_enabled",
|
"osx_notify_enabled", "osx_notify_onsnatch", "boxcar_enabled", "boxcar_onsnatch", "songkick_enabled", "songkick_filter_enabled",
|
||||||
"mpc_enabled"
|
"mpc_enabled", "email_enabled", "email_tls", "email_onsnatch", "customauth", "idtag"
|
||||||
]
|
]
|
||||||
for checked_config in checked_configs:
|
for checked_config in checked_configs:
|
||||||
if checked_config not in kwargs:
|
if checked_config not in kwargs:
|
||||||
|
|||||||
@@ -271,6 +271,7 @@ user = password = ""
|
|||||||
hostname = "musicbrainz.org"
|
hostname = "musicbrainz.org"
|
||||||
_client = ""
|
_client = ""
|
||||||
_useragent = ""
|
_useragent = ""
|
||||||
|
mb_auth = False
|
||||||
|
|
||||||
def auth(u, p):
|
def auth(u, p):
|
||||||
"""Set the username and password to be used in subsequent queries to
|
"""Set the username and password to be used in subsequent queries to
|
||||||
@@ -284,9 +285,16 @@ def hpauth(u, p):
|
|||||||
"""Set the username and password to be used in subsequent queries to
|
"""Set the username and password to be used in subsequent queries to
|
||||||
the MusicBrainz XML API that require authentication.
|
the MusicBrainz XML API that require authentication.
|
||||||
"""
|
"""
|
||||||
global hpuser, hppassword
|
global hpuser, hppassword, mb_auth
|
||||||
hpuser = u
|
hpuser = u
|
||||||
hppassword = p
|
hppassword = p
|
||||||
|
mb_auth = True
|
||||||
|
|
||||||
|
def disable_hpauth():
|
||||||
|
"""Disable the authentication for MusicBrainz XML API
|
||||||
|
"""
|
||||||
|
global mb_auth
|
||||||
|
mb_auth = False
|
||||||
|
|
||||||
def set_useragent(app, version, contact=None):
|
def set_useragent(app, version, contact=None):
|
||||||
"""Set the User-Agent to be used for requests to the MusicBrainz webservice.
|
"""Set the User-Agent to be used for requests to the MusicBrainz webservice.
|
||||||
@@ -635,7 +643,7 @@ def _mb_request(path, method='GET', auth_required=False, client_required=False,
|
|||||||
req.add_header('User-Agent', _useragent)
|
req.add_header('User-Agent', _useragent)
|
||||||
|
|
||||||
# Add headphones credentials
|
# Add headphones credentials
|
||||||
if hostname == '144.76.94.239:8181':
|
if mb_auth:
|
||||||
base64string = base64.encodestring('%s:%s' % (hpuser, hppassword)).replace('\n', '')
|
base64string = base64.encodestring('%s:%s' % (hpuser, hppassword)).replace('\n', '')
|
||||||
req.add_header("Authorization", "Basic %s" % base64string)
|
req.add_header("Authorization", "Basic %s" % base64string)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user