Browse Source

Merge branch 'refs/heads/develop' into tv

pull/2139/merge
Ruud 12 years ago
parent
commit
73efd5549f
  1. 2
      couchpotato/core/downloaders/transmission/__init__.py
  2. 4
      couchpotato/core/downloaders/transmission/main.py
  3. 2
      couchpotato/core/downloaders/utorrent/__init__.py
  4. 19
      couchpotato/core/downloaders/utorrent/main.py
  5. 8
      couchpotato/core/helpers/variable.py
  6. 8
      couchpotato/core/notifications/xbmc/__init__.py
  7. 12
      couchpotato/core/notifications/xbmc/main.py
  8. 10
      couchpotato/core/plugins/automation/main.py
  9. 7
      couchpotato/core/plugins/renamer/__init__.py
  10. 45
      couchpotato/core/plugins/renamer/main.py
  11. 7
      couchpotato/core/plugins/scanner/main.py
  12. 30
      couchpotato/core/providers/automation/imdb/__init__.py
  13. 76
      couchpotato/core/providers/automation/imdb/main.py
  14. 16
      couchpotato/core/providers/automation/rottentomatoes/__init__.py
  15. 48
      couchpotato/core/providers/automation/rottentomatoes/main.py
  16. 1
      couchpotato/core/providers/movie/_modifier/main.py
  17. 1
      couchpotato/core/providers/movie/omdbapi/main.py
  18. 1
      couchpotato/core/providers/movie/themoviedb/main.py
  19. 2
      couchpotato/runner.py
  20. 15
      couchpotato/templates/index.html
  21. 81
      init/ubuntu
  22. 8
      init/ubuntu.default

2
couchpotato/core/downloaders/transmission/__init__.py

