Browse Source

Merge branch 'develop' into redesign

pull/5180/head
Ruud 10 years ago
parent
commit
195a4764a3
  1. 9
      couchpotato/core/_base/_core.py
  2. 232
      couchpotato/core/media/_base/providers/torrent/rarbg.py
  3. 11
      couchpotato/core/media/movie/providers/torrent/rarbg.py
  4. 126
      couchpotato/core/notifications/slack.py
  5. 2
      couchpotato/core/plugins/base.py
  6. 2
      couchpotato/core/plugins/renamer.py
  7. 4
      couchpotato/templates/login.html
  8. 2
      init/freebsd

9
couchpotato/core/_base/_core.py

@ -5,6 +5,7 @@ import signal
import time
import traceback
import webbrowser
import sys
from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, addEvent
@ -64,6 +65,14 @@ class Core(Plugin):
import socket
socket.setdefaulttimeout(30)
# Don't check ssl by default
try:
if sys.version_info >= (2, 7, 9):
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
except:
log.debug('Failed setting default ssl context: %s', traceback.format_exc())
def md5Password(self, value):
return md5(value) if value else ''

232
couchpotato/core/media/_base/providers/torrent/rarbg.py

@ -0,0 +1,232 @@
import re
import traceback
import random
import time
from datetime import datetime
from couchpotato.core.helpers.variable import tryInt, getIdentifier
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.torrent.base import TorrentMagnetProvider
log = CPLog(__name__)
tokenreceived = 0
rarbgtoken = 0
class Base(TorrentMagnetProvider):
urls = {
'test': 'https://torrentapi.org/pubapi_v2.php?app_id=couchpotato',
'token': 'https://torrentapi.org/pubapi_v2.php?get_token=get_token&app_id=couchpotato',
'search': 'https://torrentapi.org/pubapi_v2.php?token=%s&mode=search&search_imdb=%s&min_seeders=%s&min_leechers'
'=%s&ranked=%s&category=movies&format=json_extended&app_id=couchpotato',
}
http_time_between_calls = 2 # Seconds
user_agent = 'CouchPotato/1.0'
@staticmethod
def find_info(filename):
# CODEC #
codec = 'x264'
v = re.search("(?i)(x265|h265|h\.265)", filename)
if v:
codec = 'x265'
v = re.search("(?i)(xvid)", filename)
if v:
codec = 'xvid'
# RESOLUTION #
resolution = 'SD'
a = re.search("(?i)(720p)", filename)
if a:
resolution = '720p'
a = re.search("(?i)(1080p)", filename)
if a:
resolution = '1080p'
a = re.search("(?i)(2160p)", filename)
if a:
resolution = '2160p'
# SOURCE #
source = 'HD-Rip'
s = re.search("(?i)(WEB-DL|WEB_DL|WEB\.DL)", filename)
if s:
source = 'WEB-DL'
s = re.search("(?i)(WEBRIP)", filename)
if s:
source = 'WEBRIP'
s = re.search("(?i)(DVDR|DVDRip|DVD-Rip)", filename)
if s:
source = 'DVD-R'
s = re.search("(?i)(BRRIP|BDRIP|BluRay)", filename)
if s:
source = 'BR-Rip'
s = re.search("(?i)BluRay(.*)REMUX", filename)
if s:
source = 'BluRay-Remux'
s = re.search("(?i)BluRay(.*)\.(AVC|VC-1)\.", filename)
if s:
source = 'BluRay-Full'
return_info = [codec, resolution, source]
return return_info
@staticmethod
def get_token(self):
global tokenreceived
global rarbgtoken
now = int(time.time())
if (rarbgtoken == 0) or (tokenreceived == 0) or (now > (tokenreceived+(15*60))):
log.debug("RARBG: Getting Rarbg token")
tokendata = self.getJsonData(self.urls['token'])
if tokendata:
try:
tokenreceived = int(time.time())
rarbgtoken = tokendata['token']
log.debug("RARBG: GOT TOKEN: %s", rarbgtoken)
except RuntimeError:
log.error('RARBG: Failed getting token from Rarbg')
rarbgtoken = 0
# return token
def _search(self, movie, quality, results):
hasresults = 0
curryear = datetime.now().year
self.get_token(self)
movieid = getIdentifier(movie)
try:
movieyear = movie['info']['year']
except:
log.error("RARBG: Couldn't get movie year")
movieyear = 0
if (rarbgtoken != 0) and (movieyear == 0 or movieyear <= curryear):
data = self.getJsonData(self.urls['search'] % (rarbgtoken, movieid, self.conf('min_seeders'),
self.conf('min_leechers'), self.conf('ranked_only')))
if data:
if 'error_code' in data:
if data['error'] == 'No results found':
log.debug("RARBG: No results returned from Rarbg")
else:
if data['error_code'] == 10:
log.error(data['error'], movieid)
else:
log.error("RARBG: There is an error in the returned JSON: %s", data['error'])
else:
hasresults = 1
try:
if hasresults:
for result in data['torrent_results']:
name = result['title']
titlesplit = re.split("-", name)
releasegroup = titlesplit[len(titlesplit)-1]
xtrainfo = self.find_info(name)
encoding = xtrainfo[0]
resolution = xtrainfo[1]
# source = xtrainfo[2]
pubdate = result['pubdate'] # .strip(" +0000")
try:
pubdate = datetime.strptime(pubdate, '%Y-%m-%d %H:%M:%S +0000')
now = datetime.utcnow()
age = (now - pubdate).days
except ValueError:
log.debug("RARBG: Bad pubdate")
age = 0
torrentscore = self.conf('extra_score')
seeders = tryInt(result['seeders'])
torrent_desc = '/ %s / %s / %s / %s seeders' % (releasegroup, resolution, encoding, seeders)
if seeders == 0:
torrentscore = 0
sliceyear = result['pubdate'][0:4]
year = tryInt(sliceyear)
results.append({
'id': random.randint(100, 9999),
'name': re.sub('[^A-Za-z0-9\-_ \(\).]+', '', '%s (%s) %s' % (name, year, torrent_desc)),
'url': result['download'],
'detail_url': result['info_page'],
'size': tryInt(result['size']/1048576), # rarbg sends in bytes
'seeders': tryInt(result['seeders']),
'leechers': tryInt(result['leechers']),
'age': tryInt(age),
'score': torrentscore
})
except RuntimeError:
log.error('RARBG: Failed getting results from %s: %s', (self.getName(), traceback.format_exc()))
config = [{
'name': 'rarbg',
'groups': [
{
'tab': 'searcher',
'list': 'torrent_providers',
'name': 'Rarbg',
'wizard': True,
'description': '<a href="https://rarbg.to/torrents.php">RARBG</a>',
'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAB+UlEQVQ4jYXTP2hcRxDH8c8JJZjbYNy8V7gIr0qhg5AiFnETX'
'+PmVAtSmKDaUhUiFyGxjXFlp0hhHy5cqFd9lSGcU55cBU6EEMIj5dsmMewSjNGmOJ3852wysMyww37n94OdXimlh49xDR/hxGr'
'8hZ/xx0qnlHK5lPKk/H/8U0r5oZTyQSmltzzr+AKfT+ed8UFLeHNAH1UVbA2r88NBfQcX8O2yv74sUqKNWT+T01sy2+zpUbS/w'
'/awvo7H+O0NQEA/LPKlQWXrSgUmR9HxcZQwmbZGw/pc4MsVAIT+IjcNw80aTjaaem1vPCNlGakj1C6uWFiqeDtyTvoyqAKhBn+'
'+E7CkxC6Zzjop57XpUSenpIuMhpXAc/zyHkAicRSjw6fHZ1ewPdqwszWAB2hXACln8+NWSlld9zX9YN7GhajQXz5+joPXR66de'
'U1J27Zi7FzaqE0OdmwNGzF2Ymzt3j+E8/gJH64AFlozKS4+Be7tjwyaIKVsOpnavX0II9x8ByDLKco5SwvjL0MI/z64tyOcwsf'
'jQw8PJvAdvsb6GSBlxI7UyTnD37i7OWhe3NrflvOit3djbDKdwR181SulXMXdrkubbdvKaOpK09S/4jP8iG9m8zmJjCoEg0HzO'
'77vna7zp7ju1TqfYIyZxT7dwCd4eWr7BR7h2X8S6gShJlbKYQAAAABJRU5ErkJggg==',
'options': [
{
'name': 'enabled',
'type': 'enabler',
'default': False,
},
{
'name': 'ranked_only',
'advanced': True,
'label': 'Ranked Only',
'type': 'int',
'default': 1,
'description': 'Only ranked torrents (internal), scene releases, rarbg releases. '
'Enter 1 (true) or 0 (false)',
},
{
'name': 'min_seeders',
'advanced': True,
'label': 'Minimum Seeders',
'type': 'int',
'default': 10,
'description': 'Minium amount of seeders the release must have.',
},
{
'name': 'min_leechers',
'advanced': True,
'label': 'Minimum leechers',
'type': 'int',
'default': 0,
'description': 'Minium amount of leechers the release must have.',
},
{
'name': 'extra_score',
'advanced': True,
'label': 'Extra Score',
'type': 'int',
'default': 0,
'description': 'Starting score for each release found via this provider.',
}
],
},
],
}]

