This commit is contained in:
Louis Vézina 2020-06-26 11:28:49 -04:00
parent d0d3a0a3d9
commit 78c40aab23
7 changed files with 616 additions and 365 deletions

View File

@ -1440,34 +1440,34 @@ class SyncSubtitles(Resource):
class BrowseBazarrFS(Resource):
@authenticate
def get(self):
path = request.args.get('id') or ''
path = request.args.get('path') or ''
data = []
result = browse_bazarr_filesystem(path)
for item in result['directories']:
data.append({'id': item['name'], 'parent': result['parent'], 'children': True})
return jsonify(data=data)
data.append({'text': item['name'], 'children': True, 'path': item['path']})
return jsonify(data)
class BrowseSonarrFS(Resource):
@authenticate
def get(self):
path = request.args.get('id') or ''
path = request.args.get('path') or ''
data = []
result = browse_sonarr_filesystem(path)
for item in result['directories']:
data.append({'id': item['name'], 'parent': result['parent'] if 'parent' in result else '#'})
return jsonify(data=data)
data.append({'text': item['name'], 'children': True, 'path': item['path']})
return jsonify(data)
class BrowseRadarrFS(Resource):
@authenticate
def get(self):
path = request.args.get('id') or ''
path = request.args.get('path') or ''
data = []
result = browse_radarr_filesystem(path)
for item in result['directories']:
data.append({'id': item['name'], 'parent': result['parent'] if 'parent' in result else '#'})
return jsonify(data=data)
data.append({'text': item['name'], 'children': True, 'path': item['path']})
return jsonify(data)
api.add_resource(Shutdown, '/shutdown')

View File

