Browse Source

Merge branch 'refs/heads/develop'

pull/2961/merge
Ruud 11 years ago
parent
commit
b19f98ef5b
  1. 1
      CouchPotato.py
  2. 9
      couchpotato/core/event.py
  3. 9
      couchpotato/core/helpers/request.py
  4. 24
      couchpotato/core/helpers/variable.py
  5. 4
      couchpotato/core/media/movie/searcher/main.py
  6. 34
      couchpotato/core/notifications/boxcar2/__init__.py
  7. 39
      couchpotato/core/notifications/boxcar2/main.py
  8. 50
      couchpotato/core/plugins/base.py
  9. 6
      couchpotato/core/plugins/dashboard/main.py
  10. 46
      couchpotato/core/plugins/renamer/main.py
  11. 36
      couchpotato/core/plugins/scanner/main.py
  12. 7
      couchpotato/core/providers/nzb/nzbclub/main.py
  13. 2
      couchpotato/core/providers/torrent/thepiratebay/main.py
  14. 7
      couchpotato/core/providers/userscript/reddit/__init__.py
  15. 17
      couchpotato/core/providers/userscript/reddit/main.py
  16. 7
      libs/axl/axel.py

1
CouchPotato.py

@ -136,6 +136,7 @@ if __name__ == '__main__':
except socket.error as e:
# log when socket receives SIGINT, but continue.
# previous code would have skipped over other types of IO errors too.
nr, msg = e
if nr != 4:
try:
l.log.critical(traceback.format_exc())

9
couchpotato/core/event.py

@ -1,5 +1,5 @@
from axl.axel import Event
from couchpotato.core.helpers.variable import mergeDicts, natcmp
from couchpotato.core.helpers.variable import mergeDicts, natsortKey
from couchpotato.core.logger import CPLog
import threading
import traceback
@ -51,11 +51,6 @@ def addEvent(name, handler, priority = 100):
})
def removeEvent(name, handler):
e = events[name]
e -= handler
def fireEvent(name, *args, **kwargs):
if name not in events: return
@ -106,7 +101,7 @@ def fireEvent(name, *args, **kwargs):
result = e(*args, **kwargs)
result_keys = result.keys()
result_keys.sort(natcmp)
result_keys.sort(key = natsortKey)
if options['single'] and not options['merge']:
results = None

9
couchpotato/core/helpers/request.py

@ -1,5 +1,5 @@
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import natcmp
from couchpotato.core.helpers.variable import natsortKey
from urllib import unquote
import re
@ -8,8 +8,13 @@ def getParams(params):
reg = re.compile('^[a-z0-9_\.]+$')
# Sort keys
param_keys = params.keys()
param_keys.sort(key = natsortKey)
temp = {}
for param, value in sorted(params.items()):
for param in param_keys:
value = params[param]
nest = re.split("([\[\]]+)", param)
if len(nest) > 1:

24
couchpotato/core/helpers/variable.py

@ -214,16 +214,9 @@ def tryFloat(s):
return float(s)
except: return 0
def natsortKey(s):
return map(tryInt, re.findall(r'(\d+|\D+)', s))
def natcmp(a, b):
a2 = natsortKey(a)
b2 = natsortKey(b)
return (a2 > b2) - (a2 < b2)
def natsortKey(string_):
"""See http://www.codinghorror.com/blog/archives/001018.html"""
return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', string_)]
def toIterable(value):
@ -295,3 +288,14 @@ def dictIsSubset(a, b):
def isSubFolder(sub_folder, base_folder):
# Returns True if sub_folder is the same as or inside base_folder
return base_folder and sub_folder and ss(os.path.normpath(base_folder).rstrip(os.path.sep) + os.path.sep) in ss(os.path.normpath(sub_folder).rstrip(os.path.sep) + os.path.sep)
# From SABNZBD
re_password = [re.compile(r'([^/\\]+)[/\\](.+)'), re.compile(r'(.+){{([^{}]+)}}$'), re.compile(r'(.+)\s+password\s*=\s*(.+)$', re.I)]
def scanForPassword(name):
m = None
for reg in re_password:
m = reg.search(name)
if m: break
if m:
return m.group(1).strip('. '), m.group(2).strip()

