Browse Source

Merge branch 'refs/heads/develop' into desktop

Conflicts:
	couchpotato/core/_base/updater/main.py
tags/build/2.0.0.pre1
Ruud 13 years ago
parent
commit
59590b3ac9
  1. 4
      couchpotato/core/_base/updater/main.py
  2. 2
      couchpotato/core/_base/updater/static/updater.js
  3. 5
      couchpotato/core/plugins/base.py
  4. 7
      couchpotato/core/plugins/manage/main.py
  5. 22
      couchpotato/core/plugins/movie/static/movie.js
  6. 45
      couchpotato/core/plugins/release/main.py
  7. 2
      couchpotato/core/plugins/renamer/__init__.py
  8. 2
      couchpotato/core/plugins/renamer/main.py
  9. 3
      couchpotato/core/plugins/searcher/main.py
  10. 5
      couchpotato/core/plugins/subtitle/main.py
  11. 7
      couchpotato/core/providers/torrent/kickasstorrents/main.py
  12. 3
      couchpotato/core/providers/torrent/torrentleech/main.py
  13. BIN
      couchpotato/static/images/icon.attention.png
  14. BIN
      couchpotato/static/images/icon.spinner.gif
  15. 1
      couchpotato/static/scripts/page/wanted.js
  16. 6
      couchpotato/static/style/main.css

4
couchpotato/core/_base/updater/main.py