@ -1 +1,474 @@
!function(e){e.fn.extend({slimScroll:function(i){var o={width:"auto",height:"250px",size:"7px",color:"#000",position:"right",distance:"1px",start:"top",opacity:.4,alwaysVisible:!1,disableFadeOut:!1,railVisible:!1,railColor:"#333",railOpacity:.2,railDraggable:!0,railClass:"slimScrollRail",barClass:"slimScrollBar",wrapperClass:"slimScrollDiv",allowPageScroll:!1,wheelStep:20,touchScrollStep:200,borderRadius:"7px",railBorderRadius:"7px"},s=e.extend(o,i);return this.each(function(){function o(t){if(h){var t=t||window.event,i=0;t.wheelDelta&&(i=-t.wheelDelta/120),t.detail&&(i=t.detail/3);var o=t.target||t.srcTarget||t.srcElement;e(o).closest("."+s.wrapperClass).is(x.parent())&&r(i,!0),t.preventDefault&&!y&&t.preventDefault(),y||(t.returnValue=!1)}}function r(e,t,i){y=!1;var o=e,r=x.outerHeight()-R.outerHeight();if(t&&(o=parseInt(R.css("top"))+e*parseInt(s.wheelStep)/100*R.outerHeight(),o=Math.min(Math.max(o,0),r),o=e>0?Math.ceil(o):Math.floor(o),R.css({top:o+"px"})),v=parseInt(R.css("top"))/(x.outerHeight()-R.outerHeight()),o=v*(x[0].scrollHeight-x.outerHeight()),i){o=e;var a=o/x[0].scrollHeight*x.outerHeight();a=Math.min(Math.max(a,0),r),R.css({top:a+"px"})}x.scrollTop(o),x.trigger("slimscrolling",~~o),n(),c()}function a(e){window.addEventListener?(e.addEventListener("DOMMouseScroll",o,!1),e.addEventListener("mousewheel",o,!1)):document.attachEvent("onmousewheel",o)}function l(){f=Math.max(x.outerHeight()/x[0].scrollHeight*x.outerHeight(),m),R.css({height:f+"px"});var e=f==x.outerHeight()?"none":"block";R.css({display:e})}function n(){if(l(),clearTimeout(p),v==~~v){if(y=s.allowPageScroll,b!=v){var e=0==~~v?"top":"bottom";x.trigger("slimscroll",e)}}else y=!1;return b=v,f>=x.outerHeight()?void(y=!0):(R.stop(!0,!0).fadeIn("fast"),void(s.railVisible&&E.stop(!0,!0).fadeIn("fast")))}function c(){s.alwaysVisible||(p=setTimeout(function(){s.disableFadeOut&&h||u||d||(R.fadeOut("slow"),E.fadeOut("slow"))},1e3))}var h,u,d,p,g,f,v,b,w="<div></div>",m=30,y=!1,x=e(this);if(x.parent().hasClass(s.wrapperClass)){var C=x.scrollTop();if(R=x.closest("."+s.barClass),E=x.closest("."+s.railClass),l(),e.isPlainObject(i)){if("height"in i&&"auto"==i.height){x.parent().css("height","auto"),x.css("height","auto");var H=x.parent().parent().height();x.parent().css("height",H),x.css("height",H)}if("scrollTo"in i)C=parseInt(s.scrollTo);else if("scrollBy"in i)C+=parseInt(s.scrollBy);else if("destroy"in i)return R.remove(),E.remove(),void x.unwrap();r(C,!1,!0)}}else if(!(e.isPlainObject(i)&&"destroy"in i)){s.height="auto"==s.height?x.parent().height():s.height;var S=e(w).addClass(s.wrapperClass).css({position:"relative",overflow:"hidden",width:s.width,height:s.height});x.css({overflow:"hidden",width:s.width,height:s.height});var E=e(w).addClass(s.railClass).css({width:s.size,height:"100%",position:"absolute",top:0,display:s.alwaysVisible&&s.railVisible?"block":"none","border-radius":s.railBorderRadius,background:s.railColor,opacity:s.railOpacity,zIndex:90}),R=e(w).addClass(s.barClass).css({background:s.color,width:s.size,position:"absolute",top:0,opacity:s.opacity,display:s.alwaysVisible?"block":"none","border-radius":s.borderRadius,BorderRadius:s.borderRadius,MozBorderRadius:s.borderRadius,WebkitBorderRadius:s.borderRadius,zIndex:99}),D="right"==s.position?{right:s.distance}:{left:s.distance};E.css(D),R.css(D),x.wrap(S),x.parent().append(R),x.parent().append(E),s.railDraggable&&R.bind("mousedown",function(i){var o=e(document);return d=!0,t=parseFloat(R.css("top")),pageY=i.pageY,o.bind("mousemove.slimscroll",function(e){currTop=t+e.pageY-pageY,R.css("top",currTop),r(0,R.position().top,!1)}),o.bind("mouseup.slimscroll",function(e){d=!1,c(),o.unbind(".slimscroll")}),!1}).bind("selectstart.slimscroll",function(e){return e.stopPropagation(),e.preventDefault(),!1}),E.hover(function(){n()},function(){c()}),R.hover(function(){u=!0},function(){u=!1}),x.hover(function(){h=!0,n(),c()},function(){h=!1,c()}),x.bind("touchstart",function(e,t){e.originalEvent.touches.length&&(g=e.originalEvent.touches[0].pageY)}),x.bind("touchmove",function(e){if(y||e.originalEvent.preventDefault(),e.originalEvent.touches.length){var t=(g-e.originalEvent.touches[0].pageY)/s.touchScrollStep;r(t,!0),g=e.originalEvent.touches[0].pageY}}),l(),"bottom"===s.start?(R.css({top:x.outerHeight()-R.outerHeight()}),r(0,!0)):"top"!==s.start&&(r(e(s.start).position().top,null,!0),s.alwaysVisible||R.hide()),a(this)}}),this}}),e.fn.extend({slimscroll:e.fn.slimScroll})}(jQuery);
/*! Copyright (c) 2011 Piotr Rochala (http://rocha.la)
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*
* Version: 1.3.8
*
*/
(function($) {
$.fn.extend({
slimScroll: function(options) {
var defaults = {
// width in pixels of the visible scroll area
width : 'auto',
// height in pixels of the visible scroll area
height : '250px',
// width in pixels of the scrollbar and rail
size : '7px',
// scrollbar color, accepts any hex/color value
color: '#000',
// scrollbar position - left/right
position : 'right',
// distance in pixels between the side edge and the scrollbar
distance : '1px',
// default scroll position on load - top / bottom / $('selector')
start : 'top',
// sets scrollbar opacity
opacity : .4,
// enables always-on mode for the scrollbar
alwaysVisible : false,
// check if we should hide the scrollbar when user is hovering over
disableFadeOut : false,
// sets visibility of the rail
railVisible : false,
// sets rail color
railColor : '#333',
// sets rail opacity
railOpacity : .2,
// whether we should use jQuery UI Draggable to enable bar dragging
railDraggable : true,
// defautlt CSS class of the slimscroll rail
railClass : 'slimScrollRail',
// defautlt CSS class of the slimscroll bar
barClass : 'slimScrollBar',
// defautlt CSS class of the slimscroll wrapper
wrapperClass : 'slimScrollDiv',
// check if mousewheel should scroll the window if we reach top/bottom
allowPageScroll : false,
// scroll amount applied to each mouse wheel step
wheelStep : 20,
// scroll amount applied when user is using gestures
touchScrollStep : 200,
// sets border radius
borderRadius: '7px',
// sets border radius of the rail
railBorderRadius : '7px'
};
var o = $.extend(defaults, options);
// do it for every element that matches selector
this.each(function(){
var isOverPanel, isOverBar, isDragg, queueHide, touchDif,
barHeight, percentScroll, lastScroll,
divS = '<div></div>',
minBarHeight = 30,
releaseScroll = false;
// used in event handlers and for better minification
var me = $(this);
// ensure we are not binding it again
if (me.parent().hasClass(o.wrapperClass))
{
// start from last bar position
var offset = me.scrollTop();
// find bar and rail
bar = me.siblings('.' + o.barClass);
rail = me.siblings('.' + o.railClass);
getBarHeight();
// check if we should scroll existing instance
if ($.isPlainObject(options))
{
// Pass height: auto to an existing slimscroll object to force a resize after contents have changed
if ( 'height' in options && options.height == 'auto' ) {
me.parent().css('height', 'auto');
me.css('height', 'auto');
var height = me.parent().parent().height();
me.parent().css('height', height);
me.css('height', height);
} else if ('height' in options) {
var h = options.height;
me.parent().css('height', h);
me.css('height', h);
}
if ('scrollTo' in options)
{
// jump to a static point
offset = parseInt(o.scrollTo);
}
else if ('scrollBy' in options)
{
// jump by value pixels
offset += parseInt(o.scrollBy);
}
else if ('destroy' in options)
{
// remove slimscroll elements
bar.remove();
rail.remove();
me.unwrap();
return;
}
// scroll content by the given offset
scrollContent(offset, false, true);
}
return;
}
else if ($.isPlainObject(options))
{
if ('destroy' in options)
{
return;
}
}
// optionally set height to the parent's height
o.height = (o.height == 'auto') ? me.parent().height() : o.height;
// wrap content
var wrapper = $(divS)
.addClass(o.wrapperClass)
.css({
position: 'relative',
overflow: 'hidden',
width: o.width,
height: o.height
});
// update style for the div
me.css({
overflow: 'hidden',
width: o.width,
height: o.height
});
// create scrollbar rail
var rail = $(divS)
.addClass(o.railClass)
.css({
width: o.size,
height: '100%',
position: 'absolute',
top: 0,
display: (o.alwaysVisible && o.railVisible) ? 'block' : 'none',
'border-radius': o.railBorderRadius,
background: o.railColor,
opacity: o.railOpacity,
zIndex: 90
});
// create scrollbar
var bar = $(divS)
.addClass(o.barClass)
.css({
background: o.color,
width: o.size,
position: 'absolute',
top: 0,
opacity: o.opacity,
display: o.alwaysVisible ? 'block' : 'none',
'border-radius' : o.borderRadius,
BorderRadius: o.borderRadius,
MozBorderRadius: o.borderRadius,
WebkitBorderRadius: o.borderRadius,
zIndex: 99
});
// set position
var posCss = (o.position == 'right') ? { right: o.distance } : { left: o.distance };
rail.css(posCss);
bar.css(posCss);
// wrap it
me.wrap(wrapper);
// append to parent div
me.parent().append(bar);
me.parent().append(rail);
// make it draggable and no longer dependent on the jqueryUI
if (o.railDraggable){
bar.bind("mousedown", function(e) {
var $doc = $(document);
isDragg = true;
t = parseFloat(bar.css('top'));
pageY = e.pageY;
$doc.bind("mousemove.slimscroll", function(e){
currTop = t + e.pageY - pageY;
bar.css('top', currTop);
scrollContent(0, bar.position().top, false);// scroll content
});
$doc.bind("mouseup.slimscroll", function(e) {
isDragg = false;hideBar();
$doc.unbind('.slimscroll');
});
return false;
}).bind("selectstart.slimscroll", function(e){
e.stopPropagation();
e.preventDefault();
return false;
});
}
// on rail over
rail.hover(function(){
showBar();
}, function(){
hideBar();
});
// on bar over
bar.hover(function(){
isOverBar = true;
}, function(){
isOverBar = false;
});
// show on parent mouseover
me.hover(function(){
isOverPanel = true;
showBar();
hideBar();
}, function(){
isOverPanel = false;
hideBar();
});
// support for mobile
me.bind('touchstart', function(e,b){
if (e.originalEvent.touches.length)
{
// record where touch started
touchDif = e.originalEvent.touches[0].pageY;
}
});
me.bind('touchmove', function(e){
// prevent scrolling the page if necessary
if(!releaseScroll)
{
e.originalEvent.preventDefault();
}
if (e.originalEvent.touches.length)
{
// see how far user swiped
var diff = (touchDif - e.originalEvent.touches[0].pageY) / o.touchScrollStep;
// scroll content
scrollContent(diff, true);
touchDif = e.originalEvent.touches[0].pageY;
}
});
// set up initial height
getBarHeight();
// check start position
if (o.start === 'bottom')
{
// scroll content to bottom
bar.css({ top: me.outerHeight() - bar.outerHeight() });
scrollContent(0, true);
}
else if (o.start !== 'top')
{
// assume jQuery selector
scrollContent($(o.start).position().top, null, true);
// make sure bar stays hidden
if (!o.alwaysVisible) { bar.hide(); }
}
// attach scroll events
attachWheel(this);
function _onWheel(e)
{
// use mouse wheel only when mouse is over
if (!isOverPanel) { return; }
var e = e || window.event;
var delta = 0;
if (e.wheelDelta) { delta = -e.wheelDelta/120; }
if (e.detail) { delta = e.detail / 3; }
var target = e.target || e.srcTarget || e.srcElement;
if ($(target).closest('.' + o.wrapperClass).is(me.parent())) {
// scroll content
scrollContent(delta, true);
}
// stop window scroll
if (e.preventDefault && !releaseScroll) { e.preventDefault(); }
if (!releaseScroll) { e.returnValue = false; }
}
function scrollContent(y, isWheel, isJump)
{
releaseScroll = false;
var delta = y;
var maxTop = me.outerHeight() - bar.outerHeight();
if (isWheel)
{
// move bar with mouse wheel
delta = parseInt(bar.css('top')) + y * parseInt(o.wheelStep) / 100 * bar.outerHeight();
// move bar, make sure it doesn't go out
delta = Math.min(Math.max(delta, 0), maxTop);
// if scrolling down, make sure a fractional change to the
// scroll position isn't rounded away when the scrollbar's CSS is set
// this flooring of delta would happened automatically when
// bar.css is set below, but we floor here for clarity
delta = (y > 0) ? Math.ceil(delta) : Math.floor(delta);
// scroll the scrollbar
bar.css({ top: delta + 'px' });
}
// calculate actual scroll amount
percentScroll = parseInt(bar.css('top')) / (me.outerHeight() - bar.outerHeight());
delta = percentScroll * (me[0].scrollHeight - me.outerHeight());
if (isJump)
{
delta = y;
var offsetTop = delta / me[0].scrollHeight * me.outerHeight();
offsetTop = Math.min(Math.max(offsetTop, 0), maxTop);
bar.css({ top: offsetTop + 'px' });
}
// scroll content
me.scrollTop(delta);
// fire scrolling event
me.trigger('slimscrolling', ~~delta);
// ensure bar is visible
showBar();
// trigger hide when scroll is stopped
hideBar();
}
function attachWheel(target)
{
if (window.addEventListener)
{
target.addEventListener('DOMMouseScroll', _onWheel, false );
target.addEventListener('mousewheel', _onWheel, false );
}
else
{
document.attachEvent("onmousewheel", _onWheel)
}
}
function getBarHeight()
{
// calculate scrollbar height and make sure it is not too small
barHeight = Math.max((me.outerHeight() / me[0].scrollHeight) * me.outerHeight(), minBarHeight);
bar.css({ height: barHeight + 'px' });
// hide scrollbar if content is not long enough
var display = barHeight == me.outerHeight() ? 'none' : 'block';
bar.css({ display: display });
}
function showBar()
{
// recalculate bar height
getBarHeight();
clearTimeout(queueHide);
// when bar reached top or bottom
if (percentScroll == ~~percentScroll)
{
//release wheel
releaseScroll = o.allowPageScroll;
// publish approporiate event
if (lastScroll != percentScroll)
{
var msg = (~~percentScroll == 0) ? 'top' : 'bottom';
me.trigger('slimscroll', msg);
}
}
else
{
releaseScroll = false;
}
lastScroll = percentScroll;
// show only when required
if(barHeight >= me.outerHeight()) {
//allow window scroll
releaseScroll = true;
return;
}
bar.stop(true,true).fadeIn('fast');
if (o.railVisible) { rail.stop(true,true).fadeIn('fast'); }
}
function hideBar()
{
// only hide when options allow it
if (!o.alwaysVisible)
{
queueHide = setTimeout(function(){
if (!(o.disableFadeOut && isOverPanel) && !isOverBar && !isDragg)
{
bar.fadeOut('slow');
rail.fadeOut('slow');
}
}, 1000);
}
}
});
// maintain chainability
return this;
}
});
$.fn.extend({
slimscroll: $.fn.slimScroll
});
})(jQuery);

