mirror of
https://github.com/rembo10/headphones.git
synced 2026-07-20 16:03:59 +01:00
Merge branch 'develop'
* develop: Release v0.5.1 Prepare for next release Fixed HTML div closing tag. Updated titles Fixed typo Allow one to disable all tasks Allow one to adjust interval settings without restarting. Prevent infinite recursion while scanning library. Fix for new paths Added the real pkg_resources from setuptools 7.0. Should fix #2001 Fixed contrib scripts. Added *.pyc cleaning scripts Check if pyOpenSSL is installed before enabling HTTPS. Ignore CSR files Fixed SSL too long errors in CherryPy. Spaces removal Add downgrade functionality (contributed script) Use urlparse to parse transmission URL Fix for #1998
This commit is contained in:
+3
-4
@@ -6,12 +6,13 @@
|
|||||||
*.pyproj
|
*.pyproj
|
||||||
*.sln
|
*.sln
|
||||||
|
|
||||||
# Logs and databases #
|
# Headphones files #
|
||||||
######################
|
######################
|
||||||
*.log
|
*.log
|
||||||
*.db*
|
*.db*
|
||||||
*.db-journal
|
*.db-journal
|
||||||
*.ini
|
*.ini
|
||||||
|
version.lock
|
||||||
logs/*
|
logs/*
|
||||||
cache/*
|
cache/*
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ cache/*
|
|||||||
##################
|
##################
|
||||||
*.crt
|
*.crt
|
||||||
*.key
|
*.key
|
||||||
|
*.csr
|
||||||
|
|
||||||
# OS generated files #
|
# OS generated files #
|
||||||
######################
|
######################
|
||||||
@@ -64,6 +66,3 @@ _ReSharper*/
|
|||||||
/logs
|
/logs
|
||||||
.project
|
.project
|
||||||
.pydevproject
|
.pydevproject
|
||||||
|
|
||||||
|
|
||||||
headphones_docs
|
|
||||||
@@ -1,5 +1,18 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v0.5.1
|
||||||
|
Released 13 November 2014
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
* Added: allow one to disable interval tasks (#2002)
|
||||||
|
* Added: script to downgrade Headphones to last version that started (Linux only)
|
||||||
|
* Fixed: SSL issues in CherryPy. Self-generated certificates will be 2048 now (#1995)
|
||||||
|
* Fixed: Transmission URL detection (#1998)
|
||||||
|
* Fixed: missing dependencies for APScheduler and CherryPy (#2001)
|
||||||
|
* Improved: symlink infinite recursion detection
|
||||||
|
|
||||||
|
The full list of commits can be found [here](https://github.com/rembo10/headphones/compare/v0.5...v0.5.1).
|
||||||
|
|
||||||
## v0.5
|
## v0.5
|
||||||
Released 10 November 2014
|
Released 10 November 2014
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -9,7 +9,7 @@ In case you read this because you are posting an issue, please take a minute and
|
|||||||
* Close your issue if you resolved it.
|
* Close your issue if you resolved it.
|
||||||
|
|
||||||
## For developers
|
## For developers
|
||||||
If you think you can contribute code to the Headphones repository, do not hesitate to submit a pull request.
|
If you think you can contribute code to the Headphones repository, do not hesitate to submit a pull request.
|
||||||
|
|
||||||
### Branches
|
### Branches
|
||||||
All pull requests should be based on the `develop` branch. When you want to develop a new feature, clone the repository with `git clone origin/develop -b FEATURE_NAME`. Use meaningful commit messages.
|
All pull requests should be based on the `develop` branch. When you want to develop a new feature, clone the repository with `git clone origin/develop -b FEATURE_NAME`. Use meaningful commit messages.
|
||||||
@@ -31,5 +31,5 @@ Altough Headphones did not adapt a code convention in the past, we try to follow
|
|||||||
* `_private_something`
|
* `_private_something`
|
||||||
* `self.__really_private_field`
|
* `self.__really_private_field`
|
||||||
* `_global`
|
* `_global`
|
||||||
|
|
||||||
Document your code!
|
Document your code!
|
||||||
@@ -164,6 +164,16 @@ def main():
|
|||||||
else:
|
else:
|
||||||
http_port = int(headphones.CONFIG.HTTP_PORT)
|
http_port = int(headphones.CONFIG.HTTP_PORT)
|
||||||
|
|
||||||
|
# Check if pyOpenSSL is installed. It is required for certificate generation
|
||||||
|
# and for CherryPy.
|
||||||
|
if headphones.CONFIG.ENABLE_HTTPS:
|
||||||
|
try:
|
||||||
|
import OpenSSL
|
||||||
|
except ImportError:
|
||||||
|
logger.warn("The pyOpenSSL module is missing. Install this " \
|
||||||
|
"module to enable HTTPS. HTTPS will be disabled.")
|
||||||
|
headphones.CONFIG.ENABLE_HTTPS = False
|
||||||
|
|
||||||
# Try to start the server. Will exit here is address is already in use.
|
# Try to start the server. Will exit here is address is already in use.
|
||||||
web_config = {
|
web_config = {
|
||||||
'http_port': http_port,
|
'http_port': http_port,
|
||||||
|
|||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Display information
|
||||||
|
echo "This script will remove *.pyc files. These files are generated by Python, but they can cause conflicts after an upgrade. It's safe to remove them, because they will be regenerated."
|
||||||
|
echo "Press enter to continue, or CTRL + C to quit."
|
||||||
|
read
|
||||||
|
|
||||||
|
# Remove the *.pyc
|
||||||
|
find "`dirname $0`/.." -type f -name "*.pyc" -exec rm -rf {} \;
|
||||||
Executable
+32
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Parameter check
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "Syntax: $0 <data directory>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Version file check
|
||||||
|
if [ ! -s "$1/version.lock" ]; then
|
||||||
|
echo "Missing the version.lock file in the data folder, or the file is empty. Did you start Headphones at least once?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Git installation check
|
||||||
|
if [ ! -x "$(command -v git)" ]; then
|
||||||
|
echo "Git is required to downgrade."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Display information
|
||||||
|
HASH=$(cat $1/version.lock)
|
||||||
|
|
||||||
|
echo "This script will try to downgrade Headphones to the last version that started, version $HASH. Make sure you have a backup of your config file and database, just in case!"
|
||||||
|
echo "Press enter to continue, or CTRL + C to quit."
|
||||||
|
read
|
||||||
|
|
||||||
|
# Downgrade
|
||||||
|
cd "`dirname $0`/.."
|
||||||
|
git reset --hard "$HASH"
|
||||||
|
|
||||||
|
echo "All done, Headphones should be downgraded to the last version that started."
|
||||||
@@ -101,6 +101,7 @@
|
|||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Interval</legend>
|
<legend>Interval</legend>
|
||||||
|
<small>An interval of 0 will disable a task.</small>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label title="Time between two searches for new downloads.">
|
<label title="Time between two searches for new downloads.">
|
||||||
Search Interval
|
Search Interval
|
||||||
@@ -137,7 +138,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<div class="configmessage">
|
<div class="configmessage">
|
||||||
<i class="fa fa-info-circle"></i> Web Interface changes require a restart to take effect
|
<i class="fa fa-info-circle"></i> Web Interface changes require a restart to take effect. Saving settings will restart intervals.
|
||||||
</div>
|
</div>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -266,7 +267,7 @@
|
|||||||
prio_force = ''
|
prio_force = ''
|
||||||
%>
|
%>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>NZBget Priority:</label>
|
<label>NZBget Priority</label>
|
||||||
<select name="nzbget_priority" id="nzbget_priority">
|
<select name="nzbget_priority" id="nzbget_priority">
|
||||||
<option value="-100" ${prio_verylow}>Very Low</option>
|
<option value="-100" ${prio_verylow}>Very Low</option>
|
||||||
<option value="-50" ${prio_low}>Low</option>
|
<option value="-50" ${prio_low}>Low</option>
|
||||||
@@ -294,7 +295,7 @@
|
|||||||
Music Download Directory:
|
Music Download Directory:
|
||||||
</label>
|
</label>
|
||||||
<input type="text" name="download_dir" value="${config['download_dir']}" size="50">
|
<input type="text" name="download_dir" value="${config['download_dir']}" size="50">
|
||||||
<small>Full path where SAB or NZBget downloads your music. e.g. /Users/name/Downloads/music</small>
|
<small>Full path where SAB or NZBget downloads your music, e.g. /Users/name/Downloads/music</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label title="Number of days of retention your usenet provider provides.">
|
<label title="Number of days of retention your usenet provider provides.">
|
||||||
@@ -381,14 +382,14 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset id="general_torrent_options">
|
<fieldset id="general_torrent_options">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Minimum seeders:</label>
|
<label>Minimum seeders</label>
|
||||||
<input type="text" name="numberofseeders" value="${config['numberofseeders']}" size="5">
|
<input type="text" name="numberofseeders" value="${config['numberofseeders']}" size="5">
|
||||||
<small>Number of minimum seeders a torrent must have to be accepted</small>
|
<small>Number of minimum seeders a torrent must have to be accepted</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Music Download Directory</label>
|
<label>Music Download Directory</label>
|
||||||
<input type="text" name="download_torrent_dir" value="${config['download_torrent_dir']}" size="50">
|
<input type="text" name="download_torrent_dir" value="${config['download_torrent_dir']}" size="50">
|
||||||
<small>Full path where your torrent client downloads your music e.g. '/Users/name/Downloads/music'</small>
|
<small>Full path where your torrent client downloads your music e.g. /Users/name/Downloads/music.</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="row checkbox">
|
<div class="row checkbox">
|
||||||
<label>Keep Files for Seeding</label>
|
<label>Keep Files for Seeding</label>
|
||||||
@@ -526,11 +527,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="config">
|
<div class="config">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Proxy URL (Optional): </label>
|
<label>Proxy URL</label>
|
||||||
<input type="text" name="piratebay_proxy_url" value="${config['piratebay_proxy_url']}" size="36">
|
<input type="text" name="piratebay_proxy_url" value="${config['piratebay_proxy_url']}" size="36">
|
||||||
|
<small>Optional. Leave empty for default.</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Seed Ratio: </label>
|
<label>Seed Ratio</label>
|
||||||
<input type="text" class="override-float" name="piratebay_ratio" value="${config['piratebay_ratio']}" size="10" title="Stop seeding when ratio met, 0 = unlimited. Scheduled job will remove torrent when post processed and finished seeding">
|
<input type="text" class="override-float" name="piratebay_ratio" value="${config['piratebay_ratio']}" size="10" title="Stop seeding when ratio met, 0 = unlimited. Scheduled job will remove torrent when post processed and finished seeding">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -543,11 +545,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="config">
|
<div class="config">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Proxy URL (Optional): </label>
|
<label>Proxy URL</label>
|
||||||
<input type="text" name="kat_proxy_url" value="${config['kat_proxy_url']}" size="36">
|
<input type="text" name="kat_proxy_url" value="${config['kat_proxy_url']}" size="36">
|
||||||
|
<small>Optional. Leave empty for default.</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Seed Ratio: </label>
|
<label>Seed Ratio</label>
|
||||||
<input type="text" class="override-float" name="kat_ratio" value="${config['kat_ratio']}" size="10" title="Stop seeding when ratio met, 0 = unlimited. Scheduled job will remove torrent when post processed and finished seeding">
|
<input type="text" class="override-float" name="kat_ratio" value="${config['kat_ratio']}" size="10" title="Stop seeding when ratio met, 0 = unlimited. Scheduled job will remove torrent when post processed and finished seeding">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -560,15 +563,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="config">
|
<div class="config">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>UID Number: </label>
|
<label>UID Number</label>
|
||||||
<input type="text" name="waffles_uid" value="${config['waffles_uid']}" size="36">
|
<input type="text" name="waffles_uid" value="${config['waffles_uid']}" size="36">
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Passkey: </label>
|
<label>Passkey</label>
|
||||||
<input type="password" name="waffles_passkey" value="${config['waffles_passkey']}" size="36">
|
<input type="password" name="waffles_passkey" value="${config['waffles_passkey']}" size="36">
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Seed Ratio: </label>
|
<label>Seed Ratio</label>
|
||||||
<input type="text" class="override-float" name="waffles_ratio" value="${config['waffles_ratio']}" size="10" title="Stop seeding when ratio met, 0 = unlimited. Scheduled job will remove torrent when post processed and finished seeding">
|
<input type="text" class="override-float" name="waffles_ratio" value="${config['waffles_ratio']}" size="10" title="Stop seeding when ratio met, 0 = unlimited. Scheduled job will remove torrent when post processed and finished seeding">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -581,15 +584,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="config">
|
<div class="config">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>User Name: </label>
|
<label>Userame</label>
|
||||||
<input type="text" name="rutracker_user" value="${config['rutracker_user']}" size="36">
|
<input type="text" name="rutracker_user" value="${config['rutracker_user']}" size="36">
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Password: </label>
|
<label>Password</label>
|
||||||
<input type="password" name="rutracker_password" value="${config['rutracker_password']}" size="36">
|
<input type="password" name="rutracker_password" value="${config['rutracker_password']}" size="36">
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Seed Ratio: </label>
|
<label>Seed Ratio</label>
|
||||||
<input type="text" class="override-float" name="rutracker_ratio" value="${config['rutracker_ratio']}" size="10" title="Stop seeding when ratio met, 0 = unlimited. Scheduled job will remove torrent when post processed and finished seeding">
|
<input type="text" class="override-float" name="rutracker_ratio" value="${config['rutracker_ratio']}" size="10" title="Stop seeding when ratio met, 0 = unlimited. Scheduled job will remove torrent when post processed and finished seeding">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -688,7 +691,7 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Search Words</legend>
|
<legend>Search Words</legend>
|
||||||
<small>Separate words with a comma, e.g. "word1,word2,word3"</small>
|
<small>Separate words with a comma, e.g. "word1,word2,word3".</small>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Ignored Words</label>
|
<label>Ignored Words</label>
|
||||||
<input type="text" name="ignored_words" value="${config['ignored_words']}" size="50">
|
<input type="text" name="ignored_words" value="${config['ignored_words']}" size="50">
|
||||||
@@ -714,6 +717,7 @@
|
|||||||
Split single file albums into multiple tracks
|
Split single file albums into multiple tracks
|
||||||
<input type="checkbox" name="cue_split" id="cue_split" value="1" ${config['cue_split']} />
|
<input type="checkbox" name="cue_split" id="cue_split" value="1" ${config['cue_split']} />
|
||||||
</label>
|
</label>
|
||||||
|
</div>
|
||||||
<div class="row checkbox left clearfix">
|
<div class="row checkbox left clearfix">
|
||||||
<label title="Freeze the database, so new artists won't be added automatically. Use this if Headphones adds artists because due to wrong snatches. This check is skipped when the folder name is appended with release group ID.">
|
<label title="Freeze the database, so new artists won't be added automatically. Use this if Headphones adds artists because due to wrong snatches. This check is skipped when the folder name is appended with release group ID.">
|
||||||
Freeze database for adding new artist
|
Freeze database for adding new artist
|
||||||
@@ -767,14 +771,18 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Path to Destination Folder</label>
|
<label>
|
||||||
|
Destination Directory:
|
||||||
|
</label>
|
||||||
<input type="text" name="destination_dir" value="${config['destination_dir']}" size="50">
|
<input type="text" name="destination_dir" value="${config['destination_dir']}" size="50">
|
||||||
<small>e.g. /Users/name/Music/iTunes or /Volumes/share/music</small>
|
<small>The directory where Headphones will move file to after post processing, e.g. /Volumes/share/music.</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Path to Lossless Destination folder (optional)</label>
|
<label>
|
||||||
|
Lossless Destination Directory:
|
||||||
|
</label>
|
||||||
<input type="text" name="lossless_destination_dir" value="${config['lossless_destination_dir']}" size="50">
|
<input type="text" name="lossless_destination_dir" value="${config['lossless_destination_dir']}" size="50">
|
||||||
<small>Set this if you have a separate directory for lossless music</small>
|
<small>Optional. Set this if you have a separate directory for lossless music.</small>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</td>
|
</td>
|
||||||
@@ -816,7 +824,7 @@
|
|||||||
<input type="checkbox" name="prowl_onsnatch" value="1" ${config['prowl_onsnatch']} /><label>Notify on snatch?</label>
|
<input type="checkbox" name="prowl_onsnatch" value="1" ${config['prowl_onsnatch']} /><label>Notify on snatch?</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Priority (-2,-1,0,1 or 2):</label>
|
<label>Priority (-2,-1,0,1 or 2)</label>
|
||||||
<input type="text" name="prowl_priority" value="${config['prowl_priority']}" size="2">
|
<input type="text" name="prowl_priority" value="${config['prowl_priority']}" size="2">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -991,11 +999,11 @@
|
|||||||
<input type="checkbox" name="pushover_onsnatch" value="1" ${config['pushover_onsnatch']} /><label>Notify on snatch?</label>
|
<input type="checkbox" name="pushover_onsnatch" value="1" ${config['pushover_onsnatch']} /><label>Notify on snatch?</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Priority (-1,0, or 1):</label>
|
<label>Priority (-1,0, or 1)</label>
|
||||||
<input type="text" name="pushover_priority" value="${config['pushover_priority']}" size="2">
|
<input type="text" name="pushover_priority" value="${config['pushover_priority']}" size="2">
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>API Token (leave blank to use Headphones default):</label><input type="text" name="pushover_apitoken" value="${config['pushover_apitoken']}" size="50">
|
<label>API Token (leave blank to use Headphones default)</label><input type="text" name="pushover_apitoken" value="${config['pushover_apitoken']}" size="50">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -1163,7 +1171,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Multi-core count:</label>
|
<label>Multi-core count</label>
|
||||||
<input type="text" name="encoder_multicore_count" value="${config['encoder_multicore_count']}" size="7">
|
<input type="text" name="encoder_multicore_count" value="${config['encoder_multicore_count']}" size="7">
|
||||||
<small>Set equal to the number of cores, or 0 for auto</small>
|
<small>Set equal to the number of cores, or 0 for auto</small>
|
||||||
</div>
|
</div>
|
||||||
@@ -1307,15 +1315,15 @@
|
|||||||
<label>Automatically mark manually added albums as wanted</label>
|
<label>Automatically mark manually added albums as wanted</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Folder Permissions:</label>
|
<label>Folder Permissions</label>
|
||||||
<input type="text" name="folder_permissions" value="${config['folder_permissions']}" size="7">
|
<input type="text" name="folder_permissions" value="${config['folder_permissions']}" size="7">
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>File Permissions:</label>
|
<label>File Permissions</label>
|
||||||
<input type="text" name="file_permissions" value="${config['file_permissions']}" size="7">
|
<input type="text" name="file_permissions" value="${config['file_permissions']}" size="7">
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Cache Size (in MB):</label>
|
<label>Cache Size (in MB)</label>
|
||||||
<input type="text" name="cache_sizemb" value="${config['cache_sizemb']}" size="7">
|
<input type="text" name="cache_sizemb" value="${config['cache_sizemb']}" size="7">
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -1336,11 +1344,11 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Log Directory:</label>
|
<label>Log Directory</label>
|
||||||
<input type="text" name="log_dir" value="${config['log_dir']}" size="50">
|
<input type="text" name="log_dir" value="${config['log_dir']}" size="50">
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Cache Directory:</label>
|
<label>Cache Directory</label>
|
||||||
<input type="text" name="cache_dir" value="${config['cache_dir']}" size="50">
|
<input type="text" name="cache_dir" value="${config['cache_dir']}" size="50">
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -1352,7 +1360,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="songkickoptions">
|
<div id="songkickoptions">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>API Key:</label>
|
<label>API Key</label>
|
||||||
<input type="text" name="songkick_apikey" value="${config['songkick_apikey']}" size="50">
|
<input type="text" name="songkick_apikey" value="${config['songkick_apikey']}" size="50">
|
||||||
</div>
|
</div>
|
||||||
<div class="row checkbox">
|
<div class="row checkbox">
|
||||||
@@ -1360,7 +1368,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="songkick_filteroptions">
|
<div id="songkick_filteroptions">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>Metro Area ID:</label>
|
<label>Metro Area ID</label>
|
||||||
<input type="text" name="songkick_location" value="${config['songkick_location']}" size="10" title="Enter the Metro Area ID, e.g. the ID for London is 24426, this can be found by clicking the link and searching/selecting the city, e.g. London should find http://www.songkick.com/metro_areas/24426-uk-london">
|
<input type="text" name="songkick_location" value="${config['songkick_location']}" size="10" title="Enter the Metro Area ID, e.g. the ID for London is 24426, this can be found by clicking the link and searching/selecting the city, e.g. London should find http://www.songkick.com/metro_areas/24426-uk-london">
|
||||||
<a target="_blank" href="http://www.songkick.com/developer/location-search">Find Area ID</a>
|
<a target="_blank" href="http://www.songkick.com/developer/location-search">Find Area ID</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+69
-32
@@ -64,6 +64,7 @@ CREATEPID = False
|
|||||||
PIDFILE = None
|
PIDFILE = None
|
||||||
|
|
||||||
SCHED = BackgroundScheduler()
|
SCHED = BackgroundScheduler()
|
||||||
|
SCHED_LOCK = threading.Lock()
|
||||||
|
|
||||||
INIT_LOCK = threading.Lock()
|
INIT_LOCK = threading.Lock()
|
||||||
_INITIALIZED = False
|
_INITIALIZED = False
|
||||||
@@ -138,13 +139,12 @@ def initialize(config_file):
|
|||||||
if not os.path.exists(CONFIG.CACHE_DIR):
|
if not os.path.exists(CONFIG.CACHE_DIR):
|
||||||
try:
|
try:
|
||||||
os.makedirs(CONFIG.CACHE_DIR)
|
os.makedirs(CONFIG.CACHE_DIR)
|
||||||
except OSError:
|
except OSError as e:
|
||||||
logger.error(
|
logger.error("Could not create cache dir '%s': %s", DATA_DIR, e)
|
||||||
'Could not create cache dir. Check permissions of datadir: %s', DATA_DIR)
|
|
||||||
|
|
||||||
# Sanity check for search interval. Set it to at least 6 hours
|
# Sanity check for search interval. Set it to at least 6 hours
|
||||||
if CONFIG.SEARCH_INTERVAL < 360:
|
if CONFIG.SEARCH_INTERVAL and CONFIG.SEARCH_INTERVAL < 360:
|
||||||
logger.info("Search interval too low. Resetting to 6 hour minimum")
|
logger.info("Search interval too low. Resetting to 6 hour minimum.")
|
||||||
CONFIG.SEARCH_INTERVAL = 360
|
CONFIG.SEARCH_INTERVAL = 360
|
||||||
|
|
||||||
# Initialize the database
|
# Initialize the database
|
||||||
@@ -154,10 +154,23 @@ def initialize(config_file):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Can't connect to the database: %s", e)
|
logger.error("Can't connect to the database: %s", e)
|
||||||
|
|
||||||
# Get the currently installed version - returns None, 'win32' or the git hash
|
# Get the currently installed version. Returns None, 'win32' or the git
|
||||||
# Also sets INSTALL_TYPE variable to 'win', 'git' or 'source'
|
# hash.
|
||||||
CURRENT_VERSION, CONFIG.GIT_BRANCH = versioncheck.getVersion()
|
CURRENT_VERSION, CONFIG.GIT_BRANCH = versioncheck.getVersion()
|
||||||
|
|
||||||
|
# Write current version to a file, so we know which version did work.
|
||||||
|
# This allowes one to restore to that version. The idea is that if we
|
||||||
|
# arrive here, most parts of Headphones seem to work.
|
||||||
|
if CURRENT_VERSION:
|
||||||
|
version_lock_file = os.path.join(DATA_DIR, "version.lock")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(version_lock_file, "w") as fp:
|
||||||
|
fp.write(CURRENT_VERSION)
|
||||||
|
except IOError as e:
|
||||||
|
logger.error("Unable to write current version to file '%s': %s",
|
||||||
|
version_lock_file, e)
|
||||||
|
|
||||||
# Check for new versions
|
# Check for new versions
|
||||||
if CONFIG.CHECK_GITHUB_ON_STARTUP:
|
if CONFIG.CHECK_GITHUB_ON_STARTUP:
|
||||||
try:
|
try:
|
||||||
@@ -244,36 +257,60 @@ def launch_browser(host, port, root):
|
|||||||
logger.error('Could not launch browser: %s', e)
|
logger.error('Could not launch browser: %s', e)
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_scheduler():
|
||||||
|
"""
|
||||||
|
Start the scheduled background tasks. Because this method can be called
|
||||||
|
multiple times, the old tasks will be first removed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from headphones import updater, searcher, librarysync, postprocessor, \
|
||||||
|
torrentfinished
|
||||||
|
|
||||||
|
with SCHED_LOCK:
|
||||||
|
# Remove all jobs
|
||||||
|
count = len(SCHED.get_jobs())
|
||||||
|
|
||||||
|
if count > 0:
|
||||||
|
logger.debug("Current number of background tasks: %d", count)
|
||||||
|
SCHED.shutdown()
|
||||||
|
SCHED.remove_all_jobs()
|
||||||
|
|
||||||
|
# Regular jobs
|
||||||
|
if CONFIG.UPDATE_DB_INTERVAL > 0:
|
||||||
|
SCHED.add_job(updater.dbUpdate, trigger=IntervalTrigger(
|
||||||
|
hours=CONFIG.UPDATE_DB_INTERVAL))
|
||||||
|
if CONFIG.SEARCH_INTERVAL > 0:
|
||||||
|
SCHED.add_job(searcher.searchforalbum, trigger=IntervalTrigger(
|
||||||
|
minutes=CONFIG.SEARCH_INTERVAL))
|
||||||
|
if CONFIG.LIBRARYSCAN_INTERVAL > 0:
|
||||||
|
SCHED.add_job(librarysync.libraryScan, trigger=IntervalTrigger(
|
||||||
|
hours=CONFIG.LIBRARYSCAN_INTERVAL))
|
||||||
|
if CONFIG.DOWNLOAD_SCAN_INTERVAL > 0:
|
||||||
|
SCHED.add_job(postprocessor.checkFolder, trigger=IntervalTrigger(
|
||||||
|
minutes=CONFIG.DOWNLOAD_SCAN_INTERVAL))
|
||||||
|
|
||||||
|
# Update check
|
||||||
|
if CONFIG.CHECK_GITHUB:
|
||||||
|
SCHED.add_job(versioncheck.checkGithub, trigger=IntervalTrigger(
|
||||||
|
minutes=CONFIG.CHECK_GITHUB_INTERVAL))
|
||||||
|
|
||||||
|
# Remove Torrent + data if Post Processed and finished Seeding
|
||||||
|
if CONFIG.TORRENT_REMOVAL_INTERVAL > 0:
|
||||||
|
SCHED.add_job(torrentfinished.checkTorrentFinished,
|
||||||
|
trigger=IntervalTrigger(
|
||||||
|
minutes=CONFIG.TORRENT_REMOVAL_INTERVAL))
|
||||||
|
|
||||||
|
# Start scheduler
|
||||||
|
logger.info("(Re-)Scheduling background tasks")
|
||||||
|
SCHED.start()
|
||||||
|
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
|
|
||||||
global started
|
global started
|
||||||
|
|
||||||
if _INITIALIZED:
|
if _INITIALIZED:
|
||||||
|
initialize_scheduler()
|
||||||
# Start our scheduled background tasks
|
|
||||||
from headphones import updater, searcher, librarysync, postprocessor, torrentfinished
|
|
||||||
SCHED.add_job(updater.dbUpdate, trigger=IntervalTrigger(
|
|
||||||
hours=CONFIG.UPDATE_DB_INTERVAL))
|
|
||||||
SCHED.add_job(searcher.searchforalbum, trigger=IntervalTrigger(
|
|
||||||
minutes=CONFIG.SEARCH_INTERVAL))
|
|
||||||
SCHED.add_job(librarysync.libraryScan, trigger=IntervalTrigger(
|
|
||||||
hours=CONFIG.LIBRARYSCAN_INTERVAL))
|
|
||||||
|
|
||||||
if CONFIG.CHECK_GITHUB:
|
|
||||||
SCHED.add_job(versioncheck.checkGithub, trigger=IntervalTrigger(
|
|
||||||
minutes=CONFIG.CHECK_GITHUB_INTERVAL))
|
|
||||||
|
|
||||||
if CONFIG.DOWNLOAD_SCAN_INTERVAL > 0:
|
|
||||||
SCHED.add_job(postprocessor.checkFolder, trigger=IntervalTrigger(
|
|
||||||
minutes=CONFIG.DOWNLOAD_SCAN_INTERVAL))
|
|
||||||
|
|
||||||
# Remove Torrent + data if Post Processed and finished Seeding
|
|
||||||
if CONFIG.TORRENT_REMOVAL_INTERVAL > 0:
|
|
||||||
SCHED.add_job(torrentfinished.checkTorrentFinished, trigger=IntervalTrigger(
|
|
||||||
minutes=CONFIG.TORRENT_REMOVAL_INTERVAL))
|
|
||||||
|
|
||||||
SCHED.start()
|
|
||||||
|
|
||||||
started = True
|
started = True
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+53
-19
@@ -604,6 +604,43 @@ def smartMove(src, dest, delete=True):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn('Error moving file %s: %s', filename.decode(headphones.SYS_ENCODING, 'replace'), e)
|
logger.warn('Error moving file %s: %s', filename.decode(headphones.SYS_ENCODING, 'replace'), e)
|
||||||
|
|
||||||
|
def walk_directory(basedir, followlinks=True):
|
||||||
|
"""
|
||||||
|
Enhanced version of 'os.walk' where symlink directores are traversed, but
|
||||||
|
with care. In case a folder is already processed, don't traverse it again.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logger
|
||||||
|
|
||||||
|
# Add the base path, because symlinks poiting to the basedir should not be
|
||||||
|
# traversed again.
|
||||||
|
traversed = [os.path.abspath(basedir)]
|
||||||
|
|
||||||
|
def _inner(root, directories, files):
|
||||||
|
for directory in directories:
|
||||||
|
path = os.path.join(root, directory)
|
||||||
|
|
||||||
|
if followlinks and os.path.islink(path):
|
||||||
|
real_path = os.path.abspath(os.readlink(path))
|
||||||
|
|
||||||
|
if real_path in traversed:
|
||||||
|
logger.debug("Skipping '%s' since it is a symlink to "\
|
||||||
|
"'%s', which is already visited.", path, real_path)
|
||||||
|
else:
|
||||||
|
traversed.append(real_path)
|
||||||
|
|
||||||
|
for args in os.walk(real_path):
|
||||||
|
for result in _inner(*args):
|
||||||
|
yield result
|
||||||
|
|
||||||
|
# Pass on actual result
|
||||||
|
yield root, directories, files
|
||||||
|
|
||||||
|
# Start traversing
|
||||||
|
for args in os.walk(basedir):
|
||||||
|
for result in _inner(*args):
|
||||||
|
yield result
|
||||||
|
|
||||||
#########################
|
#########################
|
||||||
#Sab renaming functions #
|
#Sab renaming functions #
|
||||||
#########################
|
#########################
|
||||||
@@ -660,44 +697,41 @@ def sab_sanitize_foldername(name):
|
|||||||
|
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
|
||||||
def split_string(mystring, splitvar=','):
|
def split_string(mystring, splitvar=','):
|
||||||
mylist = []
|
mylist = []
|
||||||
for each_word in mystring.split(splitvar):
|
for each_word in mystring.split(splitvar):
|
||||||
mylist.append(each_word.strip())
|
mylist.append(each_word.strip())
|
||||||
return mylist
|
return mylist
|
||||||
|
|
||||||
|
|
||||||
def create_https_certificates(ssl_cert, ssl_key):
|
def create_https_certificates(ssl_cert, ssl_key):
|
||||||
"""
|
"""
|
||||||
Stolen from SickBeard (http://github.com/midgetspy/Sick-Beard):
|
Create a pair of self-signed HTTPS certificares and store in them in
|
||||||
Create self-signed HTTPS certificares and store in paths 'ssl_cert' and 'ssl_key'
|
'ssl_cert' and 'ssl_key'. Method assumes pyOpenSSL is installed.
|
||||||
|
|
||||||
|
This code is stolen from SickBeard (http://github.com/midgetspy/Sick-Beard).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from headphones import logger
|
from headphones import logger
|
||||||
|
|
||||||
try:
|
from OpenSSL import crypto
|
||||||
from OpenSSL import crypto
|
from certgen import createKeyPair, createCertRequest, createCertificate, \
|
||||||
from certgen import createKeyPair, createCertRequest, createCertificate, TYPE_RSA, serial
|
TYPE_RSA, serial
|
||||||
except:
|
|
||||||
logger.warn("pyOpenSSL module missing, please install to enable HTTPS")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Create the CA Certificate
|
# Create the CA Certificate
|
||||||
cakey = createKeyPair(TYPE_RSA, 1024)
|
cakey = createKeyPair(TYPE_RSA, 2048)
|
||||||
careq = createCertRequest(cakey, CN='Certificate Authority')
|
careq = createCertRequest(cakey, CN="Certificate Authority")
|
||||||
cacert = createCertificate(careq, (careq, cakey), serial, (0, 60 * 60 * 24 * 365 * 10)) # ten years
|
cacert = createCertificate(careq, (careq, cakey), serial, (0, 60 * 60 * 24 * 365 * 10)) # ten years
|
||||||
|
|
||||||
cname = 'Headphones'
|
pkey = createKeyPair(TYPE_RSA, 2048)
|
||||||
pkey = createKeyPair(TYPE_RSA, 1024)
|
req = createCertRequest(pkey, CN="Headphones")
|
||||||
req = createCertRequest(pkey, CN=cname)
|
|
||||||
cert = createCertificate(req, (cacert, cakey), serial, (0, 60 * 60 * 24 * 365 * 10)) # ten years
|
cert = createCertificate(req, (cacert, cakey), serial, (0, 60 * 60 * 24 * 365 * 10)) # ten years
|
||||||
|
|
||||||
# Save the key and certificate to disk
|
# Save the key and certificate to disk
|
||||||
try:
|
try:
|
||||||
with open(ssl_key, 'w') as f:
|
with open(ssl_key, "w") as fp:
|
||||||
f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))
|
fp.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))
|
||||||
with open(ssl_cert, 'w') as f:
|
with open(ssl_cert, "w") as fp:
|
||||||
f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
|
fp.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
logger.error("Error creating SSL key and certificate: %s", e)
|
logger.error("Error creating SSL key and certificate: %s", e)
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None, cron=Fal
|
|||||||
|
|
||||||
latest_subdirectory = []
|
latest_subdirectory = []
|
||||||
|
|
||||||
for r, d, f in os.walk(dir, followlinks=True):
|
for r, d, f in helpers.walk_directory(dir):
|
||||||
# Need to abuse slicing to get a copy of the list, doing it directly
|
# Need to abuse slicing to get a copy of the list, doing it directly
|
||||||
# will skip the element after a deleted one using a list comprehension
|
# will skip the element after a deleted one using a list comprehension
|
||||||
# will not work correctly for nested subdirectories (os.walk keeps its
|
# will not work correctly for nested subdirectories (os.walk keeps its
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ from headphones import logger, helpers, common, request
|
|||||||
|
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
from httplib import HTTPSConnection
|
from httplib import HTTPSConnection
|
||||||
|
from urlparse import parse_qsl
|
||||||
from urllib import urlencode
|
from urllib import urlencode
|
||||||
from pynma import pynma
|
from pynma import pynma
|
||||||
|
|
||||||
@@ -33,12 +34,6 @@ import json
|
|||||||
import oauth2 as oauth
|
import oauth2 as oauth
|
||||||
import pythontwitter as twitter
|
import pythontwitter as twitter
|
||||||
|
|
||||||
try:
|
|
||||||
from urlparse import parse_qsl
|
|
||||||
except ImportError:
|
|
||||||
from cgi import parse_qsl
|
|
||||||
|
|
||||||
|
|
||||||
class GROWL(object):
|
class GROWL(object):
|
||||||
"""
|
"""
|
||||||
Growl notifications, for OS X.
|
Growl notifications, for OS X.
|
||||||
|
|||||||
+26
-30
@@ -18,6 +18,7 @@ from headphones import logger, request
|
|||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
import base64
|
import base64
|
||||||
|
import urlparse
|
||||||
import headphones
|
import headphones
|
||||||
|
|
||||||
# This is just a simple script to send torrents to transmission. The
|
# This is just a simple script to send torrents to transmission. The
|
||||||
@@ -126,7 +127,6 @@ def torrentAction(method, arguments):
|
|||||||
host = headphones.CONFIG.TRANSMISSION_HOST
|
host = headphones.CONFIG.TRANSMISSION_HOST
|
||||||
username = headphones.CONFIG.TRANSMISSION_USERNAME
|
username = headphones.CONFIG.TRANSMISSION_USERNAME
|
||||||
password = headphones.CONFIG.TRANSMISSION_PASSWORD
|
password = headphones.CONFIG.TRANSMISSION_PASSWORD
|
||||||
sessionid = None
|
|
||||||
|
|
||||||
if not host.startswith('http'):
|
if not host.startswith('http'):
|
||||||
host = 'http://' + host
|
host = 'http://' + host
|
||||||
@@ -134,30 +134,22 @@ def torrentAction(method, arguments):
|
|||||||
if host.endswith('/'):
|
if host.endswith('/'):
|
||||||
host = host[:-1]
|
host = host[:-1]
|
||||||
|
|
||||||
# Either the host ends with a port, or some directory, or rpc
|
# Fix the URL. We assume that the user does not point to the RPC endpoint,
|
||||||
# If it ends with /rpc we don't have to do anything
|
# so add it if it is missing.
|
||||||
# If it ends with a port we add /transmission/rpc
|
parts = list(urlparse.urlparse(host))
|
||||||
# anything else we just add rpc
|
|
||||||
if not host.endswith('/rpc'):
|
if not parts[0] in ("http", "https"):
|
||||||
# Check if it ends in a port number
|
parts[0] = "http"
|
||||||
i = host.rfind(':')
|
|
||||||
if i >= 0:
|
if not parts[2].endswith("/rpc"):
|
||||||
possible_port = host[i + 1:]
|
parts[2] += "/transmission/rpc"
|
||||||
host = host + "/rpc"
|
|
||||||
try:
|
host = urlparse.urlunparse(parts)
|
||||||
port = int(possible_port)
|
|
||||||
if port:
|
|
||||||
host = host + "/transmission/rpc"
|
|
||||||
except ValueError:
|
|
||||||
logger.debug('No port, assuming not transmission')
|
|
||||||
else:
|
|
||||||
logger.error('Transmission port missing')
|
|
||||||
return
|
|
||||||
|
|
||||||
# Retrieve session id
|
# Retrieve session id
|
||||||
auth = (username, password) if username and password else None
|
auth = (username, password) if username and password else None
|
||||||
|
response = request.request_response(host, auth=auth,
|
||||||
response = request.request_response(host, auth=auth, whitelist_status_code=[401, 409])
|
whitelist_status_code=[401, 409])
|
||||||
|
|
||||||
if response is None:
|
if response is None:
|
||||||
logger.error("Error gettings Transmission session ID")
|
logger.error("Error gettings Transmission session ID")
|
||||||
@@ -166,26 +158,30 @@ def torrentAction(method, arguments):
|
|||||||
# Parse response
|
# Parse response
|
||||||
if response.status_code == 401:
|
if response.status_code == 401:
|
||||||
if auth:
|
if auth:
|
||||||
logger.error("Username and/or password not accepted by Transmission")
|
logger.error("Username and/or password not accepted by " \
|
||||||
|
"Transmission")
|
||||||
else:
|
else:
|
||||||
logger.error("Transmission authorization required")
|
logger.error("Transmission authorization required")
|
||||||
|
|
||||||
return
|
return
|
||||||
elif response.status_code == 409:
|
elif response.status_code == 409:
|
||||||
sessionid = response.headers['x-transmission-session-id']
|
session_id = response.headers['x-transmission-session-id']
|
||||||
|
|
||||||
if not sessionid:
|
if not session_id:
|
||||||
logger.error("Error getting Session ID from Transmission")
|
logger.error("Expected a Session ID from Transmission")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Prepare next request
|
# Prepare next request
|
||||||
headers = {'x-transmission-session-id': sessionid}
|
headers = {'x-transmission-session-id': session_id}
|
||||||
data = {'method': method, 'arguments': arguments}
|
data = {'method': method, 'arguments': arguments}
|
||||||
|
|
||||||
response = request.request_json(host, method="post", data=json.dumps(data), headers=headers, auth=auth)
|
response = request.request_json(host, method="POST", data=json.dumps(data),
|
||||||
|
headers=headers, auth=auth)
|
||||||
|
|
||||||
|
print response
|
||||||
|
|
||||||
if not response:
|
if not response:
|
||||||
logger.error("Error sending torrent to Transmission")
|
logger.error("Error sending torrent to Transmission")
|
||||||
return
|
return
|
||||||
|
|
||||||
return response
|
return response
|
||||||
@@ -1241,14 +1241,17 @@ class WebInterface(object):
|
|||||||
headphones.CONFIG.add_extra_newznab(extra_newznab)
|
headphones.CONFIG.add_extra_newznab(extra_newznab)
|
||||||
|
|
||||||
# Sanity checking
|
# Sanity checking
|
||||||
if headphones.CONFIG.SEARCH_INTERVAL < 360:
|
if headphones.CONFIG.SEARCH_INTERVAL and headphones.CONFIG.SEARCH_INTERVAL < 360:
|
||||||
logger.info("Search interval too low. Resetting to 6 hour minimum")
|
logger.info("Search interval too low. Resetting to 6 hour minimum")
|
||||||
headphones.CONFIG.SEARCH_INTERVAL = 360
|
headphones.CONFIG.SEARCH_INTERVAL = 360
|
||||||
|
|
||||||
# Write the config
|
# Write the config
|
||||||
headphones.CONFIG.write()
|
headphones.CONFIG.write()
|
||||||
|
|
||||||
#reconfigure musicbrainz database connection with the new values
|
# Reconfigure scheduler
|
||||||
|
headphones.initialize_scheduler()
|
||||||
|
|
||||||
|
# Reconfigure musicbrainz database connection with the new values
|
||||||
mb.startmb()
|
mb.startmb()
|
||||||
|
|
||||||
raise cherrypy.HTTPRedirect("config")
|
raise cherrypy.HTTPRedirect("config")
|
||||||
|
|||||||
@@ -23,9 +23,7 @@ from headphones.webserve import WebInterface
|
|||||||
from headphones.helpers import create_https_certificates
|
from headphones.helpers import create_https_certificates
|
||||||
|
|
||||||
|
|
||||||
def initialize(options=None):
|
def initialize(options):
|
||||||
if options is None:
|
|
||||||
options = {}
|
|
||||||
|
|
||||||
# HTTPS stuff stolen from sickbeard
|
# HTTPS stuff stolen from sickbeard
|
||||||
enable_https = options['enable_https']
|
enable_https = options['enable_https']
|
||||||
@@ -33,16 +31,17 @@ def initialize(options=None):
|
|||||||
https_key = options['https_key']
|
https_key = options['https_key']
|
||||||
|
|
||||||
if enable_https:
|
if enable_https:
|
||||||
# If either the HTTPS certificate or key do not exist, make some self-signed ones.
|
# If either the HTTPS certificate or key do not exist, try to make
|
||||||
|
# self-signed ones.
|
||||||
if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)):
|
if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)):
|
||||||
if not create_https_certificates(https_cert, https_key):
|
if not create_https_certificates(https_cert, https_key):
|
||||||
logger.warn(u"Unable to create cert/key files, disabling HTTPS")
|
logger.warn("Unable to create certificate and key. Disabling " \
|
||||||
headphones.CONFIG.ENABLE_HTTPS = False
|
"HTTPS")
|
||||||
enable_https = False
|
enable_https = False
|
||||||
|
|
||||||
if not (os.path.exists(https_cert) and os.path.exists(https_key)):
|
if not (os.path.exists(https_cert) and os.path.exists(https_key)):
|
||||||
logger.warn(u"Disabled HTTPS because of missing CERT and KEY files")
|
logger.warn("Disabled HTTPS because of missing certificate and " \
|
||||||
headphones.CONFIG.ENABLE_HTTPS = False
|
"key.")
|
||||||
enable_https = False
|
enable_https = False
|
||||||
|
|
||||||
options_dict = {
|
options_dict = {
|
||||||
|
|||||||
@@ -1324,8 +1324,8 @@ class HTTPConnection(object):
|
|||||||
def __init__(self, server, sock, makefile=CP_fileobject):
|
def __init__(self, server, sock, makefile=CP_fileobject):
|
||||||
self.server = server
|
self.server = server
|
||||||
self.socket = sock
|
self.socket = sock
|
||||||
self.rfile = makefile(sock._sock, "rb", self.rbufsize)
|
self.rfile = makefile(sock, "rb", self.rbufsize)
|
||||||
self.wfile = makefile(sock._sock, "wb", self.wbufsize)
|
self.wfile = makefile(sock, "wb", self.wbufsize)
|
||||||
self.requests_seen = 0
|
self.requests_seen = 0
|
||||||
|
|
||||||
def communicate(self):
|
def communicate(self):
|
||||||
|
|||||||
+2892
-8
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user