Browse Source

Change anime "Available groups" to display "No groups listed..." when API is fine with no results instead of blank.

Change improve clarity of anime group lists by using terms Allow list and Block list.
tags/release_0.25.1
JackDandy 5 years ago
parent
commit
dec65748db
  1. 2
      CHANGES.md
  2. 79
      gui/slick/css/style.css
  3. 2
      gui/slick/interfaces/default/config_general.tmpl
  4. 8
      gui/slick/interfaces/default/displayShow.tmpl
  5. 4
      gui/slick/interfaces/default/editShow.tmpl
  6. 2
      gui/slick/interfaces/default/home_newShow.tmpl
  7. 2
      gui/slick/interfaces/default/inc_addShowOptions.tmpl
  8. 68
      gui/slick/interfaces/default/inc_anigrouplists.tmpl
  9. 68
      gui/slick/interfaces/default/inc_blackwhitelist.tmpl
  10. 10
      gui/slick/js/anigrouplists.js
  11. 12
      gui/slick/js/editShow.js
  12. 14
      gui/slick/js/newShow.js
  13. 54
      sickbeard/anime.py
  14. 60
      sickbeard/databases/mainDB.py
  15. 3
      sickbeard/db.py
  16. 4
      sickbeard/providers/horriblesubs.py
  17. 2
      sickbeard/search.py
  18. 20
      sickbeard/show_name_helpers.py
  19. 42
      sickbeard/show_queue.py
  20. 14
      sickbeard/tv.py
  21. 54
      sickbeard/webserve.py
  22. 2
      tests/migration_tests.py

2
CHANGES.md

@ -45,6 +45,8 @@
* Add overall failure monitoring to History/Connect fails (renamed from "Provider fails") * Add overall failure monitoring to History/Connect fails (renamed from "Provider fails")
* Change log exception during updateCache in newznab * Change log exception during updateCache in newznab
* Change make Py3.9 preparations * Change make Py3.9 preparations
* Change anime "Available groups" to display "No groups listed..." when API is fine with no results instead of blank
* Change improve clarity of anime group lists by using terms Allow list and Block list
[develop changelog] [develop changelog]

79
gui/slick/css/style.css

@ -1317,16 +1317,16 @@ div.formpaginate{
font-weight:900 font-weight:900
} }
#addShowForm #blackwhitelist{ #addShowForm #anigrouplists{
padding:0 0 0 15px padding:0 0 0 15px
} }
#edit-show #blackwhitelist, #edit-show #anigrouplists,
#edit-show #blackwhitelist h4, #edit-show #anigrouplists h4,
#edit-show #blackwhitelist p, #edit-show #anigrouplists p,
#addShowForm #blackwhitelist, #addShowForm #anigrouplists,
#addShowForm #blackwhitelist h4, #addShowForm #anigrouplists h4,
#addShowForm #blackwhitelist p{ #addShowForm #anigrouplists p{
font-size:13px font-size:13px
} }
@ -3042,21 +3042,21 @@ select .selected:before{
border:1px transparent border:1px transparent
} }
#addShowForm #add-white, #addShowForm #add-allow,
#addShowForm #add-black{ #addShowForm #add-block{
margin:0 0 10px 30px !important margin:0 0 10px 30px !important
} }
#addShowForm #remove-white, #addShowForm #remove-allow,
#addShowForm #remove-black{ #addShowForm #remove-block{
margin:0 0 0 30px !important margin:0 0 0 30px !important
} }
#edit-show #add-white, #edit-show #add-allow,
#edit-show #add-black{ #edit-show #add-block{
margin:0 0 10px !important margin:0 0 10px !important
} }
#edit-show #remove-white, #edit-show #remove-allow,
#edit-show #remove-black{ #edit-show #remove-block{
margin:0 !important margin:0 !important
} }
@ -3636,7 +3636,7 @@ option.flag{
} }
/* Anime section for editShow */ /* Anime section for editShow */
.bwlWrapper{ .anigrouplists-wrapper{
height:auto; height:auto;
margin:0 auto margin:0 auto
} }
@ -3658,62 +3658,69 @@ option.flag{
width:95% width:95%
} }
div.blackwhitelist h4{ div.anigrouplists h4{
margin-top:0 margin-top:0
} }
div.blackwhitelist{ #addShowForm .anigrouplists.pool h4{
margin-right:20px !important
}
div.anigrouplists{
text-align:center text-align:center
} }
div.blackwhitelist.white input, div.anigrouplists.allow input,
div.blackwhitelist.black input, div.anigrouplists.block input,
div.blackwhitelist.pool input{ div.anigrouplists.pool input{
margin:5px 0 !important margin:5px 0 !important
} }
div.blackwhitelist select{ div.anigrouplists select{
margin:0 !important margin:0 !important
} }
div.blackwhitelist .inuse{ div.anigrouplists .inuse{
margin-right:5px; margin-right:5px;
width:243px; width:243px;
float:left float:left
} }
div.blackwhitelist.white, div.anigrouplists.allow,
div.blackwhitelist.black{ div.anigrouplists.block{
width:243px width:243px
} }
div.blackwhitelist.white select, div.anigrouplists.allow select,
div.blackwhitelist.black select{ div.anigrouplists.block select{
margin:0; margin:0;
width:215px width:215px
/* clear:both*/ /* clear:both*/
} }
div.blackwhitelist.white select, div.anigrouplists.allow select,
div.blackwhitelist.black select{ div.anigrouplists.block select{
height:110px height:110px
} }
#edit-show div.blackwhitelist.pool{ #edit-show div.anigrouplists.pool{
width:330px; width:330px;
height:265px; height:265px;
margin-left:248px; margin-left:248px;
float:none float:none
} }
#edit-show div.blackwhitelist.pool select, #edit-show div.anigrouplists.pool select,
div.blackwhitelist.pool, div.anigrouplists.pool,
div.blackwhitelist.pool select{ div.anigrouplists.pool select{
width:330px; width:330px;
height:265px; height:265px;
float:right float:right
} }
#addShowForm #pool{
width:310px;
margin-right:20px !important
}
div.blackwhitelist span{ div.anigrouplists span{
text-align:center text-align:center
} }
div#blackwhitelist, div#anigrouplists,
div.blackwhitelist.manual{ div.anigrouplists.manual{
margin:7px 0 margin:7px 0
} }

2
gui/slick/interfaces/default/config_general.tmpl

@ -632,7 +632,7 @@
<span class="component-desc"> <span class="component-desc">
<input type="text" name="allowed_hosts" id="allowed-hosts" value="$sg_str('ALLOWED_HOSTS')" class="form-control input-sm input300"> <input type="text" name="allowed_hosts" id="allowed-hosts" value="$sg_str('ALLOWED_HOSTS')" class="form-control input-sm input300">
<p>blank for insecure allow all</p> <p>blank for insecure allow all</p>
<div class="clear-left"><p>whitelist names that browse the interface (e.g. $request_host, my_hostname)</p></div> <div class="clear-left"><p>allowed names that browse the interface (e.g. $request_host, my_hostname)</p></div>
</span> </span>
</label> </label>
</div> </div>

8
gui/slick/interfaces/default/displayShow.tmpl

@ -380,11 +380,11 @@
#if int($show_obj.is_anime) #if int($show_obj.is_anime)
<span class="label">Anime</span> <span class="label">Anime</span>
#end if #end if
#if $bwl and $bwl.whitelist #if $anigroups and $anigroups.allowlist
<span class="label addQTip" title="#echo ', '.join($bwl.whitelist).replace(',', '<br />')#">Wanted group$maybe_plural(len($bwl.whitelist))</span> <span class="label addQTip" title="#echo ', '.join($anigroups.allowlist).replace(',', '<br />')#">Wanted group$maybe_plural(len($anigroups.allowlist))</span>
#end if #end if
#if $bwl and $bwl.blacklist #if $anigroups and $anigroups.blocklist
<span class="label addQTip" title="#echo ', '.join($bwl.blacklist).replace(',', '<br />')#">Unwanted group$maybe_plural(len($bwl.blacklist))</span> <span class="label addQTip" title="#echo ', '.join($anigroups.blocklist).replace(',', '<br />')#">Unwanted group$maybe_plural(len($anigroups.blocklist))</span>
#end if #end if
</div> </div>
</div> </div>

4
gui/slick/interfaces/default/editShow.tmpl