4
couchpotato/core/media/movie/searcher/main.py

@ -282,13 +282,15 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
now = int(time.time())
now_year = date.today().year
now_month = date.today().month
if (year is None or year < now_year - 1) and (not dates or (dates.get('theater', 0) == 0 and dates.get('dvd', 0) == 0)):
return True
else:
# Don't allow movies with years to far in the future
if year is not None and year > now_year + 1:
add_year = 1 if now_month > 10 else 0 # Only allow +1 year if end of the year
if year is not None and year > (now_year + add_year):
return False
# For movies before 1972

34
couchpotato/core/notifications/boxcar2/__init__.py

@ -0,0 +1,34 @@
from .main import Boxcar2
def start():
return Boxcar2()
config = [{
'name': 'boxcar2',
'groups': [
{
'tab': 'notifications',
'list': 'notification_providers',
'name': 'boxcar2',
'options': [
{
'name': 'enabled',
'default': 0,
'type': 'enabler',
},
{
'name': 'token',
'description': ('Your Boxcar access token.', 'Can be found in the app under settings')
},
{
'name': 'on_snatch',
'default': 0,
'type': 'bool',
'advanced': True,
'description': 'Also send message when movie is snatched.',
},
],
}
],
}]

39
couchpotato/core/notifications/boxcar2/main.py

@ -0,0 +1,39 @@
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.logger import CPLog
from couchpotato.core.notifications.base import Notification
log = CPLog(__name__)
class Boxcar2(Notification):
url = 'https://new.boxcar.io/api/notifications'
def notify(self, message = '', data = None, listener = None):
if not data: data = {}
try:
message = message.strip()
long_message = ''
if listener == 'test':
long_message = 'This is a test message'
elif data.get('identifier'):
long_message = 'More movie info <a href="http://www.imdb.com/title/%s/">on IMDB</a>' % data['identifier']
data = {
'user_credentials': self.conf('token'),
'notification[title]': toUnicode(message),
'notification[long_message]': toUnicode(long_message),
}
self.urlopen(self.url, data = data)
except:
log.error('Make sure the token provided is for the correct device')
return False
log.info('Boxcar notification successful.')
return True
def isEnabled(self):
return super(Boxcar2, self).isEnabled() and self.conf('token')

50
couchpotato/core/plugins/base.py

@ -1,7 +1,7 @@
from couchpotato.core.event import fireEvent, addEvent
from couchpotato.core.helpers.encoding import ss, toSafeString, \
toUnicode, sp
from couchpotato.core.helpers.variable import getExt, md5, isLocalIP
from couchpotato.core.helpers.variable import getExt, md5, isLocalIP, scanForPassword, tryInt
from couchpotato.core.logger import CPLog
from couchpotato.environment import Env
import requests
@ -283,8 +283,17 @@ class Plugin(object):
return value
def createNzbName(self, data, media):
release_name = data.get('name')
tag = self.cpTag(media)
return '%s%s' % (toSafeString(toUnicode(data.get('name'))[:127 - len(tag)]), tag)
# Check if password is filename
name_password = scanForPassword(data.get('name'))
if name_password:
release_name, password = name_password
tag += '{{%s}}' % password
max_length = 127 - len(tag) # Some filesystems don't support 128+ long filenames
return '%s%s' % (toSafeString(toUnicode(release_name)[:max_length]), tag)
def createFileName(self, data, filedata, media):
name = sp(os.path.join(self.createNzbName(data, media)))
@ -298,6 +307,43 @@ class Plugin(object):
return ''
def checkFilesChanged(self, files, unchanged_for = 60):
now = time.time()
file_too_new = False
for cur_file in files:
# File got removed while checking
if not os.path.isfile(cur_file):
file_too_new = now
break
# File has changed in last 60 seconds
file_time = self.getFileTimes(cur_file)
for t in file_time:
if t > now - unchanged_for:
file_too_new = tryInt(time.time() - t)
break
if file_too_new:
break
if file_too_new:
try:
time_string = time.ctime(file_time[0])
except:
try:
time_string = time.ctime(file_time[1])
except:
time_string = 'unknown'
return file_too_new, time_string
return False, None
def getFileTimes(self, file_path):
return [os.path.getmtime(file_path), os.path.getctime(file_path) if os.name != 'posix' else 0]
def isDisabled(self):
return not self.isEnabled()

