Browse Source

Revert "Merge branches 'develop' and 'tv' of https://github.com/RuudBurger/CouchPotatoServer into tv"

This reverts commit b8bce948c8, reversing
changes made to 0a996857dd.
pull/2634/head
Joel Kåberg 12 years ago
parent
commit
f2fc775963
  1. 417
      couchpotato/core/media/movie/_base/main.py
  2. 33
      couchpotato/core/media/movie/_base/static/movie.actions.js
  3. 4
      couchpotato/core/plugins/score/main.py
  4. 6
      couchpotato/core/providers/torrent/yify/__init__.py
  5. 28
      couchpotato/core/providers/torrent/yify/main.py

417
couchpotato/core/media/movie/_base/main.py

@ -2,17 +2,11 @@ from couchpotato import get_session
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, fireEventAsync, addEvent from couchpotato.core.event import fireEvent, fireEventAsync, addEvent
from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import getImdb, splitString, tryInt, \ from couchpotato.core.helpers.variable import splitString, tryInt
mergeDicts
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.media.movie import MovieTypeBase from couchpotato.core.media.movie import MovieTypeBase
from couchpotato.core.settings.model import Library, LibraryTitle, Media, \ from couchpotato.core.settings.model import Media
Release
from sqlalchemy.orm import joinedload_all
from sqlalchemy.sql.expression import or_, asc, not_, desc
from string import ascii_lowercase
import time import time
import os
log = CPLog(__name__) log = CPLog(__name__)
@ -27,28 +21,6 @@ class MovieBase(MovieTypeBase):
super(MovieBase, self).__init__() super(MovieBase, self).__init__()
self.initType() self.initType()
addApiView('movie.list', self.listView, docs = {
'desc': 'List movies in wanted list',
'params': {
'status': {'type': 'array or csv', 'desc': 'Filter movie by status. Example:"active,done"'},
'release_status': {'type': 'array or csv', 'desc': 'Filter movie by status of its releases. Example:"snatched,available"'},
'limit_offset': {'desc': 'Limit and offset the movie list. Examples: "50" or "50,30"'},
'starts_with': {'desc': 'Starts with these characters. Example: "a" returns all movies starting with the letter "a"'},
'search': {'desc': 'Search movie title'},
},
'return': {'type': 'object', 'example': """{
'success': True,
'empty': bool, any movies returned or not,
'movies': array, movies found,
}"""}
})
addApiView('movie.get', self.getView, docs = {
'desc': 'Get a movie by id',
'params': {
'id': {'desc': 'The id of the movie'},
}
})
addApiView('movie.available_chars', self.charView)
addApiView('movie.add', self.addView, docs = { addApiView('movie.add', self.addView, docs = {
'desc': 'Add new movie to the wanted list', 'desc': 'Add new movie to the wanted list',
'params': { 'params': {
@ -66,256 +38,8 @@ class MovieBase(MovieTypeBase):
'default_title': {'desc': 'Movie title to use for searches. Has to be one of the titles returned by movie.search.'}, 'default_title': {'desc': 'Movie title to use for searches. Has to be one of the titles returned by movie.search.'},
} }
}) })
addApiView('movie.delete', self.deleteView, docs = {
'desc': 'Delete a movie from the wanted list',
'params': {
'id': {'desc': 'Movie ID(s) you want to delete.', 'type': 'int (comma separated)'},
'delete_from': {'desc': 'Delete movie from this page', 'type': 'string: all (default), wanted, manage'},
'with_files': {'desc': 'Delete the files as well', 'type': 'bool (true or false)'},
}
})
addEvent('movie.add', self.add) addEvent('movie.add', self.add)
addEvent('movie.delete', self.delete)
addEvent('movie.get', self.get)
addEvent('movie.list', self.list)
addEvent('movie.restatus', self.restatus)
def getView(self, id = None, **kwargs):
movie = self.get(id) if id else None
return {
'success': movie is not None,
'movie': movie,
}
def get(self, movie_id):
db = get_session()
imdb_id = getImdb(str(movie_id))
if imdb_id:
m = db.query(Media).filter(Media.library.has(identifier = imdb_id)).first()
else:
m = db.query(Media).filter_by(id = movie_id).first()
results = None
if m:
results = m.to_dict(self.default_dict)
db.expire_all()
return results
def list(self, status = None, release_status = None, limit_offset = None, starts_with = None, search = None, order = None):
db = get_session()
# Make a list from string
if status and not isinstance(status, (list, tuple)):
status = [status]
if release_status and not isinstance(release_status, (list, tuple)):
release_status = [release_status]
# query movie ids
q = db.query(Media) \
.with_entities(Media.id) \
.group_by(Media.id)
# Filter on movie status
if status and len(status) > 0:
statuses = fireEvent('status.get', status, single = len(status) > 1)
statuses = [s.get('id') for s in statuses]
q = q.filter(Media.status_id.in_(statuses))
# Filter on release status
if release_status and len(release_status) > 0:
q = q.join(Media.releases)
statuses = fireEvent('status.get', release_status, single = len(release_status) > 1)
statuses = [s.get('id') for s in statuses]
q = q.filter(Release.status_id.in_(statuses))
# Only join when searching / ordering
if starts_with or search or order != 'release_order':
q = q.join(Media.library, Library.titles) \
.filter(LibraryTitle.default == True)
# Add search filters
filter_or = []
if starts_with:
starts_with = toUnicode(starts_with.lower())
if starts_with in ascii_lowercase:
filter_or.append(LibraryTitle.simple_title.startswith(starts_with))
else:
ignore = []
for letter in ascii_lowercase:
ignore.append(LibraryTitle.simple_title.startswith(toUnicode(letter)))
filter_or.append(not_(or_(*ignore)))
if search:
filter_or.append(LibraryTitle.simple_title.like('%%' + search + '%%'))
if len(filter_or) > 0:
q = q.filter(or_(*filter_or))
total_count = q.count()
if total_count == 0:
return 0, []
if order == 'release_order':
q = q.order_by(desc(Release.last_edit))
else:
q = q.order_by(asc(LibraryTitle.simple_title))
if limit_offset:
splt = splitString(limit_offset) if isinstance(limit_offset, (str, unicode)) else limit_offset
limit = splt[0]
offset = 0 if len(splt) is 1 else splt[1]
q = q.limit(limit).offset(offset)
# Get all movie_ids in sorted order
movie_ids = [m.id for m in q.all()]
# List release statuses
releases = db.query(Release) \
.filter(Release.movie_id.in_(movie_ids)) \
.all()
release_statuses = dict((m, set()) for m in movie_ids)
releases_count = dict((m, 0) for m in movie_ids)
for release in releases:
release_statuses[release.movie_id].add('%d,%d' % (release.status_id, release.quality_id))
releases_count[release.movie_id] += 1
# Get main movie data
q2 = db.query(Media) \
.options(joinedload_all('library.titles')) \
.options(joinedload_all('library.files')) \
.options(joinedload_all('status')) \
.options(joinedload_all('files'))
q2 = q2.filter(Media.id.in_(movie_ids))
results = q2.all()
# Create dict by movie id
movie_dict = {}
for movie in results:
movie_dict[movie.id] = movie
# List movies based on movie_ids order
movies = []
for movie_id in movie_ids:
releases = []
for r in release_statuses.get(movie_id):
x = splitString(r)
releases.append({'status_id': x[0], 'quality_id': x[1]})
# Merge releases with movie dict
movies.append(mergeDicts(movie_dict[movie_id].to_dict({
'library': {'titles': {}, 'files':{}},
'files': {},
}), {
'releases': releases,
'releases_count': releases_count.get(movie_id),
}))
db.expire_all()
return total_count, movies
def availableChars(self, status = None, release_status = None):
status = status or []
release_status = release_status or []
db = get_session()
# Make a list from string
if not isinstance(status, (list, tuple)):
status = [status]
if release_status and not isinstance(release_status, (list, tuple)):
release_status = [release_status]
q = db.query(Media)
# Filter on movie status
if status and len(status) > 0:
statuses = fireEvent('status.get', status, single = len(release_status) > 1)
statuses = [s.get('id') for s in statuses]
q = q.filter(Media.status_id.in_(statuses))
# Filter on release status
if release_status and len(release_status) > 0:
statuses = fireEvent('status.get', release_status, single = len(release_status) > 1)
statuses = [s.get('id') for s in statuses]
q = q.join(Media.releases) \
.filter(Release.status_id.in_(statuses))
q = q.join(Library, LibraryTitle) \
.with_entities(LibraryTitle.simple_title) \
.filter(LibraryTitle.default == True)
titles = q.all()
chars = set()
for title in titles:
try:
char = title[0][0]
char = char if char in ascii_lowercase else '#'
chars.add(str(char))
except:
log.error('Failed getting title for %s', title.libraries_id)
if len(chars) == 25:
break
db.expire_all()
return ''.join(sorted(chars))
def listView(self, **kwargs):
status = splitString(kwargs.get('status'))
release_status = splitString(kwargs.get('release_status'))
limit_offset = kwargs.get('limit_offset')
starts_with = kwargs.get('starts_with')
search = kwargs.get('search')
order = kwargs.get('order')
total_movies, movies = self.list(
status = status,
release_status = release_status,
limit_offset = limit_offset,
starts_with = starts_with,
search = search,
order = order
)
return {
'success': True,
'empty': len(movies) == 0,
'total': total_movies,
'movies': movies,
}
def charView(self, **kwargs):
status = splitString(kwargs.get('status', None))
release_status = splitString(kwargs.get('release_status', None))
chars = self.availableChars(status, release_status)
return {
'success': True,
'empty': len(chars) == 0,
'chars': chars,
}
def add(self, params = None, force_readd = True, search_after = True, update_library = False, status_id = None): def add(self, params = None, force_readd = True, search_after = True, update_library = False, status_id = None):
if not params: params = {} if not params: params = {}
@ -451,145 +175,10 @@ class MovieBase(MovieTypeBase):
fireEvent('media.restatus', m.id) fireEvent('media.restatus', m.id)
movie_dict = m.to_dict(self.default_dict) movie_dict = m.to_dict(self.search_dict)
fireEventAsync('movie.searcher.single', movie_dict, on_complete = self.createNotifyFront(media_id)) fireEventAsync('movie.searcher.single', movie_dict, on_complete = self.createNotifyFront(media_id))
db.expire_all() db.expire_all()
return { return {
'success': True, 'success': True,
} }
def deleteView(self, id = '', **kwargs):
ids = splitString(id)
for movie_id in ids:
self.delete(movie_id, delete_from = kwargs.get('delete_from', 'all'), with_files = kwargs.get('with_files'))
return {
'success': True,
}
def deleteFiles(self, instance):
directories = dict()
# Walk through all files in the Couch database
for file_ in instance.files:
# Add the directories and filename prefixes to a list so we can
# remove the directories and related files as well
directory = os.path.dirname(file_.path)
if directory not in directories:
directories[directory] = set()
directories[directory].add(os.path.splitext(file_.path)[0])
if os.path.isfile(file_.path):
try:
os.remove(file_.path)
log.info('Removed %s', file_.path)
except:
log.error('Unable to remove %s', file_.path)
# Walk through the directories and file prefixes for removal if
# possible
for directory, prefixes in directories.iteritems():
if os.path.isdir(directory):
# If the files in the directory have the same name as the
# expected files (except for extensions and stuff), remove them
files = os.listdir(directory)
for file_ in files:
for prefix in prefixes:
if file_.startswith(prefix):
try:
os.remove(file_)
print 'rmoeving', file_
log.info('Removed %s', file_)
except:
log.error('Unable to remove %s', file_)
try:
os.rmdir(directory)
log.info('Removed %s', directory)
except:
log.error('Unable to remove %s', directory)
def delete(self, movie_id, delete_from = None, with_files = False):
db = get_session()
movie = db.query(Media).filter_by(id = movie_id).first()
if movie:
if with_files:
self.deleteFiles(movie)
deleted = False
if delete_from == 'all':
db.delete(movie)
db.commit()
deleted = True
else:
done_status = fireEvent('status.get', 'done', single = True)
total_releases = len(movie.releases)
total_deleted = 0
new_movie_status = None
for release in movie.releases:
if with_files:
self.deleteFiles(release)
if delete_from in ['wanted', 'snatched', 'late']:
if release.status_id != done_status.get('id'):
db.delete(release)
total_deleted += 1
new_movie_status = 'done'
elif delete_from == 'manage':
if release.status_id == done_status.get('id'):
db.delete(release)
total_deleted += 1
new_movie_status = 'active'
db.commit()
if total_releases == total_deleted:
db.delete(movie)
db.commit()
deleted = True
elif new_movie_status:
new_status = fireEvent('status.get', new_movie_status, single = True)
movie.profile_id = None
movie.status_id = new_status.get('id')
db.commit()
else:
fireEvent('movie.restatus', movie.id, single = True)
if deleted:
fireEvent('notify.frontend', type = 'movie.deleted', data = movie.to_dict())
db.expire_all()
return True
def restatus(self, movie_id):
active_status, done_status = fireEvent('status.get', ['active', 'done'], single = True)
db = get_session()
m = db.query(Media).filter_by(id = movie_id).first()
if not m or len(m.library.titles) == 0:
log.debug('Can\'t restatus movie, doesn\'t seem to exist.')
return False
log.debug('Changing status for %s', m.library.titles[0].title)
if not m.profile:
m.status_id = done_status.get('id')
else:
move_to_wanted = True
for t in m.profile.types:
for release in m.releases:
if t.quality.identifier is release.quality.identifier and (release.status_id is done_status.get('id') and t.finish):
move_to_wanted = False
m.status_id = active_status.get('id') if move_to_wanted else done_status.get('id')
db.commit()
return True