View File

@ -1,174 +0,0 @@
$('#settings_form')
.form({
fields: {
settings_general_ip : {
rules : [
{
type : 'regExp[/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/]',
prompt : '"General / Start-Up / Listening IP address" must be a valid IPv4 address'
},
{
type : 'empty',
prompt : '"General / Start-Up / Listening IP address" must have a value'
}
]
},
settings_general_port : {
rules : [
{
type : 'integer[1..65535]',
prompt : '"General / Start-Up / Listening port" must be an integer between 1 and 65535'
},
{
type : 'empty',
prompt : '"General / Start-Up / Listening port" must have a value'
}
]
},
settings_general_chmod: {
rules: [
{
type: 'regExp[^([0-7]{4})$]',
prompt : '"General / Start-Up / Set subtitle file permissions to" must be a 4-digit octal (e.g.: 0775)'
}
]
},
settings_auth_password : {
depends: 'settings_auth_username',
rules : [
{
type : 'empty',
prompt : '"General / Security settings / Password" must have a value and you must type it again if you change your username.'
}
]
},
sonarr_validated_checkbox : {
depends: 'settings_general_use_sonarr',
rules : [
{
type : 'checked',
prompt : '"Sonarr / Connection settings / Test" must be successful before going further'
}
]
},
settings_sonarr_ip : {
depends: 'settings_general_use_sonarr',
rules : [
{
type : 'empty',
prompt : '"Sonarr / Connection settings / Hostname or IP address" must have a value'
}
]
},
settings_sonarr_port : {
depends: 'settings_general_use_sonarr',
rules : [
{
type : 'integer[1..65535]',
prompt : '"Sonarr / Connection settings / Listening port" must be an integer between 1 and 65535'
},
{
type : 'empty',
prompt : '"Sonarr / Connection settings / Listening port" must have a value'
}
]
},
// settings_sonarr_apikey : {
// depends: 'settings_general_use_sonarr',
// rules : [
// {
// type : 'exactLength[32]',
// prompt : '"Sonarr / Connection settings / API key" must be exactly {ruleValue} characters'
// },
// {
// type : 'empty',
// prompt : '"Sonarr / Connection settings / API key" must have a value'
// }
// ]
// },
radarr_validated_checkbox : {
depends: 'settings_general_use_radarr',
rules : [
{
type : 'checked',
prompt : '"Radarr / Connection settings / Test" must be successful before going further'
}
]
},
settings_radarr_ip : {
depends: 'settings_general_use_radarr',
rules : [
{
type : 'empty',
prompt : '"Radarr / Connection settings / Hostname or IP address" must have a value'
}
]
},
settings_radarr_port : {
depends: 'settings_general_use_radarr',
rules : [
{
type : 'integer[1..65535]',
prompt : '"Radarr / Connection settings / Listening port" must be an integer between 1 and 65535'
},
{
type : 'empty',
prompt : '"Radarr / Connection settings / Listening port" must have a value'
}
]
},
// settings_radarr_apikey : {
// depends: 'settings_general_use_radarr',
// rules : [
// {
// type : 'exactLength[32]',
// prompt : '"Radarr / Connection settings / API key" must be exactly {ruleValue} characters'
// },
// {
// type : 'empty',
// prompt : '"Radarr / Connection settings / API key" must have a value'
// }
// ]
// },
settings_subliminal_providers : {
rules : [
{
type : 'minCount[1]',
prompt : '"Subtitles / Subtitles providers" must have at least one enabled provider'
}
]
},
settings_subliminal_languages : {
rules : [
{
type : 'minCount[1]',
prompt : '"Subtitles / Subtitles languages / Enabled languages" must have at least one enabled language'
}
]
},
settings_days_to_upgrade_subs : {
depends: 'settings_upgrade_subs',
rules : [
{
type : 'integer[1..30]',
prompt : '"Subtitles / Subtitles options / Number of days to go back in history..." must be an integer between 1 and 30'
}
]
}
},
inline : false,
selector : {
message: '#form_validation_error'
},
on : 'change',
onFailure: function(){
$('.submit').addClass('disabled');
return false;
},
onSuccess: function(){
$('.submit').removeClass('disabled');
$('#loader').addClass('active');
}
})
;