@ -275,8 +275,8 @@
#if $show_obj.is_anime #if $show_obj.is_anime
#import sickbeard.anime #import sickbeard.anime
#include $os.path.join($sg_str('PROG_DIR'), 'gui/slick/interfaces/default/inc_blackwhitelist.tmpl') #include $os.path.join($sg_str('PROG_DIR'), 'gui/slick/interfaces/default/inc_anigrouplists.tmpl')
<script type="text/javascript" src="$sbRoot/js/blackwhite.js?v=$sbPID"></script> <script type="text/javascript" src="$sbRoot/js/anigrouplists.js?v=$sbPID"></script>
#end if #end if
</div><!-- /component-group2 //--> </div><!-- /component-group2 //-->

2
gui/slick/interfaces/default/home_newShow.tmpl

@ -153,7 +153,7 @@
</div> </div>
<script type="text/javascript" src="$sbRoot/js/rootDirs.js?v=$sbPID"></script> <script type="text/javascript" src="$sbRoot/js/rootDirs.js?v=$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/blackwhite.js?v=$sbPID"></script> <script type="text/javascript" src="$sbRoot/js/anigrouplists.js?v=$sbPID"></script>
</div> </div>

2
gui/slick/interfaces/default/inc_addShowOptions.tmpl

@ -135,7 +135,7 @@
#if $enable_anime_options #if $enable_anime_options
#import sickbeard.anime #import sickbeard.anime
#include $os.path.join($sg_str('PROG_DIR'), 'gui/slick/interfaces/default/inc_blackwhitelist.tmpl') #include $os.path.join($sg_str('PROG_DIR'), 'gui/slick/interfaces/default/inc_anigrouplists.tmpl')
#else #else
<input type="hidden" name="anime" id="anime" value="0" /> <input type="hidden" name="anime" id="anime" value="0" />
#end if #end if

68
gui/slick/interfaces/default/inc_anigrouplists.tmpl

@ -0,0 +1,68 @@
<div class="field-pair alt" id="anigrouplists">
<input type="hidden" name="allowlist" id="allowlist">
<input type="hidden" name="blocklist" id="blocklist">
<span class="component-title">Fansub groups</span>
<span class="component-desc">
<div class="anigrouplists-wrapper">
<div class="anigrouplists all">
<div class="anigrouplists anidb">
<div class="inuse" style="padding:0">
<div class="anigrouplists allow" style="margin-bottom:10px">
<h4 style="margin:0 41px 6px 0">Allow list<br /><span class="grey-text">Only snatch releases by group(s)</span></h4>
<div style="width:243px; height:110px">
<select style="width:202px" class="pull-left" id="allow" multiple="multiple" size="12">
#for $keyword in sorted($allowlist, key=lambda x: x.lower()):
<option value="$keyword">$keyword</option>
#end for
</select>
<div style="position:relative; width:36px; height:64px; margin: -32px 0 0; top: 50%;" class="pull-right">
<input id="add-allow" class="btn" value="<<" type="button">
<input id="remove-allow" class="btn clear:right" value=">>" type="button">
</div>
</div>
</div>
<div class="anigrouplists block" style="position:relative; bottom: -1px">
<h4 style="margin:0 41px 6px 0">Block list<br /><span class="grey-text">Ignore releases by group(s)</span></h4>
<div style="width:243px; height:110px">
<select style="width:202px" class="pull-left" id="block" multiple="multiple" size="12">
#for $keyword in sorted($blocklist, key=lambda x: x.lower()):
<option value="$keyword">$keyword</option>
#end for
</select>
<div style="position:relative; width:36px; height:64px; margin: -32px 0 0; top: 50%;" class="pull-right">
<input id="add-block" class="btn" value="<<" type="button">
<input id="remove-block" class="btn clear:right" value=">>" type="button">
</div>
</div>
</div>
</div>
<div class="anigrouplists pool">
<h4 style="margin:0 0 6px 0">Available groups<br /><span class="grey-text">Name (Rating) Number of subbed episodes</span></h4>
<select id="pool" multiple="multiple" size="12">
#for $group in sorted($groups, key=lambda x: x['name'].lower())
#if $group['name'] not in $allowlist and $group['name'] not in $blocklist:
<option value="$group['name']">$group['name'] #if len($group['rating'])# ($group['rating'])#end if# $group['range']</option>
#end if
#end for
</select>
</div>
</div>
<div style="clear:both">&nbsp;</div>
<div class="anigrouplists manual">
<div class="pull-left">
<input type="text" id="addToPoolText" class="form-control form-control-inline input-sm input200" style="width:202px">
<input class="btn btn-inline" type="button" value="Add to Allow list" id="new-allow">
<input style="margin-right:0" class="btn btn-inline" type="button" value="Add to Block list" id="new-block">
</div>
<span class="pull-left">add a custom item to either the allow or block list</span>
<div style="clear:both">&nbsp;</div>
</div>
</div>
</div>
</span>
</div><!-- /anigrouplists -->

68
gui/slick/interfaces/default/inc_blackwhitelist.tmpl

@ -1,68 +0,0 @@
<div class="field-pair alt" id="blackwhitelist">
<input type="hidden" name="whitelist" id="whitelist">
<input type="hidden" name="blacklist" id="blacklist">
<span class="component-title">Fansub groups</span>
<span class="component-desc">
<div class="bwlWrapper">
<div class="blackwhitelist all">
<div class="blackwhitelist anidb">
<div class="inuse" style="padding:0">
<div class="blackwhitelist white" style="margin-bottom:10px">
<h4 style="margin:0 41px 6px 0">Whitelist<br /><span class="grey-text">Only snatch releases by group(s)</span></h4>
<div style="width:243px; height:110px">
<select style="width:202px" class="pull-left" id="white" multiple="multiple" size="12">
#for $keyword in sorted($whitelist, key=lambda x: x.lower()):
<option value="$keyword">$keyword</option>
#end for
</select>
<div style="position:relative; width:36px; height:64px; margin: -32px 0 0; top: 50%;" class="pull-right">
<input id="add-white" class="btn" value="<<" type="button">
<input id="remove-white" class="btn clear:right" value=">>" type="button">
</div>
</div>
</div>
<div class="blackwhitelist black" style="position:relative; bottom: -1px">
<h4 style="margin:0 41px 6px 0">Blacklist<br /><span class="grey-text">Ignore releases by group(s)</span></h4>
<div style="width:243px; height:110px">
<select style="width:202px" class="pull-left" id="black" multiple="multiple" size="12">
#for $keyword in sorted($blacklist, key=lambda x: x.lower()):
<option value="$keyword">$keyword</option>
#end for
</select>
<div style="position:relative; width:36px; height:64px; margin: -32px 0 0; top: 50%;" class="pull-right">
<input id="add-black" class="btn" value="<<" type="button">
<input id="remove-black" class="btn clear:right" value=">>" type="button">
</div>
</div>
</div>
</div>
<div class="blackwhitelist pool">
<h4 style="margin:0 0 6px 0">Available groups<br /><span class="grey-text">Name (Rating) Number of subbed episodes</span></h4>
<select id="pool" multiple="multiple" size="12">
#for $group in sorted($groups, key=lambda x: x['name'].lower())
#if $group['name'] not in $whitelist and $group['name'] not in $blacklist:
<option value="$group['name']">$group['name'] ($group['rating']) $group['range']</option>
#end if
#end for
</select>
</div>
</div>
<div style="clear:both">&nbsp;</div>
<div class="blackwhitelist manual">
<div class="pull-left">
<input type="text" id="addToPoolText" class="form-control form-control-inline input-sm input200" style="width:202px">
<input class="btn btn-inline" type="button" value="Add to Whitelist" id="new-white">
<input style="margin-right:0" class="btn btn-inline" type="button" value="Add to Blacklist" id="new-black">
</div>
<span class="pull-left">add a custom item to either the whitelist or blacklist</span>
<div style="clear:both">&nbsp;</div>
</div>
</div>
</div>
</span>
</div><!-- /blackwhitelist -->

10
gui/slick/js/blackwhite.js → gui/slick/js/anigrouplists.js

