diff --git a/.build/Gruntfile.js b/.build/Gruntfile.js index 56bac94ee9b502dd7bd2313c1666de48bcbe3308..c17b6261be3f3e1386b53992fd7ad1832b7e405f 100644 --- a/.build/Gruntfile.js +++ b/.build/Gruntfile.js @@ -17,6 +17,13 @@ module.exports = function(grunt) { ], 'bootstrap-formhelpers': [ 'dist/js/bootstrap-formhelpers.min.js' + ], + 'isotope': [ + "dist/isotope.pkgd.min.js" + ], + "outlayer": [ + "item.js", + "outlayer.js" ] }, bowerOptions: { diff --git a/.build/bower.json b/.build/bower.json index 8954ee4c899e14d3b29161f6f0de765951556877..e9a78d46ac93ce8ebb4983e0f39277a43e4ab102 100644 --- a/.build/bower.json +++ b/.build/bower.json @@ -14,7 +14,6 @@ "bootstrap": "~3.3.5", "bootstrap-hover-dropdown": "~2.1.3", "jquery-ui": "~1.11.4", - "jquery-form": "~3.46.0", "jquery-timeago": "~1.4.3", "jquery-tokeninput": "~1.7.0", "bootstrap3-typeahead": "~3.1.1", @@ -24,6 +23,7 @@ "qtip2": "~2.2.1", "tablesorter": "jquery.tablesorter#~2.24.5", "jquery-confirm": "~2.5.2", - "bootstrap-formhelpers": "~2.3.0" + "bootstrap-formhelpers": "~2.3.0", + "isotope": "~2.2.2" } } diff --git a/.jshintrc b/.jshintrc index 7ec9ec8b693393d2ca5bffb94bdcc5e030309f43..d7a56347f30eba25d219bd053a83c8a6ab37b85b 100644 --- a/.jshintrc +++ b/.jshintrc @@ -28,6 +28,7 @@ "_": true, "bootbox": true, "PNotify": true, - "anonURL": true + "anonURL": true, + "window": true } } diff --git a/gui/slick/js/ajaxEpSearch.js b/gui/slick/js/ajaxEpSearch.js index ff66ca7c7916d12251b395946108eccbc4ab0ec2..5d5eea0f51db3d123554ead875e0e8db60fc95bf 100644 --- a/gui/slick/js/ajaxEpSearch.js +++ b/gui/slick/js/ajaxEpSearch.js @@ -213,7 +213,7 @@ $(document).ready(function () { } // applying the quality class var rSearchTerm = /(\w+)\s\((.+?)\)/; - htmlContent = data.result.replace(rSearchTerm,"$1"+' <span class="quality '+data.quality+'">'+"$2"+'</span>'); + htmlContent = data.result.replace(rSearchTerm,"$1"+' <span class="quality '+data.quality+'">'+"$2"+'</span>'); // update the status column if it exists parent.siblings('.col-status').html(htmlContent); // Only if the queuing was successful, disable the onClick event of the loading image diff --git a/gui/slick/js/blackwhite.js b/gui/slick/js/blackwhite.js index e8618899c95ebd24c0d385f35375e579231eb83a..82c51368715a39d2a6db0e6c67f361bab4461c83 100644 --- a/gui/slick/js/blackwhite.js +++ b/gui/slick/js/blackwhite.js @@ -1,24 +1,24 @@ function generate_bwlist() { var realvalues = []; - $('#white option').each(function(i, selected) { - realvalues[i] = $(selected).val(); - }); - $("#whitelist").val(realvalues.join(",")); + $('#white option').each(function(i, selected) { + realvalues[i] = $(selected).val(); + }); + $("#whitelist").val(realvalues.join(",")); - realvalues = []; - $('#black option').each(function(i, selected) { - realvalues[i] = $(selected).val(); - }); - $("#blacklist").val(realvalues.join(",")); + realvalues = []; + $('#black option').each(function(i, selected) { + realvalues[i] = $(selected).val(); + }); + $("#blacklist").val(realvalues.join(",")); } function update_bwlist(show_name) { - $('#pool').children().remove(); + $('#pool').children().remove(); - $('#blackwhitelist').show(); - if (show_name) { - $.getJSON(srRoot + '/home/fetch_releasegroups', {'show_name': show_name}, function (data) { + $('#blackwhitelist').show(); + if (show_name) { + $.getJSON(srRoot + '/home/fetch_releasegroups', {'show_name': show_name}, function (data) { if (data.result == 'success') { $.each(data.groups, function(i, group) { var option = $("<option>"); @@ -27,9 +27,9 @@ function update_bwlist(show_name) { option.appendTo('#pool'); }); } - }); - } + }); } +} $('#removeW').click(function() { !$('#white option:selected').remove().appendTo('#pool'); diff --git a/gui/slick/js/configProviders.js b/gui/slick/js/configProviders.js index e2a7a49ed83ad5aaceb102bef6a3b250c4bac9e8..da490f82544288ca55eb870a4b24a1ac401c202a 100644 --- a/gui/slick/js/configProviders.js +++ b/gui/slick/js/configProviders.js @@ -354,7 +354,7 @@ $(document).ready(function(){ var selectedProvider = $('#editANewznabProvider :selected').val(); if (selectedProvider === "addNewznab"){ - return; + return; } var url = $('#newznab_url').val(); @@ -371,7 +371,7 @@ $(document).ready(function(){ var selectedProvider = $('#editATorrentRssProvider :selected').val(); if (selectedProvider === "addTorrentRss"){ - return; + return; } var url = $('#torrentrss_url').val(); diff --git a/gui/slick/js/core.js b/gui/slick/js/core.js index 1fcbeae568427ab310002eb23a6e9d9f37aab25b..12675949b7794879d37ffe98c9e2ec12e7b1bdf9 100644 --- a/gui/slick/js/core.js +++ b/gui/slick/js/core.js @@ -3,7 +3,7 @@ var srRoot = getMeta('srRoot'), themeSpinner = getMeta('themeSpinner'), anonURL = getMeta('anonURL'), - topImageHtml = '<img src="' + srRoot + '/images/top.gif" width="31" height="11" alt="Jump to top" />', // jshint ignore:line + topImageHtml = '<img src="' + srRoot + '/images/top.gif" width="31" height="11" alt="Jump to top" />', loading = '<img src="' + srRoot + '/images/loading16' + themeSpinner + '.gif" height="16" width="16" />'; var configSuccess = function(){ @@ -142,7 +142,7 @@ var SICKRAGE = { if (!$(this).prop('checked')) { $('#content_'+$(this).attr('id')).hide(); } }); - $(".enabler").click(function() { + $(".enabler").on('click', function() { if ($(this).prop('checked')){ $('#content_'+$(this).attr('id')).fadeIn("fast", "linear"); } else { @@ -150,7 +150,7 @@ var SICKRAGE = { } }); - $(".viewIf").click(function() { + $(".viewIf").on('click', function() { if ($(this).prop('checked')) { $('.hide_if_'+$(this).attr('id')).css('display','none'); $('.show_if_'+$(this).attr('id')).fadeIn("fast", "linear"); @@ -160,7 +160,7 @@ var SICKRAGE = { } }); - $(".datePresets").click(function() { + $(".datePresets").on('click', function() { var def = $('#date_presets').val(); if ($(this).prop('checked') && '%x' === def) { def = '%a, %b %d, %Y'; @@ -198,11 +198,11 @@ var SICKRAGE = { } }); - $('#api_key').click(function(){ + $('#api_key').on('click', function(){ $('#api_key').select(); }); - $("#generate_new_apikey").click(function(){ + $("#generate_new_apikey").on('click', function(){ $.get(srRoot + '/config/general/generateApiKey', function(data){ if (data.error !== undefined) { alert(data.error); @@ -212,7 +212,7 @@ var SICKRAGE = { }); }); - $('#branchCheckout').click(function() { + $('#branchCheckout').on('click', function() { var url = srRoot + '/home/branchCheckout?branch=' + $("#branchVersion").val(); var checkDBversion = srRoot + "/home/getDBcompare"; $.getJSON(checkDBversion, function(data){ @@ -252,7 +252,7 @@ var SICKRAGE = { $('#log_dir').fileBrowser({ title: 'Select log file folder location' }); }, backupRestore: function(){ - $('#Backup').click(function() { + $('#Backup').on('click', function() { $("#Backup").attr("disabled", true); $('#Backup-result').html(loading); var backupDir = $("#backupDir").val(); @@ -262,7 +262,7 @@ var SICKRAGE = { $("#Backup").attr("disabled", false); }); }); - $('#Restore').click(function() { + $('#Restore').on('click', function() { $("#Restore").attr("disabled", true); $('#Restore-result').html(loading); var backupFile = $("#backupFile").val(); @@ -281,7 +281,7 @@ var SICKRAGE = { if (!$(this).prop('checked')) { $('#content_'+$(this).attr('id')).hide(); } }); - $(".enabler").click(function() { + $(".enabler").on('click', function() { if ($(this).prop('checked')){ $('#content_'+$(this).attr('id')).fadeIn("fast", "linear"); } else { @@ -289,7 +289,7 @@ var SICKRAGE = { } }); - $(".viewIf").click(function() { + $(".viewIf").on('click', function() { if ($(this).prop('checked')) { $('.hide_if_'+$(this).attr('id')).css('display','none'); $('.show_if_'+$(this).attr('id')).fadeIn("fast", "linear"); @@ -299,7 +299,7 @@ var SICKRAGE = { } }); - $(".datePresets").click(function() { + $(".datePresets").on('click', function() { var def = $('#date_presets').val(); if ($(this).prop('checked') && '%x' == def) { // jshint ignore:line def = '%a, %b %d, %Y'; @@ -337,11 +337,11 @@ var SICKRAGE = { } }); - $('#api_key').click(function(){ + $('#api_key').on('click', function(){ $('#api_key').select(); }); - $("#generate_new_apikey").click(function(){ + $("#generate_new_apikey").on('click', function(){ $.get(srRoot + '/config/general/generateApiKey', function(data){ if (data.error !== undefined) { alert(data.error); @@ -351,7 +351,7 @@ var SICKRAGE = { }); }); - $('#branchCheckout').click(function() { + $('#branchCheckout').on('click', function() { var url = srRoot+'/home/branchCheckout?branch='+$("#branchVersion").val(); var checkDBversion = srRoot + "/home/getDBcompare"; $.getJSON(checkDBversion, function(data){ @@ -376,7 +376,7 @@ var SICKRAGE = { notifications: function() { $('#config-components').tabs(); - $('#testGrowl').click(function () { + $('#testGrowl').on('click', function () { var growl = {}; growl.host = $.trim($('#growl_host').val()); growl.password = $.trim($('#growl_password').val()); @@ -394,7 +394,7 @@ var SICKRAGE = { }); }); - $('#testProwl').click(function () { + $('#testProwl').on('click', function () { var prowl = {}; prowl.api = $.trim($('#prowl_api').val()); prowl.priority = $('#prowl_priority').val(); @@ -412,7 +412,7 @@ var SICKRAGE = { }); }); - $('#testKODI').click(function () { + $('#testKODI').on('click', function () { var kodi = {}; kodi.host = $.trim($('#kodi_host').val()); kodi.username = $.trim($('#kodi_username').val()); @@ -431,7 +431,7 @@ var SICKRAGE = { }); }); - $('#testPMC').click(function () { + $('#testPMC').on('click', function () { var plex = {}; plex.client = {}; plex.client.host = $.trim($('#plex_host').val()); @@ -451,7 +451,7 @@ var SICKRAGE = { }); }); - $('#testPMS').click(function () { + $('#testPMS').on('click', function () { var plex = {}; plex.server = {}; plex.server.host = $.trim($('#plex_server_host').val()); @@ -472,7 +472,7 @@ var SICKRAGE = { }); }); - $('#testEMBY').click(function () { + $('#testEMBY').on('click', function () { var emby = {}; emby.host = $('#emby_host').val(); emby.apikey = $('#emby_apikey').val(); @@ -499,7 +499,7 @@ var SICKRAGE = { }); }); - $('#testBoxcar').click(function() { + $('#testBoxcar').on('click', function() { var boxcar = {}; boxcar.username = $.trim($('#boxcar_username').val()); if (!boxcar.username) { @@ -516,7 +516,7 @@ var SICKRAGE = { }); }); - $('#testBoxcar2').click(function () { + $('#testBoxcar2').on('click', function () { var boxcar2 = {}; boxcar2.accesstoken = $.trim($('#boxcar2_accesstoken').val()); if (!boxcar2.accesstoken) { @@ -533,7 +533,7 @@ var SICKRAGE = { }); }); - $('#testPushover').click(function () { + $('#testPushover').on('click', function () { var pushover = {}; pushover.userkey = $('#pushover_userkey').val(); pushover.apikey = $('#pushover_apikey').val(); @@ -560,14 +560,14 @@ var SICKRAGE = { }); }); - $('#testLibnotify').click(function() { + $('#testLibnotify').on('click', function() { $('#testLibnotify-result').html(loading); $.get(srRoot + '/home/testLibnotify', function (data) { $('#testLibnotify-result').html(data); }); }); - $('#twitterStep1').click(function() { + $('#twitterStep1').on('click', function() { $('#testTwitter-result').html(loading); $.get(srRoot + '/home/twitterStep1', function (data) { window.open(data); @@ -576,7 +576,7 @@ var SICKRAGE = { }); }); - $('#twitterStep2').click(function () { + $('#twitterStep2').on('click', function () { var twitter = {}; twitter.key = $.trim($('#twitter_key').val()); if (!twitter.key) { @@ -591,13 +591,13 @@ var SICKRAGE = { }); }); - $('#testTwitter').click(function() { + $('#testTwitter').on('click', function() { $.get(srRoot + '/home/testTwitter', function(data) { $('#testTwitter-result').html(data); }); }); - $('#settingsNMJ').click(function() { + $('#settingsNMJ').on('click', function() { var nmj = {}; if (!$('#nmj_host').val()) { alert('Please fill in the Popcorn IP address'); @@ -630,7 +630,7 @@ var SICKRAGE = { }); }); - $('#testNMJ').click(function () { + $('#testNMJ').on('click', function () { var nmj = {}; nmj.host = $.trim($('#nmj_host').val()); nmj.database = $('#nmj_database').val(); @@ -649,7 +649,7 @@ var SICKRAGE = { }); }); - $('#settingsNMJv2').click(function() { + $('#settingsNMJv2').on('click', function() { var nmjv2 = {}; if(!$('#nmjv2_host').val()) { alert('Please fill in the Popcorn IP address'); @@ -684,7 +684,7 @@ var SICKRAGE = { }); }); - $('#testNMJv2').click(function () { + $('#testNMJv2').on('click', function () { var nmjv2 = {}; nmjv2.host = $.trim($('#nmjv2_host').val()); if (!nmjv2.host) { @@ -701,7 +701,7 @@ var SICKRAGE = { }); }); - $('#testFreeMobile').click(function () { + $('#testFreeMobile').on('click', function () { var freemobile = {}; freemobile.id = $.trim($('#freemobile_id').val()); freemobile.apikey = $.trim($('#freemobile_apikey').val()); @@ -728,7 +728,7 @@ var SICKRAGE = { }); }); - $('#TraktGetPin').click(function () { + $('#TraktGetPin').on('click', function () { var trakt = {}; trakt.pinUrl = $('#trakt_pin_url').val(); window.open(trakt.pinUrl, "popUp", "toolbar=no, scrollbars=no, resizable=no, top=200, left=200, width=650, height=550"); @@ -748,7 +748,7 @@ var SICKRAGE = { } }); - $('#authTrakt').click(function() { + $('#authTrakt').on('click', function() { var trakt = {}; trakt.pin = $('#trakt_pin').val(); if (trakt.pin.length !== 0) { @@ -761,7 +761,7 @@ var SICKRAGE = { } }); - $('#testTrakt').click(function () { + $('#testTrakt').on('click', function () { var trakt = {}; trakt.username = $.trim($('#trakt_username').val()); trakt.trendingBlacklist = $.trim($('#trakt_blacklist_name').val()); @@ -790,7 +790,7 @@ var SICKRAGE = { }); }); - $('#testEmail').click(function () { + $('#testEmail').on('click', function () { var status, host, port, tls, from, user, pwd, err, to; status = $('#testEmail-result'); status.html(loading); @@ -821,13 +821,13 @@ var SICKRAGE = { status.html('<p style="color: red;">You must provide a recipient email address!</p>'); } else { $.get(srRoot + '/home/testEmail', { - host: host, - port: port, - smtp_from: from, // jshint ignore:line - use_tls: tls, // jshint ignore:line - user: user, - pwd: pwd, - to: to + 'host': host, + 'port': port, + 'smtp_from': from, // @TODO we shouldn't be using any reserved words like "from" + 'use_tls': tls, + 'user': user, + 'pwd': pwd, + 'to': to }, function (msg) { $('#testEmail-result').html(msg); }); @@ -835,7 +835,7 @@ var SICKRAGE = { } }); - $('#testNMA').click(function () { + $('#testNMA').on('click', function () { var nma = {}; nma.api = $.trim($('#nma_api').val()); nma.priority = $('#nma_priority').val(); @@ -853,7 +853,7 @@ var SICKRAGE = { }); }); - $('#testPushalot').click(function () { + $('#testPushalot').on('click', function () { var pushalot = {}; pushalot.authToken = $.trim($('#pushalot_authorizationtoken').val()); if (!pushalot.authToken) { @@ -870,7 +870,7 @@ var SICKRAGE = { }); }); - $('#testPushbullet').click(function () { + $('#testPushbullet').on('click', function () { var pushbullet = {}; pushbullet.api = $.trim($('#pushbullet_api').val()); if (!pushbullet.api) { @@ -924,13 +924,13 @@ var SICKRAGE = { } }); - $("#pushbullet_device_list").change(function(){ + $("#pushbullet_device_list").on('change', function(){ $("#pushbullet_device").val($("#pushbullet_device_list").val()); $('#testPushbullet-result').html("Don't forget to save your new pushbullet settings."); }); } - $('#getPushbulletDevices').click(function(){ + $('#getPushbulletDevices').on('click', function(){ getPushbulletDevices("Device list updated. Please choose a device to push to."); }); @@ -938,7 +938,7 @@ var SICKRAGE = { getPushbulletDevices(); // @TODO Find out what notify_data actually does since it doesn't seem to be a real function - $('#email_show').change(function() { + $('#email_show').on('change', function() { var key = parseInt($('#email_show').val(), 10); $('#email_show_list').val(key >= 0 ? notify_data[key.toString()].list : ''); // jshint ignore:line }); @@ -967,7 +967,7 @@ var SICKRAGE = { // Load the per show notify lists everytime this page is loaded loadShowNotifyLists(); - $('#email_show_save').click(function() { + $('#email_show_save').on('click', function() { $.post(srRoot + "/home/saveShowNotifyList", { show: $('#email_show').val(), emails: $('#email_show_list').val() @@ -978,7 +978,7 @@ var SICKRAGE = { }); // show instructions for plex when enabled - $('#use_plex').click(function() { + $('#use_plex').on('click', function() { if ($(this).is(':checked')) { $('.plexinfo').removeClass('hide'); } else { @@ -1020,8 +1020,8 @@ var SICKRAGE = { example.animeType = $('input[name="naming_anime"]:checked').val(); $.get(srRoot + '/config/postProcessing/testNaming', { - pattern: example.pattern, - anime_type: 3 // jshint ignore:line + 'pattern': example.pattern, + 'anime_type': 3 // jshint ignore:line }, function (data) { if (data) { $('#naming_example').text(data + '.ext'); @@ -1032,9 +1032,9 @@ var SICKRAGE = { }); $.get(srRoot + '/config/postProcessing/testNaming', { - pattern: example.pattern, - multi: example.multi, - anime_type: 3 // jshint ignore:line + 'pattern': example.pattern, + 'multi': example.multi, + 'anime_type': 3 }, function (data) { if (data) { $('#naming_example_multi').text(data + '.ext'); @@ -1045,9 +1045,9 @@ var SICKRAGE = { }); $.get(srRoot + '/config/postProcessing/isNamingValid', { - pattern: example.pattern, - multi: example.multi, - anime_type: example.animeType // jshint ignore:line + 'pattern': example.pattern, + 'multi': example.multi, + 'anime_type': example.animeType }, function (data) { if (data === "invalid") { $('#naming_pattern').qtip('option', { @@ -1078,8 +1078,8 @@ var SICKRAGE = { var pattern = $('#naming_abd_pattern').val(); $.get(srRoot + '/config/postProcessing/testNaming', { - pattern: pattern, - abd: 'True' + 'pattern': pattern, + 'abd': 'True' }, function (data) { if (data) { $('#naming_abd_example').text(data + '.ext'); @@ -1090,8 +1090,8 @@ var SICKRAGE = { }); $.get(srRoot + '/config/postProcessing/isNamingValid', { - pattern: pattern, - abd: 'True' + 'pattern': pattern, + 'abd': 'True' }, function (data) { if (data === "invalid") { $('#naming_abd_pattern').qtip('option', { @@ -1122,8 +1122,8 @@ var SICKRAGE = { var pattern = $('#naming_sports_pattern').val(); $.get(srRoot + '/config/postProcessing/testNaming', { - pattern: pattern, - sports: 'True' + 'pattern': pattern, + 'sports': 'True' }, function (data) { if (data) { $('#naming_sports_example').text(data + '.ext'); @@ -1134,8 +1134,8 @@ var SICKRAGE = { }); $.get(srRoot + '/config/postProcessing/isNamingValid', { - pattern: pattern, - sports: 'True' + 'pattern': pattern, + 'sports': 'True' }, function (data) { if (data === "invalid") { $('#naming_sports_pattern').qtip('option', { @@ -1169,8 +1169,8 @@ var SICKRAGE = { example.animeType = $('input[name="naming_anime"]:checked').val(); $.get(srRoot + '/config/postProcessing/testNaming', { - pattern: example.pattern, - anime_type: example.animeType // jshint ignore:line + 'pattern': example.pattern, + 'anime_type': example.animeType }, function (data) { if (data) { $('#naming_example_anime').text(data + '.ext'); @@ -1181,9 +1181,9 @@ var SICKRAGE = { }); $.get(srRoot + '/config/postProcessing/testNaming', { - pattern: example.pattern, - multi: example.multi, - anime_type: example.animeType // jshint ignore:line + 'pattern': example.pattern, + 'multi': example.multi, + 'anime_type': example.animeType }, function (data) { if (data) { $('#naming_example_multi_anime').text(data + '.ext'); @@ -1194,9 +1194,9 @@ var SICKRAGE = { }); $.get(srRoot + '/config/postProcessing/isNamingValid', { - pattern: example.pattern, - multi: example.multi, - anime_type: example.animeType // jshint ignore:line + 'pattern': example.pattern, + 'multi': example.multi, + 'anime_type': example.animeType }, function (data) { if (data === "invalid") { $('#naming_pattern').qtip('option', { @@ -1307,38 +1307,38 @@ var SICKRAGE = { setupAnimeNaming(); }); - $('#naming_multi_ep').change(fillExamples); - $('#naming_pattern').focusout(fillExamples); - $('#naming_pattern').keyup(function () { + $('#naming_multi_ep').on('change', fillExamples); + $('#naming_pattern').on('focusout', fillExamples); + $('#naming_pattern').on('keyup', function() { typewatch(function () { fillExamples(); }, 500); }); - $('#naming_anime_multi_ep').change(fillAnimeExamples); - $('#naming_anime_pattern').focusout(fillAnimeExamples); - $('#naming_anime_pattern').keyup(function () { + $('#naming_anime_multi_ep').on('change', fillAnimeExamples); + $('#naming_anime_pattern').on('focusout', fillAnimeExamples); + $('#naming_anime_pattern').on('keyup', function() { typewatch(function () { fillAnimeExamples(); }, 500); }); - $('#naming_abd_pattern').focusout(fillExamples); - $('#naming_abd_pattern').keyup(function () { + $('#naming_abd_pattern').on('focusout', fillExamples); + $('#naming_abd_pattern').on('keyup', function() { typewatch(function () { fillAbdExamples(); }, 500); }); - $('#naming_sports_pattern').focusout(fillExamples); - $('#naming_sports_pattern').keyup(function () { + $('#naming_sports_pattern').on('focusout', fillExamples); + $('#naming_sports_pattern').on('keyup', function() { typewatch(function () { fillSportsExamples(); }, 500); }); - $('#naming_anime_pattern').focusout(fillExamples); - $('#naming_anime_pattern').keyup(function () { + $('#naming_anime_pattern').on('focusout', fillExamples); + $('#naming_anime_pattern').on('keyup', function() { typewatch(function () { fillAnimeExamples(); }, 500); @@ -1506,14 +1506,6 @@ var SICKRAGE = { $('#torrent_dir').fileBrowser({ title: 'Select .torrent black hole/watch location' }); $('#torrent_path').fileBrowser({ title: 'Select .torrent download location' }); - function toggleTorrentTitle(){ - if ($('#use_torrents').prop('checked')){ - $('#no_torrents').show(); - } else { - $('#no_torrents').hide(); - } - } - $.fn.nzbMethodHandler = function() { var selectedProvider = $('#nzb_method :selected').val(), blackholeSettings = '#blackhole_settings', @@ -1539,28 +1531,6 @@ var SICKRAGE = { } }; - $.fn.rtorrentScgi = function(){ - var selectedProvider = $('#torrent_method :selected').val(); - - if (selectedProvider.toLowerCase() === 'rtorrent') { - var hostname = $('#torrent_host').prop('value'); - var isMatch = hostname.substr(0, 7) === "scgi://"; - - if (isMatch) { - $('#torrent_username_option').hide(); - $('#torrent_username').prop('value', ''); - $('#torrent_password_option').hide(); - $('#torrent_password').prop('value', ''); - $('#torrent_auth_type_option').hide(); - $("#torrent_auth_type option[value=none]").attr('selected', 'selected'); - } else { - $('#torrent_username_option').show(); - $('#torrent_password_option').show(); - $('#torrent_auth_type_option').show(); - } - } - }; - $.fn.torrentMethodHandler = function() { $('#options_torrent_clients').hide(); $('#options_torrent_blackhole').hide(); @@ -1574,104 +1544,88 @@ var SICKRAGE = { rpcurl = ' RPC URL'; if (selectedProvider.toLowerCase() !== 'blackhole') { - var label_warning_deluge = '#label_warning_deluge', - label_anime_warning_deluge = '#label_anime_warning_deluge', - host_desc_rtorrent = '#host_desc_rtorrent', - host_desc_torrent = '#host_desc_torrent', - torrent_verify_cert_option = '#torrent_verify_cert_option', - torrent_path_option = '#torrent_path_option', - torrent_seed_time_option = '#torrent_seed_time_option', - torrent_high_bandwidth_option = '#torrent_high_bandwidth_option', - torrent_label_option = '#torrent_label_option', - torrent_label_anime_option = '#torrent_label_anime_option', - path_synology = '#path_synology', - torrent_paused_option = '#torrent_paused_option'; - - $(label_warning_deluge).hide(); - $(label_anime_warning_deluge).hide(); - $(label_anime_warning_deluge).hide(); - $(host_desc_rtorrent).hide(); - $(host_desc_torrent).show(); - $(torrent_verify_cert_option).hide(); - $(torrent_verify_deluge).hide(); - $(torrent_verify_rtorrent).hide(); - $(torrent_auth_type_option).hide(); - $(torrent_path_option).show(); - $(torrent_path_option).find('.fileBrowser').show(); - $(torrent_seed_time_option).hide(); - $(torrent_high_bandwidth_option).hide(); - $(torrent_label_option).show(); - $(torrent_label_anime_option).show(); - $(path_synology).hide(); - $(torrent_paused_option).show(); - $(torrent_rpcurl_option).hide(); - $(this).rtorrentScgi(); + $('#label_warning_deluge').hide(); + $('#label_anime_warning_deluge').hide(); + $('#host_desc_torrent').show(); + $('#torrent_verify_cert_option').hide(); + $('#torrent_verify_deluge').hide(); + $('#torrent_verify_rtorrent').hide(); + $('#torrent_auth_type_option').hide(); + $('#torrent_path_option').show(); + $('#torrent_path_option').find('.fileBrowser').show(); + $('#torrent_seed_time_option').hide(); + $('#torrent_high_bandwidth_option').hide(); + $('#torrent_label_option').show(); + $('#torrent_label_anime_option').show(); + $('#path_synology').hide(); + $('#torrent_paused_option').show(); + $('#torrent_rpcurl_option').hide(); if (selectedProvider.toLowerCase() === 'utorrent') { client = 'uTorrent'; - $(torrent_path_option).hide(); + $('#torrent_path_option').hide(); $('#torrent_seed_time_label').text('Minimum seeding time is'); - $(torrent_seed_time_option).show(); + $('#torrent_seed_time_option').show(); $('#host_desc_torrent').text('URL to your uTorrent client (e.g. http://localhost:8000)'); } else if (selectedProvider.toLowerCase() === 'transmission'){ client = 'Transmission'; $('#torrent_seed_time_label').text('Stop seeding when inactive for'); - $(torrent_seed_time_option).show(); - $(torrent_high_bandwidth_option).show(); - $(torrent_label_option).hide(); - $(torrent_label_anime_option).hide(); - $(torrent_rpcurl_option).show(); + $('#torrent_seed_time_option').show(); + $('#torrent_high_bandwidth_option').show(); + $('#torrent_label_option').hide(); + $('#torrent_label_anime_option').hide(); + $('#torrent_rpcurl_option').show(); $('#host_desc_torrent').text('URL to your Transmission client (e.g. http://localhost:9091)'); } else if (selectedProvider.toLowerCase() === 'deluge'){ client = 'Deluge'; - $(torrent_verify_cert_option).show(); - $(torrent_verify_deluge).show(); - $(torrent_verify_rtorrent).hide(); - $(label_warning_deluge).show(); - $(label_anime_warning_deluge).show(); + $('#torrent_verify_cert_option').show(); + $('#torrent_verify_deluge').show(); + $('#torrent_verify_rtorrent').hide(); + $('#label_warning_deluge').show(); + $('#label_anime_warning_deluge').show(); $('#torrent_username_option').hide(); $('#torrent_username').prop('value', ''); $('#host_desc_torrent').text('URL to your Deluge client (e.g. http://localhost:8112)'); - } else if ('deluged' == selectedProvider){ + } else if (selectedProvider.toLowerCase() === 'deluged'){ client = 'Deluge'; - $(torrent_verify_cert_option).hide(); - $(torrent_verify_deluge).hide(); - $(torrent_verify_rtorrent).hide(); - $(label_warning_deluge).show(); - $(label_anime_warning_deluge).show(); + $('#torrent_verify_cert_option').hide(); + $('#torrent_verify_deluge').hide(); + $('#torrent_verify_rtorrent').hide(); + $('#label_warning_deluge').show(); + $('#label_anime_warning_deluge').show(); $('#torrent_username_option').show(); $('#host_desc_torrent').text('IP or Hostname of your Deluge Daemon (e.g. scgi://localhost:58846)'); - } else if ('download_station' == selectedProvider){ + } else if (selectedProvider.toLowerCase() === 'download_station'){ client = 'Synology DS'; - $(torrent_label_option).hide(); - $(torrent_label_anime_option).hide(); + $('#torrent_label_option').hide(); + $('#torrent_label_anime_option').hide(); $('#torrent_paused_option').hide(); - $(torrent_path_option).find('.fileBrowser').hide(); + $('#torrent_path_option').find('.fileBrowser').hide(); $('#host_desc_torrent').text('URL to your Synology DS client (e.g. http://localhost:5000)'); - $(path_synology).show(); - } else if ('rtorrent' == selectedProvider){ + $('#path_synology').show(); + } else if (selectedProvider.toLowerCase() === 'rtorrent'){ client = 'rTorrent'; - $(torrent_paused_option).hide(); + $('#torrent_paused_option').hide(); $('#host_desc_torrent').text('URL to your rTorrent client (e.g. scgi://localhost:5000 <br> or https://localhost/rutorrent/plugins/httprpc/action.php)'); - $(torrent_verify_cert_option).show(); - $(torrent_verify_deluge).hide(); - $(torrent_verify_rtorrent).show(); - $(torrent_auth_type_option).show(); - } else if ('qbittorrent' == selectedProvider){ + $('#torrent_verify_cert_option').show(); + $('#torrent_verify_deluge').hide(); + $('#torrent_verify_rtorrent').show(); + $('#torrent_auth_type_option').show(); + } else if (selectedProvider.toLowerCase() === 'qbittorrent'){ client = 'qbittorrent'; - $(torrent_path_option).hide(); - $(torrent_label_option).hide(); - $(torrent_label_anime_option).hide(); + $('#torrent_path_option').hide(); + $('#torrent_label_option').hide(); + $('#torrent_label_anime_option').hide(); $('#host_desc_torrent').text('URL to your qbittorrent client (e.g. http://localhost:8080)'); - } else if ('mlnet' == selectedProvider){ + } else if (selectedProvider.toLowerCase() === 'mlnet'){ client = 'mlnet'; - $(torrent_path_option).hide(); - $(torrent_label_option).hide(); - $(torrent_verify_cert_option).hide(); - $(torrent_verify_deluge).hide(); - $(torrent_verify_rtorrent).hide(); - $(torrent_label_anime_option).hide(); - $(torrent_paused_option).hide(); + $('#torrent_path_option').hide(); + $('#torrent_label_option').hide(); + $('#torrent_verify_cert_option').hide(); + $('#torrent_verify_deluge').hide(); + $('#torrent_verify_rtorrent').hide(); + $('#torrent_label_anime_option').hide(); + $('#torrent_paused_option').hide(); $('#host_desc_torrent').text('URL to your MLDonkey (e.g. http://localhost:4080)'); } $('#host_title').text(client + host); @@ -1684,31 +1638,53 @@ var SICKRAGE = { $(optionPanel).show(); }; - $('#nzb_method').change($(this).nzbMethodHandler); + $('#torrent_host').on('input', function(){ + if($('#torrent_method :selected').val().toLowerCase() === 'rtorrent') { + var hostname = $('#torrent_host').val(); + var isMatch = hostname.substr(0, 7) === "scgi://"; + + if(isMatch) { + $('#torrent_username_option').hide(); + $('#torrent_username').prop('value', ''); + $('#torrent_password_option').hide(); + $('#torrent_password').prop('value', ''); + $('#torrent_auth_type_option').hide(); + $("#torrent_auth_type option[value=none]").attr('selected', 'selected'); + } else { + $('#torrent_username_option').show(); + $('#torrent_password_option').show(); + $('#torrent_auth_type_option').show(); + } + } + }); + + $('#nzb_method').on('change', $(this).nzbMethodHandler); $(this).nzbMethodHandler(); - $('#testSABnzbd').click(function(){ + $('#testSABnzbd').on('click', function(){ + var sab = {}; $('#testSABnzbd_result').html(loading); - var sab_host = $('#sab_host').val(); - var sab_username = $('#sab_username').val(); - var sab_password = $('#sab_password').val(); - var sab_apiKey = $('#sab_apikey').val(); - - $.get(srRoot + '/home/testSABnzbd', {'host': sab_host, 'username': sab_username, 'password': sab_password, 'apikey': sab_apiKey}, function(data){ + sab.host = $('#sab_host').val(); + sab.username = $('#sab_username').val(); + sab.password = $('#sab_password').val(); + sab.apiKey = $('#sab_apikey').val(); + + $.get(srRoot + '/home/testSABnzbd', { + 'host': sab.host, + 'username': sab.username, + 'password': sab.password, + 'apikey': sab.apiKey + }, function(data){ $('#testSABnzbd_result').html(data); }); }); - $('#torrent_method').change($(this).torrentMethodHandler); + $('#torrent_method').on('change', $.torrentMethodHandler); - $(this).torrentMethodHandler(); - - $('#use_torrents').click(function(){ - toggleTorrentTitle(); - }); + $.torrentMethodHandler(); - $('#test_torrent').click(function(){ + $('#test_torrent').on('click', function(){ var torrent = {}; $('#test_torrent_result').html(loading); torrent.method = $('#torrent_method :selected').val(); @@ -1725,8 +1701,6 @@ var SICKRAGE = { $('#test_torrent_result').html(data); }); }); - - $('#torrent_host').change($(this).rtorrentScgi); }, subtitles: function() { $.fn.showHideServices = function() { @@ -1767,7 +1741,7 @@ var SICKRAGE = { $("#service_order").val(finalArr.join(' ')); }; - $('#editAService').change(function(){ + $('#editAService').on('change', function(){ $(this).showHideServices(); }); @@ -1794,7 +1768,7 @@ var SICKRAGE = { }, manage: { init: function() { - $.makeRow = function(indexerId, season, episode, name, checked) { + $.makeEpisodeRow = function(indexerId, season, episode, name, checked) { var row = ''; row += ' <tr class="' + $('#row_class').val() + ' show-' + indexerId + '">'; row += ' <td class="tableleft" align="center"><input type="checkbox" class="' + indexerId + '-epcheck" name="' + indexerId + '-' + season + 'x' + episode + '"' + (checked ? ' checked' : '') + '></td>'; @@ -1804,6 +1778,27 @@ var SICKRAGE = { return row; }; + + $.makeSubtitleRow = function(indexerId, season, episode, name, subtitles, checked) { + var row = ''; + row += '<tr class="good show-' + indexerId + '">'; + row += '<td align="center"><input type="checkbox" class="' + indexerId + '-epcheck" name="' + indexerId + '-' + season + 'x' + episode + '"' + (checked ? ' checked' : '') + '></td>'; + row += '<td style="width: 1%;">' + season + 'x' + episode + '</td>'; + row += '<td>' + name + '</td>'; + if(subtitles.length > 0){ + row += '<td style="float: right;">'; + subtitles = subtitles.split(','); + for (var i in subtitles) { + if (subtitles.hasOwnProperty(i)) { + row += '<img src="/images/subtitles/flags/' + subtitles[i] + '.png" width="16" height="11" alt="' + subtitles[i] + '" /> '; + } + } + row += '</td>'; + } + row += '</tr>'; + + return row; + }; }, index: function() { $("#massUpdateTable:has(tbody tr)").tablesorter({ @@ -1830,19 +1825,19 @@ var SICKRAGE = { 7: { sorter: 'archive_firstmatch'}, 8: { sorter: 'paused'}, 9: { sorter: 'subtitle'}, - 10: { sorter: 'default_ep_status'}, - 11: { sorter: 'status'}, - 12: { sorter: false}, - 13: { sorter: false}, - 14: { sorter: false}, - 15: { sorter: false}, - 16: { sorter: false}, - 17: { sorter: false} + 10: { sorter: 'default_ep_status'}, + 11: { sorter: 'status'}, + 12: { sorter: false}, + 13: { sorter: false}, + 14: { sorter: false}, + 15: { sorter: false}, + 16: { sorter: false}, + 17: { sorter: false} } }); }, backlogOverview: function() { - $('#pickShow').change(function(){ + $('#pickShow').on('change', function(){ var id = $(this).val(); if (id) { $('html,body').animate({scrollTop: $('#show-' + id).offset().top -25},'slow'); @@ -1855,7 +1850,7 @@ var SICKRAGE = { sortList: [[0,0]], headers: { 3: { sorter: false } } }); - $('#limit').change(function(){ + $('#limit').on('change', function(){ window.location.href = srRoot + '/manage/failedDownloads/?limit=' + $(this).val(); }); }, @@ -1863,12 +1858,12 @@ var SICKRAGE = { $('#location').fileBrowser({ title: 'Select Show Location' }); }, episodeStatuses: function() { - $('.allCheck').click(function(){ + $('.allCheck').on('click', function(){ var indexerId = $(this).attr('id').split('-')[1]; $('.' + indexerId + '-epcheck').prop('checked', $(this).prop('checked')); }); - $('.get_more_eps').click(function(){ + $('.get_more_eps').on('click', function(){ var curIndexerId = $(this).attr('id'); var checked = $('#allCheck-' + curIndexerId).prop('checked'); var lastRow = $('tr#' + curIndexerId); @@ -1877,13 +1872,12 @@ var SICKRAGE = { if(!clicked) { $.getJSON(srRoot+'/manage/showEpisodeStatuses',{ - indexer_id: curIndexerId, // jshint ignore:line + 'indexer_id': curIndexerId, whichStatus: $('#oldStatus').val() }, function (data) { $.each(data, function(season,eps){ $.each(eps, function(episode, name) { - //alert(season+'x'+episode+': '+name); - lastRow.after($.makeRow(curIndexerId, season, episode, name, checked)); + lastRow.after($.makeEpisodeRow(curIndexerId, season, episode, name, checked)); }); }); }); @@ -1901,32 +1895,32 @@ var SICKRAGE = { }); // selects all visible episode checkboxes. - $('.selectAllShows').click(function(){ + $('.selectAllShows').on('click', function(){ $('.allCheck').each(function(){ - this.checked = true; + this.checked = true; }); $('input[class*="-epcheck"]').each(function(){ - this.checked = true; + this.checked = true; }); }); // clears all visible episode checkboxes and the season selectors - $('.unselectAllShows').click(function(){ + $('.unselectAllShows').on('click', function(){ $('.allCheck').each(function(){ - this.checked = false; + this.checked = false; }); $('input[class*="-epcheck"]').each(function(){ - this.checked = false; + this.checked = false; }); }); }, subtitleMissed: function() { - $('.allCheck').click(function(){ + $('.allCheck').on('click', function(){ var indexerId = $(this).attr('id').split('-')[1]; $('.'+indexerId+'-epcheck').prop('checked', $(this).prop('checked')); }); - $('.get_more_eps').click(function(){ + $('.get_more_eps').on('click', function(){ var indexerId = $(this).attr('id'); var checked = $('#allCheck-'+indexerId).prop('checked'); var lastRow = $('tr#'+indexerId); @@ -1935,12 +1929,12 @@ var SICKRAGE = { if (!clicked) { $.getJSON(srRoot + '/manage/showSubtitleMissed', { - indexer_id: indexerId, // jshint ignore:line + 'indexer_id': indexerId, whichSubs: $('#selectSubLang').val() }, function(data) { $.each(data, function(season, eps) { $.each(eps, function(episode, data) { - lastRow.after($.makeRow(indexerId, season, episode, data.name, data.subtitles, checked)); + lastRow.after($.makeSubtitleRow(indexerId, season, episode, data.name, data.subtitles, checked)); }); }); }); @@ -1958,22 +1952,22 @@ var SICKRAGE = { }); // selects all visible episode checkboxes. - $('.selectAllShows').click(function(){ + $('.selectAllShows').on('click', function(){ $('.allCheck').each(function(){ - this.checked = true; + this.checked = true; }); $('input[class*="-epcheck"]').each(function(){ - this.checked = true; + this.checked = true; }); }); // clears all visible episode checkboxes and the season selectors - $('.unselectAllShows').click(function(){ + $('.unselectAllShows').on('click', function(){ $('.allCheck').each(function(){ - this.checked = false; + this.checked = false; }); $('input[class*="-epcheck"]').each(function(){ - this.checked = false; + this.checked = false; }); }); } diff --git a/gui/slick/js/core.min.js b/gui/slick/js/core.min.js index 07c6080f5cac0873cd01ac7aea2ca82773f1a384..b0af1a1280876c5a80447f4db0f5d5b8cac1cb88 100644 Binary files a/gui/slick/js/core.min.js and b/gui/slick/js/core.min.js differ diff --git a/gui/slick/js/failedDownloads.js b/gui/slick/js/failedDownloads.js index f599e41295952278058651f016dc04ea31bad2eb..15be420a1861542d648243d4724378cc4d07819e 100644 --- a/gui/slick/js/failedDownloads.js +++ b/gui/slick/js/failedDownloads.js @@ -37,8 +37,7 @@ $(document).ready(function(){ $(name+':visible').each(function() { switch (found) { case 2: return false; - case 1: - this.checked = lastCheck.checked; + case 1: this.checked = lastCheck.checked; } if (this === check || this === lastCheck) { found++; } diff --git a/gui/slick/js/lib/bootstrap-anchor.min.js b/gui/slick/js/lib/bootstrap-anchor.min.js deleted file mode 100644 index b541e5689846fe03a588eb05f688cf1c2b76c96f..0000000000000000000000000000000000000000 Binary files a/gui/slick/js/lib/bootstrap-anchor.min.js and /dev/null differ diff --git a/gui/slick/js/lib/isotope.pkgd.min.js b/gui/slick/js/lib/isotope.pkgd.min.js deleted file mode 100644 index 20ea20621c7013f02f3fac6c4dd573ff16795fd2..0000000000000000000000000000000000000000 Binary files a/gui/slick/js/lib/isotope.pkgd.min.js and /dev/null differ diff --git a/gui/slick/js/lib/jquery.form-3.35.js b/gui/slick/js/lib/jquery.form-3.35.js deleted file mode 100644 index e3126cafdcb4d451e2590e698f58c813f68239d7..0000000000000000000000000000000000000000 --- a/gui/slick/js/lib/jquery.form-3.35.js +++ /dev/null @@ -1,1190 +0,0 @@ -/*! - * jQuery Form Plugin - * version: 3.35.0-2013.05.23 - * @requires jQuery v1.5 or later - * Copyright (c) 2013 M. Alsup - * Examples and documentation at: http://malsup.com/jquery/form/ - * Project repository: https://github.com/malsup/form - * Dual licensed under the MIT and GPL licenses. - * https://github.com/malsup/form#copyright-and-license - */ -/*global ActiveXObject */ -;(function($) { -"use strict"; - -/* - Usage Note: - ----------- - Do not use both ajaxSubmit and ajaxForm on the same form. These - functions are mutually exclusive. Use ajaxSubmit if you want - to bind your own submit handler to the form. For example, - - $(document).ready(function() { - $('#myForm').on('submit', function(e) { - e.preventDefault(); // <-- important - $(this).ajaxSubmit({ - target: '#output' - }); - }); - }); - - Use ajaxForm when you want the plugin to manage all the event binding - for you. For example, - - $(document).ready(function() { - $('#myForm').ajaxForm({ - target: '#output' - }); - }); - - You can also use ajaxForm with delegation (requires jQuery v1.7+), so the - form does not have to exist when you invoke ajaxForm: - - $('#myForm').ajaxForm({ - delegation: true, - target: '#output' - }); - - When using ajaxForm, the ajaxSubmit function will be invoked for you - at the appropriate time. -*/ - -/** - * Feature detection - */ -var feature = {}; -feature.fileapi = $("<input type='file'/>").get(0).files !== undefined; -feature.formdata = window.FormData !== undefined; - -var hasProp = !!$.fn.prop; - -// attr2 uses prop when it can but checks the return type for -// an expected string. this accounts for the case where a form -// contains inputs with names like "action" or "method"; in those -// cases "prop" returns the element -$.fn.attr2 = function() { - if ( ! hasProp ) - return this.attr.apply(this, arguments); - var val = this.prop.apply(this, arguments); - if ( ( val && val.jquery ) || typeof val === 'string' ) - return val; - return this.attr.apply(this, arguments); -}; - -/** - * ajaxSubmit() provides a mechanism for immediately submitting - * an HTML form using AJAX. - */ -$.fn.ajaxSubmit = function(options) { - /*jshint scripturl:true */ - - // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) - if (!this.length) { - log('ajaxSubmit: skipping submit process - no element selected'); - return this; - } - - var method, action, url, $form = this; - - if (typeof options == 'function') { - options = { success: options }; - } - - method = options.type || this.attr2('method'); - action = options.url || this.attr2('action'); - - url = (typeof action === 'string') ? $.trim(action) : ''; - url = url || window.location.href || ''; - if (url) { - // clean url (don't include hash vaue) - url = (url.match(/^([^#]+)/)||[])[1]; - } - - options = $.extend(true, { - url: url, - success: $.ajaxSettings.success, - type: method || 'GET', - iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' - }, options); - - // hook for manipulating the form data before it is extracted; - // convenient for use with rich editors like tinyMCE or FCKEditor - var veto = {}; - this.trigger('form-pre-serialize', [this, options, veto]); - if (veto.veto) { - log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); - return this; - } - - // provide opportunity to alter form data before it is serialized - if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { - log('ajaxSubmit: submit aborted via beforeSerialize callback'); - return this; - } - - var traditional = options.traditional; - if ( traditional === undefined ) { - traditional = $.ajaxSettings.traditional; - } - - var elements = []; - var qx, a = this.formToArray(options.semantic, elements); - if (options.data) { - options.extraData = options.data; - qx = $.param(options.data, traditional); - } - - // give pre-submit callback an opportunity to abort the submit - if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { - log('ajaxSubmit: submit aborted via beforeSubmit callback'); - return this; - } - - // fire vetoable 'validate' event - this.trigger('form-submit-validate', [a, this, options, veto]); - if (veto.veto) { - log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); - return this; - } - - var q = $.param(a, traditional); - if (qx) { - q = ( q ? (q + '&' + qx) : qx ); - } - if (options.type.toUpperCase() == 'GET') { - options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; - options.data = null; // data is null for 'get' - } - else { - options.data = q; // data is the query string for 'post' - } - - var callbacks = []; - if (options.resetForm) { - callbacks.push(function() { $form.resetForm(); }); - } - if (options.clearForm) { - callbacks.push(function() { $form.clearForm(options.includeHidden); }); - } - - // perform a load on the target only if dataType is not provided - if (!options.dataType && options.target) { - var oldSuccess = options.success || function(){}; - callbacks.push(function(data) { - var fn = options.replaceTarget ? 'replaceWith' : 'html'; - $(options.target)[fn](data).each(oldSuccess, arguments); - }); - } - else if (options.success) { - callbacks.push(options.success); - } - - options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg - var context = options.context || this ; // jQuery 1.4+ supports scope context - for (var i=0, max=callbacks.length; i < max; i++) { - callbacks[i].apply(context, [data, status, xhr || $form, $form]); - } - }; - - if (options.error) { - var oldError = options.error; - options.error = function(xhr, status, error) { - var context = options.context || this; - oldError.apply(context, [xhr, status, error, $form]); - }; - } - - if (options.complete) { - var oldComplete = options.complete; - options.complete = function(xhr, status) { - var context = options.context || this; - oldComplete.apply(context, [xhr, status, $form]); - }; - } - - // are there files to upload? - - // [value] (issue #113), also see comment: - // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219 - var fileInputs = $('input[type=file]:enabled[value!=""]', this); - - var hasFileInputs = fileInputs.length > 0; - var mp = 'multipart/form-data'; - var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); - - var fileAPI = feature.fileapi && feature.formdata; - log("fileAPI :" + fileAPI); - var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI; - - var jqxhr; - - // options.iframe allows user to force iframe mode - // 06-NOV-09: now defaulting to iframe mode if file input is detected - if (options.iframe !== false && (options.iframe || shouldUseFrame)) { - // hack to fix Safari hang (thanks to Tim Molendijk for this) - // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d - if (options.closeKeepAlive) { - $.get(options.closeKeepAlive, function() { - jqxhr = fileUploadIframe(a); - }); - } - else { - jqxhr = fileUploadIframe(a); - } - } - else if ((hasFileInputs || multipart) && fileAPI) { - jqxhr = fileUploadXhr(a); - } - else { - jqxhr = $.ajax(options); - } - - $form.removeData('jqxhr').data('jqxhr', jqxhr); - - // clear element array - for (var k=0; k < elements.length; k++) - elements[k] = null; - - // fire 'notify' event - this.trigger('form-submit-notify', [this, options]); - return this; - - // utility fn for deep serialization - function deepSerialize(extraData){ - var serialized = $.param(extraData, options.traditional).split('&'); - var len = serialized.length; - var result = []; - var i, part; - for (i=0; i < len; i++) { - // #252; undo param space replacement - serialized[i] = serialized[i].replace(/\+/g,' '); - part = serialized[i].split('='); - // #278; use array instead of object storage, favoring array serializations - result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]); - } - return result; - } - - // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz) - function fileUploadXhr(a) { - var formdata = new FormData(); - - for (var i=0; i < a.length; i++) { - formdata.append(a[i].name, a[i].value); - } - - if (options.extraData) { - var serializedData = deepSerialize(options.extraData); - for (i=0; i < serializedData.length; i++) - if (serializedData[i]) - formdata.append(serializedData[i][0], serializedData[i][1]); - } - - options.data = null; - - var s = $.extend(true, {}, $.ajaxSettings, options, { - contentType: false, - processData: false, - cache: false, - type: method || 'POST' - }); - - if (options.uploadProgress) { - // workaround because jqXHR does not expose upload property - s.xhr = function() { - var xhr = jQuery.ajaxSettings.xhr(); - if (xhr.upload) { - xhr.upload.addEventListener('progress', function(event) { - var percent = 0; - var position = event.loaded || event.position; /*event.position is deprecated*/ - var total = event.total; - if (event.lengthComputable) { - percent = Math.ceil(position / total * 100); - } - options.uploadProgress(event, position, total, percent); - }, false); - } - return xhr; - }; - } - - s.data = null; - var beforeSend = s.beforeSend; - s.beforeSend = function(xhr, o) { - o.data = formdata; - if(beforeSend) - beforeSend.call(this, xhr, o); - }; - return $.ajax(s); - } - - // private function for handling file uploads (hat tip to YAHOO!) - function fileUploadIframe(a) { - var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle; - var deferred = $.Deferred(); - - if (a) { - // ensure that every serialized input is still enabled - for (i=0; i < elements.length; i++) { - el = $(elements[i]); - if ( hasProp ) - el.prop('disabled', false); - else - el.removeAttr('disabled'); - } - } - - s = $.extend(true, {}, $.ajaxSettings, options); - s.context = s.context || s; - id = 'jqFormIO' + (new Date().getTime()); - if (s.iframeTarget) { - $io = $(s.iframeTarget); - n = $io.attr2('name'); - if (!n) - $io.attr2('name', id); - else - id = n; - } - else { - $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />'); - $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); - } - io = $io[0]; - - - xhr = { // mock object - aborted: 0, - responseText: null, - responseXML: null, - status: 0, - statusText: 'n/a', - getAllResponseHeaders: function() {}, - getResponseHeader: function() {}, - setRequestHeader: function() {}, - abort: function(status) { - var e = (status === 'timeout' ? 'timeout' : 'aborted'); - log('aborting upload... ' + e); - this.aborted = 1; - - try { // #214, #257 - if (io.contentWindow.document.execCommand) { - io.contentWindow.document.execCommand('Stop'); - } - } - catch(ignore) {} - - $io.attr('src', s.iframeSrc); // abort op in progress - xhr.error = e; - if (s.error) - s.error.call(s.context, xhr, e, status); - if (g) - $.event.trigger("ajaxError", [xhr, s, e]); - if (s.complete) - s.complete.call(s.context, xhr, e); - } - }; - - g = s.global; - // trigger ajax global events so that activity/block indicators work like normal - if (g && 0 === $.active++) { - $.event.trigger("ajaxStart"); - } - if (g) { - $.event.trigger("ajaxSend", [xhr, s]); - } - - if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) { - if (s.global) { - $.active--; - } - deferred.reject(); - return deferred; - } - if (xhr.aborted) { - deferred.reject(); - return deferred; - } - - // add submitting element to data if we know it - sub = form.clk; - if (sub) { - n = sub.name; - if (n && !sub.disabled) { - s.extraData = s.extraData || {}; - s.extraData[n] = sub.value; - if (sub.type == "image") { - s.extraData[n+'.x'] = form.clk_x; - s.extraData[n+'.y'] = form.clk_y; - } - } - } - - var CLIENT_TIMEOUT_ABORT = 1; - var SERVER_ABORT = 2; - - function getDoc(frame) { - /* it looks like contentWindow or contentDocument do not - * carry the protocol property in ie8, when running under ssl - * frame.document is the only valid response document, since - * the protocol is know but not on the other two objects. strange? - * "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy - */ - - var doc = null; - - // IE8 cascading access check - try { - if (frame.contentWindow) { - doc = frame.contentWindow.document; - } - } catch(err) { - // IE8 access denied under ssl & missing protocol - log('cannot get iframe.contentWindow document: ' + err); - } - - if (doc) { // successful getting content - return doc; - } - - try { // simply checking may throw in ie8 under ssl or mismatched protocol - doc = frame.contentDocument ? frame.contentDocument : frame.document; - } catch(err) { - // last attempt - log('cannot get iframe.contentDocument: ' + err); - doc = frame.document; - } - return doc; - } - - // Rails CSRF hack (thanks to Yvan Barthelemy) - var csrf_token = $('meta[name=csrf-token]').attr('content'); - var csrf_param = $('meta[name=csrf-param]').attr('content'); - if (csrf_param && csrf_token) { - s.extraData = s.extraData || {}; - s.extraData[csrf_param] = csrf_token; - } - - // take a breath so that pending repaints get some cpu time before the upload starts - function doSubmit() { - // make sure form attrs are set - var t = $form.attr2('target'), a = $form.attr2('action'); - - // update form attrs in IE friendly way - form.setAttribute('target',id); - if (!method) { - form.setAttribute('method', 'POST'); - } - if (a != s.url) { - form.setAttribute('action', s.url); - } - - // ie borks in some cases when setting encoding - if (! s.skipEncodingOverride && (!method || /post/i.test(method))) { - $form.attr({ - encoding: 'multipart/form-data', - enctype: 'multipart/form-data' - }); - } - - // support timout - if (s.timeout) { - timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout); - } - - // look for server aborts - function checkState() { - try { - var state = getDoc(io).readyState; - log('state = ' + state); - if (state && state.toLowerCase() == 'uninitialized') - setTimeout(checkState,50); - } - catch(e) { - log('Server abort: ' , e, ' (', e.name, ')'); - cb(SERVER_ABORT); - if (timeoutHandle) - clearTimeout(timeoutHandle); - timeoutHandle = undefined; - } - } - - // add "extra" data to form if provided in options - var extraInputs = []; - try { - if (s.extraData) { - for (var n in s.extraData) { - if (s.extraData.hasOwnProperty(n)) { - // if using the $.param format that allows for multiple values with the same name - if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) { - extraInputs.push( - $('<input type="hidden" name="'+s.extraData[n].name+'">').val(s.extraData[n].value) - .appendTo(form)[0]); - } else { - extraInputs.push( - $('<input type="hidden" name="'+n+'">').val(s.extraData[n]) - .appendTo(form)[0]); - } - } - } - } - - if (!s.iframeTarget) { - // add iframe to doc and submit the form - $io.appendTo('body'); - if (io.attachEvent) - io.attachEvent('onload', cb); - else - io.addEventListener('load', cb, false); - } - setTimeout(checkState,15); - - try { - form.submit(); - } catch(err) { - // just in case form has element with name/id of 'submit' - var submitFn = document.createElement('form').submit; - submitFn.apply(form); - } - } - finally { - // reset attrs and remove "extra" input elements - form.setAttribute('action',a); - if(t) { - form.setAttribute('target', t); - } else { - $form.removeAttr('target'); - } - $(extraInputs).remove(); - } - } - - if (s.forceSync) { - doSubmit(); - } - else { - setTimeout(doSubmit, 10); // this lets dom updates render - } - - var data, doc, domCheckCount = 50, callbackProcessed; - - function cb(e) { - if (xhr.aborted || callbackProcessed) { - return; - } - - doc = getDoc(io); - if(!doc) { - log('cannot access response document'); - e = SERVER_ABORT; - } - if (e === CLIENT_TIMEOUT_ABORT && xhr) { - xhr.abort('timeout'); - deferred.reject(xhr, 'timeout'); - return; - } - else if (e == SERVER_ABORT && xhr) { - xhr.abort('server abort'); - deferred.reject(xhr, 'error', 'server abort'); - return; - } - - if (!doc || doc.location.href == s.iframeSrc) { - // response not received yet - if (!timedOut) - return; - } - if (io.detachEvent) - io.detachEvent('onload', cb); - else - io.removeEventListener('load', cb, false); - - var status = 'success', errMsg; - try { - if (timedOut) { - throw 'timeout'; - } - - var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc); - log('isXml='+isXml); - if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) { - if (--domCheckCount) { - // in some browsers (Opera) the iframe DOM is not always traversable when - // the onload callback fires, so we loop a bit to accommodate - log('requeing onLoad callback, DOM not available'); - setTimeout(cb, 250); - return; - } - // let this fall through because server response could be an empty document - //log('Could not access iframe DOM after mutiple tries.'); - //throw 'DOMException: not available'; - } - - //log('response detected'); - var docRoot = doc.body ? doc.body : doc.documentElement; - xhr.responseText = docRoot ? docRoot.innerHTML : null; - xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; - if (isXml) - s.dataType = 'xml'; - xhr.getResponseHeader = function(header){ - var headers = {'content-type': s.dataType}; - return headers[header]; - }; - // support for XHR 'status' & 'statusText' emulation : - if (docRoot) { - xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status; - xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText; - } - - var dt = (s.dataType || '').toLowerCase(); - var scr = /(json|script|text)/.test(dt); - if (scr || s.textarea) { - // see if user embedded response in textarea - var ta = doc.getElementsByTagName('textarea')[0]; - if (ta) { - xhr.responseText = ta.value; - // support for XHR 'status' & 'statusText' emulation : - xhr.status = Number( ta.getAttribute('status') ) || xhr.status; - xhr.statusText = ta.getAttribute('statusText') || xhr.statusText; - } - else if (scr) { - // account for browsers injecting pre around json response - var pre = doc.getElementsByTagName('pre')[0]; - var b = doc.getElementsByTagName('body')[0]; - if (pre) { - xhr.responseText = pre.textContent ? pre.textContent : pre.innerText; - } - else if (b) { - xhr.responseText = b.textContent ? b.textContent : b.innerText; - } - } - } - else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) { - xhr.responseXML = toXml(xhr.responseText); - } - - try { - data = httpData(xhr, dt, s); - } - catch (err) { - status = 'parsererror'; - xhr.error = errMsg = (err || status); - } - } - catch (err) { - log('error caught: ',err); - status = 'error'; - xhr.error = errMsg = (err || status); - } - - if (xhr.aborted) { - log('upload aborted'); - status = null; - } - - if (xhr.status) { // we've set xhr.status - status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error'; - } - - // ordering of these callbacks/triggers is odd, but that's how $.ajax does it - if (status === 'success') { - if (s.success) - s.success.call(s.context, data, 'success', xhr); - deferred.resolve(xhr.responseText, 'success', xhr); - if (g) - $.event.trigger("ajaxSuccess", [xhr, s]); - } - else if (status) { - if (errMsg === undefined) - errMsg = xhr.statusText; - if (s.error) - s.error.call(s.context, xhr, status, errMsg); - deferred.reject(xhr, 'error', errMsg); - if (g) - $.event.trigger("ajaxError", [xhr, s, errMsg]); - } - - if (g) - $.event.trigger("ajaxComplete", [xhr, s]); - - if (g && ! --$.active) { - $.event.trigger("ajaxStop"); - } - - if (s.complete) - s.complete.call(s.context, xhr, status); - - callbackProcessed = true; - if (s.timeout) - clearTimeout(timeoutHandle); - - // clean up - setTimeout(function() { - if (!s.iframeTarget) - $io.remove(); - xhr.responseXML = null; - }, 100); - } - - var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+) - if (window.ActiveXObject) { - doc = new ActiveXObject('Microsoft.XMLDOM'); - doc.async = 'false'; - doc.loadXML(s); - } - else { - doc = (new DOMParser()).parseFromString(s, 'text/xml'); - } - return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null; - }; - var parseJSON = $.parseJSON || function(s) { - /*jslint evil:true */ - return window['eval']('(' + s + ')'); - }; - - var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4 - - var ct = xhr.getResponseHeader('content-type') || '', - xml = type === 'xml' || !type && ct.indexOf('xml') >= 0, - data = xml ? xhr.responseXML : xhr.responseText; - - if (xml && data.documentElement.nodeName === 'parsererror') { - if ($.error) - $.error('parsererror'); - } - if (s && s.dataFilter) { - data = s.dataFilter(data, type); - } - if (typeof data === 'string') { - if (type === 'json' || !type && ct.indexOf('json') >= 0) { - data = parseJSON(data); - } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) { - $.globalEval(data); - } - } - return data; - }; - - return deferred; - } -}; - -/** - * ajaxForm() provides a mechanism for fully automating form submission. - * - * The advantages of using this method instead of ajaxSubmit() are: - * - * 1: This method will include coordinates for <input type="image" /> elements (if the element - * is used to submit the form). - * 2. This method will include the submit element's name/value data (for the element that was - * used to submit the form). - * 3. This method binds the submit() method to the form for you. - * - * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely - * passes the options argument along after properly binding events for submit elements and - * the form itself. - */ -$.fn.ajaxForm = function(options) { - options = options || {}; - options.delegation = options.delegation && $.isFunction($.fn.on); - - // in jQuery 1.3+ we can fix mistakes with the ready state - if (!options.delegation && this.length === 0) { - var o = { s: this.selector, c: this.context }; - if (!$.isReady && o.s) { - log('DOM not ready, queuing ajaxForm'); - $(function() { - $(o.s,o.c).ajaxForm(options); - }); - return this; - } - // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready() - log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)')); - return this; - } - - if ( options.delegation ) { - $(document) - .off('submit.form-plugin', this.selector, doAjaxSubmit) - .off('click.form-plugin', this.selector, captureSubmittingElement) - .on('submit.form-plugin', this.selector, options, doAjaxSubmit) - .on('click.form-plugin', this.selector, options, captureSubmittingElement); - return this; - } - - return this.ajaxFormUnbind() - .bind('submit.form-plugin', options, doAjaxSubmit) - .bind('click.form-plugin', options, captureSubmittingElement); -}; - -// private event handlers -function doAjaxSubmit(e) { - /*jshint validthis:true */ - var options = e.data; - if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed - e.preventDefault(); - $(this).ajaxSubmit(options); - } -} - -function captureSubmittingElement(e) { - /*jshint validthis:true */ - var target = e.target; - var $el = $(target); - if (!($el.is("[type=submit],[type=image]"))) { - // is this a child element of the submit el? (ex: a span within a button) - var t = $el.closest('[type=submit]'); - if (t.length === 0) { - return; - } - target = t[0]; - } - var form = this; - form.clk = target; - if (target.type == 'image') { - if (e.offsetX !== undefined) { - form.clk_x = e.offsetX; - form.clk_y = e.offsetY; - } else if (typeof $.fn.offset == 'function') { - var offset = $el.offset(); - form.clk_x = e.pageX - offset.left; - form.clk_y = e.pageY - offset.top; - } else { - form.clk_x = e.pageX - target.offsetLeft; - form.clk_y = e.pageY - target.offsetTop; - } - } - // clear form vars - setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100); -} - - -// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm -$.fn.ajaxFormUnbind = function() { - return this.unbind('submit.form-plugin click.form-plugin'); -}; - -/** - * formToArray() gathers form element data into an array of objects that can - * be passed to any of the following ajax functions: $.get, $.post, or load. - * Each object in the array has both a 'name' and 'value' property. An example of - * an array for a simple login form might be: - * - * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ] - * - * It is this array that is passed to pre-submit callback functions provided to the - * ajaxSubmit() and ajaxForm() methods. - */ -$.fn.formToArray = function(semantic, elements) { - var a = []; - if (this.length === 0) { - return a; - } - - var form = this[0]; - var els = semantic ? form.getElementsByTagName('*') : form.elements; - if (!els) { - return a; - } - - var i,j,n,v,el,max,jmax; - for(i=0, max=els.length; i < max; i++) { - el = els[i]; - n = el.name; - if (!n || el.disabled) { - continue; - } - - if (semantic && form.clk && el.type == "image") { - // handle image inputs on the fly when semantic == true - if(form.clk == el) { - a.push({name: n, value: $(el).val(), type: el.type }); - a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); - } - continue; - } - - v = $.fieldValue(el, true); - if (v && v.constructor == Array) { - if (elements) - elements.push(el); - for(j=0, jmax=v.length; j < jmax; j++) { - a.push({name: n, value: v[j]}); - } - } - else if (feature.fileapi && el.type == 'file') { - if (elements) - elements.push(el); - var files = el.files; - if (files.length) { - for (j=0; j < files.length; j++) { - a.push({name: n, value: files[j], type: el.type}); - } - } - else { - // #180 - a.push({ name: n, value: '', type: el.type }); - } - } - else if (v !== null && typeof v != 'undefined') { - if (elements) - elements.push(el); - a.push({name: n, value: v, type: el.type, required: el.required}); - } - } - - if (!semantic && form.clk) { - // input type=='image' are not found in elements array! handle it here - var $input = $(form.clk), input = $input[0]; - n = input.name; - if (n && !input.disabled && input.type == 'image') { - a.push({name: n, value: $input.val()}); - a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); - } - } - return a; -}; - -/** - * Serializes form data into a 'submittable' string. This method will return a string - * in the format: name1=value1&name2=value2 - */ -$.fn.formSerialize = function(semantic) { - //hand off to jQuery.param for proper encoding - return $.param(this.formToArray(semantic)); -}; - -/** - * Serializes all field elements in the jQuery object into a query string. - * This method will return a string in the format: name1=value1&name2=value2 - */ -$.fn.fieldSerialize = function(successful) { - var a = []; - this.each(function() { - var n = this.name; - if (!n) { - return; - } - var v = $.fieldValue(this, successful); - if (v && v.constructor == Array) { - for (var i=0,max=v.length; i < max; i++) { - a.push({name: n, value: v[i]}); - } - } - else if (v !== null && typeof v != 'undefined') { - a.push({name: this.name, value: v}); - } - }); - //hand off to jQuery.param for proper encoding - return $.param(a); -}; - -/** - * Returns the value(s) of the element in the matched set. For example, consider the following form: - * - * <form><fieldset> - * <input name="A" type="text" /> - * <input name="A" type="text" /> - * <input name="B" type="checkbox" value="B1" /> - * <input name="B" type="checkbox" value="B2"/> - * <input name="C" type="radio" value="C1" /> - * <input name="C" type="radio" value="C2" /> - * </fieldset></form> - * - * var v = $('input[type=text]').fieldValue(); - * // if no values are entered into the text inputs - * v == ['',''] - * // if values entered into the text inputs are 'foo' and 'bar' - * v == ['foo','bar'] - * - * var v = $('input[type=checkbox]').fieldValue(); - * // if neither checkbox is checked - * v === undefined - * // if both checkboxes are checked - * v == ['B1', 'B2'] - * - * var v = $('input[type=radio]').fieldValue(); - * // if neither radio is checked - * v === undefined - * // if first radio is checked - * v == ['C1'] - * - * The successful argument controls whether or not the field element must be 'successful' - * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls). - * The default value of the successful argument is true. If this value is false the value(s) - * for each element is returned. - * - * Note: This method *always* returns an array. If no valid value can be determined the - * array will be empty, otherwise it will contain one or more values. - */ -$.fn.fieldValue = function(successful) { - for (var val=[], i=0, max=this.length; i < max; i++) { - var el = this[i]; - var v = $.fieldValue(el, successful); - if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) { - continue; - } - if (v.constructor == Array) - $.merge(val, v); - else - val.push(v); - } - return val; -}; - -/** - * Returns the value of the field element. - */ -$.fieldValue = function(el, successful) { - var n = el.name, t = el.type, tag = el.tagName.toLowerCase(); - if (successful === undefined) { - successful = true; - } - - if (successful && (!n || el.disabled || t == 'reset' || t == 'button' || - (t == 'checkbox' || t == 'radio') && !el.checked || - (t == 'submit' || t == 'image') && el.form && el.form.clk != el || - tag == 'select' && el.selectedIndex == -1)) { - return null; - } - - if (tag == 'select') { - var index = el.selectedIndex; - if (index < 0) { - return null; - } - var a = [], ops = el.options; - var one = (t == 'select-one'); - var max = (one ? index+1 : ops.length); - for(var i=(one ? index : 0); i < max; i++) { - var op = ops[i]; - if (op.selected) { - var v = op.value; - if (!v) { // extra pain for IE... - v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value; - } - if (one) { - return v; - } - a.push(v); - } - } - return a; - } - return $(el).val(); -}; - -/** - * Clears the form data. Takes the following actions on the form's input fields: - * - input text fields will have their 'value' property set to the empty string - * - select elements will have their 'selectedIndex' property set to -1 - * - checkbox and radio inputs will have their 'checked' property set to false - * - inputs of type submit, button, reset, and hidden will *not* be effected - * - button elements will *not* be effected - */ -$.fn.clearForm = function(includeHidden) { - return this.each(function() { - $('input,select,textarea', this).clearFields(includeHidden); - }); -}; - -/** - * Clears the selected form elements. - */ -$.fn.clearFields = $.fn.clearInputs = function(includeHidden) { - var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list - return this.each(function() { - var t = this.type, tag = this.tagName.toLowerCase(); - if (re.test(t) || tag == 'textarea') { - this.value = ''; - } - else if (t == 'checkbox' || t == 'radio') { - this.checked = false; - } - else if (tag == 'select') { - this.selectedIndex = -1; - } - else if (t == "file") { - if (/MSIE/.test(navigator.userAgent)) { - $(this).replaceWith($(this).clone(true)); - } else { - $(this).val(''); - } - } - else if (includeHidden) { - // includeHidden can be the value true, or it can be a selector string - // indicating a special test; for example: - // $('#myForm').clearForm('.special:hidden') - // the above would clean hidden inputs that have the class of 'special' - if ( (includeHidden === true && /hidden/.test(t)) || - (typeof includeHidden == 'string' && $(this).is(includeHidden)) ) - this.value = ''; - } - }); -}; - -/** - * Resets the form data. Causes all form elements to be reset to their original value. - */ -$.fn.resetForm = function() { - return this.each(function() { - // guard against an input with the name of 'reset' - // note that IE reports the reset function as an 'object' - if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) { - this.reset(); - } - }); -}; - -/** - * Enables or disables any matching elements. - */ -$.fn.enable = function(b) { - if (b === undefined) { - b = true; - } - return this.each(function() { - this.disabled = !b; - }); -}; - -/** - * Checks/unchecks any matching checkboxes or radio buttons and - * selects/deselects and matching option elements. - */ -$.fn.selected = function(select) { - if (select === undefined) { - select = true; - } - return this.each(function() { - var t = this.type; - if (t == 'checkbox' || t == 'radio') { - this.checked = select; - } - else if (this.tagName.toLowerCase() == 'option') { - var $sel = $(this).parent('select'); - if (select && $sel[0] && $sel[0].type == 'select-one') { - // deselect all other options - $sel.find('option').selected(false); - } - this.selected = select; - } - }); -}; - -// expose debug var -$.fn.ajaxSubmit.debug = false; - -// helper fn for console logging -function log() { - if (!$.fn.ajaxSubmit.debug) - return; - var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); - if (window.console && window.console.log) { - window.console.log(msg); - } - else if (window.opera && window.opera.postError) { - window.opera.postError(msg); - } -} - -})(jQuery); diff --git a/gui/slick/js/manageEpisodeStatuses.js b/gui/slick/js/manageEpisodeStatuses.js deleted file mode 100644 index 74b148338d32cf28fd0317b39e5b3fc9955e6953..0000000000000000000000000000000000000000 --- a/gui/slick/js/manageEpisodeStatuses.js +++ /dev/null @@ -1,4 +0,0 @@ -$(document).ready(function() { - - -}); diff --git a/gui/slick/js/manageSubtitleMissed.js b/gui/slick/js/manageSubtitleMissed.js deleted file mode 100644 index 2f6d65c2b74364ddb304ebfe3ac94c45c58c2b9c..0000000000000000000000000000000000000000 --- a/gui/slick/js/manageSubtitleMissed.js +++ /dev/null @@ -1,72 +0,0 @@ -$(document).ready(function() { - - function makeRow(indexerId, season, episode, name, subtitles, checked) { - checked = checked ? ' checked' : ''; - - var row = ''; - row += ' <tr class="good show-' + indexerId + '">'; - row += ' <td align="center"><input type="checkbox" class="'+indexerId+'-epcheck" name="'+indexerId+'-'+season+'x'+episode+'"'+checked+'></td>'; - row += ' <td style="width: 1%;">'+season+'x'+episode+'</td>'; - row += ' <td>'+name+'</td>'; - row += ' </tr>'; - - return row; - } - - $('.allCheck').click(function(){ - var indexerId = $(this).attr('id').split('-')[1]; - $('.'+indexerId+'-epcheck').prop('checked', $(this).prop('checked')); - }); - - $('.get_more_eps').click(function(){ - var indexerId = $(this).attr('id'); - var checked = $('#allCheck-'+indexerId).prop('checked'); - var lastRow = $('tr#'+indexerId); - var clicked = $(this).attr('data-clicked'); - var action = $(this).attr('value'); - - if (!clicked) { - $.getJSON(srRoot + '/manage/showSubtitleMissed', { - indexer_id: indexerId, // jshint ignore:line - whichSubs: $('#selectSubLang').val() - }, function(data) { - $.each(data, function(season, eps) { - $.each(eps, function(episode, data) { - //alert(season+'x'+episode+': '+name); - lastRow.after(makeRow(indexerId, season, episode, data.name, data.subtitles, checked)); - }); - }); - }); - $(this).attr('data-clicked', 1); - $(this).prop('value', 'Collapse'); - } else { - if (action === 'Collapse') { - $('table tr').filter('.show-' + indexerId).hide(); - $(this).prop('value', 'Expand'); - } else if (action === 'Expand') { - $('table tr').filter('.show-' + indexerId).show(); - $(this).prop('value', 'Collapse'); - } - } - }); - - // selects all visible episode checkboxes. - $('.selectAllShows').click(function(){ - $('.allCheck').each(function(){ - this.checked = true; - }); - $('input[class*="-epcheck"]').each(function(){ - this.checked = true; - }); - }); - - // clears all visible episode checkboxes and the season selectors - $('.unselectAllShows').click(function(){ - $('.allCheck').each(function(){ - this.checked = false; - }); - $('input[class*="-epcheck"]').each(function(){ - this.checked = false; - }); - }); -}); diff --git a/gui/slick/js/massUpdate.js b/gui/slick/js/massUpdate.js index b539e1ef6d66f65cc6d77b6359badf075e799269..032c9256f367d4121c8bf4a389b5333ed7040b9b 100644 --- a/gui/slick/js/massUpdate.js +++ b/gui/slick/js/massUpdate.js @@ -74,7 +74,7 @@ $(document).ready(function(){ }); }); - ['.editCheck', '.updateCheck', '.refreshCheck', '.renameCheck', '.deleteCheck', '.removeCheck'].forEach(function(name) { + ['.editCheck', '.updateCheck', '.refreshCheck', '.renameCheck', '.deleteCheck', '.removeCheck'].forEach(function(name) { var lastCheck = null; $(name).on('click', function(event) { @@ -89,8 +89,7 @@ $(document).ready(function(){ $(name).each(function() { switch (found) { case 2: return false; - case 1: - if(!this.disabled) { this.checked = lastCheck.checked; } + case 1: if(!this.disabled) { this.checked = lastCheck.checked; } } if(this === check || this === lastCheck) { found++; } }); diff --git a/gui/slick/js/qualityChooser.js b/gui/slick/js/qualityChooser.js index 7242113d7aa3fdd11db73b9799d63321c9c03571..fe2880be8956acdeea6fc6cd00c6882bfea26bd9 100644 --- a/gui/slick/js/qualityChooser.js +++ b/gui/slick/js/qualityChooser.js @@ -7,8 +7,8 @@ $(document).ready(function() { $('#customQuality').hide(); } - $('#anyQualities option').each(function(i) { - var result = preset & $(this).val(); // I have no clue what the & does here + $('#anyQualities option').each(function() { + var result = preset & $(this).val(); // @TODO Find out what this does if (result > 0) { $(this).attr('selected', 'selected'); } else { @@ -16,8 +16,8 @@ $(document).ready(function() { } }); - $('#bestQualities option').each(function(i) { - var result = preset & ($(this).val() << 16); // I have no clue what the & does here + $('#bestQualities option').each(function() { + var result = preset & ($(this).val() << 16); // @TODO Find out what this does if (result > 0) { $(this).attr('selected', 'selected'); } else { diff --git a/gui/slick/js/restart.js b/gui/slick/js/restart.js index f51c67b86a5d42a140cb015e800b9ba8c32d1df3..645e5019f2ede8b75b25b3bcc2c9e27e183e70d0 100644 --- a/gui/slick/js/restart.js +++ b/gui/slick/js/restart.js @@ -49,13 +49,13 @@ $(document).ready(function() { }); } - function ajaxError(x, e) { + function ajaxError(x) { if (console_debug) { // jshint ignore:line if (x.status === 0) { console.log(console_prefix + 'isAlive: Sickrage is not responding.'); - } else if (x.status == 404) { + } else if (x.status === 404) { console.log(console_prefix + 'isAlive: Requested URL not found.'); - } else if (x.status == 500) { + } else if (x.status === 500) { console.log(console_prefix + 'isAlive: Internel Server Error.'); } else { console.log(console_prefix + 'isAlive: Unknow Error.\n' + x.responseText); diff --git a/gui/slick/js/vender.min.js b/gui/slick/js/vender.min.js index 183aaff7e388bfb2a7c84d7927c2a2dd9d0f255f..b7dc4f9eb8b4ddfc8589f789c0bf2878517c747c 100644 Binary files a/gui/slick/js/vender.min.js and b/gui/slick/js/vender.min.js differ diff --git a/gui/slick/views/apiBuilder.mako b/gui/slick/views/apiBuilder.mako index 9e9f88e8769d8881cf252c8e5ee51069a3eef30d..fe48e74a997a0b8dc61679a6495136f39a2452a6 100644 --- a/gui/slick/views/apiBuilder.mako +++ b/gui/slick/views/apiBuilder.mako @@ -185,9 +185,9 @@ var commands = ${sorted(commands)}; var episodes = ${episodes}; </script> -<script type="text/javascript" src="${srRoot}/js/_bower.min.js?${sbPID}"></script> +<script type="text/javascript" src="${srRoot}/js/vender.min.js?${sbPID}"></script> <script type="text/javascript" src="${srRoot}/js/new/meta.js?${sbPID}"></script> -<script type="text/javascript" src="${srRoot}/js/new/core.js?${sbPID}"></script> +<script type="text/javascript" src="${srRoot}/js/core.min.js?${sbPID}"></script> <script type="text/javascript" src="${srRoot}/js/apibuilder.js?${sbPID}"></script> </body> </html> diff --git a/gui/slick/views/config_backuprestore.mako b/gui/slick/views/config_backuprestore.mako index 1e2365b9d2265e8de0692d42d4963827887ed93c..a93bcc664cadbbb9f38bfb3dd0bd9e8b4f101a8a 100644 --- a/gui/slick/views/config_backuprestore.mako +++ b/gui/slick/views/config_backuprestore.mako @@ -10,10 +10,6 @@ from sickbeard import metadata from sickbeard.metadata.generic import GenericMetadata %> -<%block name="scripts"> -<script type="text/javascript" src="${srRoot}/js/configBackupRestore.js?${sbPID}"></script> -<script type="text/javascript" src="${srRoot}/js/new/config_backuprestore.js"></script> -</%block> <%block name="content"> % if not header is UNDEFINED: <h1 class="header">${header}</h1> diff --git a/gui/slick/views/config_postProcessing.mako b/gui/slick/views/config_postProcessing.mako index e669c11d0322f803dc874eca2a795b1f70222261..9fd8161b2d9c0dd06a7757580ae4be07992ceae9 100644 --- a/gui/slick/views/config_postProcessing.mako +++ b/gui/slick/views/config_postProcessing.mako @@ -1036,14 +1036,11 @@ </div><!-- /naming_anime_different --> - <div></div> <input type="submit" class="btn config_submitter" value="Save Changes" /><br> - </fieldset> </div><!-- /component-group2 //--> <div id="core-component-group3" class="component-group"> - <div class="component-group-desc"> <h3>Metadata</h3> <p>The data associated to the data. These are files associated to a TV show in the form of images and text that, when supported, will enhance the viewing experience.</p> diff --git a/gui/slick/views/config_providers.mako b/gui/slick/views/config_providers.mako index a8259e69cfbe3e37b47aef928718fa30770e9817..ca7ccfbb831e6373d72dcaac255ed00a728be03f 100644 --- a/gui/slick/views/config_providers.mako +++ b/gui/slick/views/config_providers.mako @@ -6,7 +6,7 @@ from sickbeard.helpers import anon_url %> <%block name="scripts"> -<script type="text/javascript" src="/js/ConfigProviders.js"></script> +<script type="text/javascript" src="${srRoot}/js/configProviders.js"></script> <script type="text/javascript"> $(document).ready(function(){ % if sickbeard.USE_NZBS: diff --git a/gui/slick/views/config_search.mako b/gui/slick/views/config_search.mako index 3560645ce19e606e6dbd6259173fd474ccd0e395..8bc218adac83a4d0d6d9fbe3039bb56fdd85ca5e 100644 --- a/gui/slick/views/config_search.mako +++ b/gui/slick/views/config_search.mako @@ -3,11 +3,6 @@ import sickbeard from sickbeard import clients %> -<%block name="scripts"> -<script type="text/javascript" src="${srRoot}/js/configSearch.js?${sbPID}"></script> -<script type="text/javascript" src="${srRoot}/js/config.js?${sbPID}"></script> -<script type="text/javascript" src="${srRoot}/js/new/config_search.js"></script> -</%block> <%block name="content"> % if not header is UNDEFINED: <h1 class="header">${header}</h1> @@ -17,9 +12,7 @@ <div id="config"> <div id="config-content"> - <form id="configForm" action="saveSearch" method="post"> - <div id="config-components"> <ul> <li><a href="#core-component-group1">Episode Search</a></li> @@ -27,9 +20,7 @@ <li><a href="#core-component-group3">Torrent Search</a></li> </ul> - <div id="core-component-group1" class="component-group"> - <div class="component-group-desc"> <h3>Episode Search</h3> <p>How to manage searching with <a href="${srRoot}/config/providers">providers</a>.</p> @@ -428,16 +419,13 @@ </div><!-- /component-group2 //--> <div id="core-component-group3" class="component-group"> - <div class="component-group-desc"> <h3>Torrent Search</h3> <p>How to handle Torrent search results.</p> </div> <fieldset class="component-group-list"> - <div class="field-pair"> - <label for="use_torrents"> <span class="component-title">Search torrents</span> <span class="component-desc"> @@ -447,175 +435,175 @@ </label> </div> - <div id="content_use_torrents"> - <div class="field-pair"> - <label for="torrent_method"> - <span class="component-title">Send .torrent files to:</span> - <span class="component-desc"> - <select name="torrent_method" id="torrent_method" class="form-control input-sm"> -<% torrent_method_text = {'blackhole': "Black hole", 'utorrent': "uTorrent", 'transmission': "Transmission", 'deluge': "Deluge (via WebUI)", 'deluged': "Deluge (via Daemon)", 'download_station': "Synology DS", 'rtorrent': "rTorrent", 'qbittorrent': "qbittorrent", 'mlnet': "MLDonkey"} %> -% for curAction in ('blackhole', 'utorrent', 'transmission', 'deluge', 'deluged', 'download_station', 'rtorrent', 'qbittorrent', 'mlnet'): - <option value="${curAction}" ${('', 'selected="selected"')[sickbeard.TORRENT_METHOD == curAction]}>${torrent_method_text[curAction]}</option> -% endfor - </select> - </label> - - <div id="options_torrent_blackhole"> + <div id="content_use_torrents"> <div class="field-pair"> - <label> - <span class="component-title">Black hole folder location</span> - <span class="component-desc"> - <input type="text" name="torrent_dir" id="torrent_dir" value="${sickbeard.TORRENT_DIR}" class="form-control input-sm input350" /> - <div class="clear-left"><p><b>.torrent</b> files are stored at this location for external software to find and use</p></div> - </span> - </label> - </div> - - <div></div> - <input type="submit" class="btn config_submitter" value="Save Changes" /><br> - </div> - </div> - - <div id="options_torrent_clients"> - <div class="field-pair"> - <label> - <span class="component-title" id="host_title">Torrent host:port</span> - <span class="component-desc"> - <input type="text" name="torrent_host" id="torrent_host" value="${sickbeard.TORRENT_HOST}" class="form-control input-sm input350" /> - <div class="clear-left"> - <p id="host_desc_torrent">URL to your torrent client (e.g. http://localhost:8000/)</p> - </div> - </span> - </label> - </div> - - <div class="field-pair" id="torrent_rpcurl_option"> - <label> - <span class="component-title" id="rpcurl_title">Torrent RPC URL</span> - <span class="component-desc"> - <input type="text" name="torrent_rpcurl" id="torrent_rpcurl" value="${sickbeard.TORRENT_RPCURL}" class="form-control input-sm input350"/> - <div class="clear-left"> - <p id="rpcurl_desc_">The path without leading and trailing slashes (e.g. transmission)</p> - </div> - </span> - </label> - </div> - - <div class="field-pair" id="torrent_auth_type_option"> - <label> - <span class="component-title">Http Authentication</span> - <span class="component-desc"> - <select name="torrent_auth_type" id="torrent_auth_type" class="form-control input-sm"> - <% http_authtype = {'none': "None", 'basic': "Basic", 'digest': "Digest"} %> - % for authvalue, authname in http_authtype.iteritems(): - <option id="torrent_auth_type_value" value="${authvalue}" ${('', 'selected="selected"')[sickbeard.TORRENT_AUTH_TYPE == authvalue]}>${authname}</option> - % endfor - </select> - <p></p> - </span> - </label> - </div> - - <div class="field-pair" id="torrent_verify_cert_option"> - <label for="torrent_verify_cert"> - <span class="component-title">Verify certificate</span> - <span class="component-desc"> - <input type="checkbox" name="torrent_verify_cert" class="enabler" id="torrent_verify_cert" ${('', 'checked="checked"')[bool(sickbeard.TORRENT_VERIFY_CERT)]}/> - <p id="torrent_verify_deluge">disable if you get "Deluge: Authentication Error" in your log</p> - <p id="torrent_verify_rtorrent">Verify SSL certificates for HTTPS requests</p> - </span> + <label for="torrent_method"> + <span class="component-title">Send .torrent files to:</span> + <span class="component-desc"> + <select name="torrent_method" id="torrent_method" class="form-control input-sm"> + <% torrent_method_text = {'blackhole': "Black hole", 'utorrent': "uTorrent", 'transmission': "Transmission", 'deluge': "Deluge (via WebUI)", 'deluged': "Deluge (via Daemon)", 'download_station': "Synology DS", 'rtorrent': "rTorrent", 'qbittorrent': "qbittorrent", 'mlnet': "MLDonkey"} %> + % for curAction in ('blackhole', 'utorrent', 'transmission', 'deluge', 'deluged', 'download_station', 'rtorrent', 'qbittorrent', 'mlnet'): + <option value="${curAction}" ${('', 'selected="selected"')[sickbeard.TORRENT_METHOD == curAction]}>${torrent_method_text[curAction]}</option> + % endfor + </select> </label> - </div> - <div class="field-pair" id="torrent_username_option"> - <label> - <span class="component-title" id="username_title">Client username</span> - <span class="component-desc"> - <input type="text" name="torrent_username" id="torrent_username" value="${sickbeard.TORRENT_USERNAME}" class="form-control input-sm input200" /> - <p>(blank for none)</p> - </span> - </label> - </div> + <div id="options_torrent_blackhole"> + <div class="field-pair"> + <label> + <span class="component-title">Black hole folder location</span> + <span class="component-desc"> + <input type="text" name="torrent_dir" id="torrent_dir" value="${sickbeard.TORRENT_DIR}" class="form-control input-sm input350" /> + <div class="clear-left"><p><b>.torrent</b> files are stored at this location for external software to find and use</p></div> + </span> + </label> + </div> - <div class="field-pair" id="torrent_password_option"> - <label> - <span class="component-title" id="password_title">Client password</span> - <span class="component-desc"> - <input type="password" name="torrent_password" id="torrent_password" value="${sickbeard.TORRENT_PASSWORD}" class="form-control input-sm input200" /> - <p>(blank for none)</p> - </span> - </label> + <div></div> + <input type="submit" class="btn config_submitter" value="Save Changes" /><br> + </div> </div> - <div class="field-pair" id="torrent_label_option"> - <label> - <span class="component-title">Add label to torrent</span> - <span class="component-desc"> - <input type="text" name="torrent_label" id="torrent_label" value="${sickbeard.TORRENT_LABEL}" class="form-control input-sm input200" /> - <span id="label_warning_deluge" style="display:none"><p>(blank spaces are not allowed)</p> - <div class="clear-left"><p>note: label plugin must be enabled in Deluge clients</p></div> + <div id="options_torrent_clients"> + <div class="field-pair"> + <label> + <span class="component-title" id="host_title">Torrent host:port</span> + <span class="component-desc"> + <input type="text" name="torrent_host" id="torrent_host" value="${sickbeard.TORRENT_HOST}" class="form-control input-sm input350" /> + <div class="clear-left"> + <p id="host_desc_torrent">URL to your torrent client (e.g. http://localhost:8000/)</p> + </div> </span> - </span> - </label> - </div> - - <div class="field-pair" id="torrent_label_anime_option"> - <label> - <span class="component-title">Add label to torrent for anime</span> - <span class="component-desc"> - <input type="text" name="torrent_label_anime" id="torrent_label_anime" value="${sickbeard.TORRENT_LABEL_ANIME}" class="form-control input-sm input200" /> - <span id="label_anime_warning_deluge" style="display:none"><p>(blank spaces are not allowed)</p> - <div class="clear-left"><p>note: label plugin must be enabled in Deluge clients</p></div> + </label> + </div> + + <div class="field-pair" id="torrent_rpcurl_option"> + <label> + <span class="component-title" id="rpcurl_title">Torrent RPC URL</span> + <span class="component-desc"> + <input type="text" name="torrent_rpcurl" id="torrent_rpcurl" value="${sickbeard.TORRENT_RPCURL}" class="form-control input-sm input350"/> + <div class="clear-left"> + <p id="rpcurl_desc_">The path without leading and trailing slashes (e.g. transmission)</p> + </div> </span> - </span> - </label> - </div> - - <div class="field-pair" id="torrent_path_option"> - <label> - <span class="component-title" id="directory_title">Downloaded files location</span> - <span class="component-desc"> - <input type="text" name="torrent_path" id="torrent_path" value="${sickbeard.TORRENT_PATH}" class="form-control input-sm input350" /> - <div class="clear-left"><p>where <span id="torrent_client">the torrent client</span> will save downloaded files (blank for client default) - <span id="path_synology"> <b>note:</b> the destination has to be a shared folder for Synology DS</span></p> - </div> - </span> - </label> - </div> - - <div class="field-pair" id="torrent_seed_time_option"> - <label> - <span class="component-title" id="torrent_seed_time_label">Minimum seeding time is</span> - <span class="component-desc"><input type="number" step="1" name="torrent_seed_time" id="torrent_seed_time" value="${sickbeard.TORRENT_SEED_TIME}" class="form-control input-sm input100" /> - <p>hours. (default:'0' passes blank to client and '-1' passes nothing)</p></span> - </label> - </div> - - <div class="field-pair" id="torrent_paused_option"> - <label> - <span class="component-title">Start torrent paused</span> - <span class="component-desc"> - <input type="checkbox" name="torrent_paused" class="enabler" id="torrent_paused" ${('', 'checked="checked"')[bool(sickbeard.TORRENT_PAUSED)]}/> - <p>add .torrent to client but do <b style="font-weight:900">not</b> start downloading</p> - </span> - </label> - </div> - - <div class="field-pair" id="torrent_high_bandwidth_option"> - <label> - <span class="component-title">Allow high bandwidth</span> - <span class="component-desc"> - <input type="checkbox" name="torrent_high_bandwidth" class="enabler" id="torrent_high_bandwidth" ${('', 'checked="checked"')[bool(sickbeard.TORRENT_HIGH_BANDWIDTH)]}/> - <p>use high bandwidth allocation if priority is high</p> - </span> - </label> - </div> - - <div class="testNotification" id="test_torrent_result">Click below to test</div> - <input class="btn" type="button" value="Test Connection" id="test_torrent" class="btn test-button"/> - <input type="submit" class="btn config_submitter" value="Save Changes" /><br> - </div> - </div><!-- /content_use_torrents //--> + </label> + </div> + + <div class="field-pair" id="torrent_auth_type_option"> + <label> + <span class="component-title">Http Authentication</span> + <span class="component-desc"> + <select name="torrent_auth_type" id="torrent_auth_type" class="form-control input-sm"> + <% http_authtype = {'none': "None", 'basic': "Basic", 'digest': "Digest"} %> + % for authvalue, authname in http_authtype.iteritems(): + <option id="torrent_auth_type_value" value="${authvalue}" ${('', 'selected="selected"')[sickbeard.TORRENT_AUTH_TYPE == authvalue]}>${authname}</option> + % endfor + </select> + <p></p> + </span> + </label> + </div> + + <div class="field-pair" id="torrent_verify_cert_option"> + <label for="torrent_verify_cert"> + <span class="component-title">Verify certificate</span> + <span class="component-desc"> + <input type="checkbox" name="torrent_verify_cert" class="enabler" id="torrent_verify_cert" ${('', 'checked="checked"')[bool(sickbeard.TORRENT_VERIFY_CERT)]}/> + <p id="torrent_verify_deluge">disable if you get "Deluge: Authentication Error" in your log</p> + <p id="torrent_verify_rtorrent">Verify SSL certificates for HTTPS requests</p> + </span> + </label> + </div> + + <div class="field-pair" id="torrent_username_option"> + <label> + <span class="component-title" id="username_title">Client username</span> + <span class="component-desc"> + <input type="text" name="torrent_username" id="torrent_username" value="${sickbeard.TORRENT_USERNAME}" class="form-control input-sm input200" /> + <p>(blank for none)</p> + </span> + </label> + </div> + + <div class="field-pair" id="torrent_password_option"> + <label> + <span class="component-title" id="password_title">Client password</span> + <span class="component-desc"> + <input type="password" name="torrent_password" id="torrent_password" value="${sickbeard.TORRENT_PASSWORD}" class="form-control input-sm input200" /> + <p>(blank for none)</p> + </span> + </label> + </div> + + <div class="field-pair" id="torrent_label_option"> + <label> + <span class="component-title">Add label to torrent</span> + <span class="component-desc"> + <input type="text" name="torrent_label" id="torrent_label" value="${sickbeard.TORRENT_LABEL}" class="form-control input-sm input200" /> + <span id="label_warning_deluge" style="display:none"><p>(blank spaces are not allowed)</p> + <div class="clear-left"><p>note: label plugin must be enabled in Deluge clients</p></div> + </span> + </span> + </label> + </div> + + <div class="field-pair" id="torrent_label_anime_option"> + <label> + <span class="component-title">Add label to torrent for anime</span> + <span class="component-desc"> + <input type="text" name="torrent_label_anime" id="torrent_label_anime" value="${sickbeard.TORRENT_LABEL_ANIME}" class="form-control input-sm input200" /> + <span id="label_anime_warning_deluge" style="display:none"><p>(blank spaces are not allowed)</p> + <div class="clear-left"><p>note: label plugin must be enabled in Deluge clients</p></div> + </span> + </span> + </label> + </div> + + <div class="field-pair" id="torrent_path_option"> + <label> + <span class="component-title" id="directory_title">Downloaded files location</span> + <span class="component-desc"> + <input type="text" name="torrent_path" id="torrent_path" value="${sickbeard.TORRENT_PATH}" class="form-control input-sm input350" /> + <div class="clear-left"><p>where <span id="torrent_client">the torrent client</span> will save downloaded files (blank for client default) + <span id="path_synology"> <b>note:</b> the destination has to be a shared folder for Synology DS</span></p> + </div> + </span> + </label> + </div> + + <div class="field-pair" id="torrent_seed_time_option"> + <label> + <span class="component-title" id="torrent_seed_time_label">Minimum seeding time is</span> + <span class="component-desc"><input type="number" step="1" name="torrent_seed_time" id="torrent_seed_time" value="${sickbeard.TORRENT_SEED_TIME}" class="form-control input-sm input100" /> + <p>hours. (default:'0' passes blank to client and '-1' passes nothing)</p></span> + </label> + </div> + + <div class="field-pair" id="torrent_paused_option"> + <label> + <span class="component-title">Start torrent paused</span> + <span class="component-desc"> + <input type="checkbox" name="torrent_paused" class="enabler" id="torrent_paused" ${('', 'checked="checked"')[bool(sickbeard.TORRENT_PAUSED)]}/> + <p>add .torrent to client but do <b style="font-weight:900">not</b> start downloading</p> + </span> + </label> + </div> + + <div class="field-pair" id="torrent_high_bandwidth_option"> + <label> + <span class="component-title">Allow high bandwidth</span> + <span class="component-desc"> + <input type="checkbox" name="torrent_high_bandwidth" class="enabler" id="torrent_high_bandwidth" ${('', 'checked="checked"')[bool(sickbeard.TORRENT_HIGH_BANDWIDTH)]}/> + <p>use high bandwidth allocation if priority is high</p> + </span> + </label> + </div> + + <div class="testNotification" id="test_torrent_result">Click below to test</div> + <input class="btn" type="button" value="Test Connection" id="test_torrent" class="btn test-button"/> + <input type="submit" class="btn config_submitter" value="Save Changes" /><br> + </div> + </div><!-- /content_use_torrents //--> </fieldset> </div><!-- /component-group3 //--> @@ -624,10 +612,7 @@ <input type="submit" class="btn pull-left config_submitter button" value="Save Changes" /> </div><!-- /config-components //--> - </form> </div> </div> - -<div></div> </%block> diff --git a/gui/slick/views/config_subtitles.mako b/gui/slick/views/config_subtitles.mako index 08281ee0c1cbf0d2471bd41733d28d34c82d34ea..63fd4faf61aa43b7d2d8c9c60455e5fef26a6806 100644 --- a/gui/slick/views/config_subtitles.mako +++ b/gui/slick/views/config_subtitles.mako @@ -5,8 +5,6 @@ from sickbeard.helpers import anon_url %> <%block name="scripts"> -<script type="text/javascript" src="${srRoot}/js/configSubtitles.js?${sbPID}"></script> -<script type="text/javascript" src="${srRoot}/js/config.js"></script> <script> $(document).ready(function() { $("#subtitles_languages").tokenInput([${','.join("{\"id\": \"" + lang.opensubtitles + "\", name: \"" + lang.name + "\"}" for lang in subtitles.subtitleLanguageFilter())}], { diff --git a/gui/slick/views/layouts/main.mako b/gui/slick/views/layouts/main.mako index 9ff550e1e2b3bcac917472861a0d18e81a33a5fe..1a2d40f0796db9dd76de826fd04fcbabdf859095 100644 --- a/gui/slick/views/layouts/main.mako +++ b/gui/slick/views/layouts/main.mako @@ -314,7 +314,6 @@ <script type="text/javascript" src="${srRoot}/js/lib/jquery.cookiejar.js?${sbPID}"></script> <script type="text/javascript" src="${srRoot}/js/lib/jquery.json-2.2.min.js?${sbPID}"></script> <script type="text/javascript" src="${srRoot}/js/lib/jquery.selectboxes.min.js?${sbPID}"></script> - <script type="text/javascript" src="${srRoot}/js/lib/isotope.pkgd.min.js?${sbPID}"></script><!-- Can't be added to bower --> <script type="text/javascript" src="${srRoot}/js/lib/formwizard.js?${sbPID}"></script><!-- Can't be added to bower --> <script type="text/javascript" src="${srRoot}/js/new/parsers.js?${sbPID}"></script> <script type="text/javascript" src="${srRoot}/js/new/meta.js?${sbPID}"></script> diff --git a/gui/slick/views/manage_subtitleMissed.mako b/gui/slick/views/manage_subtitleMissed.mako index 5337fd8e6fbbaceb2573498f4d4c64b403d437f0..d488199aa6787ab8213e2a97c0c81c04ddfa9278 100644 --- a/gui/slick/views/manage_subtitleMissed.mako +++ b/gui/slick/views/manage_subtitleMissed.mako @@ -5,9 +5,6 @@ import sickbeard from sickbeard import common %> -<%block name="scripts"> -<script type="text/javascript" src="${srRoot}/js/manageSubtitleMissed.js?${sbPID}"></script> -</%block> <%block name="content"> <div id="content960"> % if not header is UNDEFINED: diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 54d8d0b8c638a068783126b245b6a80244f009a2..a58eb83eb77aba944e44fb38f465cd236e5789a7 100644 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -701,6 +701,9 @@ def initialize(consoleLogging=True): GIT_REMOTE_URL = check_setting_str(CFG, 'General', 'git_remote_url', 'https://github.com/%s/%s.git' % (GIT_ORG, GIT_REPO)) + if 'sickragetv' in GIT_REMOTE_URL.lower(): + GIT_REMOTE_URL = 'https://github.com/SickRage/SickRage.git' + # current commit hash CUR_COMMIT_HASH = check_setting_str(CFG, 'General', 'cur_commit_hash', '') diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index 9ea8bbe6119ed9aa778f3c84602152e3031b011e..e22bb3639a24a304f283162ba98caad064569849 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -605,8 +605,8 @@ name_parser_cache = NameParserCache() class InvalidNameException(Exception): - "The given release name is not valid" + """The given release name is not valid""" class InvalidShowException(Exception): - "The given show name is not valid" + """The given show name is not valid""" diff --git a/sickbeard/notifiers/__init__.py b/sickbeard/notifiers/__init__.py index a113129ccf2a28c03ecddba1c8cdc289c3ed499c..d7112c67cdd924e4d706c6891ceb4e0269a5d1b2 100644 --- a/sickbeard/notifiers/__init__.py +++ b/sickbeard/notifiers/__init__.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Nic Wolfe <nic@wolfeden.ca> # URL: http://code.google.com/p/sickbeard/ # @@ -41,8 +43,6 @@ import tweet import trakt import emailnotify -from sickbeard.common import * - # home theater / nas kodi_notifier = kodi.KODINotifier() plex_notifier = plex.PLEXNotifier() diff --git a/sickbeard/notifiers/boxcar.py b/sickbeard/notifiers/boxcar.py index 90252e00ac52ec87032b47c9255859a6251f55fb..0834075a6034580cca4a6916cf95a2d87b1302b2 100644 --- a/sickbeard/notifiers/boxcar.py +++ b/sickbeard/notifiers/boxcar.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Marvin Pinto <me@marvinp.ca> # Author: Dennis Lutter <lad1337@gmail.com> # URL: http://code.google.com/p/sickbeard/ @@ -17,7 +19,8 @@ # You should have received a copy of the GNU General Public License # along with SickRage. If not, see <http://www.gnu.org/licenses/>. -import urllib, urllib2 +import urllib +import urllib2 import time import sickbeard @@ -29,7 +32,7 @@ from sickrage.helper.exceptions import ex API_URL = "https://boxcar.io/devices/providers/fWc4sgSmpcN6JujtBmR6/notifications" -class BoxcarNotifier: +class BoxcarNotifier(object): def test_notify(self, boxcar_username): return self._notifyBoxcar("This is a test notification from Sick Beard", "Test", boxcar_username, force=True) @@ -52,7 +55,7 @@ class BoxcarNotifier: # if this is a subscription notification then act accordingly if subscribe: data = urllib.urlencode({'email': email}) - curUrl = curUrl + "/subscribe" + curUrl += "/subscribe" # for normal requests we need all these parameters else: @@ -63,7 +66,6 @@ class BoxcarNotifier: 'notification[from_remote_service_id]': int(time.time()) }) - # send the request to boxcar try: req = urllib2.Request(curUrl) @@ -89,7 +91,7 @@ class BoxcarNotifier: # If the user has already added your service, we'll return an HTTP status code of 401. if subscribe: logger.log(u"Already subscribed to service", logger.ERROR) - # i dont know if this is true or false ... its neither but i also dont know how we got here in the first place + # i don't know if this is true or false ... its neither but i also don't know how we got here in the first place return False # HTTP status 401 if the user doesn't have the service added @@ -114,7 +116,6 @@ class BoxcarNotifier: if sickbeard.BOXCAR_NOTIFY_ONSNATCH: self._notifyBoxcar(title, ep_name) - def notify_download(self, ep_name, title=notifyStrings[NOTIFY_DOWNLOAD]): if sickbeard.BOXCAR_NOTIFY_ONDOWNLOAD: self._notifyBoxcar(title, ep_name) @@ -123,10 +124,10 @@ class BoxcarNotifier: if sickbeard.BOXCAR_NOTIFY_ONSUBTITLEDOWNLOAD: self._notifyBoxcar(title, ep_name + ": " + lang) - def notify_git_update(self, new_version = "??"): + def notify_git_update(self, new_version="??"): if sickbeard.USE_BOXCAR: - update_text=notifyStrings[NOTIFY_GIT_UPDATE_TEXT] - title=notifyStrings[NOTIFY_GIT_UPDATE] + update_text = notifyStrings[NOTIFY_GIT_UPDATE_TEXT] + title = notifyStrings[NOTIFY_GIT_UPDATE] self._notifyBoxcar(title, update_text + new_version) def _notifyBoxcar(self, title, message, username=None, force=False): diff --git a/sickbeard/notifiers/boxcar2.py b/sickbeard/notifiers/boxcar2.py index 3dd4a9a5a31662b0de443c9d970a2e46897e00ef..5bb79cd7490b93b79eeed2c5f87c1094d73a5506 100644 --- a/sickbeard/notifiers/boxcar2.py +++ b/sickbeard/notifiers/boxcar2.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Rafael Silva <rpluto@gmail.com> # Author: Marvin Pinto <me@marvinp.ca> # Author: Dennis Lutter <lad1337@gmail.com> @@ -18,7 +20,8 @@ # You should have received a copy of the GNU General Public License # along with SickRage. If not, see <http://www.gnu.org/licenses/>. -import urllib, urllib2 +import urllib +import urllib2 import sickbeard @@ -29,7 +32,7 @@ from sickrage.helper.exceptions import ex API_URL = "https://new.boxcar.io/api/notifications" -class Boxcar2Notifier: +class Boxcar2Notifier(object): def test_notify(self, accesstoken, title="SickRage : Test"): return self._sendBoxcar2("This is a test notification from SickRage", title, accesstoken) @@ -59,7 +62,7 @@ class Boxcar2Notifier: # send the request to boxcar2 try: req = urllib2.Request(curUrl) - handle = urllib2.urlopen(req, data,timeout=60) + handle = urllib2.urlopen(req, data, timeout=60) handle.close() except Exception as e: @@ -87,7 +90,6 @@ class Boxcar2Notifier: if sickbeard.BOXCAR2_NOTIFY_ONSNATCH: self._notifyBoxcar2(title, ep_name) - def notify_download(self, ep_name, title=notifyStrings[NOTIFY_DOWNLOAD]): if sickbeard.BOXCAR2_NOTIFY_ONDOWNLOAD: self._notifyBoxcar2(title, ep_name) @@ -96,10 +98,10 @@ class Boxcar2Notifier: if sickbeard.BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD: self._notifyBoxcar2(title, ep_name + ": " + lang) - def notify_git_update(self, new_version = "??"): + def notify_git_update(self, new_version="??"): if sickbeard.USE_BOXCAR2: - update_text=notifyStrings[NOTIFY_GIT_UPDATE_TEXT] - title=notifyStrings[NOTIFY_GIT_UPDATE] + update_text = notifyStrings[NOTIFY_GIT_UPDATE_TEXT] + title = notifyStrings[NOTIFY_GIT_UPDATE] self._notifyBoxcar2(title, update_text + new_version) def _notifyBoxcar2(self, title, message, accesstoken=None): diff --git a/sickbeard/notifiers/emailnotify.py b/sickbeard/notifiers/emailnotify.py index c63b036708ea94a152ffb45721030be2e3362630..03dbdbc1e332aa5fa714b6a7eea58af7c4bbd870 100644 --- a/sickbeard/notifiers/emailnotify.py +++ b/sickbeard/notifiers/emailnotify.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Authors: # Derek Battams <derek@battams.ca> # Pedro Jose Pereira Vieito (@pvieito) <pvieito@gmail.com> @@ -34,7 +36,7 @@ from sickbeard import db from sickrage.helper.encoding import ss -class EmailNotifier: +class EmailNotifier(object): def __init__(self): self.last_err = None @@ -162,7 +164,6 @@ class EmailNotifier: else: logger.log(u"Download notification ERROR: %s" % self.last_err, logger.ERROR) - def notify_git_update(self, new_version="??"): pass @@ -171,7 +172,7 @@ class EmailNotifier: # Grab the global recipients for addr in sickbeard.EMAIL_LIST.split(','): - if (len(addr.strip()) > 0): + if len(addr.strip()) > 0: addrs.append(addr) # Grab the recipients for the show @@ -180,7 +181,7 @@ class EmailNotifier: for subs in myDB.select("SELECT notify_list FROM tv_shows WHERE show_name = ?", (s,)): if subs['notify_list']: for addr in subs['notify_list'].split(','): - if (len(addr.strip()) > 0): + if len(addr.strip()) > 0: addrs.append(addr) addrs = set(addrs) @@ -200,10 +201,10 @@ class EmailNotifier: if smtpDebug: srv.set_debuglevel(1) try: - if (use_tls == '1' or use_tls == True) or (len(user) > 0 and len(pwd) > 0): + if (use_tls == '1' or use_tls is True) or (len(user) > 0 and len(pwd) > 0): srv.ehlo() logger.log(u'Sent initial EHLO command!', logger.DEBUG) - if use_tls == '1' or use_tls == True: + if use_tls == '1' or use_tls is True: srv.starttls() logger.log(u'Sent STARTTLS command!', logger.DEBUG) if len(user) > 0 and len(pwd) > 0: diff --git a/sickbeard/notifiers/emby.py b/sickbeard/notifiers/emby.py index 69ce06cc7ea2f7903fcc4120db1fc8fa60298065..f233ed75d538b1d824f058bc9df6e5b141f8826a 100644 --- a/sickbeard/notifiers/emby.py +++ b/sickbeard/notifiers/emby.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Nic Wolfe <nic@wolfeden.ca> # URL: http://code.google.com/p/sickbeard/ # @@ -30,7 +32,7 @@ except ImportError: import simplejson as json -class EMBYNotifier: +class EMBYNotifier(object): def _notify_emby(self, message, host=None, emby_apikey=None): """Handles notifying Emby host via HTTP API @@ -46,7 +48,7 @@ class EMBYNotifier: if not emby_apikey: emby_apikey = sickbeard.EMBY_APIKEY - url = 'http://%s/emby/Notifications/Admin' % (host) + url = 'http://%s/emby/Notifications/Admin' % host values = {'Name': 'SickRage', 'Description': message, 'ImageUrl': 'https://raw.githubusercontent.com/SickRage/SickRage/master/gui/slick/images/sickrage-shark-mascot.png'} data = json.dumps(values) try: diff --git a/sickbeard/notifiers/freemobile.py b/sickbeard/notifiers/freemobile.py index ab203bcba5c0c6020abd662ede3d5acf04658217..dc040d819291291f3f54d8ba86ec3b74484ad209 100644 --- a/sickbeard/notifiers/freemobile.py +++ b/sickbeard/notifiers/freemobile.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Marvin Pinto <me@marvinp.ca> # Author: Dennis Lutter <lad1337@gmail.com> # Author: Aaron Bieber <deftly@gmail.com> @@ -23,11 +25,12 @@ import sickbeard from sickbeard import logger from sickbeard.common import notifyStrings, NOTIFY_SNATCH, NOTIFY_DOWNLOAD, NOTIFY_SUBTITLE_DOWNLOAD, NOTIFY_GIT_UPDATE, NOTIFY_GIT_UPDATE_TEXT -class FreeMobileNotifier: - def test_notify(self, id=None, apiKey=None): - return self._notifyFreeMobile('Test', "This is a test notification from SickRage", id, apiKey, force=True) - def _sendFreeMobileSMS(self, title, msg, id=None, apiKey=None): +class FreeMobileNotifier(object): + def test_notify(self, cust_id=None, apiKey=None): + return self._notifyFreeMobile('Test', "This is a test notification from SickRage", cust_id, apiKey, force=True) + + def _sendFreeMobileSMS(self, title, msg, cust_id=None, apiKey=None): """ Sends a SMS notification @@ -38,9 +41,9 @@ class FreeMobileNotifier: returns: True if the message succeeded, False otherwise """ - if id == None: - id = sickbeard.FREEMOBILE_ID - if apiKey == None: + if cust_id is None: + cust_id = sickbeard.FREEMOBILE_ID + if apiKey is None: apiKey = sickbeard.FREEMOBILE_APIKEY logger.log(u"Free Mobile in use with API KEY: " + apiKey, logger.DEBUG) @@ -48,14 +51,14 @@ class FreeMobileNotifier: # build up the URL and parameters msg = msg.strip() msg_quoted = urllib2.quote(title.encode('utf-8') + ": " + msg.encode('utf-8')) - URL = "https://smsapi.free-mobile.fr/sendmsg?user=" + id + "&pass=" + apiKey + "&msg=" + msg_quoted + URL = "https://smsapi.free-mobile.fr/sendmsg?user=" + cust_id + "&pass=" + apiKey + "&msg=" + msg_quoted req = urllib2.Request(URL) # send the request to Free Mobile try: urllib2.urlopen(req) except IOError, e: - if hasattr(e,'code'): + if hasattr(e, 'code'): if e.code == 400: message = "Missing parameter(s)." logger.log(message, logger.ERROR) @@ -81,14 +84,10 @@ class FreeMobileNotifier: logger.log(message, logger.INFO) return True, message - - - def notify_snatch(self, ep_name, title=notifyStrings[NOTIFY_SNATCH]): if sickbeard.FREEMOBILE_NOTIFY_ONSNATCH: self._notifyFreeMobile(title, ep_name) - def notify_download(self, ep_name, title=notifyStrings[NOTIFY_DOWNLOAD]): if sickbeard.FREEMOBILE_NOTIFY_ONDOWNLOAD: self._notifyFreeMobile(title, ep_name) @@ -97,19 +96,19 @@ class FreeMobileNotifier: if sickbeard.FREEMOBILE_NOTIFY_ONSUBTITLEDOWNLOAD: self._notifyFreeMobile(title, ep_name + ": " + lang) - def notify_git_update(self, new_version = "??"): + def notify_git_update(self, new_version="??"): if sickbeard.USE_FREEMOBILE: - update_text=notifyStrings[NOTIFY_GIT_UPDATE_TEXT] - title=notifyStrings[NOTIFY_GIT_UPDATE] + update_text = notifyStrings[NOTIFY_GIT_UPDATE_TEXT] + title = notifyStrings[NOTIFY_GIT_UPDATE] self._notifyFreeMobile(title, update_text + new_version) - def _notifyFreeMobile(self, title, message, id=None, apiKey=None, force=False): + def _notifyFreeMobile(self, title, message, cust_id=None, apiKey=None, force=False): """ Sends a SMS notification title: The title of the notification to send message: The message string to send - id: Your Free Mobile customer ID + cust_id: Your Free Mobile customer ID apikey: Your Free Mobile API key force: Enforce sending, for instance for testing """ @@ -120,7 +119,7 @@ class FreeMobileNotifier: logger.log(u"Sending a SMS for " + message, logger.DEBUG) - return self._sendFreeMobileSMS(title, message, id, apiKey) + return self._sendFreeMobileSMS(title, message, cust_id, apiKey) notifier = FreeMobileNotifier diff --git a/sickbeard/notifiers/growl.py b/sickbeard/notifiers/growl.py index 10e32204b20681b379081780f3dd1c4139c7ab65..a1a234c4442c59e3622d34d3b686b253136be8af 100644 --- a/sickbeard/notifiers/growl.py +++ b/sickbeard/notifiers/growl.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Nic Wolfe <nic@wolfeden.ca> # URL: http://code.google.com/p/sickbeard/ # @@ -24,7 +26,7 @@ from sickrage.helper.exceptions import ex from libgrowl import gntp -class GrowlNotifier: +class GrowlNotifier(object): sr_logo_url = 'https://raw.githubusercontent.com/SickRage/SickRage/master/gui/slick/images/sickrage-shark-mascot.png' def test_notify(self, host, password): @@ -44,10 +46,10 @@ class GrowlNotifier: if sickbeard.GROWL_NOTIFY_ONSUBTITLEDOWNLOAD: self._sendGrowl(common.notifyStrings[common.NOTIFY_SUBTITLE_DOWNLOAD], ep_name + ": " + lang) - def notify_git_update(self, new_version = "??"): + def notify_git_update(self, new_version="??"): if sickbeard.USE_GROWL: - update_text=common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT] - title=common.notifyStrings[common.NOTIFY_GIT_UPDATE] + update_text = common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT] + title = common.notifyStrings[common.NOTIFY_GIT_UPDATE] self._sendGrowl(title, update_text + new_version) def _send_growl(self, options, message=None): @@ -75,11 +77,11 @@ class GrowlNotifier: notice.add_header('Notification-Text', message) response = self._send(options['host'], options['port'], notice.encode(), options['debug']) - if isinstance(response, gntp.GNTPOK): return True - return False + return True if isinstance(response, gntp.GNTPOK) else False def _send(self, host, port, data, debug=False): - if debug: print '<Sending>\n', data, '\n</Sending>' + if debug: + print '<Sending>\n', data, '\n</Sending>' s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, port)) @@ -87,7 +89,8 @@ class GrowlNotifier: response = gntp.parse_gntp(s.recv(1024)) s.close() - if debug: print '<Recieved>\n', response, '\n</Recieved>' + if debug: + print '<Received>\n', response, '\n</Received>' return response @@ -96,10 +99,10 @@ class GrowlNotifier: if not sickbeard.USE_GROWL and not force: return False - if name == None: + if name is None: name = title - if host == None: + if host is None: hostParts = sickbeard.GROWL_HOST.split(':') else: hostParts = host.split(':') @@ -111,18 +114,16 @@ class GrowlNotifier: growlHosts = [(hostParts[0], port)] - opts = {} - - opts['name'] = name - - opts['title'] = title - opts['app'] = 'SickRage' - - opts['sticky'] = None - opts['priority'] = None - opts['debug'] = False + opts = { + 'name': name, + 'title': title, + 'app': 'SickRage', + 'sticky': None, + 'priority': None, + 'debug': False + } - if password == None: + if password is None: opts['password'] = sickbeard.GROWL_PASSWORD else: opts['password'] = password @@ -148,7 +149,7 @@ class GrowlNotifier: def _sendRegistration(self, host=None, password=None, name='SickRage Notification'): opts = {} - if host == None: + if host is None: hostParts = sickbeard.GROWL_HOST.split(':') else: hostParts = host.split(':') @@ -161,7 +162,7 @@ class GrowlNotifier: opts['host'] = hostParts[0] opts['port'] = port - if password == None: + if password is None: opts['password'] = sickbeard.GROWL_PASSWORD else: opts['password'] = password diff --git a/sickbeard/notifiers/kodi.py b/sickbeard/notifiers/kodi.py index e2303b4e8e6750ce375d891f513771f12a30304c..aeb35c7a872a497a25d6c0280a0ecd20fdc2a150 100644 --- a/sickbeard/notifiers/kodi.py +++ b/sickbeard/notifiers/kodi.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Nic Wolfe <nic@wolfeden.ca> # URL: http://code.google.com/p/sickbeard/ # @@ -40,7 +42,7 @@ except ImportError: import simplejson as json -class KODINotifier: +class KODINotifier(object): sr_logo_url = 'https://raw.githubusercontent.com/SickRage/SickRage/master/gui/slick/images/sickrage-shark-mascot.png' def _get_kodi_version(self, host, username, password): @@ -70,7 +72,7 @@ class KODINotifier: """ - # since we need to maintain python 2.5 compatability we can not pass a timeout delay to urllib2 directly (python 2.6+) + # since we need to maintain python 2.5 compatibility we can not pass a timeout delay to urllib2 directly (python 2.6+) # override socket timeout to reduce delay for this call alone socket.setdefaulttimeout(10) @@ -279,13 +281,13 @@ class KODINotifier: pathSql = 'select path.strPath from path, tvshow, tvshowlinkpath where ' \ 'tvshow.c00 = "%s" and tvshowlinkpath.idShow = tvshow.idShow ' \ - 'and tvshowlinkpath.idPath = path.idPath' % (showName) + 'and tvshowlinkpath.idPath = path.idPath' % showName # use this to get xml back for the path lookups xmlCommand = { 'command': 'SetResponseFormat(webheader;false;webfooter;false;header;<xml>;footer;</xml>;opentag;<tag>;closetag;</tag>;closefinaltag;false)'} # sql used to grab path(s) - sqlCommand = {'command': 'QueryVideoDatabase(%s)' % (pathSql)} + sqlCommand = {'command': 'QueryVideoDatabase(%s)' % pathSql} # set output back to default resetCommand = {'command': 'SetResponseFormat()'} @@ -318,7 +320,7 @@ class KODINotifier: # we do not need it double-encoded, gawd this is dumb unEncPath = urllib.unquote(path.text).decode(sickbeard.SYS_ENCODING) logger.log(u"KODI Updating " + showName + " on " + host + " at " + unEncPath, logger.DEBUG) - updateCommand = {'command': 'ExecBuiltIn', 'parameter': 'KODI.updatelibrary(video, %s)' % (unEncPath)} + updateCommand = {'command': 'ExecBuiltIn', 'parameter': 'KODI.updatelibrary(video, %s)' % unEncPath} request = self._send_to_kodi(updateCommand, host) if not request: logger.log(u"Update of show directory failed on " + showName + " on " + host + " at " + unEncPath, logger.WARNING) @@ -369,7 +371,7 @@ class KODINotifier: command = command.encode('utf-8') logger.log(u"KODI JSON command: " + command, logger.DEBUG) - url = 'http://%s/jsonrpc' % (host) + url = 'http://%s/jsonrpc' % host try: req = urllib2.Request(url, command) req.add_header("Content-type", "application/json") @@ -396,7 +398,7 @@ class KODINotifier: logger.log(u"KODI JSON response: " + str(result), logger.DEBUG) return result # need to return response for parsing except ValueError, e: - logger.log(u"Unable to decode JSON: " + str(response.read()), logger.WARNING) + logger.log(u"Unable to decode JSON: " + str(response.read()), logger.WARNING) return False except IOError, e: @@ -469,10 +471,9 @@ class KODINotifier: logger.log(u'Exact show name not matched in KODI TV show list', logger.DEBUG) return False - # lookup tv-show path if we don't already know it if not len(path): - pathCommand = '{"jsonrpc":"2.0","method":"VideoLibrary.GetTVShowDetails","params":{"tvshowid":%d, "properties": ["file"]},"id":1}' % (tvshowid) + pathCommand = '{"jsonrpc":"2.0","method":"VideoLibrary.GetTVShowDetails","params":{"tvshowid":%d, "properties": ["file"]},"id":1}' % tvshowid pathResponse = self._send_to_kodi_json(pathCommand, host) path = pathResponse["result"]["tvshowdetails"]["file"] @@ -537,7 +538,7 @@ class KODINotifier: """Public wrapper for the update library functions to branch the logic for JSON-RPC or legacy HTTP API Checks the KODI API version to branch the logic to call either the legacy HTTP API or the newer JSON-RPC over HTTP methods. - Do the ability of accepting a list of hosts deliminated by comma, only one host is updated, the first to respond with success. + Do the ability of accepting a list of hosts delimited by comma, only one host is updated, the first to respond with success. This is a workaround for SQL backend users as updating multiple clients causes duplicate entries. Future plan is to revist how we store the host/ip/username/pw/options so that it may be more flexible. diff --git a/sickbeard/notifiers/libnotify.py b/sickbeard/notifiers/libnotify.py index 402b99a1e53dfaf16264e069df4ab8efa65d8105..162dfe2189890cce139041396d2034fcacb1858e 100644 --- a/sickbeard/notifiers/libnotify.py +++ b/sickbeard/notifiers/libnotify.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Nic Wolfe <nic@wolfeden.ca> # URL: http://code.google.com/p/sickbeard/ # @@ -24,10 +26,10 @@ from sickbeard import logger, common def diagnose(): - ''' + """ Check the environment for reasons libnotify isn't working. Return a user-readable message indicating possible issues. - ''' + """ try: from gi.repository import Notify # @UnusedImport except ImportError: @@ -57,7 +59,7 @@ def diagnose(): return u"<p>Error: Unable to send notification." -class LibnotifyNotifier: +class LibnotifyNotifier(object): def __init__(self): self.Notify = None self.gobject = None @@ -94,10 +96,10 @@ class LibnotifyNotifier: if sickbeard.LIBNOTIFY_NOTIFY_ONSUBTITLEDOWNLOAD: self._notify(common.notifyStrings[common.NOTIFY_SUBTITLE_DOWNLOAD], ep_name + ": " + lang) - def notify_git_update(self, new_version = "??"): + def notify_git_update(self, new_version="??"): if sickbeard.USE_LIBNOTIFY: - update_text=common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT] - title=common.notifyStrings[common.NOTIFY_GIT_UPDATE] + update_text = common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT] + title = common.notifyStrings[common.NOTIFY_GIT_UPDATE] self._notify(title, update_text + new_version) def test_notify(self): diff --git a/sickbeard/notifiers/nma.py b/sickbeard/notifiers/nma.py index c0cb173f2d7e3f2e7ea090b969b14f80cda1acd8..d34e11089a139663901d93a400f925ac72fa9037 100644 --- a/sickbeard/notifiers/nma.py +++ b/sickbeard/notifiers/nma.py @@ -1,10 +1,12 @@ +# coding=utf-8 + import sickbeard from sickbeard import logger, common from pynma import pynma -class NMA_Notifier: +class NMA_Notifier(object): def test_notify(self, nma_api, nma_priority): return self._sendNMA(nma_api, nma_priority, event="Test", message="Testing NMA settings from SickRage", force=True) @@ -24,10 +26,10 @@ class NMA_Notifier: self._sendNMA(nma_api=None, nma_priority=None, event=common.notifyStrings[common.NOTIFY_SUBTITLE_DOWNLOAD], message=ep_name + ": " + lang) - def notify_git_update(self, new_version = "??"): + def notify_git_update(self, new_version="??"): if sickbeard.USE_NMA: - update_text=common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT] - title=common.notifyStrings[common.NOTIFY_GIT_UPDATE] + update_text = common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT] + title = common.notifyStrings[common.NOTIFY_GIT_UPDATE] self._sendNMA(nma_api=None, nma_priority=None, event=title, message=update_text + new_version) def _sendNMA(self, nma_api=None, nma_priority=None, event=None, message=None, force=False): @@ -37,10 +39,10 @@ class NMA_Notifier: if not sickbeard.USE_NMA and not force: return False - if nma_api == None: + if nma_api is None: nma_api = sickbeard.NMA_API - if nma_priority == None: + if nma_priority is None: nma_priority = sickbeard.NMA_PRIORITY batch = False @@ -49,7 +51,8 @@ class NMA_Notifier: keys = nma_api.split(',') p.addkey(keys) - if len(keys) > 1: batch = True + if len(keys) > 1: + batch = True logger.log(u"NMA: Sending notice with details: event=\"%s\", message=\"%s\", priority=%s, batch=%s" % (event, message, nma_priority, batch), logger.DEBUG) response = p.push(application=title, event=event, description=message, priority=nma_priority, batch_mode=batch) diff --git a/sickbeard/notifiers/nmj.py b/sickbeard/notifiers/nmj.py index 313998de30ffa91d9b7222bca774facdd0b781b0..8b8be514480d0b8fb88c74c0f13c0eedc46e414d 100644 --- a/sickbeard/notifiers/nmj.py +++ b/sickbeard/notifiers/nmj.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Nico Berlee http://nico.berlee.nl/ # URL: http://code.google.com/p/sickbeard/ # @@ -16,7 +18,8 @@ # You should have received a copy of the GNU General Public License # along with SickRage. If not, see <http://www.gnu.org/licenses/>. -import urllib, urllib2 +import urllib +import urllib2 import sickbeard import telnetlib import re @@ -30,7 +33,7 @@ except ImportError: import xml.etree.ElementTree as etree -class NMJNotifier: +class NMJNotifier(object): def notify_settings(self, host): """ Retrieves the settings from a NMJ/Popcorn hour @@ -41,23 +44,20 @@ class NMJNotifier: """ # establish a terminal session to the PC - terminal = False try: terminal = telnetlib.Telnet(host) except Exception: - logger.log(u"Warning: unable to get a telnet session to %s" % (host), logger.WARNING) + logger.log(u"Warning: unable to get a telnet session to %s" % host, logger.WARNING) return False # tell the terminal to output the necessary info to the screen so we can search it later - logger.log(u"Connected to %s via telnet" % (host), logger.DEBUG) + logger.log(u"Connected to %s via telnet" % host, logger.DEBUG) terminal.read_until("sh-3.00# ") terminal.write("cat /tmp/source\n") terminal.write("cat /tmp/netshare\n") terminal.write("exit\n") tnoutput = terminal.read_all() - database = "" - device = "" match = re.search(r"(.+\.db)\r\n?(.+)(?=sh-3.00# cat /tmp/netshare)", tnoutput) # if we found the database in the terminal output then save that database to the config @@ -67,7 +67,7 @@ class NMJNotifier: logger.log(u"Found NMJ database %s on device %s" % (database, device), logger.DEBUG) sickbeard.NMJ_DATABASE = database else: - logger.log(u"Could not get current NMJ database on %s, NMJ is probably not running!" % (host), logger.WARNING) + logger.log(u"Could not get current NMJ database on %s, NMJ is probably not running!" % host, logger.WARNING) return False # if the device is a remote host then try to parse the mounting URL and save it to the config @@ -76,7 +76,7 @@ class NMJNotifier: if match: mount = match.group().replace("127.0.0.1", host) - logger.log(u"Found mounting url on the Popcorn Hour in configuration: %s" % (mount), logger.DEBUG) + logger.log(u"Found mounting url on the Popcorn Hour in configuration: %s" % mount, logger.DEBUG) sickbeard.NMJ_MOUNT = mount else: logger.log(u"Detected a network share on the Popcorn Hour, but could not get the mounting url", @@ -109,7 +109,7 @@ class NMJNotifier: Sends a NMJ update command to the specified machine host: The hostname/IP to send the request to (no port) - database: The database to send the requst to + database: The database to send the request to mount: The mount URL to use (optional) Returns: True if the request succeeded, False otherwise @@ -119,7 +119,7 @@ class NMJNotifier: if mount: try: req = urllib2.Request(mount) - logger.log(u"Try to mount network drive via url: %s" % (mount), logger.DEBUG) + logger.log(u"Try to mount network drive via url: %s" % mount, logger.DEBUG) handle = urllib2.urlopen(req) except IOError, e: if hasattr(e, 'reason'): @@ -145,7 +145,7 @@ class NMJNotifier: # send the request to the server try: req = urllib2.Request(updateUrl) - logger.log(u"Sending NMJ scan update command via url: %s" % (updateUrl), logger.DEBUG) + logger.log(u"Sending NMJ scan update command via url: %s" % updateUrl, logger.DEBUG) handle = urllib2.urlopen(req) response = handle.read() except IOError, e: @@ -163,12 +163,12 @@ class NMJNotifier: et = etree.fromstring(response) result = et.findtext("returnValue") except SyntaxError, e: - logger.log(u"Unable to parse XML returned from the Popcorn Hour: %s" % (e), logger.ERROR) + logger.log(u"Unable to parse XML returned from the Popcorn Hour: %s" % e, logger.ERROR) return False # if the result was a number then consider that an error if int(result) > 0: - logger.log(u"Popcorn Hour returned an errorcode: %s" % (result), logger.ERROR) + logger.log(u"Popcorn Hour returned an error code: %s" % result, logger.ERROR) return False else: logger.log(u"NMJ started background scan", logger.INFO) diff --git a/sickbeard/notifiers/nmjv2.py b/sickbeard/notifiers/nmjv2.py index 24464b039e68ce6780f2e2eeeee7ab54c49d4fe7..a99b8c92fc9fb7d8700eac05d0037d64d95b4871 100644 --- a/sickbeard/notifiers/nmjv2.py +++ b/sickbeard/notifiers/nmjv2.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Jasper Lanting # Based on nmj.py by Nico Berlee: http://nico.berlee.nl/ # URL: http://code.google.com/p/sickbeard/ @@ -30,7 +32,7 @@ except ImportError: import xml.etree.ElementTree as etree -class NMJv2Notifier: +class NMJv2Notifier(object): def notify_snatch(self, ep_name): return False # Not implemented: Start the scanner when snatched does not make any sense @@ -53,7 +55,7 @@ class NMJv2Notifier: Retrieves the NMJv2 database location from Popcorn hour host: The hostname/IP of the Popcorn Hour server - dbloc: 'local' for PCH internal harddrive. 'network' for PCH network shares + dbloc: 'local' for PCH internal hard drive. 'network' for PCH network shares instance: Allows for selection of different DB in case of multiple databases Returns: True if the settings were retrieved successfully, False otherwise @@ -66,7 +68,7 @@ class NMJv2Notifier: xml = parseString(response1) time.sleep(300.0 / 1000.0) for node in xml.getElementsByTagName('path'): - xmlTag = node.toxml(); + xmlTag = node.toxml() xmlData = xmlTag.replace('<path>', '').replace('</path>', '').replace('[=]', '') url_db = "http://" + host + ":8008/metadata_database?arg0=check_database&arg1=" + xmlData reqdb = urllib2.Request(url_db) @@ -98,7 +100,7 @@ class NMJv2Notifier: Sends a NMJ update command to the specified machine host: The hostname/IP to send the request to (no port) - database: The database to send the requst to + database: The database to send the request to mount: The mount URL to use (optional) Returns: True if the request succeeded, False otherwise @@ -107,9 +109,9 @@ class NMJv2Notifier: # if a host is provided then attempt to open a handle to that URL try: url_scandir = "http://" + host + ":8008/metadata_database?arg0=update_scandir&arg1=" + sickbeard.NMJv2_DATABASE + "&arg2=&arg3=update_all" - logger.log(u"NMJ scan update command sent to host: %s" % (host), logger.DEBUG) + logger.log(u"NMJ scan update command sent to host: %s" % host, logger.DEBUG) url_updatedb = "http://" + host + ":8008/metadata_database?arg0=scanner_start&arg1=" + sickbeard.NMJv2_DATABASE + "&arg2=background&arg3=" - logger.log(u"Try to mount network drive via url: %s" % (host), logger.DEBUG) + logger.log(u"Try to mount network drive via url: %s" % host, logger.DEBUG) prereq = urllib2.Request(url_scandir) req = urllib2.Request(url_updatedb) handle1 = urllib2.urlopen(prereq) @@ -124,13 +126,13 @@ class NMJv2Notifier: et = etree.fromstring(response1) result1 = et.findtext("returnValue") except SyntaxError, e: - logger.log(u"Unable to parse XML returned from the Popcorn Hour: update_scandir, %s" % (e), logger.ERROR) + logger.log(u"Unable to parse XML returned from the Popcorn Hour: update_scandir, %s" % e, logger.ERROR) return False try: et = etree.fromstring(response2) result2 = et.findtext("returnValue") except SyntaxError, e: - logger.log(u"Unable to parse XML returned from the Popcorn Hour: scanner_start, %s" % (e), logger.ERROR) + logger.log(u"Unable to parse XML returned from the Popcorn Hour: scanner_start, %s" % e, logger.ERROR) return False # if the result was a number then consider that an error diff --git a/sickbeard/notifiers/plex.py b/sickbeard/notifiers/plex.py index 35f8aeaa14a73cd67da3fe48555805bbf0344634..941b8223c309f1905310e365b14003e7bec31d51 100644 --- a/sickbeard/notifiers/plex.py +++ b/sickbeard/notifiers/plex.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Nic Wolfe <nic@wolfeden.ca> # URL: http://code.google.com/p/sickbeard/ # @@ -33,7 +35,7 @@ except ImportError: import xml.etree.ElementTree as etree -class PLEXNotifier: +class PLEXNotifier(object): def _send_to_plex(self, command, host, username=None, password=None): """Handles communication to Plex hosts via HTTP API diff --git a/sickbeard/notifiers/prowl.py b/sickbeard/notifiers/prowl.py index 195631498b4ea19fc6e2472456836c6572c00f3a..20c40c47b18ae842ba0400a1cd602eab3c95b8e1 100644 --- a/sickbeard/notifiers/prowl.py +++ b/sickbeard/notifiers/prowl.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Nic Wolfe <nic@wolfeden.ca> # URL: http://code.google.com/p/sickbeard/ # @@ -33,7 +35,7 @@ import sickbeard from sickbeard import logger, common -class ProwlNotifier: +class ProwlNotifier(object): def test_notify(self, prowl_api, prowl_priority): return self._sendProwl(prowl_api, prowl_priority, event="Test", message="Testing Prowl settings from SickRage", force=True) @@ -53,10 +55,10 @@ class ProwlNotifier: self._sendProwl(prowl_api=None, prowl_priority=None, event=common.notifyStrings[common.NOTIFY_SUBTITLE_DOWNLOAD], message=ep_name + ": " + lang) - def notify_git_update(self, new_version = "??"): + def notify_git_update(self, new_version="??"): if sickbeard.USE_PROWL: - update_text=common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT] - title=common.notifyStrings[common.NOTIFY_GIT_UPDATE] + update_text = common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT] + title = common.notifyStrings[common.NOTIFY_GIT_UPDATE] self._sendProwl(prowl_api=None, prowl_priority=None, event=title, message=update_text + new_version) @@ -65,10 +67,10 @@ class ProwlNotifier: if not sickbeard.USE_PROWL and not force: return False - if prowl_api == None: + if prowl_api is None: prowl_api = sickbeard.PROWL_API - if prowl_priority == None: + if prowl_priority is None: prowl_priority = sickbeard.PROWL_PRIORITY title = "SickRage" diff --git a/sickbeard/notifiers/pushalot.py b/sickbeard/notifiers/pushalot.py index 32ed2b6e7823580b81159835c9dc5ffa5fc61e04..77c0ea71488c139c4542624a242e298341002cea 100644 --- a/sickbeard/notifiers/pushalot.py +++ b/sickbeard/notifiers/pushalot.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Maciej Olesinski (https://github.com/molesinski/) # Based on prowl.py by Nic Wolfe <nic@wolfeden.ca> # URL: http://code.google.com/p/sickbeard/ @@ -26,7 +28,7 @@ import sickbeard from sickbeard import logger, common -class PushalotNotifier: +class PushalotNotifier(object): def test_notify(self, pushalot_authorizationtoken): return self._sendPushalot(pushalot_authorizationtoken, event="Test", message="Testing Pushalot settings from SickRage", force=True) @@ -47,10 +49,10 @@ class PushalotNotifier: event=common.notifyStrings[common.NOTIFY_SUBTITLE_DOWNLOAD], message=ep_name + ": " + lang) - def notify_git_update(self, new_version = "??"): + def notify_git_update(self, new_version="??"): if sickbeard.USE_PUSHALOT: - update_text=common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT] - title=common.notifyStrings[common.NOTIFY_GIT_UPDATE] + update_text = common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT] + title = common.notifyStrings[common.NOTIFY_GIT_UPDATE] self._sendPushalot(pushalot_authorizationtoken=None, event=title, message=update_text + new_version) @@ -60,7 +62,7 @@ class PushalotNotifier: if not sickbeard.USE_PUSHALOT and not force: return False - if pushalot_authorizationtoken == None: + if pushalot_authorizationtoken is None: pushalot_authorizationtoken = sickbeard.PUSHALOT_AUTHORIZATIONTOKEN logger.log(u"Pushalot event: " + event, logger.DEBUG) diff --git a/sickbeard/notifiers/pushover.py b/sickbeard/notifiers/pushover.py index e605f3c31dee51da7f5b37a3d0ef4909bb56243a..f4f102b0bbaa3ef526f2282a815b6a35c0345445 100644 --- a/sickbeard/notifiers/pushover.py +++ b/sickbeard/notifiers/pushover.py @@ -19,7 +19,8 @@ # along with SickRage. If not, see <http://www.gnu.org/licenses/>. import httplib -import urllib, urllib2 +import urllib +import urllib2 import time import sickbeard diff --git a/sickbeard/notifiers/pytivo.py b/sickbeard/notifiers/pytivo.py index e7e9434df78a8e7372c383b6092394b687747225..dfdc8ab8991d663b9ae8ce2398ef156aefc65d96 100644 --- a/sickbeard/notifiers/pytivo.py +++ b/sickbeard/notifiers/pytivo.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Nic Wolfe <nic@wolfeden.ca> # URL: http://code.google.com/p/sickbeard/ # @@ -27,7 +29,7 @@ from sickrage.helper.encoding import ek from sickrage.helper.exceptions import ex -class pyTivoNotifier: +class pyTivoNotifier(object): def notify_snatch(self, ep_name): pass @@ -63,9 +65,7 @@ class pyTivoNotifier: # come up with. # - # Calculated values - showPath = ep_obj.show.location showName = ep_obj.show.name rootShowAndSeason = ek(os.path.dirname, ep_obj.location) @@ -79,11 +79,11 @@ class pyTivoNotifier: showAndSeason = rootShowAndSeason.replace(root, "") container = shareName + "/" + showAndSeason - file = "/" + absPath.replace(root, "") + filename = "/" + absPath.replace(root, "") # Finally create the url and make request requestUrl = "http://" + host + "/TiVoConnect?" + urlencode( - {'Command': 'Push', 'Container': container, 'File': file, 'tsn': tsn}) + {'Command': 'Push', 'Container': container, 'File': filename, 'tsn': tsn}) logger.log(u"pyTivo notification: Requesting " + requestUrl, logger.DEBUG) @@ -91,7 +91,7 @@ class pyTivoNotifier: try: response = urlopen(request) # @UnusedVariable - except HTTPError , e: + except HTTPError, e: if hasattr(e, 'reason'): logger.log(u"pyTivo notification: Error, failed to reach a server - " + e.reason, logger.ERROR) return False diff --git a/sickbeard/notifiers/synoindex.py b/sickbeard/notifiers/synoindex.py index 854eb1e43742fa8b31a62f63a8088d7e54e573b1..b1275ce95b942699ec03eef9e121b5e6ef10261d 100644 --- a/sickbeard/notifiers/synoindex.py +++ b/sickbeard/notifiers/synoindex.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Sebastien Erard <sebastien_erard@hotmail.com> # URL: http://code.google.com/p/sickbeard/ # @@ -26,7 +28,7 @@ from sickrage.helper.encoding import ek from sickrage.helper.exceptions import ex -class synoIndexNotifier: +class synoIndexNotifier(object): def notify_snatch(self, ep_name): pass diff --git a/sickbeard/notifiers/synologynotifier.py b/sickbeard/notifiers/synologynotifier.py index ee0591f0111710f70df22bcd6369d6ef0a9365e9..2f3f62d26f8d7871f782e421f844e628ec1110f6 100644 --- a/sickbeard/notifiers/synologynotifier.py +++ b/sickbeard/notifiers/synologynotifier.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Nyaran <nyayukko@gmail.com> # # This file is part of SickRage. @@ -26,7 +28,7 @@ from sickrage.helper.encoding import ek from sickrage.helper.exceptions import ex -class synologyNotifier: +class synologyNotifier(object): def notify_snatch(self, ep_name): if sickbeard.SYNOLOGYNOTIFIER_NOTIFY_ONSNATCH: self._send_synologyNotifier(ep_name, common.notifyStrings[common.NOTIFY_SNATCH]) @@ -39,10 +41,10 @@ class synologyNotifier: if sickbeard.SYNOLOGYNOTIFIER_NOTIFY_ONSUBTITLEDOWNLOAD: self._send_synologyNotifier(ep_name + ": " + lang, common.notifyStrings[common.NOTIFY_SUBTITLE_DOWNLOAD]) - def notify_git_update(self, new_version = "??"): + def notify_git_update(self, new_version="??"): if sickbeard.USE_SYNOLOGYNOTIFIER: - update_text=common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT] - title=common.notifyStrings[common.NOTIFY_GIT_UPDATE] + update_text = common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT] + title = common.notifyStrings[common.NOTIFY_GIT_UPDATE] self._send_synologyNotifier(update_text + new_version, title) def _send_synologyNotifier(self, message, title): diff --git a/sickbeard/notifiers/trakt.py b/sickbeard/notifiers/trakt.py index ab587637eddff96fcaf2815aa2b4453d7da76600..6733c5d1b38eb0e360a55fb88f9b4a89752e9b25 100644 --- a/sickbeard/notifiers/trakt.py +++ b/sickbeard/notifiers/trakt.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Dieter Blomme <dieterblomme@gmail.com> # URL: http://code.google.com/p/sickbeard/ # @@ -24,7 +26,7 @@ from libtrakt import TraktAPI from libtrakt.exceptions import traktException, traktServerBusy, traktAuthException -class TraktNotifier: +class TraktNotifier(object): """ A "notifier" for trakt.tv which keeps track of what has and hasn't been added to your library. """ @@ -74,7 +76,7 @@ class TraktNotifier: trakt_api.traktRequest("sync/watchlist/remove", data, method='POST') # Add Season and Episode + Related Episodes - data['shows'][0]['seasons']=[{'number': ep_obj.season,'episodes': [] }] + data['shows'][0]['seasons'] = [{'number': ep_obj.season, 'episodes': []}] for relEp_Obj in [ep_obj] + ep_obj.relatedEps: data['shows'][0]['seasons'][0]['episodes'].append({'number': relEp_Obj.episode}) @@ -89,7 +91,7 @@ class TraktNotifier: except (traktException, traktAuthException, traktServerBusy) as e: logger.log(u"Could not connect to Trakt service: %s" % ex(e), logger.WARNING) - def update_watchlist (self, show_obj = None, s = None, e = None, data_show = None, data_episode = None, update = "add"): + def update_watchlist(self, show_obj=None, s=None, e=None, data_show=None, data_episode=None, update="add"): """ Sends a request to trakt indicating that the given episode is part of our library. @@ -97,8 +99,8 @@ class TraktNotifier: show_obj: The TVShow object to add to trakt s: season number e: episode number - data_show: structured object of shows traktv type - data_episode: structured object of episodes traktv type + data_show: structured object of shows trakt type + data_episode: structured object of episodes trakt type update: type o action add or remove """ @@ -119,7 +121,7 @@ class TraktNotifier: 'ids': {}, } ] - } + } if trakt_id == 'tvdb_id': data['shows'][0]['ids']['tvdb'] = show_obj.indexerid @@ -135,31 +137,31 @@ class TraktNotifier: data['shows'][0].update(data_episode) elif s is not None: - # traktv URL parameters + # trakt URL parameters season = { 'season': [ { 'number': s, } ] - } + } if e is not None: - # traktv URL parameters + # trakt URL parameters episode = { 'episodes': [ { 'number': e } ] - } + } season['season'][0].update(episode) data['shows'][0].update(season) trakt_url = "sync/watchlist" - if update=="remove": + if update == "remove": trakt_url += "/remove" trakt_api.traktRequest(trakt_url, data, method='POST') @@ -225,7 +227,7 @@ class TraktNotifier: trakt_lists = trakt_api.traktRequest("users/" + username + "/lists") found = False for trakt_list in trakt_lists: - if (trakt_list['ids']['slug'] == blacklist_name): + if trakt_list['ids']['slug'] == blacklist_name: return "Test notice sent successfully to Trakt" if not found: return "Trakt blacklist doesn't exists" diff --git a/sickbeard/notifiers/tweet.py b/sickbeard/notifiers/tweet.py index de7aabbdc2d99c7eed5e9659b881540a3a85d37c..99f6554c098cbbe06431197eb0d2870b09bef144 100644 --- a/sickbeard/notifiers/tweet.py +++ b/sickbeard/notifiers/tweet.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Nic Wolfe <nic@wolfeden.ca> # URL: http://code.google.com/p/sickbeard/ # @@ -31,7 +33,7 @@ import oauth2 as oauth import pythontwitter as twitter -class TwitterNotifier: +class TwitterNotifier(object): consumer_key = "vHHtcB6WzpWDG6KYlBMr8g" consumer_secret = "zMqq5CB3f8cWKiRO2KzWPTlBanYmV0VYxSXZ0Pxds0E" @@ -52,10 +54,10 @@ class TwitterNotifier: if sickbeard.TWITTER_NOTIFY_ONSUBTITLEDOWNLOAD: self._notifyTwitter(common.notifyStrings[common.NOTIFY_SUBTITLE_DOWNLOAD] + ' ' + ep_name + ": " + lang) - def notify_git_update(self, new_version = "??"): + def notify_git_update(self, new_version="??"): if sickbeard.USE_TWITTER: - update_text=common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT] - title=common.notifyStrings[common.NOTIFY_GIT_UPDATE] + update_text = common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT] + title = common.notifyStrings[common.NOTIFY_GIT_UPDATE] self._notifyTwitter(title + " - " + update_text + new_version) def test_notify(self): @@ -82,11 +84,11 @@ class TwitterNotifier: return self.AUTHORIZATION_URL + "?oauth_token=" + request_token['oauth_token'] def _get_credentials(self, key): - request_token = {} - - request_token['oauth_token'] = sickbeard.TWITTER_USERNAME - request_token['oauth_token_secret'] = sickbeard.TWITTER_PASSWORD - request_token['oauth_callback_confirmed'] = 'true' + request_token = { + 'oauth_token': sickbeard.TWITTER_USERNAME, + 'oauth_token_secret': sickbeard.TWITTER_PASSWORD, + 'oauth_callback_confirmed': 'true' + } token = oauth.Token(request_token['oauth_token'], request_token['oauth_token_secret']) token.set_verifier(key) @@ -115,7 +117,6 @@ class TwitterNotifier: sickbeard.TWITTER_PASSWORD = access_token['oauth_token_secret'] return True - def _send_tweet(self, message=None): username = self.consumer_key diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py index e66f7c4ec6e248f3451263001b886d4a31f40492..598f28590a22e43e1f26ddf00e2eb46909a7d97d 100644 --- a/sickbeard/postProcessor.py +++ b/sickbeard/postProcessor.py @@ -921,8 +921,6 @@ class PostProcessor(object): if self.is_proper: self._log( u"File exists and new file is smaller, new file is a proper/repack, marking it safe to replace") - return True - else: self._log(u"File exists and new file is smaller, marking it unsafe to replace") return False @@ -984,6 +982,10 @@ class PostProcessor(object): if self.release_name: self._log("Found release name " + self.release_name, logger.DEBUG) cur_ep.release_name = self.release_name + elif self.file_name: + # If we can't get the release name we expect, save the original release name instead + self._log("Using original release name " + self.file_name, logger.DEBUG) + cur_ep.release_name = self.file_name else: cur_ep.release_name = "" diff --git a/sickbeard/providers/__init__.py b/sickbeard/providers/__init__.py index 4c1ef35f20de77103780ed12b28f30181129b652..d863cb052e839bd47f648cc5e858ab5cfa677b8b 100644 --- a/sickbeard/providers/__init__.py +++ b/sickbeard/providers/__init__.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Nic Wolfe <nic@wolfeden.ca> # URL: http://code.google.com/p/sickbeard/ # @@ -16,6 +18,11 @@ # You should have received a copy of the GNU General Public License # along with SickRage. If not, see <http://www.gnu.org/licenses/>. +from os import sys +from random import shuffle + +import sickbeard +from sickbeard import logger from sickbeard.providers import btn, newznab, womble, thepiratebay, torrentleech, kat, iptorrents, torrentz, \ omgwtfnzbs, scc, hdtorrents, torrentday, hdbits, hounddawgs, nextgen, speedcd, nyaatorrents, animenzb, bluetigers, cpasbien, fnt, xthor, torrentbytes, \ freshontv, titansoftv, libertalia, morethantv, bitsoup, t411, tokyotoshokan, shazbat, rarbg, alpharatio, tntvillage, binsearch, torrentproject, extratorrent, \ @@ -67,13 +74,8 @@ __all__ = ['womble', 'gftracker', 'hdspace', 'newpct' -] + ] -import sickbeard - -from sickbeard import logger -from os import sys -from random import shuffle def sortedProviderList(randomize=False): initialList = sickbeard.providerList + sickbeard.newznabProviderList + sickbeard.torrentRssProviderList @@ -233,6 +235,7 @@ def getDefaultNewznabProviders(): 'NZBs.org|https://nzbs.org/||5030,5040|0|eponly|0|0|0!!!' + \ 'Usenet-Crawler|https://www.usenet-crawler.com/||5030,5040|0|eponly|0|0|0' + def getProviderModule(name): name = name.lower() prefix = "sickbeard.providers." diff --git a/sickbeard/providers/alpharatio.py b/sickbeard/providers/alpharatio.py index 300dccdb984ec39438464a121c53a70487b0fa03..d2b096faeaf39bf4d6f50670703fe57d38e57467 100644 --- a/sickbeard/providers/alpharatio.py +++ b/sickbeard/providers/alpharatio.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Bill Nasty # URL: https://github.com/SickRage/SickRage # @@ -47,7 +49,7 @@ class AlphaRatioProvider(generic.TorrentProvider): self.url = self.urls['base_url'] - self.catagories = "&filter_cat[1]=1&filter_cat[2]=1&filter_cat[3]=1&filter_cat[4]=1&filter_cat[5]=1" + self.categories = "&filter_cat[1]=1&filter_cat[2]=1&filter_cat[3]=1&filter_cat[4]=1&filter_cat[5]=1" self.proper_strings = ['PROPER', 'REPACK'] @@ -86,8 +88,8 @@ class AlphaRatioProvider(generic.TorrentProvider): if mode is not 'RSS': logger.log(u"Search string: %s " % search_string, logger.DEBUG) - searchURL = self.urls['search'] % (search_string, self.catagories) - logger.log(u"Search URL: %s" % searchURL, logger.DEBUG) + searchURL = self.urls['search'] % (search_string, self.categories) + logger.log(u"Search URL: %s" % searchURL, logger.DEBUG) data = self.getURL(searchURL) if not data: @@ -146,6 +148,7 @@ class AlphaRatioProvider(generic.TorrentProvider): def seedRatio(self): return self.ratio + class AlphaRatioCache(tvcache.TVCache): def __init__(self, provider_obj): diff --git a/sickbeard/providers/animenzb.py b/sickbeard/providers/animenzb.py index ae122eeb9844d530e8c1565ebb797abd4fb9a8ce..f06300540ef867677d43a1db47833a792efbe351 100644 --- a/sickbeard/providers/animenzb.py +++ b/sickbeard/providers/animenzb.py @@ -1,3 +1,5 @@ +# coding=utf-8 + # Author: Nic Wolfe <nic@wolfeden.ca> # URL: http://code.google.com/p/sickbeard/ # @@ -66,7 +68,7 @@ class animenzb(generic.NZBProvider): } searchURL = self.url + "rss?" + urllib.urlencode(params) - logger.log(u"Search URL: %s" % searchURL, logger.DEBUG) + logger.log(u"Search URL: %s" % searchURL, logger.DEBUG) results = [] for curItem in self.cache.getRSSFeed(searchURL)['entries'] or []: (title, url) = self._get_title_and_url(curItem) diff --git a/sickbeard/providers/torrentz.py b/sickbeard/providers/torrentz.py index 20c3ef711aa431a314c179f661f1d5c87dfaf926..bc93864ec303f17aafd2a6421f2c3c83da408822 100644 --- a/sickbeard/providers/torrentz.py +++ b/sickbeard/providers/torrentz.py @@ -96,7 +96,7 @@ class TORRENTZProvider(generic.TorrentProvider): entries = entries if isinstance(entries, list) else [entries] for item in entries: - if 'tv' not in item.get('category', ''): + if item.get('category', None) and 'tv' not in item.get('category', ''): continue title = item.get('title', '').rsplit(' ', 1)[0].replace(' ', '.') diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 1a54e45b8d049222076449d181ab68e3a4fbecc0..9388ec6ad8adc09cba591844e0517f8a17c3896a 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -2544,10 +2544,10 @@ class TVEpisode(object): + " to show air date " + time.strftime("%b %d,%Y (%H:%M)", airdatetime)) else: logger.log(str(self.show.indexerid) + u": Unable to modify date of " + os.path.basename(self.location) - + " to show air date " + time.strftime("%b %d,%Y (%H:%M)", airdatetime), logger.ERROR) - except Exception: + + " to show air date " + time.strftime("%b %d,%Y (%H:%M)", airdatetime), logger.WARNING) + except Exception as e: logger.log(str(self.show.indexerid) + u": Failed to modify date of '" + os.path.basename(self.location) - + "' to show air date " + time.strftime("%b %d,%Y (%H:%M)", airdatetime), logger.ERROR) + + "' to show air date " + time.strftime("%b %d,%Y (%H:%M)", airdatetime) + ". Error: %s" % ex(e), logger.WARNING) def __getstate__(self): d = dict(self.__dict__)