6
couchpotato/core/plugins/dashboard/main.py

@ -1,3 +1,4 @@
from datetime import date
from couchpotato import get_session
from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent
@ -65,6 +66,7 @@ class Dashboard(Plugin):
active = q.all()
movies = []
now_year = date.today().year
if len(active) > 0:
@ -91,8 +93,8 @@ class Dashboard(Plugin):
if coming_soon:
# Don't list older movies
if ((not late and (not eta.get('dvd') and not eta.get('theater') or eta.get('dvd') and eta.get('dvd') > (now - 2419200))) or
(late and (eta.get('dvd', 0) > 0 or eta.get('theater')) and eta.get('dvd') < (now - 2419200))):
if ((not late and (year >= now_year-1) and (not eta.get('dvd') and not eta.get('theater') or eta.get('dvd') and eta.get('dvd') > (now - 2419200))) or
(late and ((year < now_year-1) or ((eta.get('dvd', 0) > 0 or eta.get('theater')) and eta.get('dvd') < (now - 2419200))))):
movie_ids.append(movie_id)
if len(movie_ids) >= limit:

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

@ -736,8 +736,15 @@ Remove it if you want it to be renamed (again, or at least let it try again)
def moveFile(self, old, dest, forcemove = False):
dest = ss(dest)
try:
if forcemove:
shutil.move(old, dest)
if forcemove or self.conf('file_action') not in ['copy', 'link']:
try:
shutil.move(old, dest)
except:
if os.path.exists(dest):
log.error('Successfully moved file "%s", but something went wrong: %s', (dest, traceback.format_exc()))
os.unlink(old)
else:
raise
elif self.conf('file_action') == 'copy':
shutil.copy(old, dest)
elif self.conf('file_action') == 'link':
@ -755,8 +762,6 @@ Remove it if you want it to be renamed (again, or at least let it try again)
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)
try:
os.chmod(dest, Env.getPermission('file'))
@ -764,15 +769,6 @@ Remove it if you want it to be renamed (again, or at least let it try again)
os.popen('icacls "' + dest + '"* /reset /T')
except:
log.error('Failed setting permissions for file: %s, %s', (dest, traceback.format_exc(1)))
except OSError as err:
# Copying from a filesystem with octal permission to an NTFS file system causes a permission error. In this case ignore it.
if not hasattr(os, 'chmod') or err.errno != errno.EPERM:
raise
else:
if os.path.exists(dest):
os.unlink(old)
except:
log.error('Couldn\'t move file "%s" to "%s": %s', (old, dest, traceback.format_exc()))
raise
@ -1127,29 +1123,9 @@ Remove it if you want it to be renamed (again, or at least let it try again)
# Check if archive is fresh and maybe still copying/moving/downloading, ignore files newer than 1 minute
if check_file_date:
file_too_new = False
for cur_file in archive['files']:
if not os.path.isfile(cur_file):
file_too_new = time.time()
break
file_time = [os.path.getmtime(cur_file), os.path.getctime(cur_file)]
for t in file_time:
if t > time.time() - 60:
file_too_new = tryInt(time.time() - t)
break
if file_too_new:
break
if file_too_new:
try:
time_string = time.ctime(file_time[0])
except:
try:
time_string = time.ctime(file_time[1])
except:
time_string = 'unknown'
files_too_new, time_string = self.checkFilesChanged(archive['files'])
if files_too_new:
log.info('Archive seems to be still copying/moving/downloading or just copied/moved/downloaded (created on %s), ignoring for now: %s', (time_string, os.path.basename(archive['file'])))
continue

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