11
couchpotato/core/media/movie/providers/torrent/rarbg.py

@ -0,0 +1,11 @@
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.torrent.rarbg import Base
from couchpotato.core.media.movie.providers.base import MovieProvider
log = CPLog(__name__)
autoload = 'Rarbg'
class Rarbg(MovieProvider, Base):
pass

126
couchpotato/core/notifications/slack.py

@ -0,0 +1,126 @@
import json
from couchpotato.core.logger import CPLog
from couchpotato.core.notifications.base import Notification
log = CPLog(__name__)
autoload = 'Slack'
class Slack(Notification):
url = 'https://slack.com/api/chat.postMessage'
required_confs = ('token', 'channels',)
def notify(self, message='', data=None, listener=None):
for key in self.required_confs:
if not self.conf(key):
log.warning('Slack notifications are enabled, but '
'"{0}" is not specified.'.format(key))
return False
data = data or {}
message = message.strip()
if self.conf('include_imdb') and 'identifier' in data:
template = ' http://www.imdb.com/title/{0[identifier]}/'
message += template.format(data)
payload = {
'token': self.conf('token'),
'text': message,
'username': self.conf('bot_name'),
'unfurl_links': self.conf('include_imdb'),
'as_user': self.conf('as_user'),
'icon_url': self.conf('icon_url'),
'icon_emoji': self.conf('icon_emoji')
}
channels = self.conf('channels').split(',')
for channel in channels:
payload['channel'] = channel.strip()
response = self.urlopen(self.url, data=payload)
response = json.loads(response)
if not response['ok']:
log.warning('Notification sending to Slack has failed. Error '
'code: %s.', response['error'])
return False
return True
config = [{
'name': 'slack',
'groups': [
{
'tab': 'notifications',
'list': 'notification_providers',
'name': 'slack',
'options': [
{
'name': 'enabled',
'default': 0,
'type': 'enabler',
},
{
'name': 'token',
'description': (
'Your Slack authentication token.',
'Can be created at https://api.slack.com/web'
)
},
{
'name': 'channels',
'description': (
'Channel to send notifications to.',
'Can be a public channel, private group or IM '
'channel. Can be an encoded ID or a name '
'(staring with a hashtag, e.g. #general). '
'Separate with commas in order to notify multiple '
'channels. It is however recommended to send '
'notifications to only one channel due to '
'the Slack API rate limits.'
)
},
{
'name': 'include_imdb',
'default': True,
'type': 'bool',
'descrpition': 'Include a link to the movie page on IMDB.'
},
{
'name': 'bot_name',
'description': 'Name of bot.',
'default': 'CouchPotato',
'advanced': True,
},
{
'name': 'as_user',
'description': 'Send message as the authentication token '
' user.',
'default': False,
'type': 'bool',
'advanced': True
},
{
'name': 'icon_url',
'description': 'URL to an image to use as the icon for '
'notifications.',
'advanced': True,
},
{
'name': 'icon_emoji',
'description': (
'Emoji to use as the icon for notifications.',
'Overrides icon_url'
),
'advanced': True,
},
{
'name': 'on_snatch',
'default': 0,
'type': 'bool',
'advanced': True,
'description': 'Also send message when movie is snatched.',
},
],
}
],
}]

