Merge branch 'refs/heads/develop'
This commit is contained in:
+4
-9
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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],
|
||||||
|
|||||||
@@ -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)
|
|
||||||
@@ -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(),
|
|
||||||
)
|
|
||||||
Reference in New Issue
Block a user