@ -1,5 +1,5 @@
function generate_bwlist() { function generateAniGroupList() {
$.each(['white', 'black'], function(i, list) { $.each(['allow', 'block'], function(i, list) {
var group_list = []; var group_list = [];
$('#' + list + ' option').each(function(i, option) { $('#' + list + ' option').each(function(i, option) {
@ -10,15 +10,15 @@ function generate_bwlist() {
}); });
} }
$('#add-white, #add-black').click(function() { $('#add-allow, #add-block').click(function() {
!$('#pool option:selected').remove().appendTo('#' + $(this).attr('id').replace(/add[-]/i, '')); !$('#pool option:selected').remove().appendTo('#' + $(this).attr('id').replace(/add[-]/i, ''));
}); });
$('#remove-white, #remove-black').click(function() { $('#remove-allow, #remove-block').click(function() {
!$('#' + $(this).attr('id').replace(/remove[-]/i, '') + ' option:selected').remove().appendTo('#pool'); !$('#' + $(this).attr('id').replace(/remove[-]/i, '') + ' option:selected').remove().appendTo('#pool');
}); });
$('#new-white, #new-black').click(function() { $('#new-allow, #new-block').click(function() {
var group = $('#addToPoolText').val(); var group = $('#addToPoolText').val();
if ('' != group) { if ('' != group) {
var option = $('<option>'); var option = $('<option>');

12
gui/slick/js/editShow.js

@ -2,7 +2,7 @@
/** @namespace config.showLang */ /** @namespace config.showLang */
/** @namespace config.showIsAnime */ /** @namespace config.showIsAnime */
/** @namespace config.expandIds */ /** @namespace config.expandIds */
/*globals $, config, sbRoot, generate_bwlist*/ /*globals $, config, sbRoot, generateAniGroupList*/
$(document).ready(function () { $(document).ready(function () {
@ -52,7 +52,7 @@ $(document).ready(function () {
$('#submit').on('click', function () { $('#submit').on('click', function () {
$('#exceptions_list').val(getExceptions()); $('#exceptions_list').val(getExceptions());
if (config.showIsAnime) if (config.showIsAnime)
generate_bwlist(); generateAniGroupList();
}); });
$('#addSceneName').on('click', function () { $('#addSceneName').on('click', function () {
@ -101,10 +101,10 @@ $(document).ready(function () {
function isAnime() { function isAnime() {
uncheck(elABD); uncheck(elSports); uncheck(elABD); uncheck(elSports);
if (config.showIsAnime) { $('#blackwhitelist').fadeIn('fast', 'linear'); } return !0; } if (config.showIsAnime) { $('#anigrouplists').fadeIn('fast', 'linear'); } return !0; }
function isScene() { uncheck(elABD); uncheck(elSports); } function isScene() { uncheck(elABD); uncheck(elSports); }
function isABD() { uncheck(elAnime); uncheck(elScene); $('#blackwhitelist, #anime-options').fadeOut('fast', 'linear'); } function isABD() { uncheck(elAnime); uncheck(elScene); $('#anigrouplists, #anime-options').fadeOut('fast', 'linear'); }
function isSports() { uncheck(elAnime); uncheck(elScene); $('#blackwhitelist, #anime-options').fadeOut('fast', 'linear'); } function isSports() { uncheck(elAnime); uncheck(elScene); $('#anigrouplists, #anime-options').fadeOut('fast', 'linear'); }
if (checked(elAnime)) { isAnime(); } if (checked(elAnime)) { isAnime(); }
if (checked(elScene)) { isScene(); } if (checked(elScene)) { isScene(); }
@ -115,7 +115,7 @@ $(document).ready(function () {
if (checked(elAnime)) if (checked(elAnime))
isAnime() && !config.showIsAnime && $('#anime-options').fadeIn('fast', 'linear'); isAnime() && !config.showIsAnime && $('#anime-options').fadeIn('fast', 'linear');
else else
$('#blackwhitelist, #anime-options').fadeOut('fast', 'linear'); $('#anigrouplists, #anime-options').fadeOut('fast', 'linear');
}); });
elIdMap.on('click', function() { elIdMap.on('click', function() {
var elMapOptions = $('#idmapping-options'), anim = {fast: 'linear'}; var elMapOptions = $('#idmapping-options'), anim = {fast: 'linear'};

14
gui/slick/js/newShow.js

@ -282,7 +282,7 @@ $(document).ready(function () {
alert('You must choose a show to continue'); alert('You must choose a show to continue');
return !1; return !1;
} }
generate_bwlist(); generateAniGroupList();
} }
$('#addShowForm').submit(); $('#addShowForm').submit();
}); });
@ -352,7 +352,7 @@ $(document).ready(function () {
else if (elInput.length && elInput.val().length) { else if (elInput.length && elInput.val().length) {
showName = $('#provided-show-name').val(); showName = $('#provided-show-name').val();
} }
update_bwlist(showName); updateAniGrouplist(showName);
var sample_text = '<p>Adding show <span class="show-name">' + cleanseText(showName, !0) + '</span>' var sample_text = '<p>Adding show <span class="show-name">' + cleanseText(showName, !0) + '</span>'
+ ('' == showName ? 'into<br />' : '<br />into') + ('' == showName ? 'into<br />' : '<br />into')
+ ' <span class="show-dest">'; + ' <span class="show-dest">';
@ -455,19 +455,19 @@ $(document).ready(function () {
option.appendTo('#pool'); option.appendTo('#pool');
} }
function update_bwlist (show_name) { function updateAniGrouplist (show_name) {
$('#black, #white, #pool').children().remove(); $('#allow, #block, #pool').children().remove();
if ($('#anime').prop('checked')) { if ($('#anime').prop('checked')) {
$('#blackwhitelist').show(); $('#anigrouplists').show();
if (show_name) { if (show_name) {
$.getJSON(sbRoot + '/home/fetch-releasegroups', {'show_name': cleanseText(show_name, !1)}, function (data) { $.getJSON(sbRoot + '/home/fetch-releasegroups', {'show_name': cleanseText(show_name, !1)}, function (data) {
if ('success' == data['result']) { if ('success' == data['result']) {
var groups = []; var groups = [];
$.each(data.groups, function (i, group) { $.each(data.groups, function (i, group) {
if ('' != group.name) { if ('' != group.name) {
groups.push(group.name + '#<3SG#' + ' (' + group.rating + ') ' + group.range) groups.push(group.name + '#<3SG#' + ('' === group.rating ? '' : ' (' + group.rating + ') ') + group.range)
} }
}); });
if (0 < groups.length) { if (0 < groups.length) {
@ -488,7 +488,7 @@ $(document).ready(function () {
}); });
} }
} else { } else {
$('#blackwhitelist').hide(); $('#anigrouplists').hide();
} }
} }
}); });

54
sickbeard/anime.py

@ -34,30 +34,30 @@ if False:
from typing import Any, AnyStr, List, Optional, Tuple from typing import Any, AnyStr, List, Optional, Tuple
class BlackWhitelistNoShowIDException(Exception): class AllowBlockNoShowIDException(Exception):
""" """
No prodid or tvid was given No prodid or tvid was given
""" """
class BlackAndWhiteList(object): class AniGroupList(object):
blacklist = [] # type: List[AnyStr] allowlist = [] # type: List[AnyStr]
whitelist = [] # type: List[AnyStr] blocklist = [] # type: List[AnyStr]
def __init__(self, tvid, prodid, tvid_prodid=None): def __init__(self, tvid, prodid, tvid_prodid=None):
# type: (int, int, AnyStr) -> None # type: (int, int, AnyStr) -> None
if not tvid or not prodid: if not tvid or not prodid:
raise BlackWhitelistNoShowIDException() raise AllowBlockNoShowIDException()
self.tvid = tvid # type: int self.tvid = tvid # type: int
self.prodid = prodid # type: int self.prodid = prodid # type: int
self.tvid_prodid = tvid_prodid # type: AnyStr self.tvid_prodid = tvid_prodid # type: AnyStr
self.load() self.load()
def load(self): def load(self):
logger.log(u'Building black and white list for %s' % self.tvid_prodid, logger.DEBUG) logger.log(u'Building allow amd block list for %s' % self.tvid_prodid, logger.DEBUG)
self.blacklist = self._load_list('blacklist') self.allowlist = self._load_list('allowlist')
self.whitelist = self._load_list('whitelist') self.blocklist = self._load_list('blocklist')
def _load_list(self, table): def _load_list(self, table):
# type: (AnyStr) -> List[AnyStr] # type: (AnyStr) -> List[AnyStr]
@ -77,32 +77,32 @@ class BlackAndWhiteList(object):
for cur_result in sql_result: for cur_result in sql_result:
groups.append(cur_result['keyword']) groups.append(cur_result['keyword'])
logger.log('BWL: %s loaded keywords from %s: %s' % (self.tvid_prodid, table, groups), logger.log('AniPermsList: %s loaded keywords from %s: %s' % (self.tvid_prodid, table, groups),
logger.DEBUG) logger.DEBUG)
return groups return groups
def set_black_keywords(self, values): def set_allow_keywords(self, values):
# type: (List[AnyStr]) -> None # type: (List[AnyStr]) -> None
""" """
:param values: list of words :param values: list of words
""" """
self._del_all_keywords('blacklist') self._del_all_keywords('allowlist')
self._add_keywords('blacklist', values) self._add_keywords('allowlist', values)
self.blacklist = values self.allowlist = values
logger.log('Blacklist set to: %s' % self.blacklist, logger.DEBUG) logger.log('Allowlist set to: %s' % self.allowlist, logger.DEBUG)
def set_white_keywords(self, values): def set_block_keywords(self, values):
# type: (List[AnyStr]) -> None # type: (List[AnyStr]) -> None
""" """
:param values: list of words :param values: list of words
""" """
self._del_all_keywords('whitelist') self._del_all_keywords('blocklist')
self._add_keywords('whitelist', values) self._add_keywords('blocklist', values)
self.whitelist = values self.blocklist = values
logger.log('Whitelist set to: %s' % self.whitelist, logger.DEBUG) logger.log('Blocklist set to: %s' % self.blocklist, logger.DEBUG)
def _del_all_keywords(self, table): def _del_all_keywords(self, table):
# type: (AnyStr) -> None # type: (AnyStr) -> None
@ -139,20 +139,12 @@ class BlackAndWhiteList(object):
logger.log('Failed to detect release group, invalid result', logger.DEBUG) logger.log('Failed to detect release group, invalid result', logger.DEBUG)
return False return False
if result.release_group.lower() in [x.lower() for x in self.whitelist] or not self.whitelist: allowed = result.release_group.lower() in [x.lower() for x in self.allowlist] or not self.allowlist
white_result = True blocked = result.release_group.lower() in [x.lower() for x in self.blocklist]
else:
white_result = False
if result.release_group.lower() in [x.lower() for x in self.blacklist]: logger.log('Allow list valid: %s. Block list valid: %s' % (allowed, blocked), logger.DEBUG)
black_result = False
else:
black_result = True
logger.log('Whitelist check passed: %s. Blacklist check passed: %s' % (white_result, black_result), return allowed and blocked
logger.DEBUG)
return white_result and black_result
def short_group_names(groups): def short_group_names(groups):

60
sickbeard/databases/mainDB.py

@ -28,7 +28,7 @@ import encodingKludge as ek
from six import iteritems from six import iteritems
MIN_DB_VERSION = 9 # oldest db version we support migrating from MIN_DB_VERSION = 9 # oldest db version we support migrating from
MAX_DB_VERSION = 20012 MAX_DB_VERSION = 20013
TEST_BASE_VERSION = None # the base production db version, only needed for TEST db versions (>=100000) TEST_BASE_VERSION = None # the base production db version, only needed for TEST db versions (>=100000)
@ -174,8 +174,9 @@ class MainSanityCheck(db.DBSanityCheck):
self.connection.action('CREATE UNIQUE INDEX idx_tv_episodes_unique ON ' self.connection.action('CREATE UNIQUE INDEX idx_tv_episodes_unique ON '
'tv_episodes(indexer,showid,season,episode)') 'tv_episodes(indexer,showid,season,episode)')
for t in [('blacklist', 'show_id'), ('history', 'showid'), ('scene_exceptions', 'indexer_id'), allowtbl, blocktbl = (('allow', 'block'), ('white', 'black'))[not self.connection.hasTable('blocklist')]
('whitelist', 'show_id')]: for t in [('%slist' % allowtbl, 'show_id'), ('%slist' % blocktbl, 'show_id'),
('history', 'showid'), ('scene_exceptions', 'indexer_id')]:
if not self.connection.hasIndex('%s' % t[0], 'idx_id_indexer_%s' % t[0]): if not self.connection.hasIndex('%s' % t[0], 'idx_id_indexer_%s' % t[0]):
# noinspection SqlResolve # noinspection SqlResolve
self.connection.action('CREATE INDEX idx_id_indexer_%s ON %s (indexer, %s)' % (t[0], t[0], t[1])) self.connection.action('CREATE INDEX idx_id_indexer_%s ON %s (indexer, %s)' % (t[0], t[0], t[1]))
@ -243,8 +244,9 @@ class InitialSchema(db.SchemaUpgrade):
if not self.hasTable('tv_shows') and not self.hasTable('db_version'): if not self.hasTable('tv_shows') and not self.hasTable('db_version'):
queries = [ queries = [
# blacklist # anime allow and block list
'CREATE TABLE blacklist (show_id INTEGER, range TEXT, keyword TEXT)', 'CREATE TABLE allowlist (show_id INTEGER, range TEXT, keyword TEXT, indexer NUMERIC)',
'CREATE TABLE blocklist (show_id INTEGER, range TEXT, keyword TEXT, indexer NUMERIC)',
# db_version # db_version
'CREATE TABLE db_version (db_version INTEGER)', 'CREATE TABLE db_version (db_version INTEGER)',
'INSERT INTO db_version (db_version) VALUES (20008)', 'INSERT INTO db_version (db_version) VALUES (20008)',
@ -305,8 +307,6 @@ class InitialSchema(db.SchemaUpgrade):
' PRIMARY KEY (indexer_id, indexer))', ' PRIMARY KEY (indexer_id, indexer))',
# webdl_types # webdl_types
'CREATE TABLE webdl_types (dname TEXT NOT NULL, regex TEXT NOT NULL)', 'CREATE TABLE webdl_types (dname TEXT NOT NULL, regex TEXT NOT NULL)',
# whitelist
'CREATE TABLE whitelist (show_id INTEGER, range TEXT, keyword TEXT)',
# xem_refresh # xem_refresh
'CREATE TABLE xem_refresh (indexer TEXT, indexer_id INTEGER PRIMARY KEY, last_refreshed INTEGER)', 'CREATE TABLE xem_refresh (indexer TEXT, indexer_id INTEGER PRIMARY KEY, last_refreshed INTEGER)',
] ]
@ -1089,13 +1089,13 @@ class AddSceneAbsoluteNumbering(db.SchemaUpgrade):
# 34 -> 35 # 34 -> 35
class AddAnimeBlacklistWhitelist(db.SchemaUpgrade): class AddAnimeAllowlistBlocklist(db.SchemaUpgrade):
def execute(self): def execute(self):
db.backup_database('sickbeard.db', self.checkDBVersion()) db.backup_database('sickbeard.db', self.checkDBVersion())
cl = [['CREATE TABLE blacklist (show_id INTEGER, range TEXT, keyword TEXT)'], cl = [['CREATE TABLE allowlist (show_id INTEGER, range TEXT, keyword TEXT, indexer NUMERIC)'],
['CREATE TABLE whitelist (show_id INTEGER, range TEXT, keyword TEXT)']] ['CREATE TABLE blocklist (show_id INTEGER, range TEXT, keyword TEXT, indexer NUMERIC)']]
self.upgrade_log(u'Creating table blacklist whitelist') self.upgrade_log(u'Creating tables for anime allow and block lists')
self.connection.mass_action(cl) self.connection.mass_action(cl)
self.incDBVersion() self.incDBVersion()
@ -1396,9 +1396,10 @@ class ChangeMapIndexer(db.SchemaUpgrade):
except (BaseException, Exception): except (BaseException, Exception):
pass pass
keep_tables = {'scene_exceptions', 'scene_exceptions_refresh', 'info', 'indexer_mapping', 'blacklist', keep_tables = {'allowlist', 'blocklist', 'whitelist', 'blacklist',
'scene_exceptions', 'scene_exceptions_refresh', 'info', 'indexer_mapping',
'db_version', 'history', 'imdb_info', 'lastUpdate', 'scene_numbering', 'tv_episodes', 'tv_shows', 'db_version', 'history', 'imdb_info', 'lastUpdate', 'scene_numbering', 'tv_episodes', 'tv_shows',
'whitelist', 'xem_refresh'} 'xem_refresh'}
current_tables = set(self.listTables()) current_tables = set(self.listTables())
remove_tables = list(current_tables - keep_tables) remove_tables = list(current_tables - keep_tables)
for table in remove_tables: for table in remove_tables:
@ -1504,14 +1505,15 @@ class AddIndexerToTables(db.SchemaUpgrade):
show_ids = {s['prod_id']: s['tv_id'] for s in show_ids = {s['prod_id']: s['tv_id'] for s in
self.connection.select('SELECT indexer AS tv_id, indexer_id AS prod_id FROM tv_shows')} self.connection.select('SELECT indexer AS tv_id, indexer_id AS prod_id FROM tv_shows')}
columns = {'blacklist': 'show_id, range, keyword, indexer', allowtbl, blocktbl = (('allow', 'block'), ('white', 'black'))[not self.connection.hasTable('blocklist')]
columns = {'%slist' % allowtbl: 'show_id, range, keyword, indexer',
'%slist' % blocktbl: 'show_id, range, keyword, indexer',
'history': 'action, date, showid, season, episode, quality, resource, provider, version, indexer', 'history': 'action, date, showid, season, episode, quality, resource, provider, version, indexer',
'scene_exceptions': 'exception_id , indexer_id, show_name, season, custom, indexer', 'scene_exceptions': 'exception_id , indexer_id, show_name, season, custom, indexer'}
'whitelist': 'show_id, range, keyword, indexer'}
# add missing indexer column # add missing indexer column
for t in [('blacklist', 'show_id'), ('history', 'showid'), ('scene_exceptions', 'indexer_id'), for t in [(allowtbl, 'show_id'), (blocktbl, 'show_id'),
('whitelist', 'show_id')]: ('history', 'showid'), ('scene_exceptions', 'indexer_id')]:
if not self.hasColumn(t[0], 'indexer'): if not self.hasColumn(t[0], 'indexer'):
self.upgrade_log(u'Adding TV info support to %s table' % t[0]) self.upgrade_log(u'Adding TV info support to %s table' % t[0])
self.addColumn(t[0], 'indexer') self.addColumn(t[0], 'indexer')
@ -1670,3 +1672,25 @@ class AddShowExludeGlobals(db.SchemaUpgrade):
self.setDBVersion(20012) self.setDBVersion(20012)
return self.checkDBVersion() return self.checkDBVersion()
# 20012 -> 20013
class RenameAllowBlockListTables(db.SchemaUpgrade):
def execute(self):
db.backup_database('sickbeard.db', self.checkDBVersion())
if not self.connection.hasTable('blocklist'):
self.upgrade_log('Renaming allow/block list tables')
for old, new in (('black', 'block'), ('white', 'allow')):
# noinspection SqlResolve
self.connection.mass_action([
['ALTER TABLE %slist RENAME TO tmp_%slist' % (old, new)],
['CREATE TABLE %slist (show_id INTEGER, range TEXT, keyword TEXT, indexer NUMERIC)' % new],
['INSERT INTO %slist(show_id, range, keyword, indexer)'
' SELECT show_id, range, keyword, indexer FROM tmp_%slist' % (new, new)],
['DROP TABLE tmp_%slist' % new]
])
self.setDBVersion(20013)
return self.checkDBVersion()

3
sickbeard/db.py

@ -581,7 +581,7 @@ def MigrationCode(my_db):
31: sickbeard.mainDB.AddAnimeTVShow, 31: sickbeard.mainDB.AddAnimeTVShow,
32: sickbeard.mainDB.AddAbsoluteNumbering, 32: sickbeard.mainDB.AddAbsoluteNumbering,
33: sickbeard.mainDB.AddSceneAbsoluteNumbering, 33: sickbeard.mainDB.AddSceneAbsoluteNumbering,
34: sickbeard.mainDB.AddAnimeBlacklistWhitelist, 34: sickbeard.mainDB.AddAnimeAllowlistBlocklist,
35: sickbeard.mainDB.AddSceneAbsoluteNumbering2, 35: sickbeard.mainDB.AddSceneAbsoluteNumbering2,
36: sickbeard.mainDB.AddXemRefresh, 36: sickbeard.mainDB.AddXemRefresh,
37: sickbeard.mainDB.AddSceneToTvShows, 37: sickbeard.mainDB.AddSceneToTvShows,
@ -619,6 +619,7 @@ def MigrationCode(my_db):
20009: sickbeard.mainDB.AddPrune, 20009: sickbeard.mainDB.AddPrune,
20010: sickbeard.mainDB.AddIndexerToTables, 20010: sickbeard.mainDB.AddIndexerToTables,
20011: sickbeard.mainDB.AddShowExludeGlobals, 20011: sickbeard.mainDB.AddShowExludeGlobals,
20012: sickbeard.mainDB.RenameAllowBlockListTables,
# 20002: sickbeard.mainDB.AddCoolSickGearFeature3, # 20002: sickbeard.mainDB.AddCoolSickGearFeature3,
} }

4
sickbeard/providers/horriblesubs.py

@ -102,11 +102,11 @@ class HorribleSubsProvider(generic.TorrentProvider):
def _season_strings(self, *args, **kwargs): def _season_strings(self, *args, **kwargs):
return [{'Season': show_name_helpers.makeSceneSeasonSearchString( return [{'Season': show_name_helpers.makeSceneSeasonSearchString(
self.show_obj, *args, ignore_wl=True, **kwargs)}] self.show_obj, *args, ignore_allowlist=True, **kwargs)}]
def _episode_strings(self, *args, **kwargs): def _episode_strings(self, *args, **kwargs):
return [{'Episode': show_name_helpers.makeSceneSearchString( return [{'Episode': show_name_helpers.makeSceneSearchString(
self.show_obj, *args, ignore_wl=True, **kwargs)}] self.show_obj, *args, ignore_allowlist=True, **kwargs)}]
def get_data(self, url): def get_data(self, url):
result = None result = None

2
sickbeard/search.py

@ -387,7 +387,7 @@ def is_final_result(result):
if best_qualities and max(best_qualities) > result.quality: if best_qualities and max(best_qualities) > result.quality:
return False return False
# if it does not match the shows black and white list its no good # if it does not match the shows block and allow list its no good
elif show_obj.is_anime and show_obj.release_groups.is_valid(result): elif show_obj.is_anime and show_obj.release_groups.is_valid(result):
return False return False

20
sickbeard/show_name_helpers.py

@ -251,14 +251,14 @@ def get_show_names_all_possible(show_obj, season=-1, scenify=True, spacer='.'):
def makeSceneSeasonSearchString(show_obj, # type: sickbeard.tv.TVShow def makeSceneSeasonSearchString(show_obj, # type: sickbeard.tv.TVShow
ep_obj, # type: sickbeard.tv.TVEpisode ep_obj, # type: sickbeard.tv.TVEpisode
ignore_wl=False, # type: bool ignore_allowlist=False, # type: bool
extra_search_type=None extra_search_type=None
): # type: (...) -> List[AnyStr] ): # type: (...) -> List[AnyStr]
""" """
:param show_obj: show object :param show_obj: show object
:param ep_obj: episode object :param ep_obj: episode object
:param ignore_wl: :param ignore_allowlist:
:param extra_search_type: :param extra_search_type:
:return: list of search strings :return: list of search strings
""" """
@ -321,9 +321,9 @@ def makeSceneSeasonSearchString(show_obj, # type: sickbeard.tv.TVShow
# for providers that don't allow multiple searches in one request we only search for Sxx style stuff # for providers that don't allow multiple searches in one request we only search for Sxx style stuff
else: else:
for cur_season in seasonStrings: for cur_season in seasonStrings:
if not ignore_wl and show_obj.is_anime \ if not ignore_allowlist and show_obj.is_anime \
and None is not show_obj.release_groups and show_obj.release_groups.whitelist: and None is not show_obj.release_groups and show_obj.release_groups.allowlist:
for keyword in show_obj.release_groups.whitelist: for keyword in show_obj.release_groups.allowlist:
to_return.append(keyword + '.' + cur_name + "." + cur_season) to_return.append(keyword + '.' + cur_name + "." + cur_season)
else: else:
@ -334,13 +334,13 @@ def makeSceneSeasonSearchString(show_obj, # type: sickbeard.tv.TVShow
def makeSceneSearchString(show_obj, # type: sickbeard.tv.TVShow def makeSceneSearchString(show_obj, # type: sickbeard.tv.TVShow
ep_obj, # type: sickbeard.tv.TVEpisode ep_obj, # type: sickbeard.tv.TVEpisode
ignore_wl=False # type: bool ignore_allowlist=False # type: bool
): # type: (...) -> List[AnyStr] ): # type: (...) -> List[AnyStr]
""" """
:param show_obj: show object :param show_obj: show object
:param ep_obj: episode object :param ep_obj: episode object
:param ignore_wl: :param ignore_allowlist:
:return: list or search strings :return: list or search strings
""" """
my_db = db.DBConnection() my_db = db.DBConnection()
@ -372,9 +372,9 @@ def makeSceneSearchString(show_obj, # type: sickbeard.tv.TVShow
for cur_show_obj in show_names: for cur_show_obj in show_names:
for cur_ep_string in ep_strings: for cur_ep_string in ep_strings:
if not ignore_wl and ep_obj.show_obj.is_anime and \ if not ignore_allowlist and ep_obj.show_obj.is_anime and \
None is not ep_obj.show_obj.release_groups and ep_obj.show_obj.release_groups.whitelist: None is not ep_obj.show_obj.release_groups and ep_obj.show_obj.release_groups.allowlist:
for keyword in ep_obj.show_obj.release_groups.whitelist: for keyword in ep_obj.show_obj.release_groups.allowlist:
to_return.append(keyword + '.' + cur_show_obj + '.' + cur_ep_string) to_return.append(keyword + '.' + cur_show_obj + '.' + cur_ep_string)
else: else:
to_return.append(cur_show_obj + '.' + cur_ep_string) to_return.append(cur_show_obj + '.' + cur_ep_string)

42
sickbeard/show_queue.py

@ -29,7 +29,7 @@ from exceptions_helper import ex
import sickbeard import sickbeard
from . import logger, ui, db, generic_queue, name_cache from . import logger, ui, db, generic_queue, name_cache
from .anime import BlackAndWhiteList from .anime import AniGroupList
from .common import SKIPPED, WANTED, UNAIRED, Quality, statusStrings from .common import SKIPPED, WANTED, UNAIRED, Quality, statusStrings
from .helpers import should_delete_episode from .helpers import should_delete_episode
from .indexermapper import map_indexers_to_show from .indexermapper import map_indexers_to_show
@ -343,7 +343,7 @@ class ShowQueue(generic_queue.GenericQueue):
return queue_item_obj return queue_item_obj
def addShow(self, tvid, prodid, show_dir, default_status=None, quality=None, flatten_folders=None, def addShow(self, tvid, prodid, show_dir, default_status=None, quality=None, flatten_folders=None,
lang='en', subtitles=None, anime=None, scene=None, paused=None, blacklist=None, whitelist=None, lang='en', subtitles=None, anime=None, scene=None, paused=None, blocklist=None, allowlist=None,
wanted_begin=None, wanted_latest=None, prune=None, tag=None, wanted_begin=None, wanted_latest=None, prune=None, tag=None,
new_show=False, show_name=None, upgrade_once=False): new_show=False, show_name=None, upgrade_once=False):
""" """
@ -370,10 +370,10 @@ class ShowQueue(generic_queue.GenericQueue):
:type scene: int or None :type scene: int or None
:param paused: :param paused:
:type paused: None or int :type paused: None or int
:param blacklist: :param blocklist:
:type blacklist: AnyStr or None :type blocklist: AnyStr or None
:param whitelist: :param allowlist:
:type whitelist: AnyStr or None :type allowlist: AnyStr or None
:param wanted_begin: :param wanted_begin:
:type wanted_begin: int or None :type wanted_begin: int or None
:param wanted_latest: :param wanted_latest:
@ -392,7 +392,7 @@ class ShowQueue(generic_queue.GenericQueue):
:rtype: QueueItemAdd :rtype: QueueItemAdd
""" """
queue_item_obj = QueueItemAdd(tvid, prodid, show_dir, default_status, quality, flatten_folders, lang, queue_item_obj = QueueItemAdd(tvid, prodid, show_dir, default_status, quality, flatten_folders, lang,
subtitles, anime, scene, paused, blacklist, whitelist, subtitles, anime, scene, paused, blocklist, allowlist,
wanted_begin, wanted_latest, prune, tag, wanted_begin, wanted_latest, prune, tag,
new_show=new_show, show_name=show_name, upgrade_once=upgrade_once) new_show=new_show, show_name=show_name, upgrade_once=upgrade_once)
@ -468,7 +468,7 @@ class ShowQueueItem(generic_queue.QueueItem):
class QueueItemAdd(ShowQueueItem): class QueueItemAdd(ShowQueueItem):
def __init__(self, tvid, prodid, show_dir, default_status, quality, flatten_folders, lang, subtitles, anime, def __init__(self, tvid, prodid, show_dir, default_status, quality, flatten_folders, lang, subtitles, anime,
scene, paused, blacklist, whitelist, default_wanted_begin, default_wanted_latest, prune, tag, scene, paused, blocklist, allowlist, default_wanted_begin, default_wanted_latest, prune, tag,
scheduled_update=False, new_show=False, show_name=None, upgrade_once=False): scheduled_update=False, new_show=False, show_name=None, upgrade_once=False):
""" """
@ -494,10 +494,10 @@ class QueueItemAdd(ShowQueueItem):
:type scene: :type scene:
:param paused: :param paused:
:type paused: :type paused:
:param blacklist: :param blocklist:
:type blacklist: :type blocklist:
:param whitelist: :param allowlist:
:type whitelist: :type allowlist:
:param default_wanted_begin: :param default_wanted_begin:
:type default_wanted_begin: :type default_wanted_begin:
:param default_wanted_latest: :param default_wanted_latest:
@ -529,8 +529,8 @@ class QueueItemAdd(ShowQueueItem):
self.anime = anime self.anime = anime
self.scene = scene self.scene = scene
self.paused = paused self.paused = paused
self.blacklist = blacklist self.blocklist = blocklist
self.whitelist = whitelist self.allowlist = allowlist
self.prune = prune self.prune = prune
self.tag = tag self.tag = tag
self.new_show = new_show self.new_show = new_show
@ -706,13 +706,13 @@ class QueueItemAdd(ShowQueueItem):
self.show_obj.tag = self.tag if None is not self.tag else 'Show List' self.show_obj.tag = self.tag if None is not self.tag else 'Show List'
if self.show_obj.anime: if self.show_obj.anime:
self.show_obj.release_groups = BlackAndWhiteList(self.show_obj.tvid, self.show_obj.release_groups = AniGroupList(self.show_obj.tvid,
self.show_obj.prodid, self.show_obj.prodid,
self.show_obj.tvid_prodid) self.show_obj.tvid_prodid)
if self.blacklist: if self.allowlist:
self.show_obj.release_groups.set_black_keywords(self.blacklist) self.show_obj.release_groups.set_allow_keywords(self.allowlist)
if self.whitelist: if self.blocklist:
self.show_obj.release_groups.set_white_keywords(self.whitelist) self.show_obj.release_groups.set_block_keywords(self.blocklist)
# be smartish about this # be smartish about this
if self.show_obj.genre and 'talk show' in self.show_obj.genre.lower(): if self.show_obj.genre and 'talk show' in self.show_obj.genre.lower():

14
sickbeard/tv.py

@ -45,7 +45,7 @@ from exceptions_helper import ex
import sickbeard import sickbeard
from . import db, helpers, history, image_cache, indexermapper, logger, \ from . import db, helpers, history, image_cache, indexermapper, logger, \
name_cache, network_timezones, notifiers, postProcessor, subtitles name_cache, network_timezones, notifiers, postProcessor, subtitles
from .anime import BlackAndWhiteList from .anime import AniGroupList
from .common import Quality, statusStrings, \ from .common import Quality, statusStrings, \
ARCHIVED, DOWNLOADED, FAILED, IGNORED, SNATCHED, SNATCHED_PROPER, SNATCHED_ANY, SKIPPED, UNAIRED, UNKNOWN, WANTED, \ ARCHIVED, DOWNLOADED, FAILED, IGNORED, SNATCHED, SNATCHED_PROPER, SNATCHED_ANY, SKIPPED, UNAIRED, UNKNOWN, WANTED, \
NAMING_DUPLICATE, NAMING_EXTEND, NAMING_LIMITED_EXTEND, NAMING_LIMITED_EXTEND_E_PREFIXED, NAMING_SEPARATED_REPEAT NAMING_DUPLICATE, NAMING_EXTEND, NAMING_LIMITED_EXTEND, NAMING_LIMITED_EXTEND_E_PREFIXED, NAMING_SEPARATED_REPEAT
@ -228,7 +228,7 @@ class TVShow(TVShowBase):
# noinspection added so that None _can_ be excluded from type annotation # noinspection added so that None _can_ be excluded from type annotation
# so that this property evaluates directly to the class on ctrl+hover instead of "multiple implementations" # so that this property evaluates directly to the class on ctrl+hover instead of "multiple implementations"
# noinspection PyTypeChecker # noinspection PyTypeChecker
self.release_groups = None # type: BlackAndWhiteList self.release_groups = None # type: AniGroupList
show_obj = helpers.find_show_by_id(self.sid_int, check_multishow=True) show_obj = helpers.find_show_by_id(self.sid_int, check_multishow=True)
if None is not show_obj: if None is not show_obj:
@ -1219,7 +1219,7 @@ class TVShow(TVShowBase):
self._imdbid = ('', imdbid)[2 < len(imdbid)] self._imdbid = ('', imdbid)[2 < len(imdbid)]
if self._anime: if self._anime:
self.release_groups = BlackAndWhiteList(self.tvid, self.prodid, self.tvid_prodid) self.release_groups = AniGroupList(self.tvid, self.prodid, self.tvid_prodid)
if not self._overview: if not self._overview:
self._overview = sql_result[0]['overview'] self._overview = sql_result[0]['overview']
@ -1505,8 +1505,8 @@ class TVShow(TVShowBase):
["DELETE FROM imdb_info WHERE indexer = ? AND indexer_id = ?", [self.tvid, self.prodid]], ["DELETE FROM imdb_info WHERE indexer = ? AND indexer_id = ?", [self.tvid, self.prodid]],
["DELETE FROM xem_refresh WHERE indexer = ? AND indexer_id = ?", [self.tvid, self.prodid]], ["DELETE FROM xem_refresh WHERE indexer = ? AND indexer_id = ?", [self.tvid, self.prodid]],
["DELETE FROM scene_numbering WHERE indexer = ? AND indexer_id = ?", [self.tvid, self.prodid]], ["DELETE FROM scene_numbering WHERE indexer = ? AND indexer_id = ?", [self.tvid, self.prodid]],
["DELETE FROM whitelist WHERE indexer = ? AND show_id = ?", [self.tvid, self.prodid]], ["DELETE FROM allowlist WHERE indexer = ? AND show_id = ?", [self.tvid, self.prodid]],
["DELETE FROM blacklist WHERE indexer = ? AND show_id = ?", [self.tvid, self.prodid]], ["DELETE FROM blocklist WHERE indexer = ? AND show_id = ?", [self.tvid, self.prodid]],
["DELETE FROM indexer_mapping WHERE indexer = ? AND indexer_id = ?", [self.tvid, self.prodid]], ["DELETE FROM indexer_mapping WHERE indexer = ? AND indexer_id = ?", [self.tvid, self.prodid]],
["DELETE FROM tv_shows_not_found WHERE indexer = ? AND indexer_id = ?", [self.tvid, self.prodid]]] ["DELETE FROM tv_shows_not_found WHERE indexer = ? AND indexer_id = ?", [self.tvid, self.prodid]]]
@ -1713,7 +1713,7 @@ class TVShow(TVShowBase):
[self.tvid, self.prodid, old_tvid, old_prodid]], [self.tvid, self.prodid, old_tvid, old_prodid]],
['UPDATE tv_episodes SET indexer = ?, showid = ?, indexerid = 0 WHERE indexer = ? AND showid = ?', ['UPDATE tv_episodes SET indexer = ?, showid = ?, indexerid = 0 WHERE indexer = ? AND showid = ?',
[self.tvid, self.prodid, old_tvid, old_prodid]], [self.tvid, self.prodid, old_tvid, old_prodid]],
['UPDATE blacklist SET indexer = ?, show_id = ? WHERE indexer = ? AND show_id = ?', ['UPDATE blocklist SET indexer = ?, show_id = ? WHERE indexer = ? AND show_id = ?',
[self.tvid, self.prodid, old_tvid, old_prodid]], [self.tvid, self.prodid, old_tvid, old_prodid]],
['UPDATE history SET indexer = ?, showid = ? WHERE indexer = ? AND showid = ?', ['UPDATE history SET indexer = ?, showid = ? WHERE indexer = ? AND showid = ?',
[self.tvid, self.prodid, old_tvid, old_prodid]], [self.tvid, self.prodid, old_tvid, old_prodid]],
@ -1723,7 +1723,7 @@ class TVShow(TVShowBase):
[self.tvid, self.prodid, old_tvid, old_prodid]], [self.tvid, self.prodid, old_tvid, old_prodid]],
['UPDATE scene_numbering SET indexer = ?, indexer_id = ? WHERE indexer = ? AND indexer_id = ?', ['UPDATE scene_numbering SET indexer = ?, indexer_id = ? WHERE indexer = ? AND indexer_id = ?',
[self.tvid, self.prodid, old_tvid, old_prodid]], [self.tvid, self.prodid, old_tvid, old_prodid]],
['UPDATE whitelist SET indexer = ?, show_id = ? WHERE indexer = ? AND show_id = ?', ['UPDATE allowlist SET indexer = ?, show_id = ? WHERE indexer = ? AND show_id = ?',
[self.tvid, self.prodid, old_tvid, old_prodid]], [self.tvid, self.prodid, old_tvid, old_prodid]],
['UPDATE xem_refresh SET indexer = ?, indexer_id = ? WHERE indexer = ? AND indexer_id = ?', ['UPDATE xem_refresh SET indexer = ?, indexer_id = ? WHERE indexer = ? AND indexer_id = ?',
[self.tvid, self.prodid, old_tvid, old_prodid]], [self.tvid, self.prodid, old_tvid, old_prodid]],

54
sickbeard/webserve.py

@ -48,7 +48,7 @@ import sg_helpers
import sickbeard import sickbeard
from . import classes, clients, config, db, helpers, history, image_cache, logger, naming, \ from . import classes, clients, config, db, helpers, history, image_cache, logger, naming, \
network_timezones, notifiers, nzbget, processTV, sab, scene_exceptions, search_queue, subtitles, ui network_timezones, notifiers, nzbget, processTV, sab, scene_exceptions, search_queue, subtitles, ui
from .anime import BlackAndWhiteList, pull_anidb_groups, short_group_names from .anime import AniGroupList, pull_anidb_groups, short_group_names
from .browser import folders_at_path from .browser import folders_at_path
from .common import ARCHIVED, DOWNLOADED, FAILED, IGNORED, SKIPPED, SNATCHED, SNATCHED_ANY, UNAIRED, UNKNOWN, WANTED, \ from .common import ARCHIVED, DOWNLOADED, FAILED, IGNORED, SKIPPED, SNATCHED, SNATCHED_ANY, UNAIRED, UNKNOWN, WANTED, \
SD, HD720p, HD1080p, UHD2160p, Overview, Quality, qualityPresetStrings, statusStrings SD, HD720p, HD1080p, UHD2160p, Overview, Quality, qualityPresetStrings, statusStrings
@ -2165,9 +2165,9 @@ class Home(MainHandler):
t.prev_title = 'Prev show, %s' % tvshow_names[(cur_sel - 2, last_item - 1)[1 == cur_sel]] t.prev_title = 'Prev show, %s' % tvshow_names[(cur_sel - 2, last_item - 1)[1 == cur_sel]]
t.next_title = 'Next show, %s' % tvshow_names[(cur_sel, 0)[last_item == cur_sel]] t.next_title = 'Next show, %s' % tvshow_names[(cur_sel, 0)[last_item == cur_sel]]
t.bwl = None t.anigroups = None
if show_obj.is_anime: if show_obj.is_anime:
t.bwl = show_obj.release_groups t.anigroups = show_obj.release_groups
t.fanart = [] t.fanart = []
cache_obj = image_cache.ImageCache() cache_obj = image_cache.ImageCache()
@ -2458,7 +2458,7 @@ class Home(MainHandler):
any_qualities=None, best_qualities=None, exceptions_list=None, any_qualities=None, best_qualities=None, exceptions_list=None,
flatten_folders=None, paused=None, direct_call=False, air_by_date=None, sports=None, dvdorder=None, flatten_folders=None, paused=None, direct_call=False, air_by_date=None, sports=None, dvdorder=None,
tvinfo_lang=None, subs=None, upgrade_once=None, rls_ignore_words=None, tvinfo_lang=None, subs=None, upgrade_once=None, rls_ignore_words=None,
rls_require_words=None, anime=None, blacklist=None, whitelist=None, rls_require_words=None, anime=None, allowlist=None, blocklist=None,
scene=None, prune=None, tag=None, quality_preset=None, reset_fanart=None, scene=None, prune=None, tag=None, quality_preset=None, reset_fanart=None,
rls_global_exclude_ignore=None, rls_global_exclude_require=None, **kwargs): rls_global_exclude_ignore=None, rls_global_exclude_require=None, **kwargs):
@ -2503,15 +2503,17 @@ class Home(MainHandler):
if show_obj.is_anime: if show_obj.is_anime:
if not show_obj.release_groups: if not show_obj.release_groups:
show_obj.release_groups = BlackAndWhiteList(show_obj.tvid, show_obj.prodid, show_obj.tvid_prodid) show_obj.release_groups = AniGroupList(show_obj.tvid, show_obj.prodid, show_obj.tvid_prodid)
t.whitelist = show_obj.release_groups.whitelist t.allowlist = show_obj.release_groups.allowlist
t.blacklist = show_obj.release_groups.blacklist t.blocklist = show_obj.release_groups.blocklist
t.groups = pull_anidb_groups(show_obj.name) t.groups = pull_anidb_groups(show_obj.name)
if None is t.groups: if None is t.groups:
t.groups = [dict(name='Did not initialise AniDB. Check debug log if reqd.', rating='', range='')] t.groups = [dict(name='Did not initialise AniDB. Check debug log if reqd.', rating='', range='')]
elif False is t.groups: elif False is t.groups:
t.groups = [dict(name='Fail: AniDB connect. Restart SG else check debug log', rating='', range='')] t.groups = [dict(name='Fail: AniDB connect. Restart SG else check debug log', rating='', range='')]
elif isinstance(t.groups, list) and 0 == len(t.groups):
t.groups = [dict(name='No groups listed in API response', rating='', range='')]
with show_obj.lock: with show_obj.lock:
t.show_obj = show_obj t.show_obj = show_obj
@ -2579,7 +2581,7 @@ class Home(MainHandler):
if type(exceptions_list) != list: if type(exceptions_list) != list:
exceptions_list = [exceptions_list] exceptions_list = [exceptions_list]
# If direct call from mass_edit_update no scene exceptions handling or blackandwhite list handling or tags # If direct call from mass_edit_update no scene exceptions handling or blockandallow list handling or tags
if direct_call: if direct_call:
do_update_exceptions = False do_update_exceptions = False
else: else:
@ -2588,19 +2590,19 @@ class Home(MainHandler):
with show_obj.lock: with show_obj.lock:
if anime: if anime:
if not show_obj.release_groups: if not show_obj.release_groups:
show_obj.release_groups = BlackAndWhiteList( show_obj.release_groups = AniGroupList(
show_obj.tvid, show_obj.prodid, show_obj.tvid_prodid) show_obj.tvid, show_obj.prodid, show_obj.tvid_prodid)
if whitelist: if allowlist:
shortwhitelist = short_group_names(whitelist) shortallowlist = short_group_names(allowlist)
show_obj.release_groups.set_white_keywords(shortwhitelist) show_obj.release_groups.set_allow_keywords(shortallowlist)
else: else:
show_obj.release_groups.set_white_keywords([]) show_obj.release_groups.set_allow_keywords([])
if blacklist: if blocklist:
shortblacklist = short_group_names(blacklist) shortblocklist = short_group_names(blocklist)
show_obj.release_groups.set_black_keywords(shortblacklist) show_obj.release_groups.set_block_keywords(shortblocklist)
else: else:
show_obj.release_groups.set_black_keywords([]) show_obj.release_groups.set_block_keywords([])
errors = [] errors = []
with show_obj.lock: with show_obj.lock:
@ -3244,6 +3246,8 @@ class Home(MainHandler):
result = dict(result='fail', resp='init') result = dict(result='fail', resp='init')
elif False is result: elif False is result:
result = dict(result='fail', resp='connect') result = dict(result='fail', resp='connect')
elif isinstance(result, list) and 0 == len(result):
result = dict(result='success', groups=[dict(name='No groups fetched in API response', rating='', range='')])
else: else:
result = dict(result='success', groups=result) result = dict(result='success', groups=result)
return json.dumps(result) return json.dumps(result)
@ -3751,8 +3755,8 @@ class AddShows(Home):
t.provided_tvid = int(tvid or sickbeard.TVINFO_DEFAULT) t.provided_tvid = int(tvid or sickbeard.TVINFO_DEFAULT)
t.infosrc = sickbeard.TVInfoAPI().search_sources t.infosrc = sickbeard.TVInfoAPI().search_sources
t.meta_lang = sickbeard.ADD_SHOWS_METALANG t.meta_lang = sickbeard.ADD_SHOWS_METALANG
t.whitelist = [] t.allowlist = []
t.blacklist = [] t.blocklist = []
t.groups = [] t.groups = []
t.show_scene_maps = list(*itervalues(sickbeard.scene_exceptions.xem_ids_list)) t.show_scene_maps = list(*itervalues(sickbeard.scene_exceptions.xem_ids_list))
@ -4880,7 +4884,7 @@ class AddShows(Home):
quality_preset=None, any_qualities=None, best_qualities=None, upgrade_once=None, quality_preset=None, any_qualities=None, best_qualities=None, upgrade_once=None,
flatten_folders=None, subs=None, flatten_folders=None, subs=None,
full_show_path=None, other_shows=None, skip_show=None, provided_tvid=None, anime=None, full_show_path=None, other_shows=None, skip_show=None, provided_tvid=None, anime=None,
scene=None, blacklist=None, whitelist=None, wanted_begin=None, wanted_latest=None, scene=None, allowlist=None, blocklist=None, wanted_begin=None, wanted_latest=None,
prune=None, tag=None, return_to=None, cancel_form=None, **kwargs): prune=None, tag=None, return_to=None, cancel_form=None, **kwargs):
""" """
Receive tvdb id, dir, and other options and create a show from them. If extra show dirs are Receive tvdb id, dir, and other options and create a show from them. If extra show dirs are
@ -4973,10 +4977,10 @@ class AddShows(Home):
flatten_folders = config.checkbox_to_value(flatten_folders) flatten_folders = config.checkbox_to_value(flatten_folders)
subs = config.checkbox_to_value(subs) subs = config.checkbox_to_value(subs)
if whitelist: if allowlist:
whitelist = short_group_names(whitelist) allowlist = short_group_names(allowlist)
if blacklist: if blocklist:
blacklist = short_group_names(blacklist) blocklist = short_group_names(blocklist)
if not any_qualities: if not any_qualities:
any_qualities = [] any_qualities = []
@ -4996,7 +5000,7 @@ class AddShows(Home):
# add the show # add the show
sickbeard.showQueueScheduler.action.addShow(tvid, prodid, show_dir, int(default_status), newQuality, sickbeard.showQueueScheduler.action.addShow(tvid, prodid, show_dir, int(default_status), newQuality,
flatten_folders, tvinfo_lang, subs, anime, flatten_folders, tvinfo_lang, subs, anime,
scene, None, blacklist, whitelist, scene, None, allowlist, blocklist,
wanted_begin, wanted_latest, prune, tag, new_show=new_show, wanted_begin, wanted_latest, prune, tag, new_show=new_show,
show_name=show_name, upgrade_once=upgrade_once) show_name=show_name, upgrade_once=upgrade_once)
# ui.notifications.message('Show added', 'Adding the specified show into ' + show_dir) # ui.notifications.message('Show added', 'Adding the specified show into ' + show_dir)

2
tests/migration_tests.py

@ -27,7 +27,7 @@ class MigrationBasicTests(test.SickbeardTestDBCase):
31: sickbeard.mainDB.AddAnimeTVShow, 31: sickbeard.mainDB.AddAnimeTVShow,
32: sickbeard.mainDB.AddAbsoluteNumbering, 32: sickbeard.mainDB.AddAbsoluteNumbering,
33: sickbeard.mainDB.AddSceneAbsoluteNumbering, 33: sickbeard.mainDB.AddSceneAbsoluteNumbering,
34: sickbeard.mainDB.AddAnimeBlacklistWhitelist, 34: sickbeard.mainDB.AddAnimeAllowlistBlocklist,
35: sickbeard.mainDB.AddSceneAbsoluteNumbering2, 35: sickbeard.mainDB.AddSceneAbsoluteNumbering2,
36: sickbeard.mainDB.AddXemRefresh, 36: sickbeard.mainDB.AddXemRefresh,
37: sickbeard.mainDB.AddSceneToTvShows, 37: sickbeard.mainDB.AddSceneToTvShows,

Loading…
Cancel
Save