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. 35
      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.core.event import fireEvent, fireEventAsync, addEvent
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import getImdb, splitString, tryInt, \
mergeDicts
from couchpotato.core.helpers.variable import splitString, tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.media.movie import MovieTypeBase
from couchpotato.core.settings.model import Library, LibraryTitle, Media, \
Release
from sqlalchemy.orm import joinedload_all
from sqlalchemy.sql.expression import or_, asc, not_, desc
from string import ascii_lowercase
from couchpotato.core.settings.model import Media
import time
import os
log = CPLog(__name__)
@ -27,28 +21,6 @@ class MovieBase(MovieTypeBase):
super(MovieBase, self).__init__()
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 = {
'desc': 'Add new movie to the wanted list',
'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.'},
}
})
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.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):
if not params: params = {}
@ -451,145 +175,10 @@ class MovieBase(MovieTypeBase):
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))
db.expire_all()
return {
'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

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

@ -431,7 +431,7 @@ MA.Release = new Class({
markMovieDone: function(){
var self = this;
Api.request('movie.delete', {
Api.request('media.delete', {
'data': {
'id': self.movie.get('id'),
'delete_from': 'wanted'
@ -450,7 +450,7 @@ MA.Release = new Class({
},
tryNextRelease: function(movie_id){
tryNextRelease: function(){
var self = this;
Api.request('movie.searcher.try_next', {
@ -792,27 +792,10 @@ MA.Delete = new Class({
new Element('a.button.delete', {
'text': 'Delete ' + self.movie.title.get('text'),
'events': {
'click': self.del.bind(self, false)
'click': self.del.bind(self)
}
})
);
/* 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');
).inject(self.movie, 'top');
}
self.movie.slide('in', self.delete_container);
@ -827,7 +810,7 @@ MA.Delete = new Class({
self.movie.slide('out');
},
del: function(withFiles, e){
del: function(e){
(e).preventDefault();
var self = this;
@ -838,11 +821,10 @@ MA.Delete = new Class({
self.callChain();
},
function(){
Api.request('movie.delete', {
Api.request('media.delete', {
'data': {
'id': self.movie.get('id'),
'delete_from': self.movie.list.options.identifier,
'with_files': !!withFiles
'delete_from': self.movie.list.options.identifier
},
'onComplete': function(){
movie.set('tween', {
@ -858,6 +840,7 @@ MA.Delete = new Class({
);
self.callChain();
}
});
@ -941,4 +924,4 @@ MA.Files = new Class({
self.movie.slide('in', self.options_container);
},
});
});

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

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

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

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

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

@ -1,8 +1,8 @@
from couchpotato.core.helpers.variable import tryInt
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.info.base import MovieProvider
from couchpotato.core.providers.torrent.base import TorrentProvider
import traceback
log = CPLog(__name__)
@ -12,22 +12,15 @@ class Yify(MultiProvider):
def getTypes(self):
return [Movie]
class Base(TorrentMagnetProvider):
class Base(TorrentProvider):
urls = {
'test' : '%s/api',
'search' : '%s/api/list.json?keywords=%s&quality=%s',
'detail': '%s/api/movie.json?id=%s'
'test' : 'https://yify-torrents.com/api',
'search' : 'https://yify-torrents.com/api/list.json?keywords=%s&quality=%s',
'detail': 'https://yify-torrents.com/api/movie.json?id=%s'
}
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):
@ -38,9 +31,7 @@ class Base(TorrentMagnetProvider):
def _search(self, movie, quality, results):
search_url = self.urls['search'] % (self.getDomain(), movie['library']['identifier'], quality['identifier'])
data = self.getJsonData(search_url)
data = self.getJsonData(self.urls['search'] % (movie['library']['identifier'], quality['identifier']))
if data and data.get('MovieList'):
try:
@ -56,8 +47,8 @@ class Base(TorrentMagnetProvider):
results.append({
'id': result['MovieID'],
'name': title,
'url': result['TorrentMagnetUrl'],
'detail_url': self.urls['detail'] % (self.getDomain(),result['MovieID']),
'url': result['TorrentUrl'],
'detail_url': self.urls['detail'] % result['MovieID'],
'size': self.parseSize(result['Size']),
'seeders': tryInt(result['TorrentSeeds']),
'leechers': tryInt(result['TorrentPeers'])
@ -66,8 +57,5 @@ class Base(TorrentMagnetProvider):
except:
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):
pass
Loading…
Cancel
Save