@ -291,41 +291,21 @@ class Scanner(Plugin):
break
# Check if movie is fresh and maybe still unpacking, ignore files newer than 1 minute
file_too_new = False
for cur_file in group['unsorted_files']:
if not os.path.isfile(cur_file):
file_too_new = time.time()
break
file_time = [os.path.getmtime(cur_file), os.path.getctime(cur_file)]
for t in file_time:
if t > time.time() - 60:
file_too_new = tryInt(time.time() - t)
break
if file_too_new:
break
if check_file_date and file_too_new:
try:
time_string = time.ctime(file_time[0])
except:
try:
time_string = time.ctime(file_time[1])
except:
time_string = 'unknown'
log.info('Files seem to be still unpacking or just unpacked (created on %s), ignoring for now: %s', (time_string, identifier))
if check_file_date:
files_too_new, time_string = self.checkFilesChanged(group['unsorted_files'])
if files_too_new:
log.info('Files seem to be still unpacking or just unpacked (created on %s), ignoring for now: %s', (time_string, identifier))
# Delete the unsorted list
del group['unsorted_files']
# Delete the unsorted list
del group['unsorted_files']
continue
continue
# Only process movies newer than x
if newer_than and newer_than > 0:
has_new_files = False
for cur_file in group['unsorted_files']:
file_time = [os.path.getmtime(cur_file), os.path.getctime(cur_file)]
file_time = self.getFileTimes(cur_file)
if file_time[0] > newer_than or file_time[1] > newer_than:
has_new_files = True
break

7
couchpotato/core/providers/nzb/nzbclub/main.py

@ -22,8 +22,11 @@ class NZBClub(NZBProvider, RSS):
q = '"%s %s"' % (title, movie['library']['year'])
params = tryUrlencode({
q_param = tryUrlencode({
'q': q,
})
params = tryUrlencode({
'ig': 1,
'rpp': 200,
'st': 5,
@ -31,7 +34,7 @@ class NZBClub(NZBProvider, RSS):
'ns': 1,
})
nzbs = self.getRSSData(self.urls['search'] % params)
nzbs = self.getRSSData(self.urls['search'] % ('%s&%s' % (q_param, params)))
for nzb in nzbs:

2
couchpotato/core/providers/torrent/thepiratebay/main.py

@ -37,7 +37,7 @@ class ThePirateBay(TorrentMagnetProvider):
'http://nl.tpb.li',
'http://proxybay.eu',
'https://www.getpirate.com',
'http://pirateproxy.ca',
'http://piratebay.io',
]
def _searchOnTitle(self, title, movie, quality, results):

7
couchpotato/core/providers/userscript/reddit/__init__.py

@ -0,0 +1,7 @@
from .main import Reddit
def start():
return Reddit()
config = []

17
couchpotato/core/providers/userscript/reddit/main.py

@ -0,0 +1,17 @@
from couchpotato import fireEvent
from couchpotato.core.helpers.variable import splitString
from couchpotato.core.providers.userscript.base import UserscriptBase
class Reddit(UserscriptBase):
includes = ['*://www.reddit.com/r/Ijustwatched/comments/*']
def getMovie(self, url):
name = splitString(url, '/')[-1]
if name.startswith('ijw_'):
name = name[4:]
year_name = fireEvent('scanner.name_year', name, single = True)
return self.search(year_name.get('name'), year_name.get('year'))

7
libs/axl/axel.py

@ -11,7 +11,7 @@
# Source: http://pypi.python.org/pypi/axel
# Docs: http://packages.python.org/axel
from couchpotato.core.helpers.variable import natcmp
from couchpotato.core.helpers.variable import natsortKey
import Queue
import hashlib
import sys
@ -158,7 +158,10 @@ class Event(object):
t.daemon = True
t.start()
for handler in sorted(self.handlers.iterkeys(), cmp = natcmp):
handler_keys = self.handlers.keys()
handler_keys.sort(key = natsortKey)
for handler in handler_keys:
self.queue.put(handler)
if self.asynchronous:

Loading…
Cancel
Save