View File

@ -1,156 +0,0 @@
$('#wizard_form')
.form({
fields: {
settings_general_ip : {
rules : [
{
type : 'regExp[/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/]',
prompt : '"General / Start-Up / Listening IP address" must be a valid IPv4 address'
},
{
type : 'empty',
prompt : '"General / Start-Up / Listening IP address" must have a value'
}
]
},
settings_general_port : {
rules : [
{
type : 'integer[1..65535]',
prompt : '"General / Start-Up / Listening port" must be an integer between 1 and 65535'
},
{
type : 'empty',
prompt : '"General / Start-Up / Listening port" must have a value'
}
]
},
sonarr_validated_checkbox : {
depends: 'settings_general_use_sonarr',
rules : [
{
type : 'checked',
prompt : '"Sonarr / Connection settings / Test" must be successful before going further'
}
]
},
settings_sonarr_ip : {
depends: 'settings_general_use_sonarr',
rules : [
{
type : 'empty',
prompt : '"Sonarr / Connection settings / Hostname or IP address" must have a value'
}
]
},
settings_sonarr_port : {
depends: 'settings_general_use_sonarr',
rules : [
{
type : 'integer[1..65535]',
prompt : '"Sonarr / Connection settings / Listening port" must be an integer between 1 and 65535'
},
{
type : 'empty',
prompt : '"Sonarr / Connection settings / Listening port" must have a value'
}
]
},
// settings_sonarr_apikey : {
// depends: 'settings_general_use_sonarr',
// rules : [
// {
// type : 'exactLength[32]',
// prompt : '"Sonarr / Connection settings / API key" must be exactly {ruleValue} characters'
// },
// {
// type : 'empty',
// prompt : '"Sonarr / Connection settings / API key" must have a value'
// }
// ]
// },
radarr_validated_checkbox : {
depends: 'settings_general_use_radarr',
rules : [
{
type : 'checked',
prompt : '"Radarr / Connection settings / Test" must be successful before going further'
}
]
},
settings_radarr_ip : {
depends: 'settings_general_use_radarr',
rules : [
{
type : 'empty',
prompt : '"Radarr / Connection settings / Hostname or IP address" must have a value'
}
]
},
settings_radarr_port : {
depends: 'settings_general_use_radarr',
rules : [
{
type : 'integer[1..65535]',
prompt : '"Radarr / Connection settings / Listening port" must be an integer between 1 and 65535'
},
{
type : 'empty',
prompt : '"Radarr / Connection settings / Listening port" must have a value'
}
]
},
// settings_radarr_apikey : {
// depends: 'settings_general_use_radarr',
// rules : [
// {
// type : 'exactLength[32]',
// prompt : '"Radarr / Connection settings / API key" must be exactly {ruleValue} characters'
// },
// {
// type : 'empty',
// prompt : '"Radarr / Connection settings / API key" must have a value'
// }
// ]
// },
settings_subliminal_providers : {
rules : [
{
type : 'minCount[1]',
prompt : '"Subtitles / Subtitles providers" must have at least one enabled provider'
}
]
},
settings_subliminal_languages : {
rules : [
{
type : 'minCount[1]',
prompt : '"Subtitles / Subtitles languages / Enabled languages" must have at least one enabled language'
}
]
}
},
inline : false,
selector : {
message: '#form_validation_error'
},
on : 'change',
onFailure: function(){
$('#submit').addClass('disabled');
$('.prev2').addClass('disabled');
$('.prev3').addClass('disabled');
$('.next2').addClass('disabled');
$('.next3').addClass('disabled');
return false;
},
onSuccess: function(){
$('#submit').removeClass('disabled');
$('.prev2').removeClass('disabled');
$('.prev3').removeClass('disabled');
$('.next2').removeClass('disabled');
$('.next3').removeClass('disabled');
}
})
;

View File

@ -77,6 +77,15 @@
.slider_span {
margin-left: 1em;
}
.filetree {
border: 1px solid #ced4da;
border-radius: .25rem;
}
#add_path_sonarr, #add_path_radarr, #add_path_bazarr {
margin-bottom: 0.5em;
}
</style>
{% endblock head %}

View File

@ -141,6 +141,12 @@
<br>
<h4>Path Mappings</h4>
<hr/>
<h5>Some tips to ensure things goes smoothly:</h5>
<ul>
<li>You should create a mapping for each Root Folders you have configured in Radarr</li>
<li>Point Bazarr to the folder containing all of your movies, not a specific one. eg. "/movies" and not "/movies/the matrix"</li>
<li>UNC path under Windows must be typed manually. eg. "\\server\share"</li>
</ul>
<div class="row">
<div class="col-sm-8">
<table class="table table-striped" id="path_mapping_movie" style="width:100%;">
@ -170,7 +176,8 @@
Path for Radarr
</div>
<div class="col-sm-8">
<input type="text" class="form-control" id="add_path_radarr" name="add_path_radarr" value="">
<input type="text" class="form-control" id="add_path_radarr" name="add_path_radarr" value="" placeholder="Browse or type...">
<div class="filetree" id="radarr_browser"></div>
</div>
</div>
<br>
@ -179,7 +186,8 @@
Path for Bazarr
</div>
<div class="col-sm-8">
<input type="text" class="form-control" id="add_path_bazarr" name="add_path_bazarr" value="">
<input type="text" class="form-control" id="add_path_bazarr" name="add_path_bazarr" value="" placeholder="Browse or type...">
<div class="filetree" id="bazarr_browser"></div>
</div>
</div>
</div>
@ -364,11 +372,61 @@
}]
});
$('#addModal').on('hidden.bs.modal', function() {
$('#add_form')[0].reset();
$('#radarr_browser').jstree('destroy');
$('#radarr_browser').slimScroll({destroy: true});
$('#bazarr_browser').jstree('destroy');
$('#bazarr_browser').slimScroll({destroy: true});
})
$('#addModal').on('show.bs.modal', function() {
$('#radarr_browser').slimScroll({
height: '200px',
start: 'top'
});
$('#radarr_browser').jstree({
'core' : {
'data' : {
'url' : '{{ url_for('api.browseradarrfs') }}',
'data' : function (node) {
if (node.original === undefined) {
return {'path': ''};
} else {
return {'path': node.original.path};
}
}
}
}
}).on('changed.jstree', function (e, data) {
$('#add_path_radarr').val(data.node.original.path);
});
$('#bazarr_browser').slimScroll({
height: '200px',
start: 'top'
});
$('#bazarr_browser').jstree({
'core' : {
'data' : {
'url' : '{{ url_for('api.browsebazarrfs') }}',
'data' : function (node) {
if (node.original === undefined) {
return {'path': ''};
} else {
return {'path': node.original.path};
}
}
}
}
}).on('changed.jstree', function (e, data) {
$('#add_path_bazarr').val(data.node.original.path);
});
})
$('#add_save_button').on('click', function(e) {
e.preventDefault();
table.row.add([ $('#add_path_radarr').val(), $('#add_path_bazarr').val()]).draw();
$('#add_path_radarr').val('');
$('#add_path_bazarr').val('');
$('#addModal').modal('hide');
$('#settings_form').trigger('change');
});

View File

@ -141,6 +141,12 @@
<br>
<h4>Path Mappings</h4>
<hr/>
<h5>Some tips to ensure things goes smoothly:</h5>
<ul>
<li>You should create a mapping for each Root Folders you have configured in Sonarr</li>
<li>Point Bazarr to the folder containing all of your tv shows, not a specific one. eg. "/tv shows" and not "/tv shows/the simpsons"</li>
<li>UNC path under Windows must be typed manually. eg. "\\server\share"</li>
</ul>
<div class="row">
<div class="col-sm-8">
<table class="table table-striped" id="path_mapping" style="width:100%;">
@ -170,8 +176,8 @@
Path for Sonarr
</div>
<div class="col-sm-8">
<input type="text" class="form-control" id="add_path_sonarr" name="add_path_sonarr" value="">
<div id="sonarr_browser"></div>
<input type="text" class="form-control" id="add_path_sonarr" name="add_path_sonarr" value="" placeholder="Browse or type...">
<div class="filetree" id="sonarr_browser"></div>
</div>
</div>
<br>
@ -180,8 +186,8 @@
Path for Bazarr
</div>
<div class="col-sm-8">
<input type="text" class="form-control" id="add_path_bazarr" name="add_path_bazarr" value="">
<div id="bazarr_browser"></div>
<input type="text" class="form-control" id="add_path_bazarr" name="add_path_bazarr" value="" placeholder="Browse or type...">
<div class="filetree" id="bazarr_browser"></div>
</div>
</div>
</div>
@ -366,11 +372,61 @@
}]
});
$('#addModal').on('hidden.bs.modal', function() {
$('#add_form')[0].reset();
$('#sonarr_browser').jstree('destroy');
$('#sonarr_browser').slimScroll({destroy: true});
$('#bazarr_browser').jstree('destroy');
$('#bazarr_browser').slimScroll({destroy: true});
})
$('#addModal').on('show.bs.modal', function() {
$('#sonarr_browser').slimScroll({
height: '200px',
start: 'top'
});
$('#sonarr_browser').jstree({
'core' : {
'data' : {
'url' : '{{ url_for('api.browsesonarrfs') }}',
'data' : function (node) {
if (node.original === undefined) {
return {'path': ''};
} else {
return {'path': node.original.path};
}
}
}
}
}).on('changed.jstree', function (e, data) {
$('#add_path_sonarr').val(data.node.original.path);
});
$('#bazarr_browser').slimScroll({
height: '200px',
start: 'top'
});
$('#bazarr_browser').jstree({
'core' : {
'data' : {
'url' : '{{ url_for('api.browsebazarrfs') }}',
'data' : function (node) {
if (node.original === undefined) {
return {'path': ''};
} else {
return {'path': node.original.path};
}
}
}
}
}).on('changed.jstree', function (e, data) {
$('#add_path_bazarr').val(data.node.original.path);
});
})
$('#add_save_button').on('click', function(e) {
e.preventDefault();
table.row.add([ $('#add_path_sonarr').val(), $('#add_path_bazarr').val()]).draw();
$('#add_path_sonarr').val('');
$('#add_path_bazarr').val('');
$('#addModal').modal('hide');
$('#settings_form').trigger('change');
});
@ -413,21 +469,6 @@
form_changed = true;
$('#save_button').prop('disabled', false).css('cursor', 'auto');
})
$('#sonarr_browser').jstree({
'core' : {
'data' : {
'url' : '{{ url_for('api.browsesonarrfs') }}'
}
}
});
$('#bazarr_browser').jstree({
'core' : {
'data' : {
'url' : '{{ url_for('api.browsebazarrfs') }}'
}
}
});
});
</script>
{% endblock tail %}