Merge remote-tracking branch 'remotes/origin/develop' into tv

This commit is contained in:
Joel Kåberg
2013-12-14 21:24:07 +01:00
10 changed files with 128 additions and 29 deletions
+19 -9
View File
@@ -1,15 +1,25 @@
#So you feel like posting a bug, sending me a pull request or just telling me how awesome I am. No problem! ## Got a issue/feature request or submitting a pull request?
##Just make sure you think of the following things: Make sure you think of the following things:
* Search through the existing (and closed) issues first. See if you can get your answer there. ## Issue
* Search through the existing (and closed) issues first, see if you can get your answer there.
* Double check the result manually, because it could be an external issue. * Double check the result manually, because it could be an external issue.
* Post logs! Without seeing what is going on, I can't reproduce the error. * Post logs! Without seeing what is going on, I can't reproduce the error.
* What is the movie + quality you are searching for. * Also check the logs before submitting, obvious errors like permission or http errors are often not related to CP.
* What are you settings for the specific problem. * What is the movie + quality you are searching for?
* What providers are you using. (While your logs include these, scanning through hundred of lines of log isn't my hobby). * What are you're settings for the specific problem?
* Give me a short step by step of how to reproduce. * What providers are you using? (While you're logs include these, scanning through hundred of lines of log isn't our hobby)
* Post the logs from config directory, please do not copy paste the UI. Use pastebin to store these logs!
* Give a short step by step of how to reproduce the error.
* What hardware / OS are you using and what are the limits? NAS can be slow and maybe have a different python installed then when you use CP on OSX or Windows for example. * What hardware / OS are you using and what are the limits? NAS can be slow and maybe have a different python installed then when you use CP on OSX or Windows for example.
* I will mark issues with the "can't reproduce" tag. Don't go asking me "why closed" if it clearly says the issue in the tag ;) * I will mark issues with the "can't reproduce" tag. Don't go asking "why closed" if it clearly says the issue in the tag ;)
* If you're running on a NAS (QNAP, Austor etc..) with pre-made packages, make sure these are setup to use our source repo (RuudBurger/CouchPotatoServer) and nothing else!!
**If I don't get enough info, the chance of the issue getting closed is a lot bigger ;)** ## Pull Request
* Make sure you're pull request is made for develop branch (or relevant feature branch)
* Have you tested your PR? If not, why?
* Are there any limitations of your PR we should know of?
* Make sure to keep you're PR up-to-date with the branch you're trying to push into.
**If we don't get enough info, the chance of the issue getting closed is a lot bigger ;)**
+3
View File
@@ -11,6 +11,9 @@ import sys
log = CPLog(__name__) log = CPLog(__name__)
def fnEscape(pattern):
return pattern.replace('[','[[').replace(']','[]]').replace('[[','[[]')
def link(src, dst): def link(src, dst):
if os.name == 'nt': if os.name == 'nt':
import ctypes import ctypes
@@ -46,6 +46,14 @@ config = [{
'advanced': True, 'advanced': True,
'description': 'Only scan new movie folder at remote XBMC servers. Works if movie location is the same.', 'description': 'Only scan new movie folder at remote XBMC servers. Works if movie location is the same.',
}, },
{
'name': 'force_full_scan',
'label': 'Always do a full scan',
'default': 0,
'type': 'bool',
'advanced': True,
'description': 'Do a full scan instead of only the new movie. Useful if the XBMC path is different from the path CPS uses.',
},
{ {
'name': 'on_snatch', 'name': 'on_snatch',
'default': 0, 'default': 0,
+1 -1
View File
@@ -36,7 +36,7 @@ class XBMC(Notification):
if data and data.get('destination_dir') and (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):
param = {} param = {}
if self.conf('remote_dir_scan') or socket.getfqdn('localhost') == socket.getfqdn(host.split(':')[0]): if not self.conf('force_full_scan') and (self.conf('remote_dir_scan') or socket.getfqdn('localhost') == socket.getfqdn(host.split(':')[0])):
param = {'directory': data['destination_dir']} param = {'directory': data['destination_dir']}
calls.append(('VideoLibrary.Scan', param)) calls.append(('VideoLibrary.Scan', param))
+3 -3
View File
@@ -3,7 +3,7 @@ from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEvent, fireEventAsync from couchpotato.core.event import addEvent, fireEvent, fireEventAsync
from couchpotato.core.helpers.encoding import toUnicode, ss, sp from couchpotato.core.helpers.encoding import toUnicode, ss, sp
from couchpotato.core.helpers.variable import getExt, mergeDicts, getTitle, \ from couchpotato.core.helpers.variable import getExt, mergeDicts, getTitle, \
getImdb, link, symlink, tryInt, splitString getImdb, link, symlink, tryInt, splitString, fnEscape
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
from couchpotato.core.settings.model import Library, File, Profile, Release, \ from couchpotato.core.settings.model import Library, File, Profile, Release, \
@@ -644,7 +644,7 @@ Remove it if you want it to be renamed (again, or at least let it try again)
# Match all found ignore files with the tag_files and delete if found # Match all found ignore files with the tag_files and delete if found
for tag_file in tag_files: for tag_file in tag_files:
ignore_file = fnmatch.filter(ignore_files, '%s.%s.ignore' % (re.escape(os.path.splitext(tag_file)[0]), tag if tag else '*')) ignore_file = fnmatch.filter(ignore_files, fnEscape('%s.%s.ignore' % (os.path.splitext(tag_file)[0], tag if tag else '*')))
for filename in ignore_file: for filename in ignore_file:
try: try:
os.remove(filename) os.remove(filename)
@@ -677,7 +677,7 @@ Remove it if you want it to be renamed (again, or at least let it try again)
# Match all found ignore files with the tag_files and return True found # Match all found ignore files with the tag_files and return True found
for tag_file in tag_files: for tag_file in tag_files:
ignore_file = fnmatch.filter(ignore_files, '%s.%s.ignore' % (os.path.splitext(tag_file)[0], tag if tag else '*')) ignore_file = fnmatch.filter(ignore_files, fnEscape('%s.%s.ignore' % (os.path.splitext(tag_file)[0], tag if tag else '*')))
if ignore_file: if ignore_file:
return True return True
+1 -1
View File
@@ -454,7 +454,7 @@ class Scanner(Plugin):
data['resolution_width'] = meta.get('resolution_width', 720) data['resolution_width'] = meta.get('resolution_width', 720)
data['resolution_height'] = meta.get('resolution_height', 480) data['resolution_height'] = meta.get('resolution_height', 480)
data['audio_channels'] = meta.get('audio_channels', 2.0) data['audio_channels'] = meta.get('audio_channels', 2.0)
data['aspect'] = meta.get('resolution_width', 720) / meta.get('resolution_height', 480) data['aspect'] = round(float(meta.get('resolution_width', 720)) / meta.get('resolution_height', 480), 2)
except: except:
log.debug('Error parsing metadata: %s %s', (cur_file, traceback.format_exc())) log.debug('Error parsing metadata: %s %s', (cur_file, traceback.format_exc()))
pass pass
@@ -84,6 +84,10 @@ class OMDBAPI(MovieProvider):
year = tryInt(movie.get('Year', '')) year = tryInt(movie.get('Year', ''))
actors = {}
for actor in splitString(movie.get('Actors', '')):
actors[actor] = '' #omdb does not return actor roles
movie_data = { movie_data = {
'type': 'movie', 'type': 'movie',
'via_imdb': True, 'via_imdb': True,
@@ -105,7 +109,7 @@ class OMDBAPI(MovieProvider):
'genres': splitString(movie.get('Genre', '')), 'genres': splitString(movie.get('Genre', '')),
'directors': splitString(movie.get('Director', '')), 'directors': splitString(movie.get('Director', '')),
'writers': splitString(movie.get('Writer', '')), 'writers': splitString(movie.get('Writer', '')),
'actors': splitString(movie.get('Actors', '')), 'actor_roles': actors,
} }
movie_data = dict((k, v) for k, v in movie_data.iteritems() if v) movie_data = dict((k, v) for k, v in movie_data.iteritems() if v)
except: except:
@@ -92,6 +92,13 @@ class TheMovieDb(MovieProvider):
poster_original = self.getImage(movie, type = 'poster', size = 'original') poster_original = self.getImage(movie, type = 'poster', size = 'original')
backdrop_original = self.getImage(movie, type = 'backdrop', size = 'original') backdrop_original = self.getImage(movie, type = 'backdrop', size = 'original')
images = {
'poster': [poster] if poster else [],
#'backdrop': [backdrop] if backdrop else [],
'poster_original': [poster_original] if poster_original else [],
'backdrop_original': [backdrop_original] if backdrop_original else [],
}
# Genres # Genres
try: try:
genres = [genre.name for genre in movie.genres] genres = [genre.name for genre in movie.genres]
@@ -103,18 +110,22 @@ class TheMovieDb(MovieProvider):
if not movie.releasedate or year == '1900' or year.lower() == 'none': if not movie.releasedate or year == '1900' or year.lower() == 'none':
year = None year = None
# Gather actors data
actors = {}
for cast_item in movie.cast:
try:
actors[toUnicode(cast_item.name)] = toUnicode(cast_item.character)
images['actor %s' % toUnicode(cast_item.name)] = self.getImage(cast_item, type = 'profile', size = 'original')
except:
log.debug('Error getting cast info for %s: %s', (cast_item, traceback.format_exc()))
movie_data = { movie_data = {
'type': 'movie', 'type': 'movie',
'via_tmdb': True, 'via_tmdb': True,
'tmdb_id': movie.id, 'tmdb_id': movie.id,
'titles': [toUnicode(movie.title)], 'titles': [toUnicode(movie.title)],
'original_title': movie.originaltitle, 'original_title': movie.originaltitle,
'images': { 'images': images,
'poster': [poster] if poster else [],
#'backdrop': [backdrop] if backdrop else [],
'poster_original': [poster_original] if poster_original else [],
'backdrop_original': [backdrop_original] if backdrop_original else [],
},
'imdb': movie.imdb, 'imdb': movie.imdb,
'runtime': movie.runtime, 'runtime': movie.runtime,
'released': str(movie.releasedate), 'released': str(movie.releasedate),
@@ -122,6 +133,7 @@ class TheMovieDb(MovieProvider):
'plot': movie.overview, 'plot': movie.overview,
'genres': genres, 'genres': genres,
'collection': getattr(movie.collection, 'name', None), 'collection': getattr(movie.collection, 'name', None),
'actor_roles': actors
} }
movie_data = dict((k, v) for k, v in movie_data.iteritems() if v) movie_data = dict((k, v) for k, v in movie_data.iteritems() if v)
@@ -145,7 +157,7 @@ class TheMovieDb(MovieProvider):
try: try:
image_url = getattr(movie, type).geturl(size = 'original') image_url = getattr(movie, type).geturl(size = 'original')
except: except:
log.debug('Failed getting %s.%s for "%s"', (type, size, movie.title)) log.debug('Failed getting %s.%s for "%s"', (type, size, movie))
return image_url return image_url
@@ -65,7 +65,7 @@ class XBMC(MetaDataBase):
name = type name = type
try: try:
if data['library'].get(type): if movie_info.get(type):
el = SubElement(nfoxml, name) el = SubElement(nfoxml, name)
el.text = toUnicode(movie_info.get(type, '')) el.text = toUnicode(movie_info.get(type, ''))
except: except:
@@ -89,10 +89,18 @@ class XBMC(MetaDataBase):
genres.text = toUnicode(genre) genres.text = toUnicode(genre)
# Actors # Actors
for actor in movie_info.get('actors', []): for actor_name in movie_info.get('actor_roles', {}):
actors = SubElement(nfoxml, 'actor') role_name = movie_info['actor_roles'][actor_name]
name = SubElement(actors, 'name')
name.text = toUnicode(actor) actor = SubElement(nfoxml, 'actor')
name = SubElement(actor, 'name')
name.text = toUnicode(actor_name)
if role_name:
role = SubElement(actor, 'role')
role.text = toUnicode(role_name)
if movie_info['images'].get('actor %s' % actor_name, ''):
thumb = SubElement(actor, 'thumb')
thumb.text = toUnicode(movie_info['images'].get('actor %s' % actor_name))
# Directors # Directors
for director_name in movie_info.get('directors', []): for director_name in movie_info.get('directors', []):
@@ -112,6 +120,51 @@ class XBMC(MetaDataBase):
sorttitle = SubElement(nfoxml, 'sorttitle') sorttitle = SubElement(nfoxml, 'sorttitle')
sorttitle.text = '%s %s' % (toUnicode(collection_name), movie_info.get('year')) sorttitle.text = '%s %s' % (toUnicode(collection_name), movie_info.get('year'))
# Images
for image_url in movie_info['images']['poster_original']:
image = SubElement(nfoxml, 'thumb')
image.text = toUnicode(image_url)
fanart = SubElement(nfoxml, 'fanart')
for image_url in movie_info['images']['backdrop_original']:
image = SubElement(fanart, 'thumb')
image.text = toUnicode(image_url)
# Add trailer if found
trailer_found = False
if data.get('renamed_files'):
for filename in data.get('renamed_files'):
if 'trailer' in filename:
trailer = SubElement(nfoxml, 'trailer')
trailer.text = toUnicode(filename)
trailer_found = True
if not trailer_found and data['files'].get('trailer'):
trailer = SubElement(nfoxml, 'trailer')
trailer.text = toUnicode(data['files']['trailer'][0])
# Add file metadata
fileinfo = SubElement(nfoxml, 'fileinfo')
streamdetails = SubElement(fileinfo, 'streamdetails')
# Video data
if data['meta_data'].get('video'):
video = SubElement(streamdetails, 'video')
codec = SubElement(video, 'codec')
codec.text = toUnicode(data['meta_data']['video'])
aspect = SubElement(video, 'aspect')
aspect.text = str(data['meta_data']['aspect'])
width = SubElement(video, 'width')
width.text = str(data['meta_data']['resolution_width'])
height = SubElement(video, 'height')
height.text = str(data['meta_data']['resolution_height'])
# Audio data
if data['meta_data'].get('audio'):
audio = SubElement(streamdetails, 'audio')
codec = SubElement(audio, 'codec')
codec.text = toUnicode(data['meta_data'].get('audio'))
channels = SubElement(audio, 'channels')
channels.text = toUnicode(data['meta_data'].get('audio_channels'))
# Clean up the xml and return it # Clean up the xml and return it
nfoxml = xml.dom.minidom.parseString(tostring(nfoxml)) nfoxml = xml.dom.minidom.parseString(tostring(nfoxml))
xml_string = nfoxml.toprettyxml(indent = ' ') xml_string = nfoxml.toprettyxml(indent = ' ')
+10 -1
View File
@@ -12,6 +12,7 @@ from urllib2 import HTTPError
from urlparse import urlparse from urlparse import urlparse
import time import time
import traceback import traceback
import urllib2
log = CPLog(__name__) log = CPLog(__name__)
@@ -161,7 +162,15 @@ class Base(NZBProvider, RSS):
return 'try_next' return 'try_next'
try: try:
data = self.urlopen(url, show_error = False) # Get final redirected url
log.debug('Checking %s for redirects.', url)
req = urllib2.Request(url)
res = urllib2.urlopen(req)
finalurl = res.geturl()
if finalurl != url:
log.debug('Redirect url used: %s', finalurl)
data = self.urlopen(finalurl, show_error = False)
self.limits_reached[host] = False self.limits_reached[host] = False
return data return data
except HTTPError, e: except HTTPError, e: