Merge branch 'refs/heads/develop'

This commit is contained in:
Ruud
2013-04-14 11:09:32 +02:00
10 changed files with 89 additions and 57 deletions
+4 -9
View File
@@ -11,16 +11,12 @@ api_nonblock = {}
class NonBlockHandler(RequestHandler): class NonBlockHandler(RequestHandler):
def __init__(self, application, request, **kwargs): stoppers = []
cls = NonBlockHandler
cls.stoppers = []
super(NonBlockHandler, self).__init__(application, request, **kwargs)
@asynchronous @asynchronous
def get(self, route): def get(self, route):
cls = NonBlockHandler
start, stop = api_nonblock[route] start, stop = api_nonblock[route]
cls.stoppers.append(stop) self.stoppers.append(stop)
start(self.onNewMessage, last_id = self.get_argument("last_id", None)) start(self.onNewMessage, last_id = self.get_argument("last_id", None))
@@ -30,12 +26,11 @@ class NonBlockHandler(RequestHandler):
self.finish(response) self.finish(response)
def on_connection_close(self): def on_connection_close(self):
cls = NonBlockHandler
for stop in cls.stoppers: for stop in self.stoppers:
stop(self.onNewMessage) stop(self.onNewMessage)
cls.stoppers = [] self.stoppers = []
def addApiView(route, func, static = False, docs = None, **kwargs): def addApiView(route, func, static = False, docs = None, **kwargs):
+1 -3
View File
@@ -52,9 +52,7 @@ class NZBGet(Downloader):
if xml_response: if xml_response:
log.info('NZB sent successfully to NZBGet') log.info('NZB sent successfully to NZBGet')
groups = rpc.listgroups() return True
nzb_id = [item['NZBID'] for item in groups if item['NZBFilename'] == nzb_name][0]
return self.downloadReturnId(nzb_id)
else: else:
log.error('NZBGet could not add %s to the queue.', nzb_name) log.error('NZBGet could not add %s to the queue.', nzb_name)
return False return False
+32 -4
View File
@@ -6,6 +6,7 @@ var MovieList = new Class({
navigation: true, navigation: true,
limit: 50, limit: 50,
load_more: true, load_more: true,
loader: true,
menu: [], menu: [],
add_new: false add_new: false
}, },
@@ -251,7 +252,7 @@ var MovieList = new Class({
'data': Object.merge({ 'data': Object.merge({
'status': self.options.status 'status': self.options.status
}, self.filter), }, self.filter),
'onComplete': function(json){ 'onSuccess': function(json){
json.chars.split('').each(function(c){ json.chars.split('').each(function(c){
self.letters[c.capitalize()].addClass('available') self.letters[c.capitalize()].addClass('available')
@@ -475,12 +476,39 @@ var MovieList = new Class({
self.load_more.set('text', 'loading...'); self.load_more.set('text', 'loading...');
} }
if(self.movies.length == 0 && self.options.loader){
self.loader_first = new Element('div.loading').adopt(
new Element('div.message', {'text': self.options.title ? 'Loading \'' + self.options.title + '\'' : 'Loading...'})
).inject(self.el, 'top');
createSpinner(self.loader_first, {
radius: 4,
length: 4,
width: 1
});
self.el.setStyle('min-height', 93);
}
Api.request(self.options.api_call || 'movie.list', { Api.request(self.options.api_call || 'movie.list', {
'data': Object.merge({ 'data': Object.merge({
'status': self.options.status, 'status': self.options.status,
'limit_offset': self.options.limit + ',' + self.offset 'limit_offset': self.options.limit + ',' + self.offset
}, self.filter), }, self.filter),
'onComplete': function(json){ 'onSuccess': function(json){
if(self.loader_first){
var lf = self.loader_first;
self.loader_first.addClass('hide')
self.loader_first = null;
setTimeout(function(){
lf.destroy();
}, 20000);
self.el.setStyle('min-height', null);
}
self.store(json.movies); self.store(json.movies);
self.addMovies(json.movies, json.total); self.addMovies(json.movies, json.total);
if(self.scrollspy) { if(self.scrollspy) {
@@ -488,7 +516,7 @@ var MovieList = new Class({
self.scrollspy.start(); self.scrollspy.start();
} }
self.checkIfEmpty() self.checkIfEmpty();
} }
}); });
}, },
@@ -518,7 +546,7 @@ var MovieList = new Class({
self.description[is_empty ? 'hide' : 'show']() self.description[is_empty ? 'hide' : 'show']()
if(is_empty && self.options.on_empty_element){ if(is_empty && self.options.on_empty_element){
self.el.grab(self.options.on_empty_element); self.options.on_empty_element.inject(self.loader_first || self.title || self.movie_list, 'after');
if(self.navigation) if(self.navigation)
self.navigation.hide(); self.navigation.hide();
@@ -4,7 +4,33 @@
z-index: 3; z-index: 3;
} }
.movies h2 { .movies .loading {
display: block;
padding: 20px 0 0 0;
width: 100%;
z-index: 3;
transition: all .4s cubic-bezier(0.9,0,0.1,1);
height: 40px;
opacity: 1;
position: absolute;
text-align: center;
}
.movies .loading.hide {
height: 0;
padding: 20px 0 0 0;
opacity: 0;
margin-top: -20px;
}
.movies .loading .spinner {
display: inline-block;
}
.movies .loading .message {
margin: 0 20px;
}
.movies > h2 {
margin-bottom: 20px; margin-bottom: 20px;
} }
@@ -27,6 +53,7 @@
.home .movies { .home .movies {
padding-top: 6px; padding-top: 6px;
} }
.movies.mass_edit_list { .movies.mass_edit_list {
padding-top: 90px; padding-top: 90px;
+1 -1
View File
@@ -117,7 +117,7 @@ config = [{
'label': 'File Action', 'label': 'File Action',
'default': 'move', 'default': 'move',
'type': 'dropdown', 'type': 'dropdown',
'values': [('Move', 'move'), ('Copy', 'copy'), ('Hard link', 'hardlink'), ('Sym link', 'symlink')], 'values': [('Move', 'move'), ('Copy', 'copy'), ('Hard link', 'hardlink'), ('Sym link', 'symlink'), ('Move & Sym link', 'move_symlink')],
'description': 'Define which kind of file operation you want to use. Before you start using <a href="http://en.wikipedia.org/wiki/Hard_link">hard links</a> or <a href="http://en.wikipedia.org/wiki/Sym_link">sym links</a>, PLEASE read about their possible drawbacks.', 'description': 'Define which kind of file operation you want to use. Before you start using <a href="http://en.wikipedia.org/wiki/Hard_link">hard links</a> or <a href="http://en.wikipedia.org/wiki/Sym_link">sym links</a>, PLEASE read about their possible drawbacks.',
'advanced': True, 'advanced': True,
}, },
+8 -4
View File
@@ -10,8 +10,8 @@ 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, \
ReleaseInfo ReleaseInfo
from couchpotato.environment import Env from couchpotato.environment import Env
from linktastic.linktastic import link, symlink
import errno import errno
import linktastic.linktastic as linktastic
import os import os
import re import re
import shutil import shutil
@@ -89,7 +89,8 @@ class Renamer(Plugin):
# Check to see if the "to" folder is inside the "from" folder. # Check to see if the "to" folder is inside the "from" folder.
if movie_folder and not os.path.isdir(movie_folder) or not os.path.isdir(self.conf('from')) or not os.path.isdir(self.conf('to')): if movie_folder and not os.path.isdir(movie_folder) or not os.path.isdir(self.conf('from')) or not os.path.isdir(self.conf('to')):
log.error('"To" and "From" have to exist.') l = log.debug if movie_folder else log.error
l('Both the "To" and "From" have to exist.')
return return
elif self.conf('from') in self.conf('to'): elif self.conf('from') in self.conf('to'):
log.error('The "to" can\'t be inside of the "from" folder. You\'ll get an infinite loop.') log.error('The "to" can\'t be inside of the "from" folder. You\'ll get an infinite loop.')
@@ -521,11 +522,14 @@ Remove it if you want it to be renamed (again, or at least let it try again)
dest = ss(dest) dest = ss(dest)
try: try:
if self.conf('file_action') == 'hardlink': if self.conf('file_action') == 'hardlink':
linktastic.link(old, dest) link(old, dest)
elif self.conf('file_action') == 'symlink': elif self.conf('file_action') == 'symlink':
linktastic.symlink(old, dest) symlink(old, dest)
elif self.conf('file_action') == 'copy': elif self.conf('file_action') == 'copy':
shutil.copy(old, dest) shutil.copy(old, dest)
elif self.conf('file_action') == 'move_symlink':
shutil.move(old, dest)
symlink(dest, old)
else: else:
shutil.move(old, dest) shutil.move(old, dest)
+1
View File
@@ -104,6 +104,7 @@ class YarrProvider(Provider):
try: try:
cookiejar = cookielib.CookieJar() cookiejar = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar)) opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar))
opener.addheaders = []
urllib2.install_opener(opener) urllib2.install_opener(opener)
log.info2('Logging into %s', self.urls['login']) log.info2('Logging into %s', self.urls['login'])
f = opener.open(self.urls['login'], self.getLoginParams()) f = opener.open(self.urls['login'], self.getLoginParams())
+14 -3
View File
@@ -25,7 +25,18 @@ Page.Home = new Class({
'view': 'list', 'view': 'list',
'actions': [MA.IMDB, MA.Trailer, MA.Release, MA.Refresh, MA.Delete], 'actions': [MA.IMDB, MA.Trailer, MA.Release, MA.Refresh, MA.Delete],
'title': 'Snatched & Available', 'title': 'Snatched & Available',
'on_empty_element': new Element('div'), 'description': 'These movies have been snatched or have finished downloading',
'on_empty_element': new Element('div').adopt(
new Element('h2', {'text': 'Snatched & Available'}),
new Element('span', {
'html': 'No snatched movies or anything!? Damn.. <a>Maybe add a movie.</a>',
'events': {
'click': function(){
$(document.body).getElement('.search_form input').focus();
}
}
})
),
'filter': { 'filter': {
'release_status': 'snatched,available' 'release_status': 'snatched,available'
} }
@@ -39,7 +50,7 @@ Page.Home = new Class({
'title': 'Available soon', 'title': 'Available soon',
'description': 'These are being searched for and should be available soon as they will be released on DVD in the next few weeks.', 'description': 'These are being searched for and should be available soon as they will be released on DVD in the next few weeks.',
'on_empty_element': new Element('div').adopt( 'on_empty_element': new Element('div').adopt(
new Element('h1', {'text': 'Available soon'}), new Element('h2', {'text': 'Available soon'}),
new Element('span', {'text': 'There are no movies available soon. Add some movies, so you have something to watch later.'}) new Element('span', {'text': 'There are no movies available soon. Add some movies, so you have something to watch later.'})
), ),
'filter': { 'filter': {
@@ -58,10 +69,10 @@ Page.Home = new Class({
'limit': 50, 'limit': 50,
'title': 'Still not available', 'title': 'Still not available',
'description': 'Try another quality profile or maybe add more providers in <a href="'+App.createUrl('settings/searcher/providers/')+'">Settings</a>.', 'description': 'Try another quality profile or maybe add more providers in <a href="'+App.createUrl('settings/searcher/providers/')+'">Settings</a>.',
'on_empty_element': new Element('div'),
'filter': { 'filter': {
'late': true 'late': true
}, },
'loader': false,
'load_more': false, 'load_more': false,
'view': 'list', 'view': 'list',
'actions': [MA.IMDB, MA.Trailer, MA.Edit, MA.Refresh, MA.Delete], 'actions': [MA.IMDB, MA.Trailer, MA.Edit, MA.Refresh, MA.Delete],
-19
View File
@@ -1,19 +0,0 @@
Linktastic
Linktastic is an extension of the os.link and os.symlink functionality provided
by the python language since version 2. Python only supports file linking on
*NIX-based systems, even though it is relatively simple to engineer a solution
to utilize NTFS's built-in linking functionality. Linktastic attempts to unify
linking on the windows platform with linking on *NIX-based systems.
Usage
Linktastic is a single python module and can be imported as such. Examples:
# Hard linking src to dest
import linktastic
linktastic.link(src, dest)
# Symlinking src to dest
import linktastic
linktastic.symlink(src, dest)
-13
View File
@@ -1,13 +0,0 @@
from distutils.core import setup
setup(
name='Linktastic',
version='0.1.0',
author='Jon "Berkona" Monroe',
author_email='solipsis.dev@gmail.com',
py_modules=['linktastic'],
url="http://github.com/berkona/linktastic",
license='MIT License - See http://opensource.org/licenses/MIT for details',
description='Truly platform-independent file linking',
long_description=open('README.txt').read(),
)