Merge remote-tracking branch 'remotes/origin/develop' into tv
This commit is contained in:
+19
-9
@@ -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 ;)**
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,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
|
||||||
|
|
||||||
|
|||||||
@@ -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 = ' ')
|
||||||
|
|||||||
@@ -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:
|
||||||
@@ -217,4 +226,4 @@ class Episode(EpisodeProvider, Base):
|
|||||||
'apikey': api_key,
|
'apikey': api_key,
|
||||||
'extended': 1
|
'extended': 1
|
||||||
})
|
})
|
||||||
return query
|
return query
|
||||||
|
|||||||
Reference in New Issue
Block a user