Merge branch 'refs/heads/develop'

This commit is contained in:
Ruud
2014-06-11 23:51:05 +02:00
50 changed files with 652 additions and 335 deletions
+1 -1
View File
@@ -45,7 +45,7 @@ class WebHandler(BaseHandler):
self.write({'success': False, 'error': 'Failed returning results'})
def addView(route, func, static = False):
def addView(route, func):
views[route] = func
@@ -72,6 +72,9 @@ class DownloaderBase(Provider):
return
return self.download(data = data, media = media, filedata = filedata)
def download(self, *args, **kwargs):
return False
def _getAllDownloadStatus(self, download_ids):
if self.isDisabled(manual = True, data = {}):
return
@@ -40,15 +40,16 @@ var DownloadersBase = new Class({
button.set('text', button_name);
var message;
if(json.success){
var message = new Element('span.success', {
message = new Element('span.success', {
'text': 'Connection successful'
}).inject(button, 'after')
}
else {
var msg_text = 'Connection failed. Check logs for details.';
if(json.hasOwnProperty('msg')) msg_text = json.msg;
var message = new Element('span.failed', {
message = new Element('span.failed', {
'text': msg_text
}).inject(button, 'after')
}
+1 -1
View File
@@ -10,7 +10,7 @@ from threading import RLock
from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEvent, fireEventAsync
from couchpotato.core.helpers.encoding import ss, sp
from couchpotato.core.helpers.encoding import sp
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from couchpotato.environment import Env
+2 -2
View File
@@ -130,7 +130,7 @@ class NZBVortex(DownloaderBase):
url = cleanHost(self.conf('host'), ssl = self.conf('ssl')) + 'api/' + call
try:
data = self.urlopen('%s?%s' % (url, params), *args, verify_ssl = False, **kwargs)
data = self.urlopen('%s?%s' % (url, params), *args, **kwargs)
if data:
return json.loads(data)
@@ -154,7 +154,7 @@ class NZBVortex(DownloaderBase):
url = cleanHost(self.conf('host')) + 'api/app/apilevel'
try:
data = self.urlopen(url, show_error = False, verify_ssl = False)
data = self.urlopen(url, show_error = False)
self.api_level = float(json.loads(data).get('apilevel'))
except URLError as e:
if hasattr(e, 'code') and e.code == 403:
+1 -1
View File
@@ -194,7 +194,7 @@ class Sabnzbd(DownloaderBase):
'output': 'json'
}))
data = self.urlopen(url, timeout = 60, show_error = False, verify_ssl = False, headers = {'User-Agent': Env.getIdentifier()}, **kwargs)
data = self.urlopen(url, timeout = 60, show_error = False, headers = {'User-Agent': Env.getIdentifier()}, **kwargs)
if use_json:
d = json.loads(data)
if d.get('error'):
+1
View File
@@ -90,6 +90,7 @@ class SynologyRPC(object):
self.download_url = 'http://%s:%s/webapi/DownloadStation/task.cgi' % (host, port)
self.auth_url = 'http://%s:%s/webapi/auth.cgi' % (host, port)
self.sid = None
self.username = username
self.password = password
self.destination = destination
+1 -1
View File
@@ -168,7 +168,7 @@ class uTorrent(DownloaderBase):
status = 'busy'
if (torrent[1] & self.status_flags['STARTED'] or torrent[1] & self.status_flags['QUEUED']) and torrent[4] == 1000:
status = 'seeding'
elif (torrent[1] & self.status_flags['ERROR']):
elif torrent[1] & self.status_flags['ERROR']:
status = 'failed'
elif torrent[4] == 1000:
status = 'completed'
+2 -2
View File
@@ -1,7 +1,7 @@
import os
import traceback
from couchpotato import get_db, CPLog
from couchpotato import CPLog
from couchpotato.core.event import addEvent, fireEvent, fireEventAsync
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.plugins.base import Plugin
@@ -28,7 +28,7 @@ class MediaBase(Plugin):
media = fireEvent('media.get', media_id, single = True)
event_name = '%s.searcher.single' % media.get('type')
fireEventAsync(event_name, media, on_complete = self.createNotifyFront(media_id))
fireEventAsync(event_name, media, on_complete = self.createNotifyFront(media_id), manual = True)
except:
log.error('Failed creating onComplete: %s', traceback.format_exc())
+2 -2
View File
@@ -99,7 +99,7 @@ from couchpotato.core.helpers.encoding import simplifyString"""
class TitleIndex(TreeBasedIndex):
_version = 3
_version = 4
custom_header = """from CodernityDB.tree_index import TreeBasedIndex
from string import ascii_letters
@@ -128,7 +128,7 @@ from couchpotato.core.helpers.encoding import toUnicode, simplifyString"""
title = title[len(prefix):]
break
return str(nr_prefix + title).ljust(32, '_')[:32]
return str(nr_prefix + title).ljust(32, ' ')[:32]
class StartsWithIndex(TreeBasedIndex):
@@ -125,7 +125,6 @@ class MediaPlugin(MediaBase):
imdb_id = getImdb(str(media_id))
media = None
if imdb_id:
media = db.get('media', 'imdb-%s' % imdb_id, with_doc = True)['doc']
else:
@@ -129,6 +129,9 @@ class YarrProvider(Provider):
else:
return []
def buildUrl(self, *args, **kwargs):
pass
def login(self):
# Check if we are still logged in every hour
@@ -91,7 +91,7 @@ class Base(NZBProvider, RSS):
# Extract a password from the description
password = re.search('(?:' + self.passwords_regex + ')(?: *)(?:\:|\=)(?: *)(.*?)\<br\>|\n|$', description, flags = re.I).group(1)
if password:
name = name + ' {{%s}}' % password.strip()
name += ' {{%s}}' % password.strip()
except:
log.debug('Error getting details of "%s": %s', (name, traceback.format_exc()))
@@ -51,6 +51,7 @@ class Base(TorrentProvider):
results_table = None
data_split = splitString(data, '<table')
soup = None
for x in data_split:
soup = BeautifulSoup(x)
results_table = soup.find('table', attrs = {'class': 'koptekst'})
@@ -1,4 +1,3 @@
from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
@@ -7,7 +7,6 @@
text-align: right;
height: 100%;
transition: all .4s cubic-bezier(0.9,0,0.1,1);
position: absolute;
z-index: 20;
border: 0 solid transparent;
border-bottom-width: 4px;
@@ -357,12 +357,8 @@
top: 30px;
clear: both;
bottom: 30px;
overflow: hidden;
position: absolute;
}
.movies .data:hover .description {
overflow: auto;
}
.movies.list_list .movie:not(.details_view) .info .description,
.movies.mass_edit_list .info .description,
.movies.thumbs_list .info .description {
@@ -158,7 +158,7 @@ var Movie = new Class({
'text': self.data.info.year || 'n/a'
})
),
self.description = new Element('div.description', {
self.description = new Element('div.description.tiny_scroll', {
'text': self.data.info.plot
}),
self.quality = new Element('div.quality', {
@@ -45,6 +45,7 @@ class Charts(Plugin):
if catched_charts:
return catched_charts
charts = []
try:
self.update_in_progress = True
charts = fireEvent('automation.get_chart_list', merge = True)
@@ -3,26 +3,21 @@
margin-bottom: 30px;
}
.charts > h2 {
height: 40px;
}
.charts > h2 {
height: 40px;
}
.charts .chart {
display: inline-block;
width: 50%;
vertical-align: top;
max-height: 510px;
overflow: hidden;
scrollbar-base-color: #4e5969;
}
.charts .chart {
display: inline-block;
width: 50%;
vertical-align: top;
max-height: 510px;
scrollbar-base-color: #4e5969;
}
.charts .chart:hover {
overflow-y: auto;
}
.charts .chart .media_result.hidden {
display: none;
}
.charts .chart .media_result.hidden {
display: none;
}
.charts .refresh {
clear:both;
@@ -36,30 +31,30 @@
text-align:center;
}
.charts .refresh a {
text-align: center;
padding: 0;
display: none;
width: 30px;
height: 30px;
position: absolute;
right: 10px;
top: -40px;
opacity: .7;
}
.charts .refresh a {
text-align: center;
padding: 0;
display: none;
width: 30px;
height: 30px;
position: absolute;
right: 10px;
top: -40px;
opacity: .7;
}
.charts .refresh a:hover {
opacity: 1;
}
.charts .refresh a:hover {
opacity: 1;
}
.charts p.no_charts_enabled {
padding: 0.7em 1em;
display: none;
}
.charts p.no_charts_enabled {
padding: 0.7em 1em;
display: none;
}
.charts .chart h3 a {
color: #fff;
}
.charts .chart h3 a {
color: #fff;
}
.charts .chart .media_result {
@@ -148,7 +143,6 @@
padding: 0 3px 10px 0;
}
.charts .chart .media_result .data:before {
bottom: 0;
content: '';
display: block;
height: 10px;
@@ -22,9 +22,11 @@ var Charts = new Class({
'events': {
'click': function(e) {
e.preventDefault();
self.el.getChildren('div.chart').destroy();
self.el.getElements('.chart').destroy();
self.el_refreshing_text.show();
self.el_refresh_link.hide();
self.api_request = Api.request('charts.view', {
'data': { 'force_update': 1 },
'onComplete': self.fill.bind(self)
@@ -72,7 +74,7 @@ var Charts = new Class({
Object.each(json.charts, function(chart){
var c = new Element('div.chart').grab(
var c = new Element('div.chart.tiny_scroll').grab(
new Element('h3').grab( new Element('a', {
'text': chart.name,
'href': chart.url
@@ -51,19 +51,14 @@ class FanartTV(MovieProvider):
def _parseMovie(self, movie):
images = {
'landscape': [],
'landscape': self._getMultImages(movie.get('moviethumb', []), 1),
'logo': [],
'disc_art': [],
'clear_art': [],
'banner': [],
'disc_art': self._getMultImages(self._trimDiscs(movie.get('moviedisc', [])), 1),
'clear_art': self._getMultImages(movie.get('hdmovieart', []), 1),
'banner': self._getMultImages(movie.get('moviebanner', []), 1),
'extra_fanart': [],
}
images['landscape'] = self._getMultImages(movie.get('moviethumb', []), 1)
images['banner'] = self._getMultImages(movie.get('moviebanner', []), 1)
images['disc_art'] = self._getMultImages(self._trimDiscs(movie.get('moviedisc', [])), 1)
images['clear_art'] = self._getMultImages(movie.get('hdmovieart', []), 1)
if len(images['clear_art']) == 0:
images['clear_art'] = self._getMultImages(movie.get('movieart', []), 1)
@@ -105,10 +100,10 @@ class FanartTV(MovieProvider):
return image_url
def _getMultImages(self, images, n):
'''
"""
Chooses the best n images and returns them as a list.
If n<0, all images will be returned.
'''
"""
image_urls = []
pool = []
for image in images:
@@ -1,6 +1,6 @@
import traceback
from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.event import addEvent
from couchpotato.core.helpers.encoding import simplifyString, toUnicode, ss
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
@@ -0,0 +1,36 @@
import os
from couchpotato.core.media.movie.providers.metadata.base import MovieMetaData
autoload = 'MediaBrowser'
class MediaBrowser(MovieMetaData):
def getThumbnailName(self, name, root, i):
return os.path.join(root, 'folder.jpg')
def getFanartName(self, name, root, i):
return os.path.join(root, 'backdrop.jpg')
config = [{
'name': 'mediabrowser',
'groups': [
{
'tab': 'renamer',
'subtab': 'metadata',
'name': 'mediabrowser_metadata',
'label': 'MediaBrowser',
'description': 'Generate folder.jpg and backdrop.jpg',
'options': [
{
'name': 'meta_enabled',
'default': False,
'type': 'enabler',
},
],
},
],
}]
@@ -0,0 +1,33 @@
import os
from couchpotato.core.media.movie.providers.metadata.base import MovieMetaData
autoload = 'SonyPS3'
class SonyPS3(MovieMetaData):
def getThumbnailName(self, name, root, i):
return os.path.join(root, 'cover.jpg')
config = [{
'name': 'sonyps3',
'groups': [
{
'tab': 'renamer',
'subtab': 'metadata',
'name': 'sonyps3_metadata',
'label': 'Sony PS3',
'description': 'Generate cover.jpg',
'options': [
{
'name': 'meta_enabled',
'default': False,
'type': 'enabler',
},
],
},
],
}]
@@ -1,5 +1,4 @@
from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.event import fireEvent
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.torrent.sceneaccess import Base
from couchpotato.core.media.movie.providers.base import MovieProvider
@@ -11,3 +11,6 @@ class TrailerProvider(Provider):
def __init__(self):
addEvent('trailer.search', self.search)
def search(self, *args, **kwargs):
pass
+43 -12
View File
@@ -58,13 +58,13 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
def searchAllView(self, **kwargs):
fireEventAsync('movie.searcher.all')
fireEventAsync('movie.searcher.all', manual = True)
return {
'success': not self.in_progress
}
def searchAll(self):
def searchAll(self, manual = False):
if self.in_progress:
log.info('Search already in progress')
@@ -91,7 +91,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
media = fireEvent('media.get', media_id, single = True)
try:
self.single(media, search_protocols)
self.single(media, search_protocols, manual = manual)
except IndexError:
log.error('Forcing library update for %s, if you see this often, please report: %s', (getIdentifier(media), traceback.format_exc()))
fireEvent('movie.update_info', media_id)
@@ -109,7 +109,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
self.in_progress = False
def single(self, movie, search_protocols = None, manual = False):
def single(self, movie, search_protocols = None, manual = False, force_download = False):
# Find out search type
try:
@@ -128,6 +128,9 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
found_releases = []
previous_releases = movie.get('releases', [])
too_early_to_search = []
outside_eta_results = 0
alway_search = self.conf('always_search')
ignore_eta = manual
default_title = getTitle(movie)
if not default_title:
@@ -137,6 +140,14 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
fireEvent('notify.frontend', type = 'movie.searcher.started', data = {'_id': movie['_id']}, message = 'Searching for "%s"' % default_title)
# Ignore eta once every 7 days
if not alway_search:
prop_name = 'last_ignored_eta.%s' % movie['_id']
last_ignored_eta = float(Env.prop(prop_name, default = 0))
if last_ignored_eta > time.time() - 604800:
ignore_eta = True
Env.prop(prop_name, value = time.time())
db = get_db()
profile = db.get('id', movie['profile_id'])
@@ -154,9 +165,13 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
index += 1
if not self.conf('always_search') and not self.couldBeReleased(q_identifier in pre_releases, release_dates, movie['info']['year']):
could_not_be_released = not self.couldBeReleased(q_identifier in pre_releases, release_dates, movie['info']['year'])
if not alway_search and could_not_be_released:
too_early_to_search.append(q_identifier)
continue
# Skip release, if ETA isn't ignored
if not ignore_eta:
continue
has_better_quality = 0
@@ -177,15 +192,19 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
break
quality = fireEvent('quality.single', identifier = q_identifier, single = True)
log.info('Search for %s in %s', (default_title, quality['label']))
log.info('Search for %s in %s%s', (default_title, quality['label'], ' ignoring ETA' if alway_search or ignore_eta else ''))
# Extend quality with profile customs
quality['custom'] = quality_custom
results = fireEvent('searcher.search', search_protocols, movie, quality, single = True) or []
if len(results) == 0:
results_count = len(results)
if results_count == 0:
log.debug('Nothing found for %s in %s', (default_title, quality['label']))
# Keep track of releases found outside ETA window
outside_eta_results += results_count if could_not_be_released else 0
# Check if movie isn't deleted while searching
if not fireEvent('media.get', movie.get('_id'), single = True):
break
@@ -193,8 +212,13 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
# Add them to this movie releases list
found_releases += fireEvent('release.create_from_search', results, movie, quality, single = True)
# Don't trigger download, but notify user of available releases
if could_not_be_released:
if results_count > 0:
log.debug('Found %s releases for "%s", but ETA isn\'t correct yet.', (results_count, default_title))
# Try find a valid result and download it
if fireEvent('release.try_download_result', results, movie, quality_custom, manual, single = True):
if (force_download or not could_not_be_released) and fireEvent('release.try_download_result', results, movie, quality_custom, single = True):
ret = True
# Remove releases that aren't found anymore
@@ -214,6 +238,13 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
if len(too_early_to_search) > 0:
log.info2('Too early to search for %s, %s', (too_early_to_search, default_title))
if outside_eta_results > 0:
message = 'Found %s releases for "%s" before ETA. Select and download via the dashboard.' % (outside_eta_results, default_title)
log.info(message)
if not manual:
fireEvent('media.available', message = message, data = {})
fireEvent('notify.frontend', type = 'movie.searcher.ended', data = {'_id': movie['_id']})
return ret
@@ -334,13 +365,13 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
def tryNextReleaseView(self, media_id = None, **kwargs):
trynext = self.tryNextRelease(media_id, manual = True)
trynext = self.tryNextRelease(media_id, manual = True, force_download = True)
return {
'success': trynext
}
def tryNextRelease(self, media_id, manual = False):
def tryNextRelease(self, media_id, manual = False, force_download = False):
try:
db = get_db()
@@ -352,7 +383,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
movie_dict = fireEvent('media.get', media_id, single = True)
log.info('Trying next release for: %s', getTitle(movie_dict))
self.single(movie_dict, manual = manual)
self.single(movie_dict, manual = manual, force_download = force_download)
return True
@@ -84,7 +84,6 @@ class Suggestion(Plugin):
# Get new results and add them
if len(new_suggestions) - 1 < limit:
db = get_db()
active_movies = fireEvent('media.with_status', ['active', 'done'], single = True)
movies = [getIdentifier(x) for x in active_movies]
movies.extend(seen)
+1
View File
@@ -15,6 +15,7 @@ class Notification(Provider):
test_message = 'ZOMG Lazors Pewpewpew!'
listen_to = [
'media.available',
'renamer.after', 'movie.snatched',
'updater.available', 'updater.updated',
'core.message.important',
@@ -28,6 +28,7 @@ class CoreNotifier(Notification):
m_lock = None
listen_to = [
'media.available',
'renamer.after', 'movie.snatched',
'updater.available', 'updater.updated',
'core.message', 'core.message.important',
+2 -1
View File
@@ -22,10 +22,11 @@ class NMJ(Notification):
# noinspection PyMissingConstructor
def __init__(self):
addEvent('renamer.after', self.addToLibrary)
addApiView(self.testNotifyName(), self.test)
addApiView('notify.nmj.auto_config', self.autoConfig)
addEvent('renamer.after', self.addToLibrary)
def autoConfig(self, host = 'localhost', **kwargs):
mount = ''
+3 -1
View File
@@ -1,6 +1,7 @@
import os
import subprocess
from couchpotato.api import addApiView
from couchpotato.core.event import addEvent
from couchpotato.core.logger import CPLog
from couchpotato.core.notifications.base import Notification
@@ -16,7 +17,8 @@ class Synoindex(Notification):
index_path = '/usr/syno/bin/synoindex'
def __init__(self):
super(Synoindex, self).__init__()
addApiView(self.testNotifyName(), self.test)
addEvent('renamer.after', self.addToLibrary)
def addToLibrary(self, message = None, group = None):
+1 -1
View File
@@ -166,7 +166,7 @@ class Plugin(object):
log.error('Couldn\'t remove empty directory %s: %s', (folder, traceback.format_exc()))
# http request
def urlopen(self, url, timeout = 30, data = None, headers = None, files = None, show_error = True, verify_ssl = True):
def urlopen(self, url, timeout = 30, data = None, headers = None, files = None, show_error = True):
url = quote(ss(url), safe = "%/:=&?~#+!$,;'@()*[]")
if not headers: headers = {}
+2 -2
View File
@@ -49,8 +49,8 @@ class FileManager(Plugin):
files.extend(file_dict[x])
for f in os.listdir(cache_dir):
if os.path.splitext(f.name)[1] in ['.png', '.jpg', '.jpeg']:
file_path = os.path.join(cache_dir, f.name)
if os.path.splitext(f)[1] in ['.png', '.jpg', '.jpeg']:
file_path = os.path.join(cache_dir, f)
if toUnicode(file_path) not in files:
os.remove(file_path)
except:
+2 -2
View File
@@ -134,8 +134,8 @@ class Logging(Plugin):
logs_raw = toUnicode(log_content).split('[0m\n')
logs = []
for log in logs_raw:
split = splitString(log, '\x1b')
for log_line in logs_raw:
split = splitString(log_line, '\x1b')
if split:
try:
date, time, log_type = splitString(split[0], ' ')
+1 -1
View File
@@ -23,7 +23,7 @@
cursor: pointer;
}
.page.log .nav li:hover:not(.active, .filter) {
.page.log .nav li:hover:not(.active):not(.filter) {
background: rgba(255, 255, 255, 0.1);
}
+11 -8
View File
@@ -32,7 +32,7 @@ class Manage(Plugin):
# Add files after renaming
def after_rename(message = None, group = None):
if not group: group = {}
return self.scanFilesToLibrary(folder = group['destination_dir'], files = group['renamed_files'])
return self.scanFilesToLibrary(folder = group['destination_dir'], files = group['renamed_files'], release_download = group['release_download'])
addEvent('renamer.after', after_rename, priority = 110)
addApiView('manage.update', self.updateLibraryView, docs = {
@@ -210,14 +210,14 @@ class Manage(Plugin):
'to_go': total_found,
})
self.updateProgress(folder, to_go)
if group['media'] and group['identifier']:
added_identifiers.append(group['identifier'])
# Add it to release and update the info
fireEvent('release.add', group = group, update_info = False)
fireEvent('movie.update_info', identifier = group['identifier'], on_complete = self.createAfterUpdate(folder, group['identifier']))
else:
self.updateProgress(folder)
return addToLibrary
@@ -228,7 +228,6 @@ class Manage(Plugin):
if not self.in_progress or self.shuttingDown():
return
self.updateProgress(folder)
total = self.in_progress[folder]['total']
movie_dict = fireEvent('media.get', identifier, single = True)
@@ -236,10 +235,11 @@ class Manage(Plugin):
return afterUpdate
def updateProgress(self, folder):
def updateProgress(self, folder, to_go):
pr = self.in_progress[folder]
pr['to_go'] -= 1
if to_go < pr['to_go']:
pr['to_go'] = to_go
avg = (time.time() - pr['started']) / (pr['total'] - pr['to_go'])
pr['eta'] = tryInt(avg * pr['to_go'])
@@ -254,7 +254,7 @@ class Manage(Plugin):
return []
def scanFilesToLibrary(self, folder = None, files = None):
def scanFilesToLibrary(self, folder = None, files = None, release_download = None):
folder = os.path.normpath(folder)
@@ -263,7 +263,10 @@ class Manage(Plugin):
if groups:
for group in groups.values():
if group.get('media'):
fireEvent('release.add', group = group)
if release_download and release_download.get('release_id'):
fireEvent('release.add', group = group, update_id = release_download.get('release_id'))
else:
fireEvent('release.add', group = group)
def getDiskSpace(self):
+39 -23
View File
@@ -104,7 +104,7 @@ class Release(Plugin):
elif rel['status'] in ['snatched', 'downloaded']:
self.updateStatus(rel['_id'], status = 'ignore')
def add(self, group, update_info = True):
def add(self, group, update_info = True, update_id = None):
try:
db = get_db()
@@ -120,27 +120,43 @@ class Release(Plugin):
'profile_id': None,
}, search_after = False, update_after = update_info, notify_after = False, status = 'done', single = True)
# Add Release
release = {
'_t': 'release',
'media_id': media['_id'],
'identifier': release_identifier,
'quality': group['meta_data']['quality'].get('identifier'),
'is_3d': group['meta_data']['quality'].get('is_3d', 0),
'last_edit': int(time.time()),
'status': 'done'
}
try:
r = db.get('release_identifier', release_identifier, with_doc = True)['doc']
r['media_id'] = media['_id']
except:
r = db.insert(release)
release = None
if update_id:
try:
release = db.get('id', update_id)
release.update({
'identifier': release_identifier,
'last_edit': int(time.time()),
'status': 'done',
})
except:
log.error('Failed updating existing release: %s', traceback.format_exc())
else:
# Update with ref and _id
release.update({
'_id': r['_id'],
'_rev': r['_rev'],
})
# Add Release
if not release:
release = {
'_t': 'release',
'media_id': media['_id'],
'identifier': release_identifier,
'quality': group['meta_data']['quality'].get('identifier'),
'is_3d': group['meta_data']['quality'].get('is_3d', 0),
'last_edit': int(time.time()),
'status': 'done'
}
try:
r = db.get('release_identifier', release_identifier, with_doc = True)['doc']
r['media_id'] = media['_id']
except:
log.error('Failed updating release by identifier: %s', traceback.format_exc())
r = db.insert(release)
# Update with ref and _id
release.update({
'_id': r['_id'],
'_rev': r['_rev'],
})
# Empty out empty file groups
release['files'] = dict((k, [toUnicode(x) for x in v]) for k, v in group['files'].items() if v)
@@ -341,7 +357,7 @@ class Release(Plugin):
return True
def tryDownloadResult(self, results, media, quality_custom, manual = False):
def tryDownloadResult(self, results, media, quality_custom):
wait_for = False
let_through = False
@@ -375,7 +391,7 @@ class Release(Plugin):
wait_for = True
continue
downloaded = fireEvent('release.download', data = rel, media = media, manual = manual, single = True)
downloaded = fireEvent('release.download', data = rel, media = media, single = True)
if downloaded is True:
return True
elif downloaded != 'try_next':
+6 -3
View File
@@ -227,6 +227,7 @@ class Renamer(Plugin):
for group_identifier in groups:
group = groups[group_identifier]
group['release_download'] = None
rename_files = {}
remove_files = []
remove_releases = []
@@ -456,7 +457,7 @@ class Renamer(Plugin):
mdia['last_edit'] = int(time.time())
db.update(mdia)
except Exception as e:
except:
log.error('Failed marking movie finished: %s', (traceback.format_exc()))
# Go over current movie releases
@@ -504,13 +505,15 @@ class Renamer(Plugin):
if release_download['status'] == 'completed':
# Set the release to downloaded
fireEvent('release.update_status', release['_id'], status = 'downloaded', single = True)
group['release_download'] = release_download
elif release_download['status'] == 'seeding':
# Set the release to seeding
fireEvent('release.update_status', release['_id'], status = 'seeding', single = True)
elif release.get('identifier') == group['meta_data']['quality']['identifier']:
# Set the release to downloaded
fireEvent('release.update_status', release['_id'], status = 'downloaded', single = True)
# Set the release to downloaded
fireEvent('release.update_status', release['_id'], status = 'downloaded', single = True)
group['release_download'] = release_download
# Remove leftover files
if not remove_leftovers: # Don't remove anything
+3 -1
View File
@@ -364,6 +364,7 @@ class Scanner(Plugin):
if return_ignored is False and identifier in ignored_identifiers:
log.debug('Ignore file found, ignoring release: %s', identifier)
total_found -= 1
continue
# Group extra (and easy) files first
@@ -384,6 +385,7 @@ class Scanner(Plugin):
if len(group['files']['movie']) == 0:
log.error('Couldn\'t find any movie files for %s', identifier)
total_found -= 1
continue
log.debug('Getting metadata for %s', identifier)
@@ -429,7 +431,7 @@ class Scanner(Plugin):
# Notify parent & progress on something found
if on_found:
on_found(group, total_found, total_found - len(processed_movies))
on_found(group, total_found, len(valid_files))
# Wait for all the async events calm down a bit
while threading.activeCount() > 100 and not self.shuttingDown():
@@ -90,7 +90,7 @@ Page.Wizard = new Class({
self.parent(action, params);
self.addEvent('create', function(){
self.order();
self.orderGroups();
});
self.initialized = true;
@@ -106,7 +106,7 @@ Page.Wizard = new Class({
}).delay(1)
},
order: function(){
orderGroups: function(){
var self = this;
var form = self.el.getElement('.uniForm');
-1
View File
@@ -1,5 +1,4 @@
from __future__ import with_statement
import traceback
import ConfigParser
from hashlib import md5
+2 -2
View File
@@ -7,9 +7,9 @@ var ApiClass = new Class({
},
request: function(type, options){
var self = this;
var self = this,
r_type = self.options.is_remote ? 'JSONP' : 'JSON';
var r_type = self.options.is_remote ? 'JSONP' : 'JSON';
return new Request[r_type](Object.merge({
'callbackKey': 'callback_func',
'method': 'get',
+3 -3
View File
@@ -54,7 +54,7 @@
},
pushState: function(e){
if((!e.meta && Browser.Platform.mac) || (!e.control && !Browser.Platform.mac)){
if((!e.meta && Browser.platform.mac) || (!e.control && !Browser.platform.mac)){
(e).preventDefault();
var url = e.target.get('href');
if(History.getPath() != url)
@@ -63,7 +63,7 @@
},
isMac: function(){
return Browser.Platform.mac
return Browser.platform.mac
},
createLayout: function(){
@@ -322,7 +322,7 @@
var url = 'http://www.dereferer.org/?' + el.get('href');
if(el.get('target') == '_blank' || (e.meta && Browser.Platform.mac) || (e.control && !Browser.Platform.mac))
if(el.get('target') == '_blank' || (e.meta && Browser.platform.mac) || (e.control && !Browser.platform.mac))
window.open(url);
else
window.location = url;
+253 -138
View File
@@ -20,7 +20,7 @@ description: The heart of MooTools.
license: MIT-style license.
copyright: Copyright (c) 2006-2012 [Valerio Proietti](http://mad4milk.net/).
copyright: Copyright (c) 2006-2014 [Valerio Proietti](http://mad4milk.net/).
authors: The MooTools production team (http://mootools.net/developers/)
@@ -36,8 +36,8 @@ provides: [Core, MooTools, Type, typeOf, instanceOf, Native]
(function(){
this.MooTools = {
version: '1.4.5',
build: 'ab8ea8824dc3b24b6666867a2c4ed58ebb762cf0'
version: '1.5.0',
build: '0f7b690afee9349b15909f33016a25d2e4d9f4e3'
};
// typeOf, instanceOf
@@ -50,7 +50,7 @@ var typeOf = this.typeOf = function(item){
if (item.nodeType == 1) return 'element';
if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace';
} else if (typeof item.length == 'number'){
if (item.callee) return 'arguments';
if ('callee' in item) return 'arguments';
if ('item' in item) return 'collection';
}
@@ -267,7 +267,7 @@ var force = function(name, object, methods){
if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){
fn.call(prototype, prototype[methods[i]], methods[i]);
}
for (var key in prototype) fn.call(prototype, prototype[key], key)
for (var key in prototype) fn.call(prototype, prototype[key], key);
};
}
@@ -275,7 +275,7 @@ var force = function(name, object, methods){
};
force('String', String, [
'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
'charAt', 'charCodeAt', 'concat', 'contains', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase'
])('Array', Array, [
'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
@@ -325,11 +325,13 @@ Object.each = Object.forEach;
Array.implement({
/*<!ES5>*/
forEach: function(fn, bind){
for (var i = 0, l = this.length; i < l; i++){
if (i in this) fn.call(bind, this[i], i, this);
}
},
/*</!ES5>*/
each: function(fn, bind){
Array.forEach(this, fn, bind);
@@ -421,7 +423,7 @@ description: Contains Array Prototypes like each, contains, and erase.
license: MIT-style license.
requires: Type
requires: [Type]
provides: Array
@@ -564,7 +566,7 @@ Array.implement({
if (this.length != 3) return null;
var rgb = this.map(function(value){
if (value.length == 1) value += value;
return value.toInt(16);
return parseInt(value, 16);
});
return (array) ? rgb : 'rgb(' + rgb + ')';
},
@@ -594,7 +596,7 @@ description: Contains String Prototypes like camelCase, capitalize, test, and to
license: MIT-style license.
requires: Type
requires: [Type, Array]
provides: String
@@ -603,14 +605,16 @@ provides: String
String.implement({
//<!ES6>
contains: function(string, index){
return (index ? String(this).slice(index) : String(this)).indexOf(string) > -1;
},
//</!ES6>
test: function(regex, params){
return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this);
},
contains: function(string, separator){
return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : String(this).indexOf(string) > -1;
},
trim: function(){
return String(this).replace(/^\s+|\s+$/g, '');
},
@@ -669,6 +673,8 @@ String.implement({
});
/*
---
@@ -1063,37 +1069,47 @@ provides: [Browser, Window, Document]
var document = this.document;
var window = document.window = this;
var ua = navigator.userAgent.toLowerCase(),
platform = navigator.platform.toLowerCase(),
UA = ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/) || [null, 'unknown', 0],
mode = UA[1] == 'ie' && document.documentMode;
var parse = function(ua, platform){
ua = ua.toLowerCase();
platform = (platform ? platform.toLowerCase() : '');
var Browser = this.Browser = {
var UA = ua.match(/(opera|ie|firefox|chrome|trident|crios|version)[\s\/:]([\w\d\.]+)?.*?(safari|(?:rv[\s\/:]|version[\s\/:])([\w\d\.]+)|$)/) || [null, 'unknown', 0];
extend: Function.prototype.extend,
if (UA[1] == 'trident'){
UA[1] = 'ie';
if (UA[4]) UA[2] = UA[4];
} else if (UA[1] == 'crios') {
UA[1] = 'chrome';
}
name: (UA[1] == 'version') ? UA[3] : UA[1],
var platform = ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0];
if (platform == 'win') platform = 'windows';
version: mode || parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]),
return {
extend: Function.prototype.extend,
name: (UA[1] == 'version') ? UA[3] : UA[1],
version: parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]),
platform: platform
};
};
Platform: {
name: ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0]
},
var Browser = this.Browser = parse(navigator.userAgent, navigator.platform);
if (Browser.ie){
Browser.version = document.documentMode;
}
Browser.extend({
Features: {
xpath: !!(document.evaluate),
air: !!(window.runtime),
query: !!(document.querySelector),
json: !!(window.JSON)
},
parseUA: parse
});
Plugins: {}
};
Browser[Browser.name] = true;
Browser[Browser.name + parseInt(Browser.version, 10)] = true;
Browser.Platform[Browser.Platform.name] = true;
// Request
@@ -1126,18 +1142,7 @@ Browser.Request = (function(){
Browser.Features.xhr = !!(Browser.Request);
// Flash detection
var version = (Function.attempt(function(){
return navigator.plugins['Shockwave Flash'].description;
}, function(){
return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
}) || '0 r0').match(/\d+/g);
Browser.Plugins.Flash = {
version: Number(version[0] || '0.' + version[1]) || 0,
build: Number(version[2]) || 0
};
// String scripts
@@ -1756,7 +1761,7 @@ local.setDocument = function(document){
// native matchesSelector function
features.nativeMatchesSelector = root.matchesSelector || /*root.msMatchesSelector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector;
features.nativeMatchesSelector = root.matches || /*root.msMatchesSelector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector;
if (features.nativeMatchesSelector) try {
// if matchesSelector trows errors on incorrect sintaxes we can use it
features.nativeMatchesSelector.call(root, ':slick');
@@ -2590,12 +2595,12 @@ license: MIT-style license.
requires: [Window, Document, Array, String, Function, Object, Number, Slick.Parser, Slick.Finder]
provides: [Element, Elements, $, $$, Iframe, Selectors]
provides: [Element, Elements, $, $$, IFrame, Selectors]
...
*/
var Element = function(tag, props){
var Element = this.Element = function(tag, props){
var konstructor = Element.Constructors[tag];
if (konstructor) return konstructor(props);
if (typeof tag != 'string') return document.id(tag).set(props);
@@ -2779,7 +2784,7 @@ Array.mirror(Elements);
/*<ltIE8>*/
var createElementAcceptsHTML;
try {
createElementAcceptsHTML = (document.createElement('<input name=x>').name == 'x');
createElementAcceptsHTML = (document.createElement('<input name=x>').name == 'x');
} catch (e){}
var escapeQuotes = function(html){
@@ -3112,7 +3117,28 @@ var pollutesGetAttribute = (function(div){
return (div.getAttribute('random') == 'attribute');
})(document.createElement('div'));
/* <ltIE9> */
var hasCloneBug = (function(test){
test.innerHTML = '<object><param name="should_fix" value="the unknown"></object>';
return test.cloneNode(true).firstChild.childNodes.length != 1;
})(document.createElement('div'));
/* </ltIE9> */
var hasClassList = !!document.createElement('div').classList;
var classes = function(className){
var classNames = (className || '').clean().split(" "), uniques = {};
return classNames.filter(function(className){
if (className !== "" && !uniques[className]) return uniques[className] = className;
});
};
var addToClassList = function(name){
this.classList.add(name);
};
var removeFromClassList = function(name){
this.classList.remove(name);
};
Element.implement({
@@ -3122,7 +3148,8 @@ Element.implement({
setter(this, value);
} else {
/* <ltIE9> */
if (pollutesGetAttribute) var attributeWhiteList = this.retrieve('$attributeWhiteList', {});
var attributeWhiteList;
if (pollutesGetAttribute) attributeWhiteList = this.retrieve('$attributeWhiteList', {});
/* </ltIE9> */
if (value == null){
@@ -3194,17 +3221,27 @@ Element.implement({
return this;
},
hasClass: function(className){
hasClass: hasClassList ? function(className){
return this.classList.contains(className);
} : function(className){
return this.className.clean().contains(className, ' ');
},
addClass: function(className){
if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
addClass: hasClassList ? function(className){
classes(className).forEach(addToClassList, this);
return this;
} : function(className){
this.className = classes(className + ' ' + this.className).join(' ');
return this;
},
removeClass: function(className){
this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
removeClass: hasClassList ? function(className){
classes(className).forEach(removeFromClassList, this);
return this;
} : function(className){
var classNames = classes(this.className);
classes(className).forEach(classNames.erase, classNames);
this.className = classNames.join(' ');
return this;
},
@@ -3279,6 +3316,37 @@ Element.implement({
});
// appendHTML
var appendInserters = {
before: 'beforeBegin',
after: 'afterEnd',
bottom: 'beforeEnd',
top: 'afterBegin',
inside: 'beforeEnd'
};
Element.implement('appendHTML', ('insertAdjacentHTML' in document.createElement('div')) ? function(html, where){
this.insertAdjacentHTML(appendInserters[where || 'bottom'], html);
return this;
} : function(html, where){
var temp = new Element('div', {html: html}),
children = temp.childNodes,
fragment = temp.firstChild;
if (!fragment) return this;
if (children.length > 1){
fragment = document.createDocumentFragment();
for (var i = 0, l = children.length; i < l; i++){
fragment.appendChild(children[i]);
}
}
inserters[where || 'bottom'](fragment, this);
return this;
});
var collected = {}, storage = {};
var get = function(uid){
@@ -3344,7 +3412,7 @@ Element.implement({
}
/*<ltIE9>*/
if (Browser.ie){
if (hasCloneBug){
var co = clone.getElementsByTagName('object'), to = this.getElementsByTagName('object');
for (i = co.length; i--;) co[i].outerHTML = to[i].outerHTML;
}
@@ -3357,13 +3425,7 @@ Element.implement({
[Element, Window, Document].invoke('implement', {
addListener: function(type, fn){
if (type == 'unload'){
var old = fn, self = this;
fn = function(){
self.removeListener('unload', fn);
old();
};
} else {
if (window.attachEvent && !window.addEventListener){
collected[Slick.uidOf(this)] = this;
}
if (this.addEventListener) this.addEventListener(type, fn, !!arguments[2]);
@@ -3398,10 +3460,14 @@ Element.implement({
});
/*<ltIE9>*/
if (window.attachEvent && !window.addEventListener) window.addListener('unload', function(){
Object.each(collected, clean);
if (window.CollectGarbage) CollectGarbage();
});
if (window.attachEvent && !window.addEventListener){
var gc = function(){
Object.each(collected, clean);
if (window.CollectGarbage) CollectGarbage();
window.removeListener('unload', gc);
}
window.addListener('unload', gc);
}
/*</ltIE9>*/
Element.Properties = {};
@@ -3446,11 +3512,13 @@ Element.Properties.html = {
};
var supportsHTML5Elements = true, supportsTableInnerHTML = true, supportsTRInnerHTML = true;
/*<ltIE9>*/
// technique by jdbarlett - http://jdbartlett.com/innershiv/
var div = document.createElement('div');
div.innerHTML = '<nav></nav>';
var supportsHTML5Elements = (div.childNodes.length == 1);
supportsHTML5Elements = (div.childNodes.length == 1);
if (!supportsHTML5Elements){
var tags = 'abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video'.split(' '),
fragment = document.createDocumentFragment(), l = tags.length;
@@ -3460,7 +3528,7 @@ div = null;
/*</ltIE9>*/
/*<IE>*/
var supportsTableInnerHTML = Function.attempt(function(){
supportsTableInnerHTML = Function.attempt(function(){
var table = document.createElement('table');
table.innerHTML = '<tr><td></td></tr>';
return true;
@@ -3469,7 +3537,7 @@ var supportsTableInnerHTML = Function.attempt(function(){
/*<ltFF4>*/
var tr = document.createElement('tr'), html = '<td></td>';
tr.innerHTML = html;
var supportsTRInnerHTML = (tr.innerHTML == html);
supportsTRInnerHTML = (tr.innerHTML == html);
tr = null;
/*</ltFF4>*/
@@ -3514,11 +3582,12 @@ if (testForm.firstChild.value != 's') Element.Properties.value = {
var tag = this.get('tag');
if (tag != 'select') return this.setProperty('value', value);
var options = this.getElements('option');
value = String(value);
for (var i = 0; i < options.length; i++){
var option = options[i],
attr = option.getAttributeNode('value'),
optionValue = (attr && attr.specified) ? option.value : option.get('text');
if (optionValue == value) return option.selected = true;
if (optionValue === value) return option.selected = true;
}
},
@@ -3572,17 +3641,24 @@ provides: Element.Style
(function(){
var html = document.html;
var html = document.html, el;
//<ltIE9>
// Check for oldIE, which does not remove styles when they're set to null
var el = document.createElement('div');
el = document.createElement('div');
el.style.color = 'red';
el.style.color = null;
var doesNotRemoveStyles = el.style.color == 'red';
// check for oldIE, which returns border* shorthand styles in the wrong order (color-width-style instead of width-style-color)
var border = '1px solid #123abc';
el.style.border = border;
var returnsBordersInWrongOrder = el.style.border != border;
el = null;
//</ltIE9>
var hasGetComputedStyle = !!window.getComputedStyle;
Element.Properties.styles = {set: function(styles){
this.setStyles(styles);
}};
@@ -3596,16 +3672,25 @@ var setVisibility = function(element, opacity){
element.style.visibility = opacity > 0 || opacity == null ? 'visible' : 'hidden';
};
//<ltIE9>
var setFilter = function(element, regexp, value){
var style = element.style,
filter = style.filter || element.getComputedStyle('filter') || '';
style.filter = (regexp.test(filter) ? filter.replace(regexp, value) : filter + ' ' + value).trim();
if (!style.filter) style.removeAttribute('filter');
};
//</ltIE9>
var setOpacity = (hasOpacity ? function(element, opacity){
element.style.opacity = opacity;
} : (hasFilter ? function(element, opacity){
var style = element.style;
if (!element.currentStyle || !element.currentStyle.hasLayout) style.zoom = 1;
if (opacity == null || opacity == 1) opacity = '';
else opacity = 'alpha(opacity=' + (opacity * 100).limit(0, 100).round() + ')';
var filter = style.filter || element.getComputedStyle('filter') || '';
style.filter = reAlpha.test(filter) ? filter.replace(reAlpha, opacity) : filter + opacity;
if (!style.filter) style.removeAttribute('filter');
if (!element.currentStyle || !element.currentStyle.hasLayout) element.style.zoom = 1;
if (opacity == null || opacity == 1){
setFilter(element, reAlpha, '');
if (opacity == 1 && getOpacity(element) != 1) setFilter(element, reAlpha, 'alpha(opacity=100)');
} else {
setFilter(element, reAlpha, 'alpha(opacity=' + (opacity * 100).limit(0, 100).round() + ')');
}
} : setVisibility));
var getOpacity = (hasOpacity ? function(element){
@@ -3622,15 +3707,27 @@ var getOpacity = (hasOpacity ? function(element){
return opacity;
}));
var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat';
var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat',
namedPositions = {left: '0%', top: '0%', center: '50%', right: '100%', bottom: '100%'},
hasBackgroundPositionXY = (html.style.backgroundPositionX != null);
//<ltIE9>
var removeStyle = function(style, property){
if (property == 'backgroundPosition'){
style.removeAttribute(property + 'X');
property += 'Y';
}
style.removeAttribute(property);
};
//</ltIE9>
Element.implement({
getComputedStyle: function(property){
if (this.currentStyle) return this.currentStyle[property.camelCase()];
if (!hasGetComputedStyle && this.currentStyle) return this.currentStyle[property.camelCase()];
var defaultView = Element.getDocument(this).defaultView,
computed = defaultView ? defaultView.getComputedStyle(this, null) : null;
return (computed) ? computed.getPropertyValue((property == floatName) ? 'float' : property.hyphenate()) : null;
return (computed) ? computed.getPropertyValue((property == floatName) ? 'float' : property.hyphenate()) : '';
},
setStyle: function(property, value){
@@ -3652,7 +3749,7 @@ Element.implement({
this.style[property] = value;
//<ltIE9>
if ((value == '' || value == null) && doesNotRemoveStyles && this.style.removeAttribute){
this.style.removeAttribute(property);
removeStyle(this.style, property);
}
//</ltIE9>
return this;
@@ -3663,20 +3760,25 @@ Element.implement({
property = (property == 'float' ? floatName : property).camelCase();
var result = this.style[property];
if (!result || property == 'zIndex'){
result = [];
for (var style in Element.ShortStyles){
if (property != style) continue;
for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s));
if (Element.ShortStyles.hasOwnProperty(property)){
result = [];
for (var s in Element.ShortStyles[property]) result.push(this.getStyle(s));
return result.join(' ');
}
result = this.getComputedStyle(property);
}
if (hasBackgroundPositionXY && /^backgroundPosition[XY]?$/.test(property)){
return result.replace(/(top|right|bottom|left)/g, function(position){
return namedPositions[position];
}) || '0px';
}
if (!result && property == 'backgroundPosition') return '0px 0px';
if (result){
result = String(result);
var color = result.match(/rgba?\([\d\s,]+\)/);
if (color) result = result.replace(color[0], color[0].rgbToHex());
}
if (Browser.opera || Browser.ie){
if (!hasGetComputedStyle && !this.style[property]){
if ((/^(height|width)$/).test(property) && !(/px$/.test(result))){
var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
values.each(function(value){
@@ -3684,10 +3786,15 @@ Element.implement({
}, this);
return this['offset' + property.capitalize()] - size + 'px';
}
if (Browser.ie && (/^border(.+)Width|margin|padding/).test(property) && isNaN(parseFloat(result))){
if ((/^border(.+)Width|margin|padding/).test(property) && isNaN(parseFloat(result))){
return '0px';
}
}
//<ltIE9>
if (returnsBordersInWrongOrder && /^border(Top|Right|Bottom|Left)?$/.test(property) && /^#/.test(result)){
return result.replace(/^(.+)\s(.+)\s(.+)$/, '$2 $3 $1');
}
//</ltIE9>
return result;
},
@@ -3709,7 +3816,7 @@ Element.implement({
Element.Styles = {
left: '@px', top: '@px', bottom: '@px', right: '@px',
width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
backgroundColor: 'rgb(@, @, @)', backgroundSize: '@px', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
@@ -3738,6 +3845,7 @@ Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, bor
Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
});
if (hasBackgroundPositionXY) Element.ShortStyles.backgroundPosition = {backgroundPositionX: '@', backgroundPositionY: '@'};
})();
@@ -3779,7 +3887,7 @@ var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){
if (type.indexOf('key') == 0){
var code = this.code = (event.which || event.keyCode);
this.key = _keys[code];
if (type == 'keydown'){
if (type == 'keydown' || type == 'keyup'){
if (code > 111 && code < 124) this.key = 'f' + (code - 111);
else if (code > 95 && code < 106) this.key = code - 96;
}
@@ -4001,23 +4109,27 @@ Element.NativeEvents = {
gesturestart: 2, gesturechange: 2, gestureend: 2, // gesture
focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, input: 2, //form elements
load: 2, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
hashchange: 1, popstate: 2, // history
error: 1, abort: 1, scroll: 1 //misc
};
Element.Events = {mousewheel: {
base: (Browser.firefox) ? 'DOMMouseScroll' : 'mousewheel'
}};
Element.Events = {
mousewheel: {
base: 'onwheel' in document ? 'wheel' : 'onmousewheel' in document ? 'mousewheel' : 'DOMMouseScroll'
}
};
var check = function(event){
var related = event.relatedTarget;
if (related == null) return true;
if (!related) return false;
return (related != this && related.prefix != 'xul' && typeOf(this) != 'document' && !this.contains(related));
};
if ('onmouseenter' in document.documentElement){
Element.NativeEvents.mouseenter = Element.NativeEvents.mouseleave = 2;
Element.MouseenterCheck = check;
} else {
var check = function(event){
var related = event.relatedTarget;
if (related == null) return true;
if (!related) return false;
return (related != this && related.prefix != 'xul' && typeOf(this) != 'document' && !this.contains(related));
};
Element.Events.mouseenter = {
base: 'mouseover',
condition: check
@@ -4035,12 +4147,12 @@ if (!window.addEventListener){
Element.Events.change = {
base: function(){
var type = this.type;
return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbox')) ? 'propertychange' : 'change'
return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbox')) ? 'propertychange' : 'change';
},
condition: function(event){
return this.type != 'radio' || (event.event.propertyName == 'checked' && this.checked);
return event.type != 'propertychange' || event.event.propertyName == 'checked';
}
}
};
}
/*</ltIE9>*/
@@ -4080,10 +4192,12 @@ var bubbleUp = function(self, match, fn, event, target){
var map = {
mouseenter: {
base: 'mouseover'
base: 'mouseover',
condition: Element.MouseenterCheck
},
mouseleave: {
base: 'mouseout'
base: 'mouseout',
condition: Element.MouseenterCheck
},
focus: {
base: 'focus' + (eventListenerSupport ? '' : 'in'),
@@ -4190,8 +4304,8 @@ var delegation = {
};
var elementEvent = Element.Events[_type];
if (elementEvent && elementEvent.condition){
var __match = match, condition = elementEvent.condition;
if (_map.condition || elementEvent && elementEvent.condition){
var __match = match, condition = _map.condition || elementEvent.condition;
match = function(target, event){
return __match(target, event) && condition.call(target, event, type);
};
@@ -4226,7 +4340,7 @@ var delegation = {
if (_map.remove) _map.remove(this, _uid);
delete stored[_uid];
storage[_type] = stored;
return removeEvent.call(this, type, delegator);
return removeEvent.call(this, type, delegator, _map.capture);
}
var __uid, s;
@@ -4344,7 +4458,9 @@ Element.implement({
},
getOffsets: function(){
if (this.getBoundingClientRect && !Browser.Platform.ios){
var hasGetBoundingClientRect = this.getBoundingClientRect;
if (hasGetBoundingClientRect){
var bound = this.getBoundingClientRect(),
html = document.id(this.getDocument().documentElement),
htmlScroll = html.getScroll(),
@@ -4364,27 +4480,9 @@ Element.implement({
position.x += element.offsetLeft;
position.y += element.offsetTop;
if (Browser.firefox){
if (!borderBox(element)){
position.x += leftBorder(element);
position.y += topBorder(element);
}
var parent = element.parentNode;
if (parent && styleString(parent, 'overflow') != 'visible'){
position.x += leftBorder(parent);
position.y += topBorder(parent);
}
} else if (element != this && Browser.safari){
position.x += leftBorder(element);
position.y += topBorder(element);
}
element = element.offsetParent;
}
if (Browser.firefox && !borderBox(this)){
position.x -= leftBorder(this);
position.y -= topBorder(this);
}
return position;
},
@@ -4666,13 +4764,17 @@ var Fx = this.Fx = new Class({
},
resume: function(){
if ((this.frame < this.frames) && !this.isRunning()) pushInstance.call(this, this.options.fps);
if (this.isPaused()) pushInstance.call(this, this.options.fps);
return this;
},
isRunning: function(){
var list = instances[this.options.fps];
return list && list.contains(this);
},
isPaused: function(){
return (this.frame < this.frames) && !this.isRunning();
}
});
@@ -4745,7 +4847,7 @@ Fx.CSS = new Class({
from = element.getStyle(property);
var unit = this.options.unit;
// adapted from: https://github.com/ryanmorr/fx/blob/master/fx.js#L299
if (unit && from.slice(-unit.length) != unit && parseFloat(from) != 0){
if (unit && from && typeof from == 'string' && from.slice(-unit.length) != unit && parseFloat(from) != 0){
element.setStyle(property, to + unit);
var value = element.getComputedStyle(property);
// IE and Opera support pixelLeft or pixelWidth
@@ -4817,11 +4919,13 @@ Fx.CSS = new Class({
search: function(selector){
if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector];
var to = {}, selectorTest = new RegExp('^' + selector.escapeRegExp() + '$');
Array.each(document.styleSheets, function(sheet, j){
var href = sheet.href;
if (href && href.contains('://') && !href.contains(document.domain)) return;
var rules = sheet.rules || sheet.cssRules;
var searchStyles = function(rules){
Array.each(rules, function(rule, i){
if (rule.media){
searchStyles(rule.rules || rule.cssRules);
return;
}
if (!rule.style) return;
var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){
return m.toLowerCase();
@@ -4833,6 +4937,13 @@ Fx.CSS = new Class({
to[style] = ((/^rgb/).test(value)) ? value.rgbToHex() : value;
});
});
};
Array.each(document.styleSheets, function(sheet, j){
var href = sheet.href;
if (href && href.indexOf('://') > -1 && href.indexOf(document.domain) == -1) return;
var rules = sheet.rules || sheet.cssRules;
searchStyles(rules);
});
return Fx.CSS.Cache[selector] = to;
}
@@ -5369,10 +5480,10 @@ var Request = this.Request = new Class({
if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition);
if (this.options.noCache)
url += (url.contains('?') ? '&' : '?') + String.uniqueID();
url += (url.indexOf('?') > -1 ? '&' : '?') + String.uniqueID();
if (data && method == 'get'){
url += (url.contains('?') ? '&' : '?') + data;
if (data && (method == 'get' || method == 'delete')){
url += (url.indexOf('?') > -1 ? '&' : '?') + data;
data = null;
}
@@ -5526,10 +5637,14 @@ JSON.encode = JSON.stringify ? function(obj){
return null;
};
JSON.secure = true;
JSON.decode = function(string, secure){
if (!string || typeOf(string) != 'string') return null;
if (secure || JSON.secure){
if (secure == null) secure = JSON.secure;
if (secure){
if (JSON.parse) return JSON.parse(string);
if (!JSON.validate(string)) throw new Error('JSON could not decode the input; security is enabled and the value is not secure.');
}
@@ -1,6 +1,16 @@
// MooTools: the javascript framework.
// Load this file's selection again by visiting: http://mootools.net/more/0f75cfbac1aabbedaba7630beef8d10c
// Or build this file again with packager using: packager build More/Events.Pseudos More/Date More/Date.Extras More/Element.Forms More/Element.Position More/Element.Shortcuts More/Fx.Scroll More/Fx.Slide More/Sortables More/Request.JSONP More/Request.Periodical
/*
---
MooTools: the javascript framework
web build:
- http://mootools.net/more/0f75cfbac1aabbedaba7630beef8d10c
packager build:
- packager build More/Events.Pseudos More/Date More/Date.Extras More/Element.Forms More/Element.Position More/Element.Shortcuts More/Fx.Scroll More/Fx.Slide More/Sortables More/Request.JSONP More/Request.Periodical
...
*/
/*
---
@@ -31,8 +41,8 @@ provides: [MooTools.More]
*/
MooTools.More = {
'version': '1.4.0.1',
'build': 'a4244edf2aa97ac8a196fc96082dd35af1abab87'
version: '1.5.0',
build: '73db5e24e6e9c5c87b3a27aebef2248053f7db37'
};
@@ -48,7 +58,7 @@ license: MIT-style license
authors:
- Arian Stolwijk
requires: [Core/Class.Extras, Core/Slick.Parser, More/MooTools.More]
requires: [Core/Class.Extras, Core/Slick.Parser, MooTools.More]
provides: [Events.Pseudos]
@@ -211,7 +221,7 @@ authors:
requires:
- Core/Object
- /MooTools.More
- MooTools.More
provides: [Object.Extras]
@@ -280,8 +290,8 @@ authors:
requires:
- Core/Events
- /Object.Extras
- /MooTools.More
- Object.Extras
- MooTools.More
provides: [Locale, Lang]
@@ -444,7 +454,7 @@ authors:
- Aaron Newton
requires:
- /Locale
- Locale
provides: [Locale.en-US.Date]
@@ -1079,7 +1089,7 @@ authors:
- Scott Kyle
requires:
- /Date
- Date
provides: [Date.Extras]
@@ -1235,10 +1245,8 @@ var special = {
'S': /[ŠŞŚ]/g,
't': /[ťţ]/g,
'T': /[ŤŢ]/g,
'ue': /[ü]/g,
'UE': /[Ü]/g,
'u': /[ùúûůµ]/g,
'U': /[ÙÚÛŮ]/g,
'u': /[ùúûůüµ]/g,
'U': /[ÙÚÛŮÜ]/g,
'y': /[ÿý]/g,
'Y': /[ŸÝ]/g,
'z': /[žźż]/g,
@@ -1263,7 +1271,16 @@ tidy = {
'-': /[\u2013]/g,
// '--': /[\u2014]/g,
'&raquo;': /[\uFFFD]/g
};
},
conversions = {
ms: 1,
s: 1000,
m: 6e4,
h: 36e5
},
findUnits = /(\d*.?\d+)([msh]+)/;
var walk = function(string, replacements){
var result = string, key;
@@ -1325,6 +1342,13 @@ String.implement({
if (trail) string += trail;
}
return string;
},
ms: function(){
// "Borrowed" from https://gist.github.com/1503944
var units = findUnits.exec(this);
if (units == null) return Number(this);
return Number(units[1]) * conversions[units[2]];
}
});
@@ -1348,8 +1372,8 @@ authors:
requires:
- Core/Element
- /String.Extras
- /MooTools.More
- String.Extras
- MooTools.More
provides: [Element.Forms]
@@ -1493,7 +1517,7 @@ authors:
requires:
- Core/Element.Style
- Core/Element.Dimensions
- /MooTools.More
- MooTools.More
provides: [Element.Measure]
@@ -1710,13 +1734,15 @@ var local = Element.Position = {
},
setOffsetOption: function(element, options){
var parentOffset = {x: 0, y: 0},
offsetParent = element.measure(function(){
return document.id(this.getOffsetParent());
}),
parentScroll = offsetParent.getScroll();
var parentOffset = {x: 0, y: 0};
var parentScroll = {x: 0, y: 0};
var offsetParent = element.measure(function(){
return document.id(this.getOffsetParent());
});
if (!offsetParent || offsetParent == element.getDocument().body) return;
parentScroll = offsetParent.getScroll();
parentOffset = offsetParent.measure(function(){
var position = this.getPosition();
if (this.getStyle('position') == 'fixed'){
@@ -1896,7 +1922,7 @@ authors:
requires:
- Core/Element.Style
- /MooTools.More
- MooTools.More
provides: [Element.Shortcuts]
@@ -1976,7 +2002,7 @@ requires:
- Core/Fx
- Core/Element.Event
- Core/Element.Dimensions
- /MooTools.More
- MooTools.More
provides: [Fx.Scroll]
@@ -2014,7 +2040,6 @@ Fx.Scroll = new Class({
set: function(){
var now = Array.flatten(arguments);
if (Browser.firefox) now = [Math.round(now[0]), Math.round(now[1])]; // not needed anymore in newer firefox versions
this.element.scrollTo(now[0], now[1]);
return this;
},
@@ -2148,7 +2173,7 @@ authors:
requires:
- Core/Fx
- Core/Element.Style
- /MooTools.More
- MooTools.More
provides: [Fx.Slide]
@@ -2325,7 +2350,7 @@ requires:
- Core/Element.Event
- Core/Element.Style
- Core/Element.Dimensions
- /MooTools.More
- MooTools.More
provides: [Drag]
...
@@ -2371,10 +2396,10 @@ var Drag = new Class({
this.mouse = {'now': {}, 'pos': {}};
this.value = {'start': {}, 'now': {}};
this.selection = (Browser.ie) ? 'selectstart' : 'mousedown';
this.selection = 'selectstart' in document ? 'selectstart' : 'mousedown';
if (Browser.ie && !Drag.ondragstartFixed){
if ('ondragstart' in document && !('FileReader' in window) && !Drag.ondragstartFixed){
document.ondragstart = Function.from(false);
Drag.ondragstartFixed = true;
}
@@ -2559,7 +2584,7 @@ authors:
requires:
- Core/Element.Dimensions
- /Drag
- Drag
provides: [Drag.Move]
@@ -2586,10 +2611,7 @@ Drag.Move = new Class({
element = this.element;
this.droppables = $$(this.options.droppables);
this.container = document.id(this.options.container);
if (this.container && typeOf(this.container) != 'element')
this.container = document.id(this.container.getDocument().body);
this.setContainer(this.options.container);
if (this.options.style){
if (this.options.modifiers.x == 'left' && this.options.modifiers.y == 'top'){
@@ -2606,6 +2628,13 @@ Drag.Move = new Class({
this.addEvent('start', this.checkDroppables, true);
this.overed = null;
},
setContainer: function(container) {
this.container = document.id(container);
if (this.container && typeOf(this.container) != 'element'){
this.container = document.id(this.container.getDocument().body);
}
},
start: function(event){
if (this.container) this.options.limit = this.calculateLimit();
@@ -2670,7 +2699,9 @@ Drag.Move = new Class({
if (container != offsetParent){
left += containerMargin.left + offsetParentPadding.left;
top += ((Browser.ie6 || Browser.ie7) ? 0 : containerMargin.top) + offsetParentPadding.top;
if (!offsetParentPadding.left && left < 0) left = 0;
top += offsetParent == document.body ? 0 : containerMargin.top + offsetParentPadding.top;
if (!offsetParentPadding.top && top < 0) top = 0;
}
} else {
left -= elementMargin.left;
@@ -2754,7 +2785,7 @@ authors:
requires:
- Core/Fx.Morph
- /Drag.Move
- Drag.Move
provides: [Sortables]
@@ -2773,7 +2804,8 @@ var Sortables = new Class({
clone: false,
revert: false,
handle: false,
dragOptions: {}
dragOptions: {},
unDraggableTags: ['button', 'input', 'a', 'textarea', 'select', 'option']
},
initialize: function(lists, options){
@@ -2839,6 +2871,24 @@ var Sortables = new Class({
return list;
}, this));
},
getDroppableCoordinates: function (element){
var offsetParent = element.getOffsetParent();
var position = element.getPosition(offsetParent);
var scroll = {
w: window.getScroll(),
offsetParent: offsetParent.getScroll()
};
position.x += scroll.offsetParent.x;
position.y += scroll.offsetParent.y;
if (offsetParent.getStyle('position') == 'fixed'){
position.x -= scroll.w.x;
position.y -= scroll.w.y;
}
return position;
},
getClone: function(event, element){
if (!this.options.clone) return new Element(element.tagName).inject(document.body);
@@ -2859,7 +2909,7 @@ var Sortables = new Class({
});
}
return clone.inject(this.list).setPosition(element.getPosition(element.getOffsetParent()));
return clone.inject(this.list).setPosition(this.getDroppableCoordinates(this.element));
},
getDroppables: function(){
@@ -2884,7 +2934,7 @@ var Sortables = new Class({
if (
!this.idle ||
event.rightClick ||
['button', 'input', 'a', 'textarea'].contains(event.target.get('tag'))
(!this.options.handle && this.options.unDraggableTags.contains(event.target.get('tag')))
) return;
this.idle = false;
@@ -2915,14 +2965,16 @@ var Sortables = new Class({
end: function(){
this.drag.detach();
this.element.setStyle('opacity', this.opacity);
var self = this;
if (this.effect){
var dim = this.element.getStyles('width', 'height'),
clone = this.clone,
pos = clone.computePosition(this.element.getPosition(this.clone.getOffsetParent()));
pos = clone.computePosition(this.getDroppableCoordinates(clone));
var destroy = function(){
this.removeEvent('cancel', destroy);
clone.destroy();
self.reset();
};
this.effect.element = clone;
@@ -2935,8 +2987,9 @@ var Sortables = new Class({
}).addEvent('cancel', destroy).chain(destroy);
} else {
this.clone.destroy();
self.reset();
}
this.reset();
},
reset: function(){
@@ -3125,7 +3178,7 @@ authors:
requires:
- Core/Request
- /MooTools.More
- MooTools.More
provides: [Request.Periodical]
+11 -11
View File
@@ -1,15 +1,15 @@
var Question = new Class( {
initialize : function(question, hint, answers) {
var self = this
var self = this;
self.question = question
self.hint = hint
self.answers = answers
self.question = question;
self.hint = hint;
self.answers = answers;
self.createQuestion();
self.answers.each(function(answer) {
self.createAnswer(answer)
self.createAnswer(answer);
})
},
@@ -29,14 +29,14 @@ var Question = new Class( {
},
createAnswer : function(options) {
var self = this
var self = this;
var answer = new Element('a', Object.merge(options, {
'class' : 'answer button '+(options['class'] || '')+(options['cancel'] ? ' cancel' : '')
})).inject(this.container)
})).inject(this.container);
if (options.cancel) {
answer.addEvent('click', self.close.bind(self))
answer.addEvent('click', self.close.bind(self));
}
else if (options.request) {
answer.addEvent('click', function(e){
@@ -44,7 +44,7 @@ var Question = new Class( {
new Request(Object.merge(options, {
'url': options.href,
'onComplete': function() {
(options.onComplete || function(){})()
(options.onComplete || function(){})();
self.close();
}
})).send();
@@ -59,7 +59,7 @@ var Question = new Class( {
},
toElement : function() {
return this.container
return this.container;
}
})
});
+2 -2
View File
@@ -27,8 +27,8 @@ Page.Settings = new Class({
},
openTab: function(action){
var self = this;
var action = (action == 'index' ? 'about' : action) || self.action;
var self = this,
action = (action == 'index' ? 'about' : action) || self.action;
if(self.current)
self.toggleTab(self.current, true);
+26
View File
@@ -8,6 +8,7 @@ body, html {
padding: 0;
background: #4e5969;
-webkit-font-smoothing: subpixel-antialiased;
-moz-osx-font-smoothing: grayscale;
}
body { overflow-y: scroll; }
body.noscroll { overflow: hidden; }
@@ -52,6 +53,30 @@ input:-moz-placeholder {
font-style: italic;
}
.tiny_scroll {
overflow: hidden;
}
.tiny_scroll:hover {
overflow-y: auto;
}
.tiny_scroll::-webkit-scrollbar {
width: 5px;
}
.tiny_scroll::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.4);
-webkit-border-radius: 5px;
border-radius: 5px;
}
.tiny_scroll::-webkit-scrollbar-thumb {
-webkit-border-radius: 5px;
border-radius: 5px;
background: rgba(255,255,255,0.3);
}
a img {
border:none;
}
@@ -166,6 +191,7 @@ body > .spinner, .mask{
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-size: 15px;
color: #FFF;
}