2
couchpotato/core/plugins/base.py

@ -145,7 +145,7 @@ class Plugin(object):
f.close()
os.chmod(path, Env.getPermission('file'))
except:
log.error('Unable writing to file "%s": %s', (path, traceback.format_exc()))
log.error('Unable to write file "%s": %s', (path, traceback.format_exc()))
if os.path.isfile(path):
os.remove(path)

2
couchpotato/core/plugins/renamer.py

@ -1447,7 +1447,7 @@ config = [{
'default': 'link',
'type': 'dropdown',
'values': [('Link', 'link'), ('Copy', 'copy'), ('Move', 'move')],
'description': 'See above. It is prefered to use link when downloading torrents as it will save you space, while still beeing able to seed.',
'description': 'See above. It is prefered to use link when downloading torrents as it will save you space, while still being able to seed.',
'advanced': True,
},
{

4
couchpotato/templates/login.html

@ -36,8 +36,8 @@
<body class="page login">
<form action="" method="post">
<h1>CouchPotato</h1>
<div class="ctrlHolder"><input class="inlay" name="username" type="text" placeholder="Username" autocomplete="off" /></div>
<div class="ctrlHolder"><input class="inlay" name="password" type="password" placeholder="Password" autocomplete="off" /></div>
<div class="ctrlHolder"><input class="inlay" name="username" type="text" placeholder="Username" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" /></div>
<div class="ctrlHolder"><input class="inlay" name="password" type="password" placeholder="Password" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" /></div>
<div class="ctrlHolder">
<label class="remember_me" title="for 30 days"><input class="inlay" id="remember_me" name="remember_me" type="checkbox" value="1" checked="checked" /> Remember me</label>
<input class="button" name="submit" type="submit" value="Login" />

2
init/freebsd

@ -1,7 +1,7 @@
#!/bin/sh
#
# PROVIDE: couchpotato
# REQUIRE: DAEMON
# REQUIRE: LOGIN
# KEYWORD: shutdown
# Add the following lines to /etc/rc.conf to enable couchpotato:

Loading…
Cancel
Save