Merge branch 'refs/heads/develop'
This commit is contained in:
@@ -78,6 +78,7 @@ def page_not_found(error):
|
|||||||
r = '%s%s' % (request.url.rstrip('/'), index_url + '#' + url)
|
r = '%s%s' % (request.url.rstrip('/'), index_url + '#' + url)
|
||||||
return redirect(r)
|
return redirect(r)
|
||||||
else:
|
else:
|
||||||
time.sleep(0.1)
|
if not Env.get('dev'):
|
||||||
|
time.sleep(0.1)
|
||||||
return 'Wrong API key used', 404
|
return 'Wrong API key used', 404
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ def fireEvent(name, *args, **kwargs):
|
|||||||
|
|
||||||
# Merge
|
# Merge
|
||||||
if options['merge'] and len(results) > 0:
|
if options['merge'] and len(results) > 0:
|
||||||
|
results.reverse() # Priority 1 is higher then 100
|
||||||
|
|
||||||
# Dict
|
# Dict
|
||||||
if isinstance(results[0], dict):
|
if isinstance(results[0], dict):
|
||||||
merged = {}
|
merged = {}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
from migrate.changeset.schema import create_column
|
||||||
|
from sqlalchemy.schema import MetaData, Column, Table, Index
|
||||||
|
from sqlalchemy.types import Integer
|
||||||
|
|
||||||
|
meta = MetaData()
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(migrate_engine):
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
|
||||||
|
# Change release, add last_edit and index
|
||||||
|
last_edit_column = Column('last_edit', Integer)
|
||||||
|
release = Table('release', meta, last_edit_column)
|
||||||
|
|
||||||
|
create_column(last_edit_column, release)
|
||||||
|
Index('ix_release_last_edit', release.c.last_edit).create()
|
||||||
|
|
||||||
|
# Change movie last_edit
|
||||||
|
last_edit_column = Column('last_edit', Integer)
|
||||||
|
movie = Table('movie', meta, last_edit_column)
|
||||||
|
Index('ix_movie_last_edit', movie.c.last_edit).create()
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(migrate_engine):
|
||||||
|
pass
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
from couchpotato.core.helpers.encoding import toUnicode
|
from couchpotato.core.helpers.encoding import toUnicode
|
||||||
|
from couchpotato.core.helpers.variable import splitString
|
||||||
from couchpotato.core.logger import CPLog
|
from couchpotato.core.logger import CPLog
|
||||||
from couchpotato.core.notifications.base import Notification
|
from couchpotato.core.notifications.base import Notification
|
||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
@@ -39,7 +40,7 @@ class Email(Notification):
|
|||||||
|
|
||||||
# Send the e-mail
|
# Send the e-mail
|
||||||
log.debug("Sending the email")
|
log.debug("Sending the email")
|
||||||
mailserver.sendmail(from_address, to_address, message.as_string())
|
mailserver.sendmail(from_address, splitString(to_address), message.as_string())
|
||||||
|
|
||||||
# Close the SMTP connection
|
# Close the SMTP connection
|
||||||
mailserver.quit()
|
mailserver.quit()
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
from .main import Pushalot
|
||||||
|
|
||||||
|
def start():
|
||||||
|
return Pushalot()
|
||||||
|
|
||||||
|
config = [{
|
||||||
|
'name': 'pushalot',
|
||||||
|
'groups': [
|
||||||
|
{
|
||||||
|
'tab': 'notifications',
|
||||||
|
'list': 'notification_providers',
|
||||||
|
'name': 'pushalot',
|
||||||
|
'description': 'for Windows Phone and Windows 8',
|
||||||
|
'options': [
|
||||||
|
{
|
||||||
|
'name': 'enabled',
|
||||||
|
'default': 0,
|
||||||
|
'type': 'enabler',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'auth_token',
|
||||||
|
'label': 'Auth Token',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'silent',
|
||||||
|
'label': 'Silent',
|
||||||
|
'default': 0,
|
||||||
|
'type': 'bool',
|
||||||
|
'description': 'Don\'t send Toast notifications. Only update Live Tile',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'important',
|
||||||
|
'label': 'High Priority',
|
||||||
|
'default': 0,
|
||||||
|
'type': 'bool',
|
||||||
|
'description': 'Send message with High priority.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'on_snatch',
|
||||||
|
'default': 0,
|
||||||
|
'type': 'bool',
|
||||||
|
'advanced': True,
|
||||||
|
'description': 'Also send message when movie is snatched.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}]
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
from couchpotato.core.helpers.encoding import toUnicode
|
||||||
|
from couchpotato.core.logger import CPLog
|
||||||
|
from couchpotato.core.notifications.base import Notification
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
log = CPLog(__name__)
|
||||||
|
|
||||||
|
class Pushalot(Notification):
|
||||||
|
|
||||||
|
urls = {
|
||||||
|
'api': 'https://pushalot.com/api/sendmessage'
|
||||||
|
}
|
||||||
|
|
||||||
|
def notify(self, message = '', data = {}, listener = None):
|
||||||
|
if self.isDisabled(): return
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'AuthorizationToken': self.conf('auth_token'),
|
||||||
|
'Title': self.default_title,
|
||||||
|
'Body': toUnicode(message),
|
||||||
|
'LinkTitle': toUnicode("CouchPotato"),
|
||||||
|
'link': toUnicode("https://couchpota.to/"),
|
||||||
|
'IsImportant': self.conf('important'),
|
||||||
|
'IsSilent': self.conf('silent'),
|
||||||
|
}
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'Content-type': 'application/x-www-form-urlencoded'
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.urlopen(self.urls['api'], headers = headers, params = data, multipart = True, show_error = False)
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
log.error('PushAlot failed: %s', traceback.format_exc())
|
||||||
|
|
||||||
|
return False
|
||||||
@@ -6,8 +6,9 @@ from couchpotato.core.helpers.variable import splitString, tryInt
|
|||||||
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 Movie
|
from couchpotato.core.settings.model import Movie
|
||||||
from sqlalchemy.sql.expression import or_
|
from sqlalchemy.orm import joinedload_all
|
||||||
import random
|
import random
|
||||||
|
import time
|
||||||
|
|
||||||
log = CPLog(__name__)
|
log = CPLog(__name__)
|
||||||
|
|
||||||
@@ -41,7 +42,6 @@ class Dashboard(Plugin):
|
|||||||
identifiers = [m.library.identifier for m in movies]
|
identifiers = [m.library.identifier for m in movies]
|
||||||
|
|
||||||
suggestions = fireEvent('movie.suggest', movies = identifiers, single = True)
|
suggestions = fireEvent('movie.suggest', movies = identifiers, single = True)
|
||||||
print suggestions
|
|
||||||
|
|
||||||
return jsonified({
|
return jsonified({
|
||||||
'result': True,
|
'result': True,
|
||||||
@@ -52,6 +52,7 @@ class Dashboard(Plugin):
|
|||||||
|
|
||||||
params = getParams()
|
params = getParams()
|
||||||
db = get_session()
|
db = get_session()
|
||||||
|
now = time.time()
|
||||||
|
|
||||||
# Get profiles first, determine pre or post theater
|
# Get profiles first, determine pre or post theater
|
||||||
profiles = fireEvent('profile.all', single = True)
|
profiles = fireEvent('profile.all', single = True)
|
||||||
@@ -72,10 +73,16 @@ class Dashboard(Plugin):
|
|||||||
profile_pre[profile.get('id')] = contains
|
profile_pre[profile.get('id')] = contains
|
||||||
|
|
||||||
# Get all active movies
|
# Get all active movies
|
||||||
q = db.query(Movie) \
|
active_status = fireEvent('status.get', 'active', single = True)
|
||||||
.join(Movie.profile, Movie.library) \
|
subq = db.query(Movie).filter(Movie.status_id == active_status.get('id')).subquery()
|
||||||
.filter(or_(*[Movie.status.has(identifier = s) for s in ['active']])) \
|
|
||||||
.group_by(Movie.id)
|
q = db.query(Movie).join((subq, subq.c.id == Movie.id)) \
|
||||||
|
.options(joinedload_all('releases')) \
|
||||||
|
.options(joinedload_all('profile.types')) \
|
||||||
|
.options(joinedload_all('library.titles')) \
|
||||||
|
.options(joinedload_all('library.files')) \
|
||||||
|
.options(joinedload_all('status')) \
|
||||||
|
.options(joinedload_all('files'))
|
||||||
|
|
||||||
# Add limit
|
# Add limit
|
||||||
limit_offset = params.get('limit_offset')
|
limit_offset = params.get('limit_offset')
|
||||||
@@ -92,7 +99,7 @@ class Dashboard(Plugin):
|
|||||||
movies = []
|
movies = []
|
||||||
for movie in all_movies:
|
for movie in all_movies:
|
||||||
pp = profile_pre.get(movie.profile.id)
|
pp = profile_pre.get(movie.profile.id)
|
||||||
eta = movie.library.info.get('release_date', {})
|
eta = movie.library.info.get('release_date', {}) or {}
|
||||||
coming_soon = False
|
coming_soon = False
|
||||||
|
|
||||||
# Theater quality
|
# Theater quality
|
||||||
@@ -101,6 +108,7 @@ class Dashboard(Plugin):
|
|||||||
if pp.get('dvd') and fireEvent('searcher.could_be_released', False, eta, single = True):
|
if pp.get('dvd') and fireEvent('searcher.could_be_released', False, eta, single = True):
|
||||||
coming_soon = True
|
coming_soon = True
|
||||||
|
|
||||||
|
|
||||||
if coming_soon:
|
if coming_soon:
|
||||||
temp = movie.to_dict({
|
temp = movie.to_dict({
|
||||||
'profile': {'types': {}},
|
'profile': {'types': {}},
|
||||||
@@ -108,7 +116,11 @@ class Dashboard(Plugin):
|
|||||||
'library': {'titles': {}, 'files':{}},
|
'library': {'titles': {}, 'files':{}},
|
||||||
'files': {},
|
'files': {},
|
||||||
})
|
})
|
||||||
movies.append(temp)
|
|
||||||
|
# Don't list older movies
|
||||||
|
if ((not params.get('late') and (not eta.get('dvd') or (eta.get('dvd') and eta.get('dvd') > (now - 2419200)))) or \
|
||||||
|
(params.get('late') and eta.get('dvd') and eta.get('dvd') < (now - 2419200))):
|
||||||
|
movies.append(temp)
|
||||||
|
|
||||||
if len(movies) >= limit:
|
if len(movies) >= limit:
|
||||||
break
|
break
|
||||||
@@ -118,3 +130,5 @@ class Dashboard(Plugin):
|
|||||||
'empty': len(movies) == 0,
|
'empty': len(movies) == 0,
|
||||||
'movies': movies,
|
'movies': movies,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
getLateView = getSoonView
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class LibraryPlugin(Plugin):
|
|||||||
|
|
||||||
title = LibraryTitle(
|
title = LibraryTitle(
|
||||||
title = toUnicode(attrs.get('title')),
|
title = toUnicode(attrs.get('title')),
|
||||||
simple_title = self.simplifyTitle(attrs.get('title'))
|
simple_title = self.simplifyTitle(attrs.get('title')),
|
||||||
)
|
)
|
||||||
|
|
||||||
l.titles.append(title)
|
l.titles.append(title)
|
||||||
@@ -96,6 +96,7 @@ class LibraryPlugin(Plugin):
|
|||||||
|
|
||||||
titles = info.get('titles', [])
|
titles = info.get('titles', [])
|
||||||
log.debug('Adding titles: %s', titles)
|
log.debug('Adding titles: %s', titles)
|
||||||
|
counter = 0
|
||||||
for title in titles:
|
for title in titles:
|
||||||
if not title:
|
if not title:
|
||||||
continue
|
continue
|
||||||
@@ -103,9 +104,10 @@ class LibraryPlugin(Plugin):
|
|||||||
t = LibraryTitle(
|
t = LibraryTitle(
|
||||||
title = title,
|
title = title,
|
||||||
simple_title = self.simplifyTitle(title),
|
simple_title = self.simplifyTitle(title),
|
||||||
default = title.lower() == toUnicode(default_title.lower()) or (toUnicode(default_title) == u'' and toUnicode(titles[0]) == title)
|
default = (len(default_title) == 0 and counter == 0) or len(titles) == 1 or title.lower() == toUnicode(default_title.lower()) or (toUnicode(default_title) == u'' and toUnicode(titles[0]) == title)
|
||||||
)
|
)
|
||||||
library.titles.append(t)
|
library.titles.append(t)
|
||||||
|
counter += 1
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from couchpotato.environment import Env
|
|||||||
from sqlalchemy.orm import joinedload_all
|
from sqlalchemy.orm import joinedload_all
|
||||||
from sqlalchemy.sql.expression import or_, asc, not_, desc
|
from sqlalchemy.sql.expression import or_, asc, not_, desc
|
||||||
from string import ascii_lowercase
|
from string import ascii_lowercase
|
||||||
|
import time
|
||||||
|
|
||||||
log = CPLog(__name__)
|
log = CPLog(__name__)
|
||||||
|
|
||||||
@@ -96,32 +97,33 @@ class MoviePlugin(Plugin):
|
|||||||
addEvent('movie.list', self.list)
|
addEvent('movie.list', self.list)
|
||||||
addEvent('movie.restatus', self.restatus)
|
addEvent('movie.restatus', self.restatus)
|
||||||
|
|
||||||
|
# Clean releases that didn't have activity in the last week
|
||||||
addEvent('app.load', self.cleanReleases)
|
addEvent('app.load', self.cleanReleases)
|
||||||
|
fireEvent('schedule.interval', 'movie.clean_releases', self.cleanReleases, hours = 4)
|
||||||
|
|
||||||
def cleanReleases(self):
|
def cleanReleases(self):
|
||||||
|
|
||||||
prop_name = 'cleaned_releases'
|
log.debug('Removing releases from dashboard')
|
||||||
already_cleaned = Env.prop(prop_name, default = False)
|
|
||||||
if already_cleaned:
|
|
||||||
return True
|
|
||||||
|
|
||||||
log.info('Removing releases from library movies')
|
now = time.time()
|
||||||
|
week = 262080
|
||||||
db = get_session()
|
|
||||||
|
|
||||||
movies = db.query(Movie).all()
|
|
||||||
|
|
||||||
done_status = fireEvent('status.get', 'done', single = True)
|
done_status = fireEvent('status.get', 'done', single = True)
|
||||||
available_status = fireEvent('status.get', 'available', single = True)
|
available_status = fireEvent('status.get', 'available', single = True)
|
||||||
snatched_status = fireEvent('status.get', 'snatched', single = True)
|
snatched_status = fireEvent('status.get', 'snatched', single = True)
|
||||||
|
|
||||||
for movie in movies:
|
db = get_session()
|
||||||
if movie.status_id == done_status.get('id'):
|
|
||||||
for rel in movie.releases:
|
|
||||||
if rel.status_id in [available_status.get('id'), snatched_status.get('id')]:
|
|
||||||
fireEvent('release.delete', id = rel.id, single = True)
|
|
||||||
|
|
||||||
Env.prop(prop_name, True)
|
# get movies last_edit more than a week ago
|
||||||
|
movies = db.query(Movie) \
|
||||||
|
.filter(Movie.status_id == done_status.get('id'), Movie.last_edit < (now - week)) \
|
||||||
|
.all()
|
||||||
|
|
||||||
|
#
|
||||||
|
for movie in movies:
|
||||||
|
for rel in movie.releases:
|
||||||
|
if rel.status_id in [available_status.get('id'), snatched_status.get('id')]:
|
||||||
|
fireEvent('release.delete', id = rel.id, single = True)
|
||||||
|
|
||||||
def getView(self):
|
def getView(self):
|
||||||
|
|
||||||
@@ -366,7 +368,9 @@ class MoviePlugin(Plugin):
|
|||||||
|
|
||||||
# Status
|
# Status
|
||||||
status_active = fireEvent('status.add', 'active', single = True)
|
status_active = fireEvent('status.add', 'active', single = True)
|
||||||
status_snatched = fireEvent('status.add', 'snatched', single = True)
|
snatched_status = fireEvent('status.add', 'snatched', single = True)
|
||||||
|
ignored_status = fireEvent('status.add', 'ignored', single = True)
|
||||||
|
downloaded_status = fireEvent('status.add', 'downloaded', single = True)
|
||||||
|
|
||||||
default_profile = fireEvent('profile.default', single = True)
|
default_profile = fireEvent('profile.default', single = True)
|
||||||
|
|
||||||
@@ -390,10 +394,14 @@ class MoviePlugin(Plugin):
|
|||||||
fireEventAsync('library.update', params.get('identifier'), default_title = params.get('title', ''), on_complete = onComplete)
|
fireEventAsync('library.update', params.get('identifier'), default_title = params.get('title', ''), on_complete = onComplete)
|
||||||
search_after = False
|
search_after = False
|
||||||
elif force_readd:
|
elif force_readd:
|
||||||
|
|
||||||
# Clean snatched history
|
# Clean snatched history
|
||||||
for release in m.releases:
|
for release in m.releases:
|
||||||
if release.status_id == status_snatched.get('id'):
|
if release.status_id in [downloaded_status.get('id'), snatched_status.get('id')]:
|
||||||
release.delete()
|
if params.get('ignore_previous', False):
|
||||||
|
release.status_id = ignored_status.get('id')
|
||||||
|
else:
|
||||||
|
fireEvent('release.delete', release.id, single = True)
|
||||||
|
|
||||||
m.profile_id = params.get('profile_id', default_profile.get('id'))
|
m.profile_id = params.get('profile_id', default_profile.get('id'))
|
||||||
else:
|
else:
|
||||||
@@ -402,6 +410,7 @@ class MoviePlugin(Plugin):
|
|||||||
|
|
||||||
if force_readd:
|
if force_readd:
|
||||||
m.status_id = status_id if status_id else status_active.get('id')
|
m.status_id = status_id if status_id else status_active.get('id')
|
||||||
|
m.last_edit = int(time.time())
|
||||||
do_search = True
|
do_search = True
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|||||||
@@ -27,7 +27,12 @@ var MovieList = new Class({
|
|||||||
|
|
||||||
self.el = new Element('div.movies').adopt(
|
self.el = new Element('div.movies').adopt(
|
||||||
self.title = self.options.title ? new Element('h2', {
|
self.title = self.options.title ? new Element('h2', {
|
||||||
'text': self.options.title
|
'text': self.options.title,
|
||||||
|
'styles': {'display': 'none'}
|
||||||
|
}) : null,
|
||||||
|
self.description = self.options.description ? new Element('div.description', {
|
||||||
|
'html': self.options.description,
|
||||||
|
'styles': {'display': 'none'}
|
||||||
}) : null,
|
}) : null,
|
||||||
self.movie_list = new Element('div'),
|
self.movie_list = new Element('div'),
|
||||||
self.load_more = self.options.load_more ? new Element('a.load_more', {
|
self.load_more = self.options.load_more ? new Element('a.load_more', {
|
||||||
@@ -37,7 +42,7 @@ var MovieList = new Class({
|
|||||||
}) : null
|
}) : null
|
||||||
);
|
);
|
||||||
|
|
||||||
self.changeView(self.options.view || 'details');
|
self.changeView(self.getSavedView() || self.options.view || 'details');
|
||||||
|
|
||||||
self.getMovies();
|
self.getMovies();
|
||||||
|
|
||||||
@@ -121,18 +126,14 @@ var MovieList = new Class({
|
|||||||
|
|
||||||
createMovie: function(movie, inject_at){
|
createMovie: function(movie, inject_at){
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// Attach proper actions
|
|
||||||
var a = self.options.actions,
|
|
||||||
status = Status.get(movie.status_id),
|
|
||||||
actions = a ? a[status.identifier.capitalize()] || a.Wanted : {};
|
|
||||||
|
|
||||||
var m = new Movie(self, {
|
var m = new Movie(self, {
|
||||||
'actions': actions,
|
'actions': self.options.actions,
|
||||||
'view': self.current_view,
|
'view': self.current_view,
|
||||||
'onSelect': self.calculateSelected.bind(self)
|
'onSelect': self.calculateSelected.bind(self)
|
||||||
}, movie);
|
}, movie);
|
||||||
|
|
||||||
$(m).inject(self.movie_list, inject_at || 'bottom');
|
$(m).inject(self.movie_list, inject_at || 'bottom');
|
||||||
|
|
||||||
m.fireEvent('injected');
|
m.fireEvent('injected');
|
||||||
|
|
||||||
self.movies.include(m)
|
self.movies.include(m)
|
||||||
@@ -398,8 +399,11 @@ var MovieList = new Class({
|
|||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self.movies = []
|
self.movies = []
|
||||||
self.calculateSelected()
|
if(self.mass_edit_select)
|
||||||
self.navigation_alpha.getElements('.active').removeClass('active')
|
self.calculateSelected()
|
||||||
|
if(self.navigation_alpha)
|
||||||
|
self.navigation_alpha.getElements('.active').removeClass('active')
|
||||||
|
|
||||||
self.offset = 0;
|
self.offset = 0;
|
||||||
if(self.scrollspy){
|
if(self.scrollspy){
|
||||||
self.load_more.show();
|
self.load_more.show();
|
||||||
@@ -430,7 +434,7 @@ var MovieList = new Class({
|
|||||||
|
|
||||||
getSavedView: function(){
|
getSavedView: function(){
|
||||||
var self = this;
|
var self = this;
|
||||||
return Cookie.read(self.options.identifier+'_view') || 'thumbs';
|
return Cookie.read(self.options.identifier+'_view') || 'details';
|
||||||
},
|
},
|
||||||
|
|
||||||
search: function(){
|
search: function(){
|
||||||
@@ -505,11 +509,14 @@ var MovieList = new Class({
|
|||||||
checkIfEmpty: function(){
|
checkIfEmpty: function(){
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var is_empty = self.movies.length == 0 && self.total_movies == 0;
|
var is_empty = self.movies.length == 0 && (self.total_movies == 0 || self.total_movies === undefined);
|
||||||
|
|
||||||
if(self.title)
|
if(self.title)
|
||||||
self.title[is_empty ? 'hide' : 'show']()
|
self.title[is_empty ? 'hide' : 'show']()
|
||||||
|
|
||||||
|
if(self.description)
|
||||||
|
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.el.grab(self.options.on_empty_element);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,699 @@
|
|||||||
|
var MovieAction = new Class({
|
||||||
|
|
||||||
|
class_name: 'action icon',
|
||||||
|
|
||||||
|
initialize: function(movie){
|
||||||
|
var self = this;
|
||||||
|
self.movie = movie;
|
||||||
|
|
||||||
|
self.create();
|
||||||
|
if(self.el)
|
||||||
|
self.el.addClass(self.class_name)
|
||||||
|
},
|
||||||
|
|
||||||
|
create: function(){},
|
||||||
|
|
||||||
|
disable: function(){
|
||||||
|
this.el.addClass('disable')
|
||||||
|
},
|
||||||
|
|
||||||
|
enable: function(){
|
||||||
|
this.el.removeClass('disable')
|
||||||
|
},
|
||||||
|
|
||||||
|
createMask: function(){
|
||||||
|
var self = this;
|
||||||
|
self.mask = new Element('div.mask', {
|
||||||
|
'styles': {
|
||||||
|
'z-index': '1'
|
||||||
|
}
|
||||||
|
}).inject(self.movie, 'top').fade('hide');
|
||||||
|
//self.positionMask();
|
||||||
|
},
|
||||||
|
|
||||||
|
positionMask: function(){
|
||||||
|
var self = this,
|
||||||
|
movie = $(self.movie),
|
||||||
|
s = movie.getSize()
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
return self.mask.setStyles({
|
||||||
|
'width': s.x,
|
||||||
|
'height': s.y
|
||||||
|
}).position({
|
||||||
|
'relativeTo': movie
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
toElement: function(){
|
||||||
|
return this.el || null
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
var MA = {};
|
||||||
|
|
||||||
|
MA.IMDB = new Class({
|
||||||
|
|
||||||
|
Extends: MovieAction,
|
||||||
|
id: null,
|
||||||
|
|
||||||
|
create: function(){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.id = self.movie.get('identifier');
|
||||||
|
|
||||||
|
self.el = new Element('a.imdb', {
|
||||||
|
'title': 'Go to the IMDB page of ' + self.movie.getTitle(),
|
||||||
|
'href': 'http://www.imdb.com/title/'+self.id+'/',
|
||||||
|
'target': '_blank'
|
||||||
|
});
|
||||||
|
|
||||||
|
if(!self.id) self.disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
MA.Release = new Class({
|
||||||
|
|
||||||
|
Extends: MovieAction,
|
||||||
|
|
||||||
|
create: function(){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.el = new Element('a.releases.icon.download', {
|
||||||
|
'title': 'Show the releases that are available for ' + self.movie.getTitle(),
|
||||||
|
'events': {
|
||||||
|
'click': self.show.bind(self)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(self.movie.data.releases.length == 0){
|
||||||
|
self.el.hide()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
var buttons_done = false;
|
||||||
|
|
||||||
|
self.movie.data.releases.sortBy('-info.score').each(function(release){
|
||||||
|
if(buttons_done) return;
|
||||||
|
|
||||||
|
var status = Status.get(release.status_id);
|
||||||
|
|
||||||
|
if((self.next_release && (status.identifier == 'ignored' || status.identifier == 'failed')) || (!self.next_release && status.identifier == 'available')){
|
||||||
|
self.hide_on_click = false;
|
||||||
|
self.show();
|
||||||
|
buttons_done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
show: function(e){
|
||||||
|
var self = this;
|
||||||
|
if(e)
|
||||||
|
(e).preventDefault();
|
||||||
|
|
||||||
|
if(!self.options_container){
|
||||||
|
self.options_container = new Element('div.options').adopt(
|
||||||
|
self.release_container = new Element('div.releases.table').adopt(
|
||||||
|
self.trynext_container = new Element('div.buttons.try_container')
|
||||||
|
)
|
||||||
|
).inject(self.movie, 'top');
|
||||||
|
|
||||||
|
// Header
|
||||||
|
new Element('div.item.head').adopt(
|
||||||
|
new Element('span.name', {'text': 'Release name'}),
|
||||||
|
new Element('span.status', {'text': 'Status'}),
|
||||||
|
new Element('span.quality', {'text': 'Quality'}),
|
||||||
|
new Element('span.size', {'text': 'Size'}),
|
||||||
|
new Element('span.age', {'text': 'Age'}),
|
||||||
|
new Element('span.score', {'text': 'Score'}),
|
||||||
|
new Element('span.provider', {'text': 'Provider'})
|
||||||
|
).inject(self.release_container)
|
||||||
|
|
||||||
|
self.movie.data.releases.sortBy('-info.score').each(function(release){
|
||||||
|
|
||||||
|
var status = Status.get(release.status_id),
|
||||||
|
quality = Quality.getProfile(release.quality_id) || {},
|
||||||
|
info = release.info,
|
||||||
|
provider = self.get(release, 'provider') + (release.info['provider_extra'] ? self.get(release, 'provider_extra') : '');
|
||||||
|
release.status = status;
|
||||||
|
|
||||||
|
var release_name = self.get(release, 'name');
|
||||||
|
if(release.files && release.files.length > 0){
|
||||||
|
try {
|
||||||
|
var movie_file = release.files.filter(function(file){
|
||||||
|
var type = File.Type.get(file.type_id);
|
||||||
|
return type && type.identifier == 'movie'
|
||||||
|
}).pick();
|
||||||
|
release_name = movie_file.path.split(Api.getOption('path_sep')).getLast();
|
||||||
|
}
|
||||||
|
catch(e){}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create release
|
||||||
|
new Element('div', {
|
||||||
|
'class': 'item '+status.identifier,
|
||||||
|
'id': 'release_'+release.id
|
||||||
|
}).adopt(
|
||||||
|
new Element('span.name', {'text': release_name, 'title': release_name}),
|
||||||
|
new Element('span.status', {'text': status.identifier, 'class': 'release_status '+status.identifier}),
|
||||||
|
new Element('span.quality', {'text': quality.get('label') || 'n/a'}),
|
||||||
|
new Element('span.size', {'text': release.info['size'] ? Math.floor(self.get(release, 'size')) : 'n/a'}),
|
||||||
|
new Element('span.age', {'text': self.get(release, 'age')}),
|
||||||
|
new Element('span.score', {'text': self.get(release, 'score')}),
|
||||||
|
new Element('span.provider', { 'text': provider, 'title': provider }),
|
||||||
|
release.info['detail_url'] ? new Element('a.info.icon', {
|
||||||
|
'href': release.info['detail_url'],
|
||||||
|
'target': '_blank'
|
||||||
|
}) : null,
|
||||||
|
new Element('a.download.icon', {
|
||||||
|
'events': {
|
||||||
|
'click': function(e){
|
||||||
|
(e).preventDefault();
|
||||||
|
if(!this.hasClass('completed'))
|
||||||
|
self.download(release);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new Element('a.delete.icon', {
|
||||||
|
'events': {
|
||||||
|
'click': function(e){
|
||||||
|
(e).preventDefault();
|
||||||
|
self.ignore(release);
|
||||||
|
this.getParent('.item').toggleClass('ignored')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
).inject(self.release_container)
|
||||||
|
|
||||||
|
if(status.identifier == 'ignored' || status.identifier == 'failed' || status.identifier == 'snatched'){
|
||||||
|
if(!self.last_release || (self.last_release && self.last_release.status.identifier != 'snatched' && status.identifier == 'snatched'))
|
||||||
|
self.last_release = release;
|
||||||
|
}
|
||||||
|
else if(!self.next_release && status.identifier == 'available'){
|
||||||
|
self.next_release = release;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(self.last_release){
|
||||||
|
self.release_container.getElement('#release_'+self.last_release.id).addClass('last_release');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(self.next_release){
|
||||||
|
self.release_container.getElement('#release_'+self.next_release.id).addClass('next_release');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(self.next_release || self.last_release){
|
||||||
|
|
||||||
|
self.trynext_container.adopt(
|
||||||
|
new Element('span.or', {
|
||||||
|
'text': 'This movie is snatched, if anything went wrong, download'
|
||||||
|
}),
|
||||||
|
self.last_release ? new Element('a.button.orange', {
|
||||||
|
'text': 'the same release again',
|
||||||
|
'events': {
|
||||||
|
'click': self.trySameRelease.bind(self)
|
||||||
|
}
|
||||||
|
}) : null,
|
||||||
|
self.next_release && self.last_release ? new Element('span.or', {
|
||||||
|
'text': ','
|
||||||
|
}) : null,
|
||||||
|
self.next_release ? [new Element('a.button.green', {
|
||||||
|
'text': self.last_release ? 'another release' : 'the best release',
|
||||||
|
'events': {
|
||||||
|
'click': self.tryNextRelease.bind(self)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new Element('span.or', {
|
||||||
|
'text': 'or pick one below'
|
||||||
|
})] : null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
self.movie.slide('in', self.options_container);
|
||||||
|
},
|
||||||
|
|
||||||
|
get: function(release, type){
|
||||||
|
return release.info[type] || 'n/a'
|
||||||
|
},
|
||||||
|
|
||||||
|
download: function(release){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var release_el = self.release_container.getElement('#release_'+release.id),
|
||||||
|
icon = release_el.getElement('.download.icon');
|
||||||
|
|
||||||
|
icon.addClass('spinner');
|
||||||
|
|
||||||
|
Api.request('release.download', {
|
||||||
|
'data': {
|
||||||
|
'id': release.id
|
||||||
|
},
|
||||||
|
'onComplete': function(json){
|
||||||
|
icon.removeClass('spinner')
|
||||||
|
if(json.success)
|
||||||
|
icon.addClass('completed');
|
||||||
|
else
|
||||||
|
icon.addClass('attention').set('title', 'Something went wrong when downloading, please check logs.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
ignore: function(release){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
Api.request('release.ignore', {
|
||||||
|
'data': {
|
||||||
|
'id': release.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
tryNextRelease: function(movie_id){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if(self.last_release)
|
||||||
|
self.ignore(self.last_release);
|
||||||
|
|
||||||
|
if(self.next_release)
|
||||||
|
self.download(self.next_release);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
trySameRelease: function(movie_id){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if(self.last_release)
|
||||||
|
self.download(self.last_release);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
MA.Trailer = new Class({
|
||||||
|
|
||||||
|
Extends: MovieAction,
|
||||||
|
id: null,
|
||||||
|
|
||||||
|
create: function(){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.el = new Element('a.trailer', {
|
||||||
|
'title': 'Watch the trailer of ' + self.movie.getTitle(),
|
||||||
|
'events': {
|
||||||
|
'click': self.watch.bind(self)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: function(offset){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var data_url = 'http://gdata.youtube.com/feeds/videos?vq="{title}" {year} trailer&max-results=1&alt=json-in-script&orderby=relevance&sortorder=descending&format=5&fmt=18'
|
||||||
|
var url = data_url.substitute({
|
||||||
|
'title': encodeURI(self.movie.getTitle()),
|
||||||
|
'year': self.movie.get('year'),
|
||||||
|
'offset': offset || 1
|
||||||
|
}),
|
||||||
|
size = $(self.movie).getSize(),
|
||||||
|
height = (size.x/16)*9,
|
||||||
|
id = 'trailer-'+randomString();
|
||||||
|
|
||||||
|
self.player_container = new Element('div[id='+id+']');
|
||||||
|
self.container = new Element('div.hide.trailer_container')
|
||||||
|
.adopt(self.player_container)
|
||||||
|
.inject($(self.movie), 'top');
|
||||||
|
|
||||||
|
self.container.setStyle('height', 0);
|
||||||
|
self.container.removeClass('hide');
|
||||||
|
|
||||||
|
self.close_button = new Element('a.hide.hide_trailer', {
|
||||||
|
'text': 'Hide trailer',
|
||||||
|
'events': {
|
||||||
|
'click': self.stop.bind(self)
|
||||||
|
}
|
||||||
|
}).inject(self.movie);
|
||||||
|
|
||||||
|
self.container.setStyle('height', height);
|
||||||
|
$(self.movie).setStyle('height', height);
|
||||||
|
|
||||||
|
new Request.JSONP({
|
||||||
|
'url': url,
|
||||||
|
'onComplete': function(json){
|
||||||
|
var video_url = json.feed.entry[0].id.$t.split('/'),
|
||||||
|
video_id = video_url[video_url.length-1];
|
||||||
|
|
||||||
|
self.player = new YT.Player(id, {
|
||||||
|
'height': height,
|
||||||
|
'width': size.x,
|
||||||
|
'videoId': video_id,
|
||||||
|
'playerVars': {
|
||||||
|
'autoplay': 1,
|
||||||
|
'showsearch': 0,
|
||||||
|
'wmode': 'transparent',
|
||||||
|
'iv_load_policy': 3
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.close_button.removeClass('hide');
|
||||||
|
|
||||||
|
var quality_set = false;
|
||||||
|
var change_quality = function(state){
|
||||||
|
if(!quality_set && (state.data == 1 || state.data || 2)){
|
||||||
|
try {
|
||||||
|
self.player.setPlaybackQuality('hd720');
|
||||||
|
quality_set = true;
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.player.addEventListener('onStateChange', change_quality);
|
||||||
|
|
||||||
|
}
|
||||||
|
}).send()
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
stop: function(){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.player.stopVideo();
|
||||||
|
self.container.addClass('hide');
|
||||||
|
self.close_button.addClass('hide');
|
||||||
|
$(self.movie).setStyle('height', null);
|
||||||
|
|
||||||
|
setTimeout(function(){
|
||||||
|
self.container.destroy()
|
||||||
|
self.close_button.destroy();
|
||||||
|
}, 1800)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
MA.Edit = new Class({
|
||||||
|
|
||||||
|
Extends: MovieAction,
|
||||||
|
|
||||||
|
create: function(){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.el = new Element('a.edit', {
|
||||||
|
'title': 'Change movie information, like title and quality.',
|
||||||
|
'events': {
|
||||||
|
'click': self.editMovie.bind(self)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
editMovie: function(e){
|
||||||
|
var self = this;
|
||||||
|
(e).preventDefault();
|
||||||
|
|
||||||
|
if(!self.options_container){
|
||||||
|
self.options_container = new Element('div.options').adopt(
|
||||||
|
new Element('div.form').adopt(
|
||||||
|
self.title_select = new Element('select', {
|
||||||
|
'name': 'title'
|
||||||
|
}),
|
||||||
|
self.profile_select = new Element('select', {
|
||||||
|
'name': 'profile'
|
||||||
|
}),
|
||||||
|
new Element('a.button.edit', {
|
||||||
|
'text': 'Save & Search',
|
||||||
|
'events': {
|
||||||
|
'click': self.save.bind(self)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
).inject(self.movie, 'top');
|
||||||
|
|
||||||
|
Array.each(self.movie.data.library.titles, function(alt){
|
||||||
|
new Element('option', {
|
||||||
|
'text': alt.title
|
||||||
|
}).inject(self.title_select);
|
||||||
|
|
||||||
|
if(alt['default'])
|
||||||
|
self.title_select.set('value', alt.title);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Quality.getActiveProfiles().each(function(profile){
|
||||||
|
|
||||||
|
var profile_id = profile.id ? profile.id : profile.data.id;
|
||||||
|
|
||||||
|
new Element('option', {
|
||||||
|
'value': profile_id,
|
||||||
|
'text': profile.label ? profile.label : profile.data.label
|
||||||
|
}).inject(self.profile_select);
|
||||||
|
|
||||||
|
if(self.movie.profile && self.movie.profile.data && self.movie.profile.data.id == profile_id)
|
||||||
|
self.profile_select.set('value', profile_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
self.movie.slide('in', self.options_container);
|
||||||
|
},
|
||||||
|
|
||||||
|
save: function(e){
|
||||||
|
(e).preventDefault();
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
Api.request('movie.edit', {
|
||||||
|
'data': {
|
||||||
|
'id': self.movie.get('id'),
|
||||||
|
'default_title': self.title_select.get('value'),
|
||||||
|
'profile_id': self.profile_select.get('value')
|
||||||
|
},
|
||||||
|
'useSpinner': true,
|
||||||
|
'spinnerTarget': $(self.movie),
|
||||||
|
'onComplete': function(){
|
||||||
|
self.movie.quality.set('text', self.profile_select.getSelected()[0].get('text'));
|
||||||
|
self.movie.title.set('text', self.title_select.getSelected()[0].get('text'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.movie.slide('out');
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
MA.Refresh = new Class({
|
||||||
|
|
||||||
|
Extends: MovieAction,
|
||||||
|
|
||||||
|
create: function(){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.el = new Element('a.refresh', {
|
||||||
|
'title': 'Refresh the movie info and do a forced search',
|
||||||
|
'events': {
|
||||||
|
'click': self.doRefresh.bind(self)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
doRefresh: function(e){
|
||||||
|
var self = this;
|
||||||
|
(e).preventDefault();
|
||||||
|
|
||||||
|
Api.request('movie.refresh', {
|
||||||
|
'data': {
|
||||||
|
'id': self.movie.get('id')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
MA.Readd = new Class({
|
||||||
|
|
||||||
|
Extends: MovieAction,
|
||||||
|
|
||||||
|
create: function(){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var movie_done = Status.get(self.movie.data.status_id).identifier == 'done';
|
||||||
|
if(!movie_done)
|
||||||
|
var snatched = self.movie.data.releases.filter(function(release){
|
||||||
|
return release.status && (release.status.identifier == 'snatched' || release.status.identifier == 'downloaded' || release.status.identifier == 'done');
|
||||||
|
}).length;
|
||||||
|
|
||||||
|
if(movie_done || snatched && snatched > 0)
|
||||||
|
self.el = new Element('a.readd', {
|
||||||
|
'title': 'Readd the movie and mark all previous snatched/downloaded as ignored',
|
||||||
|
'events': {
|
||||||
|
'click': self.doReadd.bind(self)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
doReadd: function(e){
|
||||||
|
var self = this;
|
||||||
|
(e).preventDefault();
|
||||||
|
|
||||||
|
Api.request('movie.add', {
|
||||||
|
'data': {
|
||||||
|
'identifier': self.movie.get('identifier'),
|
||||||
|
'ignore_previous': 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
MA.Delete = new Class({
|
||||||
|
|
||||||
|
Extends: MovieAction,
|
||||||
|
|
||||||
|
Implements: [Chain],
|
||||||
|
|
||||||
|
create: function(){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.el = new Element('a.delete', {
|
||||||
|
'title': 'Remove the movie from this CP list',
|
||||||
|
'events': {
|
||||||
|
'click': self.showConfirm.bind(self)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
showConfirm: function(e){
|
||||||
|
var self = this;
|
||||||
|
(e).preventDefault();
|
||||||
|
|
||||||
|
if(!self.delete_container){
|
||||||
|
self.delete_container = new Element('div.buttons.delete_container').adopt(
|
||||||
|
new Element('a.cancel', {
|
||||||
|
'text': 'Cancel',
|
||||||
|
'events': {
|
||||||
|
'click': self.hideConfirm.bind(self)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new Element('span.or', {
|
||||||
|
'text': 'or'
|
||||||
|
}),
|
||||||
|
new Element('a.button.delete', {
|
||||||
|
'text': 'Delete ' + self.movie.title.get('text'),
|
||||||
|
'events': {
|
||||||
|
'click': self.del.bind(self)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
).inject(self.movie, 'top');
|
||||||
|
}
|
||||||
|
|
||||||
|
self.movie.slide('in', self.delete_container);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
hideConfirm: function(e){
|
||||||
|
var self = this;
|
||||||
|
(e).preventDefault();
|
||||||
|
|
||||||
|
self.movie.slide('out');
|
||||||
|
},
|
||||||
|
|
||||||
|
del: function(e){
|
||||||
|
(e).preventDefault();
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var movie = $(self.movie);
|
||||||
|
|
||||||
|
self.chain(
|
||||||
|
function(){
|
||||||
|
self.callChain();
|
||||||
|
},
|
||||||
|
function(){
|
||||||
|
Api.request('movie.delete', {
|
||||||
|
'data': {
|
||||||
|
'id': self.movie.get('id'),
|
||||||
|
'delete_from': self.movie.list.options.identifier
|
||||||
|
},
|
||||||
|
'onComplete': function(){
|
||||||
|
movie.set('tween', {
|
||||||
|
'duration': 300,
|
||||||
|
'onComplete': function(){
|
||||||
|
self.movie.destroy()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
movie.tween('height', 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
self.callChain();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
MA.Files = new Class({
|
||||||
|
|
||||||
|
Extends: MovieAction,
|
||||||
|
|
||||||
|
create: function(){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.el = new Element('a.directory', {
|
||||||
|
'title': 'Available files',
|
||||||
|
'events': {
|
||||||
|
'click': self.showFiles.bind(self)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
showFiles: function(e){
|
||||||
|
var self = this;
|
||||||
|
(e).preventDefault();
|
||||||
|
|
||||||
|
if(!self.options_container){
|
||||||
|
self.options_container = new Element('div.options').adopt(
|
||||||
|
self.files_container = new Element('div.files.table')
|
||||||
|
).inject(self.movie, 'top');
|
||||||
|
|
||||||
|
// Header
|
||||||
|
new Element('div.item.head').adopt(
|
||||||
|
new Element('span.name', {'text': 'File'}),
|
||||||
|
new Element('span.type', {'text': 'Type'}),
|
||||||
|
new Element('span.is_available', {'text': 'Available'})
|
||||||
|
).inject(self.files_container)
|
||||||
|
|
||||||
|
Array.each(self.movie.data.releases, function(release){
|
||||||
|
|
||||||
|
var rel = new Element('div.release').inject(self.files_container);
|
||||||
|
|
||||||
|
Array.each(release.files, function(file){
|
||||||
|
new Element('div.file.item').adopt(
|
||||||
|
new Element('span.name', {'text': file.path}),
|
||||||
|
new Element('span.type', {'text': File.Type.get(file.type_id).name}),
|
||||||
|
new Element('span.available', {'text': file.available})
|
||||||
|
).inject(rel)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
self.movie.slide('in', self.options_container);
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
@@ -1,11 +1,25 @@
|
|||||||
.movies {
|
.movies {
|
||||||
padding: 60px 0 20px;
|
padding: 60px 0 20px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.movies h2 {
|
.movies h2 {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.movies > .description {
|
||||||
|
position: absolute;
|
||||||
|
top: 30px;
|
||||||
|
right: 0;
|
||||||
|
font-style: italic;
|
||||||
|
text-shadow: none;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
.movies:hover > .description {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.movies.thumbs_list {
|
.movies.thumbs_list {
|
||||||
padding: 20px 0 20px;
|
padding: 20px 0 20px;
|
||||||
}
|
}
|
||||||
@@ -272,7 +286,7 @@
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
right: 0;
|
right: 0;
|
||||||
margin-right: 50px;
|
margin-right: 50px;
|
||||||
z-index: 2;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.movies .data .quality .available,
|
.movies .data .quality .available,
|
||||||
@@ -303,6 +317,11 @@
|
|||||||
line-height: 0;
|
line-height: 0;
|
||||||
margin-top: -25px;
|
margin-top: -25px;
|
||||||
}
|
}
|
||||||
|
.movies.thumbs_list .data .actions {
|
||||||
|
bottom: 8px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.movies .data:hover .action { opacity: 0.6; }
|
.movies .data:hover .action { opacity: 0.6; }
|
||||||
.movies .data:hover .action:hover { opacity: 1; }
|
.movies .data:hover .action:hover { opacity: 1; }
|
||||||
.movies.mass_edit_list .data .actions {
|
.movies.mass_edit_list .data .actions {
|
||||||
@@ -505,7 +524,7 @@
|
|||||||
.movies .alph_nav {
|
.movies .alph_nav {
|
||||||
transition: box-shadow .4s linear;
|
transition: box-shadow .4s linear;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 2;
|
z-index: 4;
|
||||||
top: 0;
|
top: 0;
|
||||||
padding: 100px 60px 7px;
|
padding: 100px 60px 7px;
|
||||||
width: 1080px;
|
width: 1080px;
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ var Movie = new Class({
|
|||||||
var self = this;
|
var self = this;
|
||||||
self.mask = new Element('div.mask', {
|
self.mask = new Element('div.mask', {
|
||||||
'styles': {
|
'styles': {
|
||||||
'z-index': '1'
|
'z-index': 4
|
||||||
}
|
}
|
||||||
}).inject(self.el, 'top').fade('hide');
|
}).inject(self.el, 'top').fade('hide');
|
||||||
},
|
},
|
||||||
@@ -290,395 +290,4 @@ var Movie = new Class({
|
|||||||
return this.el;
|
return this.el;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
var MovieAction = new Class({
|
|
||||||
|
|
||||||
class_name: 'action icon',
|
|
||||||
|
|
||||||
initialize: function(movie){
|
|
||||||
var self = this;
|
|
||||||
self.movie = movie;
|
|
||||||
|
|
||||||
self.create();
|
|
||||||
if(self.el)
|
|
||||||
self.el.addClass(self.class_name)
|
|
||||||
},
|
|
||||||
|
|
||||||
create: function(){},
|
|
||||||
|
|
||||||
disable: function(){
|
|
||||||
this.el.addClass('disable')
|
|
||||||
},
|
|
||||||
|
|
||||||
enable: function(){
|
|
||||||
this.el.removeClass('disable')
|
|
||||||
},
|
|
||||||
|
|
||||||
createMask: function(){
|
|
||||||
var self = this;
|
|
||||||
self.mask = new Element('div.mask', {
|
|
||||||
'styles': {
|
|
||||||
'z-index': '1'
|
|
||||||
}
|
|
||||||
}).inject(self.movie, 'top').fade('hide');
|
|
||||||
//self.positionMask();
|
|
||||||
},
|
|
||||||
|
|
||||||
positionMask: function(){
|
|
||||||
var self = this,
|
|
||||||
movie = $(self.movie),
|
|
||||||
s = movie.getSize()
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
return self.mask.setStyles({
|
|
||||||
'width': s.x,
|
|
||||||
'height': s.y
|
|
||||||
}).position({
|
|
||||||
'relativeTo': movie
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
toElement: function(){
|
|
||||||
return this.el || null
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
var IMDBAction = new Class({
|
|
||||||
|
|
||||||
Extends: MovieAction,
|
|
||||||
id: null,
|
|
||||||
|
|
||||||
create: function(){
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
self.id = self.movie.get('identifier');
|
|
||||||
|
|
||||||
self.el = new Element('a.imdb', {
|
|
||||||
'title': 'Go to the IMDB page of ' + self.movie.getTitle(),
|
|
||||||
'href': 'http://www.imdb.com/title/'+self.id+'/',
|
|
||||||
'target': '_blank'
|
|
||||||
});
|
|
||||||
|
|
||||||
if(!self.id) self.disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
var ReleaseAction = new Class({
|
|
||||||
|
|
||||||
Extends: MovieAction,
|
|
||||||
|
|
||||||
create: function(){
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
self.el = new Element('a.releases.icon.download', {
|
|
||||||
'title': 'Show the releases that are available for ' + self.movie.getTitle(),
|
|
||||||
'events': {
|
|
||||||
'click': self.show.bind(self)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if(self.movie.data.releases.length == 0){
|
|
||||||
self.el.hide()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
var buttons_done = false;
|
|
||||||
|
|
||||||
self.movie.data.releases.sortBy('-info.score').each(function(release){
|
|
||||||
if(buttons_done) return;
|
|
||||||
|
|
||||||
var status = Status.get(release.status_id);
|
|
||||||
|
|
||||||
if((self.next_release && (status.identifier == 'ignored' || status.identifier == 'failed')) || (!self.next_release && status.identifier == 'available')){
|
|
||||||
self.hide_on_click = false;
|
|
||||||
self.show();
|
|
||||||
buttons_done = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
show: function(e){
|
|
||||||
var self = this;
|
|
||||||
if(e)
|
|
||||||
(e).preventDefault();
|
|
||||||
|
|
||||||
if(!self.options_container){
|
|
||||||
self.options_container = new Element('div.options').adopt(
|
|
||||||
self.release_container = new Element('div.releases.table').adopt(
|
|
||||||
self.trynext_container = new Element('div.buttons.try_container')
|
|
||||||
)
|
|
||||||
).inject(self.movie, 'top');
|
|
||||||
|
|
||||||
// Header
|
|
||||||
new Element('div.item.head').adopt(
|
|
||||||
new Element('span.name', {'text': 'Release name'}),
|
|
||||||
new Element('span.status', {'text': 'Status'}),
|
|
||||||
new Element('span.quality', {'text': 'Quality'}),
|
|
||||||
new Element('span.size', {'text': 'Size'}),
|
|
||||||
new Element('span.age', {'text': 'Age'}),
|
|
||||||
new Element('span.score', {'text': 'Score'}),
|
|
||||||
new Element('span.provider', {'text': 'Provider'})
|
|
||||||
).inject(self.release_container)
|
|
||||||
|
|
||||||
self.movie.data.releases.sortBy('-info.score').each(function(release){
|
|
||||||
|
|
||||||
var status = Status.get(release.status_id),
|
|
||||||
quality = Quality.getProfile(release.quality_id) || {},
|
|
||||||
info = release.info,
|
|
||||||
provider = self.get(release, 'provider') + (release.info['provider_extra'] ? self.get(release, 'provider_extra') : '');
|
|
||||||
release.status = status;
|
|
||||||
|
|
||||||
// Create release
|
|
||||||
new Element('div', {
|
|
||||||
'class': 'item '+status.identifier,
|
|
||||||
'id': 'release_'+release.id
|
|
||||||
}).adopt(
|
|
||||||
new Element('span.name', {'text': self.get(release, 'name'), 'title': self.get(release, 'name')}),
|
|
||||||
new Element('span.status', {'text': status.identifier, 'class': 'release_status '+status.identifier}),
|
|
||||||
new Element('span.quality', {'text': quality.get('label') || 'n/a'}),
|
|
||||||
new Element('span.size', {'text': release.info['size'] ? Math.floor(self.get(release, 'size')) : 'n/a'}),
|
|
||||||
new Element('span.age', {'text': self.get(release, 'age')}),
|
|
||||||
new Element('span.score', {'text': self.get(release, 'score')}),
|
|
||||||
new Element('span.provider', { 'text': provider, 'title': provider }),
|
|
||||||
release.info['detail_url'] ? new Element('a.info.icon', {
|
|
||||||
'href': release.info['detail_url'],
|
|
||||||
'target': '_blank'
|
|
||||||
}) : null,
|
|
||||||
new Element('a.download.icon', {
|
|
||||||
'events': {
|
|
||||||
'click': function(e){
|
|
||||||
(e).preventDefault();
|
|
||||||
if(!this.hasClass('completed'))
|
|
||||||
self.download(release);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
new Element('a.delete.icon', {
|
|
||||||
'events': {
|
|
||||||
'click': function(e){
|
|
||||||
(e).preventDefault();
|
|
||||||
self.ignore(release);
|
|
||||||
this.getParent('.item').toggleClass('ignored')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
).inject(self.release_container)
|
|
||||||
|
|
||||||
if(status.identifier == 'ignored' || status.identifier == 'failed' || status.identifier == 'snatched'){
|
|
||||||
if(!self.last_release || (self.last_release && self.last_release.status.identifier != 'snatched' && status.identifier == 'snatched'))
|
|
||||||
self.last_release = release;
|
|
||||||
}
|
|
||||||
else if(!self.next_release && status.identifier == 'available'){
|
|
||||||
self.next_release = release;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if(self.last_release){
|
|
||||||
self.release_container.getElement('#release_'+self.last_release.id).addClass('last_release');
|
|
||||||
}
|
|
||||||
|
|
||||||
if(self.next_release){
|
|
||||||
self.release_container.getElement('#release_'+self.next_release.id).addClass('next_release');
|
|
||||||
}
|
|
||||||
|
|
||||||
if(self.next_release || self.last_release){
|
|
||||||
|
|
||||||
self.trynext_container.adopt(
|
|
||||||
new Element('span.or', {
|
|
||||||
'text': 'This movie is snatched, if anything went wrong, download'
|
|
||||||
}),
|
|
||||||
self.last_release ? new Element('a.button.orange', {
|
|
||||||
'text': 'the same release again',
|
|
||||||
'events': {
|
|
||||||
'click': self.trySameRelease.bind(self)
|
|
||||||
}
|
|
||||||
}) : null,
|
|
||||||
self.next_release && self.last_release ? new Element('span.or', {
|
|
||||||
'text': ','
|
|
||||||
}) : null,
|
|
||||||
self.next_release ? [new Element('a.button.green', {
|
|
||||||
'text': self.last_release ? 'another release' : 'the best release',
|
|
||||||
'events': {
|
|
||||||
'click': self.tryNextRelease.bind(self)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
new Element('span.or', {
|
|
||||||
'text': 'or pick one below'
|
|
||||||
})] : null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
self.movie.slide('in', self.options_container);
|
|
||||||
},
|
|
||||||
|
|
||||||
get: function(release, type){
|
|
||||||
return release.info[type] || 'n/a'
|
|
||||||
},
|
|
||||||
|
|
||||||
download: function(release){
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
var release_el = self.release_container.getElement('#release_'+release.id),
|
|
||||||
icon = release_el.getElement('.download.icon');
|
|
||||||
|
|
||||||
icon.addClass('spinner');
|
|
||||||
|
|
||||||
Api.request('release.download', {
|
|
||||||
'data': {
|
|
||||||
'id': release.id
|
|
||||||
},
|
|
||||||
'onComplete': function(json){
|
|
||||||
icon.removeClass('spinner')
|
|
||||||
if(json.success)
|
|
||||||
icon.addClass('completed');
|
|
||||||
else
|
|
||||||
icon.addClass('attention').set('title', 'Something went wrong when downloading, please check logs.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
ignore: function(release){
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
Api.request('release.ignore', {
|
|
||||||
'data': {
|
|
||||||
'id': release.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
tryNextRelease: function(movie_id){
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
if(self.last_release)
|
|
||||||
self.ignore(self.last_release);
|
|
||||||
|
|
||||||
if(self.next_release)
|
|
||||||
self.download(self.next_release);
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
trySameRelease: function(movie_id){
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
if(self.last_release)
|
|
||||||
self.download(self.last_release);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
var TrailerAction = new Class({
|
|
||||||
|
|
||||||
Extends: MovieAction,
|
|
||||||
id: null,
|
|
||||||
|
|
||||||
create: function(){
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
self.el = new Element('a.trailer', {
|
|
||||||
'title': 'Watch the trailer of ' + self.movie.getTitle(),
|
|
||||||
'events': {
|
|
||||||
'click': self.watch.bind(self)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: function(offset){
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
var data_url = 'http://gdata.youtube.com/feeds/videos?vq="{title}" {year} trailer&max-results=1&alt=json-in-script&orderby=relevance&sortorder=descending&format=5&fmt=18'
|
|
||||||
var url = data_url.substitute({
|
|
||||||
'title': encodeURI(self.movie.getTitle()),
|
|
||||||
'year': self.movie.get('year'),
|
|
||||||
'offset': offset || 1
|
|
||||||
}),
|
|
||||||
size = $(self.movie).getSize(),
|
|
||||||
height = (size.x/16)*9,
|
|
||||||
id = 'trailer-'+randomString();
|
|
||||||
|
|
||||||
self.player_container = new Element('div[id='+id+']');
|
|
||||||
self.container = new Element('div.hide.trailer_container')
|
|
||||||
.adopt(self.player_container)
|
|
||||||
.inject($(self.movie), 'top');
|
|
||||||
|
|
||||||
self.container.setStyle('height', 0);
|
|
||||||
self.container.removeClass('hide');
|
|
||||||
|
|
||||||
self.close_button = new Element('a.hide.hide_trailer', {
|
|
||||||
'text': 'Hide trailer',
|
|
||||||
'events': {
|
|
||||||
'click': self.stop.bind(self)
|
|
||||||
}
|
|
||||||
}).inject(self.movie);
|
|
||||||
|
|
||||||
self.container.setStyle('height', height);
|
|
||||||
$(self.movie).setStyle('height', height);
|
|
||||||
|
|
||||||
new Request.JSONP({
|
|
||||||
'url': url,
|
|
||||||
'onComplete': function(json){
|
|
||||||
var video_url = json.feed.entry[0].id.$t.split('/'),
|
|
||||||
video_id = video_url[video_url.length-1];
|
|
||||||
|
|
||||||
self.player = new YT.Player(id, {
|
|
||||||
'height': height,
|
|
||||||
'width': size.x,
|
|
||||||
'videoId': video_id,
|
|
||||||
'playerVars': {
|
|
||||||
'autoplay': 1,
|
|
||||||
'showsearch': 0,
|
|
||||||
'wmode': 'transparent',
|
|
||||||
'iv_load_policy': 3
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
self.close_button.removeClass('hide');
|
|
||||||
|
|
||||||
var quality_set = false;
|
|
||||||
var change_quality = function(state){
|
|
||||||
if(!quality_set && (state.data == 1 || state.data || 2)){
|
|
||||||
try {
|
|
||||||
self.player.setPlaybackQuality('hd720');
|
|
||||||
quality_set = true;
|
|
||||||
}
|
|
||||||
catch(e){
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.player.addEventListener('onStateChange', change_quality);
|
|
||||||
|
|
||||||
}
|
|
||||||
}).send()
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
stop: function(){
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
self.player.stopVideo();
|
|
||||||
self.container.addClass('hide');
|
|
||||||
self.close_button.addClass('hide');
|
|
||||||
$(self.movie).setStyle('height', null);
|
|
||||||
|
|
||||||
setTimeout(function(){
|
|
||||||
self.container.destroy()
|
|
||||||
self.close_button.destroy();
|
|
||||||
}, 1800)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -202,7 +202,8 @@
|
|||||||
.movie_result .info h2 span:before { content: "("; }
|
.movie_result .info h2 span:before { content: "("; }
|
||||||
.movie_result .info h2 span:after { content: ")"; }
|
.movie_result .info h2 span:after { content: ")"; }
|
||||||
|
|
||||||
.search_form .mask {
|
.search_form .mask,
|
||||||
|
.movie_result .mask {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ Block.Search.Item = new Class({
|
|||||||
loadingMask: function(){
|
loadingMask: function(){
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self.mask = new Element('span.mask').inject(self.el).fade('hide')
|
self.mask = new Element('div.mask').inject(self.el).fade('hide')
|
||||||
|
|
||||||
createSpinner(self.mask)
|
createSpinner(self.mask)
|
||||||
self.mask.fade('in')
|
self.mask.fade('in')
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import errno
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
log = CPLog(__name__)
|
log = CPLog(__name__)
|
||||||
@@ -275,6 +276,7 @@ class Renamer(Plugin):
|
|||||||
for profile_type in movie.profile.types:
|
for profile_type in movie.profile.types:
|
||||||
if profile_type.quality_id == group['meta_data']['quality']['id'] and profile_type.finish:
|
if profile_type.quality_id == group['meta_data']['quality']['id'] and profile_type.finish:
|
||||||
movie.status_id = done_status.get('id')
|
movie.status_id = done_status.get('id')
|
||||||
|
movie.last_edit = int(time.time())
|
||||||
db.commit()
|
db.commit()
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
log.error('Failed marking movie finished: %s %s', (e, traceback.format_exc()))
|
log.error('Failed marking movie finished: %s %s', (e, traceback.format_exc()))
|
||||||
@@ -316,8 +318,10 @@ class Renamer(Plugin):
|
|||||||
log.debug('Marking release as downloaded')
|
log.debug('Marking release as downloaded')
|
||||||
try:
|
try:
|
||||||
release.status_id = downloaded_status.get('id')
|
release.status_id = downloaded_status.get('id')
|
||||||
|
release.last_edit = int(time.time())
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
log.error('Failed marking release as finished: %s %s', (e, traceback.format_exc()))
|
log.error('Failed marking release as finished: %s %s', (e, traceback.format_exc()))
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
# Remove leftover files
|
# Remove leftover files
|
||||||
@@ -556,6 +560,7 @@ class Renamer(Plugin):
|
|||||||
if rel.movie.status_id == done_status.get('id'):
|
if rel.movie.status_id == done_status.get('id'):
|
||||||
log.debug('Found a completed movie with a snatched release : %s. Setting release status to ignored...' , default_title)
|
log.debug('Found a completed movie with a snatched release : %s. Setting release status to ignored...' , default_title)
|
||||||
rel.status_id = ignored_status.get('id')
|
rel.status_id = ignored_status.get('id')
|
||||||
|
rel.last_edit = int(time.time())
|
||||||
db.commit()
|
db.commit()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -580,6 +585,7 @@ class Renamer(Plugin):
|
|||||||
fireEvent('searcher.try_next_release', movie_id = rel.movie_id)
|
fireEvent('searcher.try_next_release', movie_id = rel.movie_id)
|
||||||
else:
|
else:
|
||||||
rel.status_id = failed_status.get('id')
|
rel.status_id = failed_status.get('id')
|
||||||
|
rel.last_edit = int(time.time())
|
||||||
db.commit()
|
db.commit()
|
||||||
elif item['status'] == 'completed':
|
elif item['status'] == 'completed':
|
||||||
log.info('Download of %s completed!', item['name'])
|
log.info('Download of %s completed!', item['name'])
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ class Searcher(Plugin):
|
|||||||
|
|
||||||
# See if better quality is available
|
# See if better quality is available
|
||||||
for release in movie['releases']:
|
for release in movie['releases']:
|
||||||
if release['quality']['order'] <= quality_type['quality']['order'] and release['status_id'] not in [available_status.get('id'), ignored_status.get('id')]:
|
if release['quality']['order'] < quality_type['quality']['order'] and release['status_id'] not in [available_status.get('id'), ignored_status.get('id')]:
|
||||||
has_better_quality += 1
|
has_better_quality += 1
|
||||||
|
|
||||||
# Don't search for quality lower then already available.
|
# Don't search for quality lower then already available.
|
||||||
@@ -209,6 +209,7 @@ class Searcher(Plugin):
|
|||||||
db.add(rls)
|
db.add(rls)
|
||||||
else:
|
else:
|
||||||
[db.delete(old_info) for old_info in rls.info]
|
[db.delete(old_info) for old_info in rls.info]
|
||||||
|
rls.last_edit = int(time.time())
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
@@ -293,7 +294,10 @@ class Searcher(Plugin):
|
|||||||
db = get_session()
|
db = get_session()
|
||||||
rls = db.query(Release).filter_by(identifier = md5(data['url'])).first()
|
rls = db.query(Release).filter_by(identifier = md5(data['url'])).first()
|
||||||
if rls:
|
if rls:
|
||||||
rls.status_id = snatched_status.get('id')
|
renamer_enabled = Env.setting('enabled', 'renamer')
|
||||||
|
|
||||||
|
done_status = fireEvent('status.get', 'done', single = True)
|
||||||
|
rls.status_id = done_status.get('id') if not renamer_enabled else snatched_status.get('id')
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
log_movie = '%s (%s) in %s' % (getTitle(movie['library']), movie['library']['year'], rls.quality.label)
|
log_movie = '%s (%s) in %s' % (getTitle(movie['library']), movie['library']['year'], rls.quality.label)
|
||||||
@@ -301,26 +305,28 @@ class Searcher(Plugin):
|
|||||||
log.info(snatch_message)
|
log.info(snatch_message)
|
||||||
fireEvent('movie.snatched', message = snatch_message, data = rls.to_dict())
|
fireEvent('movie.snatched', message = snatch_message, data = rls.to_dict())
|
||||||
|
|
||||||
# If renamer isn't used, mark movie done
|
# If renamer isn't used, mark movie done
|
||||||
if not Env.setting('enabled', 'renamer'):
|
if not renamer_enabled:
|
||||||
active_status = fireEvent('status.get', 'active', single = True)
|
active_status = fireEvent('status.get', 'active', single = True)
|
||||||
done_status = fireEvent('status.get', 'done', single = True)
|
done_status = fireEvent('status.get', 'done', single = True)
|
||||||
try:
|
try:
|
||||||
if movie['status_id'] == active_status.get('id'):
|
if movie['status_id'] == active_status.get('id'):
|
||||||
for profile_type in movie['profile']['types']:
|
for profile_type in movie['profile']['types']:
|
||||||
if rls and profile_type['quality_id'] == rls.quality.id and profile_type['finish']:
|
if profile_type['quality_id'] == rls.quality.id and profile_type['finish']:
|
||||||
log.info('Renamer disabled, marking movie as finished: %s', log_movie)
|
log.info('Renamer disabled, marking movie as finished: %s', log_movie)
|
||||||
|
|
||||||
# Mark release done
|
# Mark release done
|
||||||
rls.status_id = done_status.get('id')
|
rls.status_id = done_status.get('id')
|
||||||
db.commit()
|
rls.last_edit = int(time.time())
|
||||||
|
db.commit()
|
||||||
|
|
||||||
# Mark movie done
|
# Mark movie done
|
||||||
mvie = db.query(Movie).filter_by(id = movie['id']).first()
|
mvie = db.query(Movie).filter_by(id = movie['id']).first()
|
||||||
mvie.status_id = done_status.get('id')
|
mvie.status_id = done_status.get('id')
|
||||||
db.commit()
|
mvie.last_edit = int(time.time())
|
||||||
except:
|
db.commit()
|
||||||
log.error('Failed marking movie finished, renamer disabled: %s', traceback.format_exc())
|
except:
|
||||||
|
log.error('Failed marking movie finished, renamer disabled: %s', traceback.format_exc())
|
||||||
|
|
||||||
except:
|
except:
|
||||||
log.error('Failed marking movie finished: %s', traceback.format_exc())
|
log.error('Failed marking movie finished: %s', traceback.format_exc())
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ Page.Wizard = new Class({
|
|||||||
'target': self.el
|
'target': self.el
|
||||||
},
|
},
|
||||||
'onComplete': function(){
|
'onComplete': function(){
|
||||||
window.location = App.createUrl();
|
window.location = App.createUrl('wanted');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class Movie(Entity):
|
|||||||
The files belonging to the movie object are global for the whole movie
|
The files belonging to the movie object are global for the whole movie
|
||||||
such as trailers, nfo, thumbnails"""
|
such as trailers, nfo, thumbnails"""
|
||||||
|
|
||||||
last_edit = Field(Integer, default = lambda: int(time.time()))
|
last_edit = Field(Integer, default = lambda: int(time.time()), index = True)
|
||||||
|
|
||||||
library = ManyToOne('Library', cascade = 'delete, delete-orphan', single_parent = True)
|
library = ManyToOne('Library', cascade = 'delete, delete-orphan', single_parent = True)
|
||||||
status = ManyToOne('Status')
|
status = ManyToOne('Status')
|
||||||
@@ -95,6 +95,7 @@ class Release(Entity):
|
|||||||
"""Logically groups all files that belong to a certain release, such as
|
"""Logically groups all files that belong to a certain release, such as
|
||||||
parts of a movie, subtitles."""
|
parts of a movie, subtitles."""
|
||||||
|
|
||||||
|
last_edit = Field(Integer, default = lambda: int(time.time()), index = True)
|
||||||
identifier = Field(String(100), index = True)
|
identifier = Field(String(100), index = True)
|
||||||
|
|
||||||
movie = ManyToOne('Movie')
|
movie = ManyToOne('Movie')
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 778 B |
@@ -8,8 +8,14 @@ Page.Home = new Class({
|
|||||||
indexAction: function(param){
|
indexAction: function(param){
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if(self.soon_list)
|
if(self.soon_list){
|
||||||
|
|
||||||
|
// Reset lists
|
||||||
|
self.available_list.update();
|
||||||
|
self.late_list.update();
|
||||||
|
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Snatched
|
// Snatched
|
||||||
self.available_list = new MovieList({
|
self.available_list = new MovieList({
|
||||||
@@ -17,48 +23,55 @@ Page.Home = new Class({
|
|||||||
'identifier': 'snatched',
|
'identifier': 'snatched',
|
||||||
'load_more': false,
|
'load_more': false,
|
||||||
'view': 'list',
|
'view': 'list',
|
||||||
'actions': MovieActions,
|
'actions': [MA.IMDB, MA.Trailer, MA.Files, MA.Release, MA.Edit, MA.Readd, MA.Refresh, MA.Delete],
|
||||||
'title': 'Snatched & Available',
|
'title': 'Snatched & Available',
|
||||||
|
'on_empty_element': new Element('div'),
|
||||||
'filter': {
|
'filter': {
|
||||||
'release_status': 'snatched,available'
|
'release_status': 'snatched,available'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Downloaded
|
// Coming Soon
|
||||||
// self.downloaded_list = new MovieList({
|
|
||||||
// 'navigation': false,
|
|
||||||
// 'identifier': 'downloaded',
|
|
||||||
// 'load_more': false,
|
|
||||||
// 'view': 'titles',
|
|
||||||
// 'filter': {
|
|
||||||
// 'release_status': 'done',
|
|
||||||
// 'order': 'release_order'
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// self.el.adopt(
|
|
||||||
// new Element('h2', {
|
|
||||||
// 'text': 'Just downloaded'
|
|
||||||
// }),
|
|
||||||
// $(self.downloaded_list)
|
|
||||||
// );
|
|
||||||
|
|
||||||
// Comming Soon
|
|
||||||
self.soon_list = new MovieList({
|
self.soon_list = new MovieList({
|
||||||
'navigation': false,
|
'navigation': false,
|
||||||
'identifier': 'soon',
|
'identifier': 'soon',
|
||||||
'limit': 24,
|
'limit': 18,
|
||||||
'title': 'Soon',
|
'title': 'Available soon',
|
||||||
|
'description': 'These are being searches 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(
|
||||||
|
new Element('h1', {'text': 'Available soon'}),
|
||||||
|
new Element('span', {'text': 'There are no movies available soon. Add some movies, so you have something to watch later.'})
|
||||||
|
),
|
||||||
'filter': {
|
'filter': {
|
||||||
'random': true
|
'random': true
|
||||||
},
|
},
|
||||||
|
'actions': [MA.IMDB, MA.Refresh],
|
||||||
'load_more': false,
|
'load_more': false,
|
||||||
'view': 'thumbs',
|
'view': 'thumbs',
|
||||||
'api_call': 'dashboard.soon'
|
'api_call': 'dashboard.soon'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Still not available
|
||||||
|
self.late_list = new MovieList({
|
||||||
|
'navigation': false,
|
||||||
|
'identifier': 'late',
|
||||||
|
'limit': 50,
|
||||||
|
'title': 'Still not available',
|
||||||
|
'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': {
|
||||||
|
'late': true
|
||||||
|
},
|
||||||
|
'load_more': false,
|
||||||
|
'view': 'list',
|
||||||
|
'actions': [MA.IMDB, MA.Trailer, MA.Edit, MA.Refresh, MA.Delete],
|
||||||
|
'api_call': 'dashboard.soon'
|
||||||
|
});
|
||||||
|
|
||||||
self.el.adopt(
|
self.el.adopt(
|
||||||
$(self.available_list),
|
$(self.available_list),
|
||||||
$(self.soon_list)
|
$(self.soon_list),
|
||||||
|
$(self.late_list)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Suggest
|
// Suggest
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ Page.Manage = new Class({
|
|||||||
'filter': {
|
'filter': {
|
||||||
'release_status': 'done'
|
'release_status': 'done'
|
||||||
},
|
},
|
||||||
'actions': MovieActions,
|
'actions': [MA.IMDB, MA.Trailer, MA.Files, MA.Readd, MA.Edit, MA.Delete],
|
||||||
'menu': [self.refresh_button, self.refresh_quick],
|
'menu': [self.refresh_button, self.refresh_quick],
|
||||||
'on_empty_element': new Element('div.empty_manage').adopt(
|
'on_empty_element': new Element('div.empty_manage').adopt(
|
||||||
new Element('div', {
|
new Element('div', {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ Page.Wanted = new Class({
|
|||||||
self.wanted = new MovieList({
|
self.wanted = new MovieList({
|
||||||
'identifier': 'wanted',
|
'identifier': 'wanted',
|
||||||
'status': 'active',
|
'status': 'active',
|
||||||
'actions': MovieActions,
|
'actions': [MA.IMDB, MA.Trailer, MA.Release, MA.Edit, MA.Refresh, MA.Readd, MA.Delete],
|
||||||
'add_new': true,
|
'add_new': true,
|
||||||
'menu': [self.manual_search],
|
'menu': [self.manual_search],
|
||||||
'on_empty_element': App.createUserscriptButtons().addClass('empty_wanted')
|
'on_empty_element': App.createUserscriptButtons().addClass('empty_wanted')
|
||||||
@@ -71,283 +71,4 @@ Page.Wanted = new Class({
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var MovieActions = {};
|
|
||||||
window.addEvent('domready', function(){
|
|
||||||
|
|
||||||
MovieActions.Wanted = {
|
|
||||||
'IMDB': IMDBAction
|
|
||||||
,'Trailer': TrailerAction
|
|
||||||
,'Releases': ReleaseAction
|
|
||||||
,'Edit': new Class({
|
|
||||||
|
|
||||||
Extends: MovieAction,
|
|
||||||
|
|
||||||
create: function(){
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
self.el = new Element('a.edit', {
|
|
||||||
'title': 'Change movie information, like title and quality.',
|
|
||||||
'events': {
|
|
||||||
'click': self.editMovie.bind(self)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
editMovie: function(e){
|
|
||||||
var self = this;
|
|
||||||
(e).preventDefault();
|
|
||||||
|
|
||||||
if(!self.options_container){
|
|
||||||
self.options_container = new Element('div.options').adopt(
|
|
||||||
new Element('div.form').adopt(
|
|
||||||
self.title_select = new Element('select', {
|
|
||||||
'name': 'title'
|
|
||||||
}),
|
|
||||||
self.profile_select = new Element('select', {
|
|
||||||
'name': 'profile'
|
|
||||||
}),
|
|
||||||
new Element('a.button.edit', {
|
|
||||||
'text': 'Save & Search',
|
|
||||||
'events': {
|
|
||||||
'click': self.save.bind(self)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
).inject(self.movie, 'top');
|
|
||||||
|
|
||||||
Array.each(self.movie.data.library.titles, function(alt){
|
|
||||||
new Element('option', {
|
|
||||||
'text': alt.title
|
|
||||||
}).inject(self.title_select);
|
|
||||||
|
|
||||||
if(alt['default'])
|
|
||||||
self.title_select.set('value', alt.title);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
Quality.getActiveProfiles().each(function(profile){
|
|
||||||
|
|
||||||
var profile_id = profile.id ? profile.id : profile.data.id;
|
|
||||||
|
|
||||||
new Element('option', {
|
|
||||||
'value': profile_id,
|
|
||||||
'text': profile.label ? profile.label : profile.data.label
|
|
||||||
}).inject(self.profile_select);
|
|
||||||
|
|
||||||
if(self.movie.profile && self.movie.profile.data && self.movie.profile.data.id == profile_id)
|
|
||||||
self.profile_select.set('value', profile_id);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
self.movie.slide('in', self.options_container);
|
|
||||||
},
|
|
||||||
|
|
||||||
save: function(e){
|
|
||||||
(e).preventDefault();
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
Api.request('movie.edit', {
|
|
||||||
'data': {
|
|
||||||
'id': self.movie.get('id'),
|
|
||||||
'default_title': self.title_select.get('value'),
|
|
||||||
'profile_id': self.profile_select.get('value')
|
|
||||||
},
|
|
||||||
'useSpinner': true,
|
|
||||||
'spinnerTarget': $(self.movie),
|
|
||||||
'onComplete': function(){
|
|
||||||
self.movie.quality.set('text', self.profile_select.getSelected()[0].get('text'));
|
|
||||||
self.movie.title.set('text', self.title_select.getSelected()[0].get('text'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
self.movie.slide('out');
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
,'Refresh': new Class({
|
|
||||||
|
|
||||||
Extends: MovieAction,
|
|
||||||
|
|
||||||
create: function(){
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
self.el = new Element('a.refresh', {
|
|
||||||
'title': 'Refresh the movie info and do a forced search',
|
|
||||||
'events': {
|
|
||||||
'click': self.doRefresh.bind(self)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
doRefresh: function(e){
|
|
||||||
var self = this;
|
|
||||||
(e).preventDefault();
|
|
||||||
|
|
||||||
Api.request('movie.refresh', {
|
|
||||||
'data': {
|
|
||||||
'id': self.movie.get('id')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
,'Delete': new Class({
|
|
||||||
|
|
||||||
Extends: MovieAction,
|
|
||||||
|
|
||||||
Implements: [Chain],
|
|
||||||
|
|
||||||
create: function(){
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
self.el = new Element('a.delete', {
|
|
||||||
'title': 'Remove the movie from this CP list',
|
|
||||||
'events': {
|
|
||||||
'click': self.showConfirm.bind(self)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
showConfirm: function(e){
|
|
||||||
var self = this;
|
|
||||||
(e).preventDefault();
|
|
||||||
|
|
||||||
if(!self.delete_container){
|
|
||||||
self.delete_container = new Element('div.buttons.delete_container').adopt(
|
|
||||||
new Element('a.cancel', {
|
|
||||||
'text': 'Cancel',
|
|
||||||
'events': {
|
|
||||||
'click': self.hideConfirm.bind(self)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
new Element('span.or', {
|
|
||||||
'text': 'or'
|
|
||||||
}),
|
|
||||||
new Element('a.button.delete', {
|
|
||||||
'text': 'Delete ' + self.movie.title.get('text'),
|
|
||||||
'events': {
|
|
||||||
'click': self.del.bind(self)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
).inject(self.movie, 'top');
|
|
||||||
}
|
|
||||||
|
|
||||||
self.movie.slide('in', self.delete_container);
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
hideConfirm: function(e){
|
|
||||||
var self = this;
|
|
||||||
(e).preventDefault();
|
|
||||||
|
|
||||||
self.movie.slide('out');
|
|
||||||
},
|
|
||||||
|
|
||||||
del: function(e){
|
|
||||||
(e).preventDefault();
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
var movie = $(self.movie);
|
|
||||||
|
|
||||||
self.chain(
|
|
||||||
function(){
|
|
||||||
self.callChain();
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
Api.request('movie.delete', {
|
|
||||||
'data': {
|
|
||||||
'id': self.movie.get('id'),
|
|
||||||
'delete_from': self.movie.list.options.identifier
|
|
||||||
},
|
|
||||||
'onComplete': function(){
|
|
||||||
movie.set('tween', {
|
|
||||||
'duration': 300,
|
|
||||||
'onComplete': function(){
|
|
||||||
self.movie.destroy()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
movie.tween('height', 0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
self.callChain();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
MovieActions.Snatched = {
|
|
||||||
'IMDB': IMDBAction
|
|
||||||
,'Delete': MovieActions.Wanted.Delete
|
|
||||||
};
|
|
||||||
|
|
||||||
MovieActions.Done = {
|
|
||||||
'IMDB': IMDBAction
|
|
||||||
,'Edit': MovieActions.Wanted.Edit
|
|
||||||
,'Trailer': TrailerAction
|
|
||||||
,'Files': new Class({
|
|
||||||
|
|
||||||
Extends: MovieAction,
|
|
||||||
|
|
||||||
create: function(){
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
self.el = new Element('a.directory', {
|
|
||||||
'title': 'Available files',
|
|
||||||
'events': {
|
|
||||||
'click': self.showFiles.bind(self)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
showFiles: function(e){
|
|
||||||
var self = this;
|
|
||||||
(e).preventDefault();
|
|
||||||
|
|
||||||
if(!self.options_container){
|
|
||||||
self.options_container = new Element('div.options').adopt(
|
|
||||||
self.files_container = new Element('div.files.table')
|
|
||||||
).inject(self.movie, 'top');
|
|
||||||
|
|
||||||
// Header
|
|
||||||
new Element('div.item.head').adopt(
|
|
||||||
new Element('span.name', {'text': 'File'}),
|
|
||||||
new Element('span.type', {'text': 'Type'}),
|
|
||||||
new Element('span.is_available', {'text': 'Available'})
|
|
||||||
).inject(self.files_container)
|
|
||||||
|
|
||||||
Array.each(self.movie.data.releases, function(release){
|
|
||||||
|
|
||||||
var rel = new Element('div.release').inject(self.files_container);
|
|
||||||
|
|
||||||
Array.each(release.files, function(file){
|
|
||||||
new Element('div.file.item').adopt(
|
|
||||||
new Element('span.name', {'text': file.path}),
|
|
||||||
new Element('span.type', {'text': File.Type.get(file.type_id).name}),
|
|
||||||
new Element('span.available', {'text': file.available})
|
|
||||||
).inject(rel)
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
self.movie.slide('in', self.options_container);
|
|
||||||
},
|
|
||||||
|
|
||||||
})
|
|
||||||
,'Delete': MovieActions.Wanted.Delete
|
|
||||||
};
|
|
||||||
|
|
||||||
})
|
|
||||||
@@ -157,6 +157,7 @@ body > .spinner, .mask{
|
|||||||
.icon.folder { background-image: url('../images/icon.folder.png'); }
|
.icon.folder { background-image: url('../images/icon.folder.png'); }
|
||||||
.icon.imdb { background-image: url('../images/icon.imdb.png'); }
|
.icon.imdb { background-image: url('../images/icon.imdb.png'); }
|
||||||
.icon.refresh { background-image: url('../images/icon.refresh.png'); }
|
.icon.refresh { background-image: url('../images/icon.refresh.png'); }
|
||||||
|
.icon.readd { background-image: url('../images/icon.readd.png'); }
|
||||||
.icon.rating { background-image: url('../images/icon.rating.png'); }
|
.icon.rating { background-image: url('../images/icon.rating.png'); }
|
||||||
.icon.files { background-image: url('../images/icon.files.png'); }
|
.icon.files { background-image: url('../images/icon.files.png'); }
|
||||||
.icon.info { background-image: url('../images/icon.info.png'); }
|
.icon.info { background-image: url('../images/icon.info.png'); }
|
||||||
@@ -584,7 +585,7 @@ body > .spinner, .mask{
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
width: 240px;
|
width: 240px;
|
||||||
z-index: 2;
|
z-index: 20;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|||||||
+30
-25
@@ -12,51 +12,56 @@
|
|||||||
# Description: starts instance of CouchPotato using start-stop-daemon
|
# Description: starts instance of CouchPotato using start-stop-daemon
|
||||||
### END INIT INFO
|
### END INIT INFO
|
||||||
|
|
||||||
############### EDIT ME ##################
|
# Check for existance of defaults file
|
||||||
# path to app
|
# and utilze if available
|
||||||
APP_PATH=/usr/local/sbin/CouchPotatoServer/
|
if [ -f /etc/default/couchpotato ]; then
|
||||||
|
. /etc/default/couchpotato
|
||||||
|
else
|
||||||
|
echo "/etc/default/couchpotato not found using default settings.";
|
||||||
|
fi
|
||||||
|
|
||||||
# user
|
# Script name
|
||||||
RUN_AS=YOUR_USERNAME_HERE
|
|
||||||
|
|
||||||
# path to python bin
|
|
||||||
DAEMON=/usr/bin/python
|
|
||||||
|
|
||||||
# Path to store PID file
|
|
||||||
PID_FILE=/var/run/couchpotato.pid
|
|
||||||
|
|
||||||
# script name
|
|
||||||
NAME=couchpotato
|
NAME=couchpotato
|
||||||
|
|
||||||
# app name
|
# App name
|
||||||
DESC=CouchPotato
|
DESC=CouchPotato
|
||||||
|
|
||||||
# startup args
|
# Path to app root
|
||||||
DAEMON_OPTS=" CouchPotato.py --daemon --pid_file=${PID_FILE}"
|
CP_APP_PATH=${APP_PATH-/usr/local/sbin/CouchPotatoServer/}
|
||||||
|
|
||||||
############### END EDIT ME ##################
|
# User to run CP as
|
||||||
|
CP_RUN_AS=${RUN_AS-root}
|
||||||
|
|
||||||
test -x $DAEMON || exit 0
|
# Path to python bin
|
||||||
|
CP_DAEMON=${DAEMON_PATH-/usr/bin/python}
|
||||||
|
|
||||||
|
# Path to store PID file
|
||||||
|
CP_PID_FILE=${PID_FILE-/var/run/couchpotato.pid}
|
||||||
|
|
||||||
|
# Other startup args
|
||||||
|
CP_DAEMON_OPTS=" CouchPotato.py --daemon --pid_file=${CP_PID_FILE}"
|
||||||
|
|
||||||
|
test -x $CP_DAEMON || exit 0
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
start)
|
start)
|
||||||
echo "Starting $DESC"
|
echo "Starting $DESC"
|
||||||
rm -rf $PID_FILE || return 1
|
rm -rf $CP_PID_FILE || return 1
|
||||||
touch $PID_FILE
|
touch $CP_PID_FILE
|
||||||
chown $RUN_AS $PID_FILE
|
chown $CP_RUN_AS $CP_PID_FILE
|
||||||
start-stop-daemon -d $APP_PATH -c $RUN_AS --start --background --pidfile $PID_FILE --exec $DAEMON -- $DAEMON_OPTS
|
start-stop-daemon -d $CP_APP_PATH -c $CP_RUN_AS --start --background --pidfile $CP_PID_FILE --exec $CP_DAEMON -- $CP_DAEMON_OPTS
|
||||||
;;
|
;;
|
||||||
stop)
|
stop)
|
||||||
echo "Stopping $DESC"
|
echo "Stopping $DESC"
|
||||||
start-stop-daemon --stop --pidfile $PID_FILE --retry 15
|
start-stop-daemon --stop --pidfile $CP_PID_FILE --retry 15
|
||||||
;;
|
;;
|
||||||
|
|
||||||
restart|force-reload)
|
restart|force-reload)
|
||||||
echo "Restarting $DESC"
|
echo "Restarting $DESC"
|
||||||
start-stop-daemon --stop --pidfile $PID_FILE --retry 15
|
start-stop-daemon --stop --pidfile $CP_PID_FILE --retry 15
|
||||||
start-stop-daemon -d $APP_PATH -c $RUN_AS --start --background --pidfile $PID_FILE --exec $DAEMON -- $DAEMON_OPTS
|
start-stop-daemon -d $CP_APP_PATH -c $CP_RUN_AS --start --background --pidfile $CP_PID_FILE --exec $CP_DAEMON -- $CP_DAEMON_OPTS
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
N=/etc/init.d/$NAME
|
N=/etc/init.d/$NAME
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# COPY THIS FILE TO /etc/default/couchpotato
|
||||||
|
# OPTIONS: APP_PATH, RUN_AS, DAEMON_PATH, CP_PID_FILE
|
||||||
|
|
||||||
|
APP_PATH=
|
||||||
|
RUN_AS=root
|
||||||
Reference in New Issue
Block a user