@ -32,7 +32,7 @@ class Updater(Plugin):
self.updater = SourceUpdater() self.updater = SourceUpdater()
fireEvent('schedule.interval', 'updater.check', self.autoUpdate, hours = 6) fireEvent('schedule.interval', 'updater.check', self.autoUpdate, hours = 6)
addEvent('app.load', self.check) addEvent('app.load', self.autoUpdate)
addEvent('updater.info', self.info) addEvent('updater.info', self.info)
addApiView('updater.info', self.getInfo, docs = { addApiView('updater.info', self.getInfo, docs = {
@ -208,7 +208,7 @@ class GitUpdater(BaseUpdater):
def check(self): def check(self):
if self.update_version: if self.update_version:
return return True
log.info('Checking for new version on github for %s', self.repo_name) log.info('Checking for new version on github for %s', self.repo_name)
if not Env.get('dev'): if not Env.get('dev'):

2
couchpotato/core/_base/updater/static/updater.js

@ -62,6 +62,8 @@ var UpdaterBase = new Class({
createMessage: function(data){ createMessage: function(data){
var self = this; var self = this;
if(self.message) return;
var changelog = 'https://github.com/'+data.repo_name+'/compare/'+data.version.hash+'...'+data.branch; var changelog = 'https://github.com/'+data.repo_name+'/compare/'+data.version.hash+'...'+data.branch;
if(data.update_version.changelog) if(data.update_version.changelog)
changelog = data.update_version.changelog + '#' + data.version.hash+'...'+data.update_version.hash changelog = data.update_version.changelog + '#' + data.version.hash+'...'+data.update_version.hash

5
couchpotato/core/plugins/base.py

@ -95,7 +95,10 @@ class Plugin(object):
return False return False
# http request # http request
def urlopen(self, url, timeout = 30, params = {}, headers = {}, opener = None, multipart = False, show_error = True): def urlopen(self, url, timeout = 30, params = None, headers = None, opener = None, multipart = False, show_error = True):
if not headers: headers = {}
if not params: params = {}
# Fill in some headers # Fill in some headers
if not headers.get('Referer'): if not headers.get('Referer'):

7
couchpotato/core/plugins/manage/main.py

@ -73,6 +73,13 @@ class Manage(Plugin):
for done_movie in done_movies: for done_movie in done_movies:
if done_movie['library']['identifier'] not in added_identifiers: if done_movie['library']['identifier'] not in added_identifiers:
fireEvent('movie.delete', movie_id = done_movie['id'], delete_from = 'all') fireEvent('movie.delete', movie_id = done_movie['id'], delete_from = 'all')
else:
for release in done_movie.get('releases', []):
for release_file in release.get('files', []):
# Remove release not available anymore
if not os.path.isfile(release_file['path']):
fireEvent('release.clean', release['id'])
break
Env.prop('manage.last_update', time.time()) Env.prop('manage.last_update', time.time())

22
couchpotato/core/plugins/movie/static/movie.js

@ -357,7 +357,7 @@ var ReleaseAction = new Class({
Array.each(self.movie.data.releases, function(release){ Array.each(self.movie.data.releases, function(release){
var status = Status.get(release.status_id), var status = Status.get(release.status_id),
quality = Quality.getProfile(release.quality_id), quality = Quality.getProfile(release.quality_id) || {},
info = release.info; info = release.info;
try { try {
@ -365,7 +365,8 @@ var ReleaseAction = new Class({
} catch(e){} } catch(e){}
new Element('div', { new Element('div', {
'class': 'item '+status.identifier 'class': 'item '+status.identifier,
'id': 'release_'+release.id
}).adopt( }).adopt(
new Element('span.name', {'text': self.get(release, 'name'), 'title': self.get(release, 'name')}), 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.status', {'text': status.identifier, 'class': 'release_status '+status.identifier}),
@ -382,7 +383,8 @@ var ReleaseAction = new Class({
'events': { 'events': {
'click': function(e){ 'click': function(e){
(e).preventDefault(); (e).preventDefault();
self.download(release); if(!this.hasClass('completed'))
self.download(release);
} }
} }
}), }),
@ -414,9 +416,21 @@ var ReleaseAction = new Class({
download: function(release){ download: function(release){
var self = this; 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', { Api.request('release.download', {
'data': { 'data': {
'id': release.id '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.');
} }
}); });
}, },
@ -456,7 +470,7 @@ var TrailerAction = new Class({
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 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({ var url = data_url.substitute({
'title': self.movie.getTitle(), 'title': encodeURI(self.movie.getTitle()),
'year': self.movie.get('year'), 'year': self.movie.get('year'),
'offset': offset || 1 'offset': offset || 1
}), }),

45
couchpotato/core/plugins/release/main.py

@ -7,6 +7,7 @@ from couchpotato.core.plugins.base import Plugin
from couchpotato.core.plugins.scanner.main import Scanner from couchpotato.core.plugins.scanner.main import Scanner
from couchpotato.core.settings.model import File, Release as Relea, Movie from couchpotato.core.settings.model import File, Release as Relea, Movie
from sqlalchemy.sql.expression import and_, or_ from sqlalchemy.sql.expression import and_, or_
import os
log = CPLog(__name__) log = CPLog(__name__)
@ -22,7 +23,7 @@ class Release(Plugin):
'id': {'type': 'id', 'desc': 'ID of the release object in release-table'} 'id': {'type': 'id', 'desc': 'ID of the release object in release-table'}
} }
}) })
addApiView('release.delete', self.delete, docs = { addApiView('release.delete', self.deleteView, docs = {
'desc': 'Delete releases', 'desc': 'Delete releases',
'params': { 'params': {
'id': {'type': 'id', 'desc': 'ID of the release object in release-table'} 'id': {'type': 'id', 'desc': 'ID of the release object in release-table'}
@ -35,6 +36,9 @@ class Release(Plugin):
} }
}) })
addEvent('release.delete', self.delete)
addEvent('release.clean', self.clean)
def add(self, group): def add(self, group):
db = get_session() db = get_session()
@ -99,20 +103,41 @@ class Release(Plugin):
# Check database and update/insert if necessary # Check database and update/insert if necessary
return fireEvent('file.add', path = filepath, part = fireEvent('scanner.partnumber', file, single = True), type_tuple = Scanner.file_types.get(type), properties = properties, single = True) return fireEvent('file.add', path = filepath, part = fireEvent('scanner.partnumber', file, single = True), type_tuple = Scanner.file_types.get(type), properties = properties, single = True)
def delete(self): def deleteView(self):
release_id = getParam('id')
#db.close()
return jsonified({
'success': self.delete(release_id)
})
def delete(self, id):
db = get_session() db = get_session()
id = getParam('id')
rel = db.query(Relea).filter_by(id = id).first() rel = db.query(Relea).filter_by(id = id).first()
if rel: if rel:
rel.delete() rel.delete()
db.commit() db.commit()
return True
#db.close() return False
return jsonified({
'success': True def clean(self, id):
})
db = get_session()
rel = db.query(Relea).filter_by(id = id).first()
if rel:
for release_file in rel.files:
if not os.path.isfile(release_file.path):
db.delete(release_file)
db.commit()
return True
return False
def ignore(self): def ignore(self):
@ -146,16 +171,16 @@ class Release(Plugin):
provider = fireEvent('provider.belongs_to', item['url'], provider = item.get('provider'), single = True) provider = fireEvent('provider.belongs_to', item['url'], provider = item.get('provider'), single = True)
item['download'] = provider.download item['download'] = provider.download
fireEvent('searcher.download', data = item, movie = rel.movie.to_dict({ success = fireEvent('searcher.download', data = item, movie = rel.movie.to_dict({
'profile': {'types': {'quality': {}}}, 'profile': {'types': {'quality': {}}},
'releases': {'status': {}, 'quality': {}}, 'releases': {'status': {}, 'quality': {}},
'library': {'titles': {}, 'files':{}}, 'library': {'titles': {}, 'files':{}},
'files': {} 'files': {}
}), manual = True) }), manual = True, single = True)
#db.close() #db.close()
return jsonified({ return jsonified({
'success': True 'success': success
}) })
else: else:
log.error('Couldn\'t find release with id: %s', id) log.error('Couldn\'t find release with id: %s', id)

2
couchpotato/core/plugins/renamer/__init__.py

@ -84,7 +84,7 @@ config = [{
'advanced': True, 'advanced': True,
'name': 'separator', 'name': 'separator',
'label': 'Separator', 'label': 'Separator',
'description': 'Replace all the spaces with a character. Example: ".", "-". Leave empty to use spaces.', 'description': 'Replace all the spaces with a character. Example: ".", "-" (without quotes). Leave empty to use spaces.',
}, },
{ {
'advanced': True, 'advanced': True,

2
couchpotato/core/plugins/renamer/main.py

@ -165,7 +165,6 @@ class Renamer(Plugin):
# Group filename without cd extension # Group filename without cd extension
replacements['cd'] = '' replacements['cd'] = ''
replacements['cd_nr'] = '' replacements['cd_nr'] = ''
group['filename'] = self.doReplace(file_name, replacements)[:-(len(getExt(final_file_name)) + 1)]
# Meta naming # Meta naming
if file_type is 'trailer': if file_type is 'trailer':
@ -238,6 +237,7 @@ class Renamer(Plugin):
) )
rename_files = mergeDicts(rename_files, rename_extras) rename_files = mergeDicts(rename_files, rename_extras)
group['filename'] = self.doReplace(file_name, replacements)[:-(len(getExt(final_file_name)) + 1)]
group['destination_dir'] = os.path.join(destination, final_folder_name) group['destination_dir'] = os.path.join(destination, final_folder_name)
if multiple: if multiple:

3
couchpotato/core/plugins/searcher/main.py

@ -29,9 +29,6 @@ class Searcher(Plugin):
# Schedule cronjob # Schedule cronjob
fireEvent('schedule.cron', 'searcher.all', self.all_movies, day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute')) fireEvent('schedule.cron', 'searcher.all', self.all_movies, day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute'))
addEvent('app.load', self.all_movies)
def all_movies(self): def all_movies(self):
if self.in_progress: if self.in_progress:

5
couchpotato/core/plugins/subtitle/main.py

@ -54,11 +54,12 @@ class Subtitle(Plugin):
for lang in self.getLanguages(): for lang in self.getLanguages():
if lang not in available_languages: if lang not in available_languages:
download = subliminal.download_subtitles(files, multi = True, force = False, languages = [lang], services = self.services, cache_dir = Env.get('cache_dir')) download = subliminal.download_subtitles(files, multi = True, force = False, languages = [lang], services = self.services, cache_dir = Env.get('cache_dir'))
downloaded.extend(download) for subtitle in download:
downloaded.extend(download[subtitle])
for d_sub in downloaded: for d_sub in downloaded:
group['files']['subtitle'].add(d_sub.path) group['files']['subtitle'].add(d_sub.path)
group['subtitle_language'][d_sub.path] = [d_sub.language] group['subtitle_language'][d_sub.path] = [d_sub.language.alpha2]
return True return True

7
couchpotato/core/providers/torrent/kickasstorrents/main.py

@ -1,6 +1,6 @@
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from couchpotato.core.event import fireEvent from couchpotato.core.event import fireEvent
from couchpotato.core.helpers.variable import tryInt, getTitle from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.providers.torrent.base import TorrentProvider from couchpotato.core.providers.torrent.base import TorrentProvider
import StringIO import StringIO
@ -16,7 +16,7 @@ class KickAssTorrents(TorrentProvider):
urls = { urls = {
'test': 'http://www.kat.ph/', 'test': 'http://www.kat.ph/',
'detail': 'http://www.kat.ph/%s-t%s.html', 'detail': 'http://www.kat.ph/%s-t%s.html',
'search': 'http://www.kat.ph/%s-i%s/', 'search': 'http://www.kat.ph/i%s/',
'download': 'http://torcache.net/', 'download': 'http://torcache.net/',
} }
@ -30,6 +30,7 @@ class KickAssTorrents(TorrentProvider):
] ]
http_time_between_calls = 1 #seconds http_time_between_calls = 1 #seconds
cat_backup_id = None
def search(self, movie, quality): def search(self, movie, quality):
@ -38,7 +39,7 @@ class KickAssTorrents(TorrentProvider):
return results return results
cache_key = 'kickasstorrents.%s.%s' % (movie['library']['identifier'], quality.get('identifier')) cache_key = 'kickasstorrents.%s.%s' % (movie['library']['identifier'], quality.get('identifier'))
data = self.getCache(cache_key, self.urls['search'] % (getTitle(movie['library']), movie['library']['identifier'].replace('tt', ''))) data = self.getCache(cache_key, self.urls['search'] % (movie['library']['identifier'].replace('tt', '')))
if data: if data:
cat_ids = self.getCatId(quality['identifier']) cat_ids = self.getCatId(quality['identifier'])

3
couchpotato/core/providers/torrent/torrentleech/main.py

@ -52,6 +52,9 @@ class TorrentLeech(TorrentProvider):
try: try:
result_table = html.find('table', attrs = {'id' : 'torrenttable'}) result_table = html.find('table', attrs = {'id' : 'torrenttable'})
if not result_table:
return results
entries = result_table.find_all('tr') entries = result_table.find_all('tr')
for result in entries[1:]: for result in entries[1:]:

BIN
couchpotato/static/images/icon.attention.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
couchpotato/static/images/icon.spinner.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

1
couchpotato/static/scripts/page/wanted.js

@ -244,6 +244,7 @@ window.addEvent('domready', function(){
MovieActions.Done = { MovieActions.Done = {
'IMDB': IMDBAction 'IMDB': IMDBAction
,'Edit': MovieActions.Wanted.Edit ,'Edit': MovieActions.Wanted.Edit
,'Trailer': TrailerAction
,'Files': new Class({ ,'Files': new Class({
Extends: MovieAction, Extends: MovieAction,

6
couchpotato/static/style/main.css

@ -147,7 +147,7 @@ body > .spinner, .mask{
.icon.delete { background-image: url('../images/icon.delete.png'); } .icon.delete { background-image: url('../images/icon.delete.png'); }
.icon.download { background-image: url('../images/icon.download.png'); } .icon.download { background-image: url('../images/icon.download.png'); }
.icon.edit { background-image: url('../images/icon.edit.png'); } .icon.edit { background-image: url('../images/icon.edit.png'); }
.icon.check { background-image: url('../images/icon.check.png'); } .icon.completed { background-image: url('../images/icon.check.png'); }
.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'); }
@ -155,6 +155,8 @@ body > .spinner, .mask{
.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'); }
.icon.trailer { background-image: url('../images/icon.trailer.png'); } .icon.trailer { background-image: url('../images/icon.trailer.png'); }
.icon.spinner { background-image: url('../images/icon.spinner.gif'); }
.icon.attention { background-image: url('../images/icon.attention.png'); }
/*** Navigation ***/ /*** Navigation ***/
.header { .header {
@ -313,7 +315,7 @@ body > .spinner, .mask{
.header .message.update { .header .message.update {
text-align: center; text-align: center;
position: relative; position: relative;
top: -100px; top: -70px;
padding: 2px 0; padding: 2px 0;
background: #ff6134; background: #ff6134;
font-size: 12px; font-size: 12px;

Loading…
Cancel
Save