@ -47,7 +47,7 @@ config = [{
{
'name': 'remove_complete',
'label': 'Remove torrent',
'default': False,
'default': True,
'advanced': True,
'type': 'bool',
'description': 'Remove the torrent from Transmission after it finished seeding.',

4
couchpotato/core/downloaders/transmission/main.py

@ -129,9 +129,9 @@ class Transmission(Downloader):
def pause(self, item, pause = True):
if pause:
return self.trpc.stop_torrent(item['hashString'])
return self.trpc.stop_torrent(item['id'])
else:
return self.trpc.start_torrent(item['hashString'])
return self.trpc.start_torrent(item['id'])
def removeFailed(self, item):
log.info('%s failed downloading, deleting...', item['name'])

2
couchpotato/core/downloaders/utorrent/__init__.py

@ -39,7 +39,7 @@ config = [{
{
'name': 'remove_complete',
'label': 'Remove torrent',
'default': False,
'default': True,
'advanced': True,
'type': 'bool',
'description': 'Remove the torrent from uTorrent after it finished seeding.',

19
couchpotato/core/downloaders/utorrent/main.py

@ -10,7 +10,9 @@ from multipartpost import MultipartPostHandler
import cookielib
import httplib
import json
import os
import re
import stat
import time
import urllib
import urllib2
@ -52,7 +54,7 @@ class uTorrent(Downloader):
new_settings['seed_prio_limitul_flag'] = True
log.info('Updated uTorrent settings to set a torrent to complete after it the seeding requirements are met.')
if settings.get('bt.read_only_on_complete'): #This doesnt work as this option seems to be not available through the api
if settings.get('bt.read_only_on_complete'): #This doesn't work as this option seems to be not available through the api. Mitigated with removeReadOnly function
new_settings['bt.read_only_on_complete'] = False
log.info('Updated uTorrent settings to not set the files to read only after completing.')
@ -93,7 +95,7 @@ class uTorrent(Downloader):
else:
self.utorrent_api.add_torrent_file(torrent_filename, filedata)
# Change settings of added torrents
# Change settings of added torrent
self.utorrent_api.set_torrent(torrent_hash, torrent_params)
if self.conf('paused', default = 0):
self.utorrent_api.pause_torrent(torrent_hash)
@ -130,8 +132,10 @@ class uTorrent(Downloader):
status = 'busy'
if 'Finished' in item[21]:
status = 'completed'
self.removeReadOnly(item[26])
elif 'Seeding' in item[21]:
status = 'seeding'
self.removeReadOnly(item[26])
statuses.append({
'id': item[0],
@ -145,10 +149,10 @@ class uTorrent(Downloader):
return statuses
def pause(self, download_info, pause = True):
def pause(self, item, pause = True):
if not self.connect():
return False
return self.utorrent_api.pause_torrent(download_info['id'], pause)
return self.utorrent_api.pause_torrent(item['id'], pause)
def removeFailed(self, item):
log.info('%s failed downloading, deleting...', item['name'])
@ -161,6 +165,13 @@ class uTorrent(Downloader):
if not self.connect():
return False
return self.utorrent_api.remove_torrent(item['id'], remove_data = delete_files)
def removeReadOnly(self, folder):
#Removes all read-only flags in a folder
if folder and os.path.isdir(folder):
for root, folders, filenames in os.walk(folder):
for filename in filenames:
os.chmod(os.path.join(root, filename), stat.S_IWRITE)
class uTorrentAPI(object):

8
couchpotato/core/helpers/variable.py

@ -128,7 +128,7 @@ def getImdb(txt, check_inside = True, multiple = False):
try:
ids = re.findall('(tt\d{7})', txt)
if multiple:
return ids if len(ids) > 0 else []
return list(set(ids)) if len(ids) > 0 else []
return ids[0]
except IndexError:
pass
@ -140,7 +140,11 @@ def tryInt(s):
except: return 0
def tryFloat(s):
try: return float(s) if '.' in s else tryInt(s)
try:
if isinstance(s, str):
return float(s) if '.' in s else tryInt(s)
else:
return float(s)
except: return 0
def natsortKey(s):

8
couchpotato/core/notifications/xbmc/__init__.py

@ -39,6 +39,14 @@ config = [{
'description': 'Only update the first host when movie snatched, useful for synced XBMC',
},
{
'name': 'remote_dir_scan',
'label': 'Remote Folder Scan',
'default': 0,
'type': 'bool',
'advanced': True,
'description': 'Only scan new movie folder at remote XBMC servers. Works if movie location is the same.',
},
{
'name': 'on_snatch',
'default': 0,
'type': 'bool',

12
couchpotato/core/notifications/xbmc/main.py

@ -13,7 +13,7 @@ log = CPLog(__name__)
class XBMC(Notification):
listen_to = ['renamer.after']
listen_to = ['renamer.after', 'movie.snatched']
use_json_notifications = {}
http_time_between_calls = 0
@ -33,15 +33,19 @@ class XBMC(Notification):
('GUI.ShowNotification', {'title': self.default_title, 'message': message, 'image': self.getNotificationImage('small')}),
]
if not self.conf('only_first') or hosts.index(host) == 0:
calls.append(('VideoLibrary.Scan', {}))
if data and data.get('destination_dir') and (not self.conf('only_first') or hosts.index(host) == 0):
param = {}
if self.conf('remote_dir_scan') or socket.getfqdn('localhost') == socket.getfqdn(host.split(':')[0]):
param = {'directory': data['destination_dir']}
calls.append(('VideoLibrary.Scan', param))
max_successful += len(calls)
response = self.request(host, calls)
else:
response = self.notifyXBMCnoJSON(host, {'title':self.default_title, 'message':message})
if not self.conf('only_first') or hosts.index(host) == 0:
if data and data.get('destination_dir') and (not self.conf('only_first') or hosts.index(host) == 0):
response += self.request(host, [('VideoLibrary.Scan', {})])
max_successful += 1

10
couchpotato/core/plugins/automation/main.py

@ -26,6 +26,10 @@ class Automation(Plugin):
movie_ids = []
for imdb_id in movies:
if self.shuttingDown():
break
prop_name = 'automation.added.%s' % imdb_id
added = Env.prop(prop_name, default = False)
if not added:
@ -35,5 +39,11 @@ class Automation(Plugin):
Env.prop(prop_name, True)
for movie_id in movie_ids:
if self.shuttingDown():
break
movie_dict = fireEvent('movie.get', movie_id, single = True)
fireEvent('movie.searcher.single', movie_dict)
return True

7
couchpotato/core/plugins/renamer/__init__.py

@ -27,6 +27,7 @@ rename_options = {
'imdb_id': 'IMDB id (tt0123456)',
'cd': 'CD number (cd1)',
'cd_nr': 'Just the cd nr. (1)',
'mpaa': 'MPAA Rating',
},
}
@ -119,10 +120,10 @@ config = [{
{
'name': 'file_action',
'label': 'Torrent File Action',
'default': 'move',
'default': 'link',
'type': 'dropdown',
'values': [('Move', 'move'), ('Copy', 'copy'), ('Hard link', 'hardlink'), ('Move & Sym link', 'move_symlink')],
'description': 'Define which kind of file operation you want to use for torrents. Before you start using <a href="http://en.wikipedia.org/wiki/Hard_link">hard links</a> or <a href="http://en.wikipedia.org/wiki/Sym_link">sym links</a>, PLEASE read about their possible drawbacks.',
'values': [('Link', 'link'), ('Copy', 'copy'), ('Move', 'move')],
'description': '<strong>Link</strong> or <strong>Copy</strong> after downloading completed (and allow for seeding), or <strong>Move</strong> after seeding completed. Link first tries <a href="http://en.wikipedia.org/wiki/Hard_link">hard link</a>, then <a href="http://en.wikipedia.org/wiki/Sym_link">sym link</a> and falls back to Copy.',
'advanced': True,
},
{

45
couchpotato/core/plugins/renamer/main.py

@ -205,6 +205,7 @@ class Renamer(Plugin):
'imdb_id': library['identifier'],
'cd': '',
'cd_nr': '',
'mpaa': library['info'].get('mpaa', ''),
}
for file_type in group['files']:
@ -212,7 +213,7 @@ class Renamer(Plugin):
# Move nfo depending on settings
if file_type is 'nfo' and not self.conf('rename_nfo'):
log.debug('Skipping, renaming of %s disabled', file_type)
if self.conf('cleanup') and not (self.conf('file_action') != 'move' and self.downloadIsTorrent(download_info)):
if self.conf('cleanup') and not self.downloadIsTorrent(download_info):
for current_file in group['files'][file_type]:
remove_files.append(current_file)
continue
@ -394,7 +395,7 @@ class Renamer(Plugin):
# Remove leftover files
if self.conf('cleanup') and not self.conf('move_leftover') and remove_leftovers and \
not (self.conf('file_action') != 'move' and self.downloadIsTorrent(download_info)):
not self.downloadIsTorrent(download_info):
log.debug('Removing leftover files')
for current_file in group['files']['leftover']:
remove_files.append(current_file)
@ -451,8 +452,7 @@ class Renamer(Plugin):
self.tagDir(group, 'failed_rename')
# Tag folder if it is in the 'from' folder and it will not be removed because it is a torrent
if self.movieInFromFolder(movie_folder) and \
self.conf('file_action') != 'move' and self.downloadIsTorrent(download_info):
if self.movieInFromFolder(movie_folder) and self.downloadIsTorrent(download_info):
self.tagDir(group, 'renamed_already')
# Remove matching releases
@ -463,8 +463,7 @@ class Renamer(Plugin):
except:
log.error('Failed removing %s: %s', (release.identifier, traceback.format_exc()))
if group['dirname'] and group['parentdir'] and \
not (self.conf('file_action') != 'move' and self.downloadIsTorrent(download_info)):
if group['dirname'] and group['parentdir'] and not self.downloadIsTorrent(download_info):
try:
log.info('Deleting folder: %s', group['parentdir'])
self.deleteEmptyFolder(group['parentdir'])
@ -524,22 +523,22 @@ Remove it if you want it to be renamed (again, or at least let it try again)
if ignore_file:
self.createFile(ignore_file, text)
def untagDir(self, folder, tag = None):
def untagDir(self, folder, tag = ''):
if not os.path.isdir(folder):
return
# Remove any .ignore files
for root, dirnames, filenames in os.walk(folder):
for filename in fnmatch.filter(filenames, '%s.ignore' % tag if tag else '*'):
for filename in fnmatch.filter(filenames, '*%s.ignore' % tag):
os.remove((os.path.join(root, filename)))
def hastagDir(self, folder, tag = None):
def hastagDir(self, folder, tag = ''):
if not os.path.isdir(folder):
return False
# Find any .ignore files
for root, dirnames, filenames in os.walk(folder):
if fnmatch.filter(filenames, '%s.ignore' % tag if tag else '*'):
if fnmatch.filter(filenames, '*%s.ignore' % tag):
return True
return False
@ -549,17 +548,23 @@ Remove it if you want it to be renamed (again, or at least let it try again)
try:
if forcemove:
shutil.move(old, dest)
elif self.conf('file_action') == 'hardlink':
elif self.conf('file_action') == 'copy':
shutil.copy(old, dest)
elif self.conf('file_action') == 'link':
# First try to hardlink
try:
log.debug('Hardlinking file "%s" to "%s"...', (old, dest))
link(old, dest)
except:
log.error('Couldn\'t hardlink file "%s" to "%s". Copying instead. Error: %s. ', (old, dest, traceback.format_exc()))
# Try to simlink next
log.debug('Couldn\'t hardlink file "%s" to "%s". Simlinking instead. Error: %s. ', (old, dest, traceback.format_exc()))
shutil.copy(old, dest)
elif self.conf('file_action') == 'copy':
shutil.copy(old, dest)
elif self.conf('file_action') == 'move_symlink':
shutil.move(old, dest)
symlink(dest, old)
try:
symlink(dest, old + '.link')
os.unlink(old)
os.rename(old + '.link', old)
except:
log.error('Couldn\'t symlink file "%s" to "%s". Copied instead. Error: %s. ', (old, dest, traceback.format_exc()))
else:
shutil.move(old, dest)
@ -764,10 +769,10 @@ Remove it if you want it to be renamed (again, or at least let it try again)
for item in scan_items:
# Ask the renamer to scan the item
if item['scan']:
if item['pause'] and self.conf('file_action') == 'move_symlink':
if item['pause'] and self.conf('file_action') == 'link':
fireEvent('download.pause', item = item, pause = True, single = True)
fireEvent('renamer.scan', download_info = item)
if item['pause'] and self.conf('file_action') == 'move_symlink':
if item['pause'] and self.conf('file_action') == 'link':
fireEvent('download.pause', item = item, pause = False, single = True)
if item['process_complete']:
#First make sure the files were succesfully processed
@ -826,6 +831,6 @@ Remove it if you want it to be renamed (again, or at least let it try again)
def statusInfoComplete(self, item):
return item['id'] and item['downloader'] and item['folder']
def movieInFromFolder(self, movie_folder):
return movie_folder and self.conf('from') in movie_folder or not movie_folder

7
couchpotato/core/plugins/scanner/main.py

@ -329,14 +329,17 @@ class Scanner(Plugin):
del movie_files
total_found = len(valid_files)
# Make sure only one movie was found if a download ID is provided
if download_info and not len(valid_files) == 1:
if download_info and total_found == 0:
log.info('Download ID provided (%s), but no groups found! Make sure the download contains valid media files (fully extracted).', download_info.get('imdb_id'))
elif download_info and total_found > 1:
log.info('Download ID provided (%s), but more than one group found (%s). Ignoring Download ID...', (download_info.get('imdb_id'), len(valid_files)))
download_info = None
# Determine file types
processed_movies = {}
total_found = len(valid_files)
while True and not self.shuttingDown():
try:
identifier, group = valid_files.popitem()

30
couchpotato/core/providers/automation/imdb/__init__.py

@ -9,7 +9,7 @@ config = [{
{
'tab': 'automation',
'list': 'watchlist_providers',
'name': 'imdb_automation',
'name': 'imdb_automation_watchlist',
'label': 'IMDB',
'description': 'From any <strong>public</strong> IMDB watchlists. Url should be the CSV link.',
'options': [
@ -30,5 +30,33 @@ config = [{
},
],
},
{
'tab': 'automation',
'list': 'automation_providers',
'name': 'imdb_automation_charts',
'label': 'IMDB',
'description': 'Import movies from IMDB Charts',
'options': [
{
'name': 'automation_providers_enabled',
'default': False,
'type': 'enabler',
},
{
'name': 'automation_charts_theater',
'type': 'bool',
'label': 'In Theaters',
'description': 'New Movies <a href="http://www.imdb.com/movies-in-theaters/">In-Theaters</a> chart',
'default': True,
},
{
'name': 'automation_charts_top250',
'type': 'bool',
'label': 'TOP 250',
'description': 'IMDB <a href="http://www.imdb.com/chart/top/">TOP 250</a> chart',
'default': True,
},
],
},
],
}]

76
couchpotato/core/providers/automation/imdb/main.py

@ -1,38 +1,100 @@
import traceback
from bs4 import BeautifulSoup
from couchpotato import fireEvent
from couchpotato.core.helpers.rss import RSS
from couchpotato.core.helpers.variable import getImdb, splitString, tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.automation.base import Automation
import traceback
from couchpotato.core.providers.base import MultiProvider
log = CPLog(__name__)
class IMDB(Automation, RSS):
class IMDB(MultiProvider):
def getTypes(self):
return [IMDBWatchlist, IMDBAutomation]
class IMDBBase(Automation, RSS):
interval = 1800
def getInfo(self, imdb_id):
return fireEvent('movie.info', identifier = imdb_id, merge = True)
class IMDBWatchlist(IMDBBase):
enabled_option = 'automation_enabled'
def getIMDBids(self):
movies = []
enablers = [tryInt(x) for x in splitString(self.conf('automation_urls_use'))]
urls = splitString(self.conf('automation_urls'))
watchlist_enablers = [tryInt(x) for x in splitString(self.conf('automation_urls_use'))]
watchlist_urls = splitString(self.conf('automation_urls'))
index = -1
for url in urls:
for watchlist_url in watchlist_urls:
index += 1
if not enablers[index]:
if not watchlist_enablers[index]:
continue
try:
rss_data = self.getHTMLData(url)
log.debug('Started IMDB watchlists: %s', watchlist_url)
rss_data = self.getHTMLData(watchlist_url)
imdbs = getImdb(rss_data, multiple = True) if rss_data else []
for imdb in imdbs:
movies.append(imdb)
if self.shuttingDown():
break
except:
log.error('Failed loading IMDB watchlist: %s %s', (url, traceback.format_exc()))
return movies
class IMDBAutomation(IMDBBase):
enabled_option = 'automation_providers_enabled'
chart_urls = {
'theater': 'http://www.imdb.com/movies-in-theaters/',
'top250': 'http://www.imdb.com/chart/top',
}
def getIMDBids(self):
movies = []
for url in self.chart_urls:
if self.conf('automation_charts_%s' % url):
data = self.getHTMLData(self.chart_urls[url])
if data:
html = BeautifulSoup(data)
try:
result_div = html.find('div', attrs = {'id': 'main'})
imdb_ids = getImdb(str(result_div), multiple = True)
for imdb_id in imdb_ids:
info = self.getInfo(imdb_id)
if info and self.isMinimalMovie(info):
movies.append(imdb_id)
if self.shuttingDown():
break
except:
log.error('Failed loading IMDB chart results from %s: %s', (url, traceback.format_exc()))
return movies

16
couchpotato/core/providers/automation/rottentomatoes/__init__.py

@ -11,7 +11,7 @@ config = [{
'list': 'automation_providers',
'name': 'rottentomatoes_automation',
'label': 'Rottentomatoes',
'description': 'Imports movies from the rottentomatoes "in theaters"-feed.',
'description': 'Imports movies from rottentomatoes rss feeds specified below.',
'options': [
{
'name': 'automation_enabled',
@ -19,11 +19,23 @@ config = [{
'type': 'enabler',
},
{
'name': 'automation_urls_use',
'label': 'Use',
'default': '1',
},
{
'name': 'automation_urls',
'label': 'url',
'type': 'combined',
'combine': ['automation_urls_use', 'automation_urls'],
'default': 'http://www.rottentomatoes.com/syndication/rss/in_theaters.xml',
},
{
'name': 'tomatometer_percent',
'default': '80',
'label': 'Tomatometer',
'description': 'Use as extra scoring requirement',
}
},
],
},
],

48
couchpotato/core/providers/automation/rottentomatoes/main.py

@ -1,5 +1,5 @@
from couchpotato.core.helpers.rss import RSS
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.helpers.variable import tryInt, splitString
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.automation.base import Automation
from xml.etree.ElementTree import QName
@ -11,38 +11,42 @@ log = CPLog(__name__)
class Rottentomatoes(Automation, RSS):
interval = 1800
urls = {
'namespace': 'http://www.rottentomatoes.com/xmlns/rtmovie/',
'theater': 'http://www.rottentomatoes.com/syndication/rss/in_theaters.xml',
}
def getIMDBids(self):
movies = []
rss_movies = self.getRSSData(self.urls['theater'])
rating_tag = str(QName(self.urls['namespace'], 'tomatometer_percent'))
rotten_tomatoes_namespace = 'http://www.rottentomatoes.com/xmlns/rtmovie/'
urls = dict(zip(splitString(self.conf('automation_urls')), [tryInt(x) for x in splitString(self.conf('automation_urls_use'))]))
for movie in rss_movies:
for url in urls:
value = self.getTextElement(movie, "title")
result = re.search('(?<=%\s).*', value)
if not urls[url]:
continue
if result:
rss_movies = self.getRSSData(url)
rating_tag = str(QName(rotten_tomatoes_namespace, 'tomatometer_percent'))
log.info2('Something smells...')
rating = tryInt(self.getTextElement(movie, rating_tag))
name = result.group(0)
for movie in rss_movies:
if rating < tryInt(self.conf('tomatometer_percent')):
log.info2('%s seems to be rotten...', name)
else:
value = self.getTextElement(movie, "title")
result = re.search('(?<=%\s).*', value)
log.info2('Found %s fresh enough movies, enqueuing: %s', (rating, name))
year = datetime.datetime.now().strftime("%Y")
imdb = self.search(name, year)
if result:
if imdb and self.isMinimalMovie(imdb):
movies.append(imdb['imdb'])
log.info2('Something smells...')
rating = tryInt(self.getTextElement(movie, rating_tag))
name = result.group(0)
if rating < tryInt(self.conf('tomatometer_percent')):
log.info2('%s seems to be rotten...', name)
else:
log.info2('Found %s fresh enough movies, enqueuing: %s', (rating, name))
year = datetime.datetime.now().strftime("%Y")
imdb = self.search(name, year)
if imdb and self.isMinimalMovie(imdb):
movies.append(imdb['imdb'])
return movies

1
couchpotato/core/providers/movie/_modifier/main.py

@ -28,6 +28,7 @@ class MovieResultModifier(Plugin):
'tagline': '',
'imdb': '',
'genres': [],
'mpaa': None
}
def __init__(self):

1
couchpotato/core/providers/movie/omdbapi/main.py

@ -95,6 +95,7 @@ class OMDBAPI(MovieProvider):
#'rotten': (tryFloat(movie.get('tomatoRating', 0)), tryInt(movie.get('tomatoReviews', '').replace(',', ''))),
},
'imdb': str(movie.get('imdbID', '')),
'mpaa': str(movie.get('Rated', '')),
'runtime': self.runtimeToMinutes(movie.get('Runtime', '')),
'released': movie.get('Released'),
'year': year if isinstance(year, (int)) else None,

1
couchpotato/core/providers/movie/themoviedb/main.py

@ -167,6 +167,7 @@ class TheMovieDb(MovieProvider):
'backdrop_original': [backdrop_original] if backdrop_original else [],
},
'imdb': movie.get('imdb_id'),
'mpaa': movie.get('certification', ''),
'runtime': movie.get('runtime'),
'released': movie.get('released'),
'year': year,

2
couchpotato/runner.py

@ -214,7 +214,7 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En
# app.debug = development
config = {
'use_reloader': reloader,
'port': tryInt(Env.setting('port', default = 5000)),
'port': tryInt(Env.setting('port', default = 5050)),
'host': host if host and len(host) > 0 else '0.0.0.0',
'ssl_cert': Env.setting('ssl_cert', default = None),
'ssl_key': Env.setting('ssl_key', default = None),

15
couchpotato/templates/index.html

@ -22,17 +22,18 @@
<script type="text/javascript">
if($(window).getSize().x <= 480)
window.addEvent('load', function() {
window.addEvent('load', function(){
setTimeout(function(){
window.scrollTo(0, 1);
window.scrollTo(0, 0);
}, 100);
if(window.getSize().x <= 480)
setTimeout(function(){
window.scrollTo(0, 1);
window.scrollTo(0, 0);
}, 100);
});
});
window.addEvent('domready', function() {
new Uniform();
Api.setup({

81
init/ubuntu

@ -26,48 +26,89 @@ NAME=couchpotato
# App name
DESC=CouchPotato
# Path to app root
CP_APP_PATH=${APP_PATH-/usr/local/sbin/CouchPotatoServer/}
## Don't edit this file
## Edit user configuation in /etc/default/couchpotato to change
##
## CP_USER= #$RUN_AS, username to run couchpotato under, the default is couchpotato
## CP_HOME= #$APP_PATH, the location of couchpotato.py, the default is /opt/couchpotato
## CP_DATA= #$DATA_DIR, the location of couchpotato.db, cache, logs, the default is /var/couchpotato
## CP_PIDFILE= #$PID_FILE, the location of couchpotato.pid, the default is /var/run/couchpotato.pid
## PYTHON_BIN= #$DAEMON, the location of the python binary, the default is /usr/bin/python
## CP_OPTS= #$EXTRA_DAEMON_OPTS, extra cli option for couchpotato, i.e. " --config_file=/home/couchpotato/couchpotato.ini"
## SSD_OPTS= #$EXTRA_SSD_OPTS, extra start-stop-daemon option like " --group=users"
##
## EXAMPLE if want to run as different user
## add CP_USER=username to /etc/default/couchpotato
## otherwise default couchpotato is used
# Run CP as username
RUN_AS=${CP_USER-couchpotato}
# Path to app
# CP_HOME=path_to_app_CouchPotato.py
APP_PATH=${CP_HOME-/opt/couchpotato/}
# Data directory where couchpotato.db, cache and logs are stored
DATA_DIR=${CP_DATA-/var/couchpotato}
# User to run CP as
CP_RUN_AS=${RUN_AS-root}
# Path to store PID file
PID_FILE=${CP_PID_FILE-/var/run/couchpotato.pid}
# Path to python bin
CP_DAEMON=${DAEMON_PATH-/usr/bin/python}
# path to python bin
DAEMON=${PYTHON_BIN-/usr/bin/python}
# Path to store PID file
CP_PID_FILE=${PID_FILE-/var/run/couchpotato.pid}
# Extra daemon option like: CP_OPTS=" --config=/home/couchpotato/couchpotato.ini"
EXTRA_DAEMON_OPTS=${CP_OPTS-}
# Extra start-stop-daemon option like START_OPTS=" --group=users"
EXTRA_SSD_OPTS=${SSD_OPTS-}
PID_PATH=`dirname $PID_FILE`
DAEMON_OPTS=" CouchPotato.py --quiet --daemon --pid_file=${PID_FILE} --data_dir=${DATA_DIR} ${EXTRA_DAEMON_OPTS}"
# Other startup args
CP_DAEMON_OPTS=" CouchPotato.py --daemon --pid_file=${CP_PID_FILE}"
test -x $CP_DAEMON || exit 0
test -x $DAEMON || exit 0
set -e
. /lib/lsb/init-functions
# Create PID directory if not exist and ensure the CouchPotato user can write to it
if [ ! -d $PID_PATH ]; then
mkdir -p $PID_PATH
chown $RUN_AS $PID_PATH
fi
if [ ! -d $DATA_DIR ]; then
mkdir -p $DATA_DIR
chown $RUN_AS $DATA_DIR
fi
if [ -e $PID_FILE ]; then
PID=`cat $PID_FILE`
if ! kill -0 $PID > /dev/null 2>&1; then
echo "Removing stale $PID_FILE"
rm $PID_FILE
fi
fi
case "$1" in
start)
echo "Starting $DESC"
rm -rf $CP_PID_FILE || return 1
touch $CP_PID_FILE
chown $CP_RUN_AS $CP_PID_FILE
start-stop-daemon -d $CP_APP_PATH -c $CP_RUN_AS --start --background --pidfile $CP_PID_FILE --exec $CP_DAEMON -- $CP_DAEMON_OPTS
start-stop-daemon -d $APP_PATH -c $RUN_AS $EXTRA_SSD_OPTS --start --pidfile $PID_FILE --exec $DAEMON -- $DAEMON_OPTS
;;
stop)
echo "Stopping $DESC"
start-stop-daemon --stop --pidfile $CP_PID_FILE --retry 15
start-stop-daemon --stop --pidfile $PID_FILE --retry 15
;;
restart|force-reload)
echo "Restarting $DESC"
start-stop-daemon --stop --pidfile $CP_PID_FILE --retry 15
start-stop-daemon -d $CP_APP_PATH -c $CP_RUN_AS --start --background --pidfile $CP_PID_FILE --exec $CP_DAEMON -- $CP_DAEMON_OPTS
start-stop-daemon --stop --pidfile $PID_FILE --retry 15
start-stop-daemon -d $APP_PATH -c $RUN_AS $EXTRA_SSD_OPTS --start --pidfile $PID_FILE --exec $DAEMON -- $DAEMON_OPTS
;;
status)
status_of_proc -p $CP_PID_FILE "$CP_DAEMON" "$NAME"
status_of_proc -p $PID_FILE "$DAEMON" "$NAME"
;;
*)
N=/etc/init.d/$NAME

8
init/ubuntu.default

@ -1,5 +1,5 @@
# COPY THIS FILE TO /etc/default/couchpotato
# OPTIONS: APP_PATH, RUN_AS, DAEMON_PATH, CP_PID_FILE
# COPY THIS FILE TO /etc/default/couchpotato
# OPTIONS: CP_HOME, CP_USER, CP_DATA, CP_PIDFILE, PYTHON_BIN, CP_OPTS, SSD_OPTS
APP_PATH=
RUN_AS=root
CP_HOME=
CP_USER=root
Loading…
Cancel
Save