33
couchpotato/core/media/movie/_base/static/movie.actions.js

@ -431,7 +431,7 @@ MA.Release = new Class({
markMovieDone: function(){ markMovieDone: function(){
var self = this; var self = this;
Api.request('movie.delete', { Api.request('media.delete', {
'data': { 'data': {
'id': self.movie.get('id'), 'id': self.movie.get('id'),
'delete_from': 'wanted' 'delete_from': 'wanted'
@ -450,7 +450,7 @@ MA.Release = new Class({
}, },
tryNextRelease: function(movie_id){ tryNextRelease: function(){
var self = this; var self = this;
Api.request('movie.searcher.try_next', { Api.request('movie.searcher.try_next', {
@ -792,27 +792,10 @@ MA.Delete = new Class({
new Element('a.button.delete', { new Element('a.button.delete', {
'text': 'Delete ' + self.movie.title.get('text'), 'text': 'Delete ' + self.movie.title.get('text'),
'events': { 'events': {
'click': self.del.bind(self, false) 'click': self.del.bind(self)
} }
}) })
); ).inject(self.movie, 'top');
/* Deleting files is only useful if it's already downloaded */
if(self.movie.list.options.identifier == 'manage'){
self.delete_container.adopt(
new Element('span', {
'text': ' '
}),
new Element('a.button.delete', {
'text': '+ Files',
'events': {
'click': self.del.bind(self, true)
}
})
);
}
self.delete_container.inject(self.movie, 'top');
} }
self.movie.slide('in', self.delete_container); self.movie.slide('in', self.delete_container);
@ -827,7 +810,7 @@ MA.Delete = new Class({
self.movie.slide('out'); self.movie.slide('out');
}, },
del: function(withFiles, e){ del: function(e){
(e).preventDefault(); (e).preventDefault();
var self = this; var self = this;
@ -838,11 +821,10 @@ MA.Delete = new Class({
self.callChain(); self.callChain();
}, },
function(){ function(){
Api.request('movie.delete', { Api.request('media.delete', {
'data': { 'data': {
'id': self.movie.get('id'), 'id': self.movie.get('id'),
'delete_from': self.movie.list.options.identifier, 'delete_from': self.movie.list.options.identifier
'with_files': !!withFiles
}, },
'onComplete': function(){ 'onComplete': function(){
movie.set('tween', { movie.set('tween', {
@ -858,6 +840,7 @@ MA.Delete = new Class({
); );
self.callChain(); self.callChain();
} }
}); });

4
couchpotato/core/plugins/score/main.py

@ -35,8 +35,8 @@ class Score(Plugin):
# Torrents only # Torrents only
if nzb.get('seeders'): if nzb.get('seeders'):
try: try:
score += nzb.get('seeders') * 100 / 15 score += nzb.get('seeders') / 5
score += nzb.get('leechers') * 100 / 30 score += nzb.get('leechers') / 10
except: except:
pass pass

6
couchpotato/core/providers/torrent/yify/__init__.py

@ -19,12 +19,6 @@ config = [{
'default': 0 'default': 0
}, },
{ {
'name': 'domain',
'advanced': True,
'label': 'Proxy server',
'description': 'Domain for requests, keep empty to let CouchPotato pick.',
},
{
'name': 'seed_ratio', 'name': 'seed_ratio',
'label': 'Seed ratio', 'label': 'Seed ratio',
'type': 'float', 'type': 'float',

28
couchpotato/core/providers/torrent/yify/main.py

@ -1,8 +1,8 @@
from couchpotato.core.helpers.variable import tryInt from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentMagnetProvider
from couchpotato.core.providers.base import MultiProvider from couchpotato.core.providers.base import MultiProvider
from couchpotato.core.providers.info.base import MovieProvider from couchpotato.core.providers.info.base import MovieProvider
from couchpotato.core.providers.torrent.base import TorrentProvider
import traceback import traceback
log = CPLog(__name__) log = CPLog(__name__)
@ -12,23 +12,16 @@ class Yify(MultiProvider):
def getTypes(self): def getTypes(self):
return [Movie] return [Movie]
class Base(TorrentMagnetProvider): class Base(TorrentProvider):
urls = { urls = {
'test' : '%s/api', 'test' : 'https://yify-torrents.com/api',
'search' : '%s/api/list.json?keywords=%s&quality=%s', 'search' : 'https://yify-torrents.com/api/list.json?keywords=%s&quality=%s',
'detail': '%s/api/movie.json?id=%s' 'detail': 'https://yify-torrents.com/api/movie.json?id=%s'
} }
http_time_between_calls = 1 #seconds http_time_between_calls = 1 #seconds
proxy_list = [
'https://yify-torrents.im',
'http://yify.unlocktorrent.com',
'http://yify.ftwnet.co.uk',
'http://yify-torrents.com.come.in',
]
def search(self, movie, quality): def search(self, movie, quality):
if not quality.get('hd', False): if not quality.get('hd', False):
@ -38,9 +31,7 @@ class Base(TorrentMagnetProvider):
def _search(self, movie, quality, results): def _search(self, movie, quality, results):
search_url = self.urls['search'] % (self.getDomain(), movie['library']['identifier'], quality['identifier']) data = self.getJsonData(self.urls['search'] % (movie['library']['identifier'], quality['identifier']))
data = self.getJsonData(search_url)
if data and data.get('MovieList'): if data and data.get('MovieList'):
try: try:
@ -56,8 +47,8 @@ class Base(TorrentMagnetProvider):
results.append({ results.append({
'id': result['MovieID'], 'id': result['MovieID'],
'name': title, 'name': title,
'url': result['TorrentMagnetUrl'], 'url': result['TorrentUrl'],
'detail_url': self.urls['detail'] % (self.getDomain(),result['MovieID']), 'detail_url': self.urls['detail'] % result['MovieID'],
'size': self.parseSize(result['Size']), 'size': self.parseSize(result['Size']),
'seeders': tryInt(result['TorrentSeeds']), 'seeders': tryInt(result['TorrentSeeds']),
'leechers': tryInt(result['TorrentPeers']) 'leechers': tryInt(result['TorrentPeers'])
@ -66,8 +57,5 @@ class Base(TorrentMagnetProvider):
except: except:
log.error('Failed getting results from %s: %s', (self.getName(), traceback.format_exc())) log.error('Failed getting results from %s: %s', (self.getName(), traceback.format_exc()))
def correctProxy(self, data):
return 'title="YIFY-Torrents RSS feed"' in data
class Movie(MovieProvider, Base): class Movie(MovieProvider, Base):
pass pass
Loading…
Cancel
Save