more removal of cloud services, progress on setup wizard

This commit is contained in:
2021-02-06 00:21:58 +01:00
parent 38f0a44fa0
commit 3fb7f4ddd1
4 changed files with 294 additions and 373 deletions

View File

@@ -1,6 +1,6 @@
<% <%
import jellypy import jellypy
from jellypy import common, helpers from jellypy import common, helpers
%> %>
<!doctype html> <!doctype html>
@@ -69,7 +69,8 @@
<label for="http_username">Username</label> <label for="http_username">Username</label>
<div class="row"> <div class="row">
<div class="col-xs-8"> <div class="col-xs-8">
<input type="text" class="form-control auth-settings" id="http_username" name="http_username" value="" size="30"> <input type="text" class="form-control auth-settings" id="http_username"
name="http_username" value="" size="30">
</div> </div>
</div> </div>
</div> </div>
@@ -77,18 +78,20 @@
<label for="http_password">Password</label> <label for="http_password">Password</label>
<div class="row"> <div class="row">
<div class="col-xs-8"> <div class="col-xs-8">
<input type="password" class="form-control auth-settings" id="http_password" name="http_password" value="" size="30" autocomplete="new-password"> <input type="password" class="form-control auth-settings" id="http_password"
name="http_password" value="" size="30" autocomplete="new-password">
</div> </div>
</div> </div>
</div> </div>
<input type="hidden" class="form-control" name="http_hash_password" id="http_hash_password" value="1"> <input type="hidden" class="form-control" name="http_hash_password" id="http_hash_password"
value="1">
<input type="hidden" class="form-control" name="http_plex_admin" id="http_plex_admin" value="1"> <input type="hidden" class="form-control" name="http_plex_admin" id="http_plex_admin" value="1">
<input type="hidden" id="authentication_valid" data-validate="validateAuthentication" value=""> <input type="hidden" id="authentication_valid" data-validate="validateAuthentication" value="">
<span style="display: none;" id="authentication-status"></span> <span style="display: none;" id="authentication-status"></span>
</div> </div>
<div class="wizard-card" data-cardname="card3"> <div class="wizard-card" data-cardname="card3">
<h3>Jellyfin</h3> <h3>Jellyfin Server</h3>
<div class="wizard-input-section"> <div class="wizard-input-section">
<p class="help-block"> <p class="help-block">
Select your Jellyfin Server from the dropdown menu or enter an IP address or hostname. Select your Jellyfin Server from the dropdown menu or enter an IP address or hostname.
@@ -108,7 +111,8 @@
data-ssl="${config['pms_ssl']}" data-ssl="${config['pms_ssl']}"
data-is_cloud="${config['pms_is_cloud']}" data-is_cloud="${config['pms_is_cloud']}"
data-label="${config['pms_name'] or 'Local'}" data-label="${config['pms_name'] or 'Local'}"
selected>${config['pms_ip']}</option> selected>${config['pms_ip']}
</option>
% endif % endif
</select> </select>
</div> </div>
@@ -118,12 +122,15 @@
<label for="pms_port">Jellyfin Port</label> <label for="pms_port">Jellyfin Port</label>
<div class="row"> <div class="row">
<div class="col-xs-3"> <div class="col-xs-3">
<input type="text" class="form-control pms-settings" name="pms_port" id="pms_port" placeholder="32400" value="${config['pms_port']}" required> <input type="text" class="form-control pms-settings" name="pms_port" id="pms_port"
placeholder="8096" value="${config['pms_port']}" required>
</div> </div>
<div class="col-xs-4"> <div class="col-xs-4">
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" id="pms_ssl_checkbox" class="checkbox-toggle pms-settings" data-id="pms_ssl" value="1" ${helpers.checked(config['pms_ssl'])}> Use SSL <input type="checkbox" id="pms_ssl_checkbox"
class="checkbox-toggle pms-settings" data-id="pms_ssl" value="1"
${helpers.checked(config['pms_ssl'])}> Use SSL
<input type="hidden" id="pms_ssl" name="pms_ssl" value="${config['pms_ssl']}"> <input type="hidden" id="pms_ssl" name="pms_ssl" value="${config['pms_ssl']}">
</label> </label>
</div> </div>
@@ -131,22 +138,50 @@
<div class="col-xs-4"> <div class="col-xs-4">
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" id="pms_is_remote_checkbox" class="checkbox-toggle pms-settings" data-id="pms_is_remote" value="1" ${helpers.checked(config['pms_is_remote'])}> Remote Server <input type="checkbox" id="pms_is_remote_checkbox"
<input type="hidden" id="pms_is_remote" name="pms_is_remote" value="${config['pms_is_remote']}"> class="checkbox-toggle pms-settings" data-id="pms_is_remote" value="1"
${helpers.checked(config['pms_is_remote'])}> Remote Server
<input type="hidden" id="pms_is_remote" name="pms_is_remote"
value="${config['pms_is_remote']}">
</label> </label>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<input type="hidden" id="pms_valid" data-validate="validatePMSip" value="">
<input type="hidden" id="pms_ip" name="pms_ip" value="${config['pms_ip']}"> <input type="hidden" id="pms_ip" name="pms_ip" value="${config['pms_ip']}">
<input type="hidden" id="pms_is_cloud" name="pms_is_cloud" value="${config['pms_is_cloud']}"> </div>
<div class="wizard-card" data-cardname="card4">
<h3>Jellyfin Auth</h3>
<div class="wizard-input-section">
<p class="help-block">
Authentificate with your Jellyfin instance.
</p>
</div>
<div class="wizard-input-section">
<label for="jellyfin_user">Jellyfin Username</label>
<div class="row">
<div class="col-xs-4">
<input type="text" class="form-control pms-settings" name="jellyfin_user"
id="jellyfin_user" value="" required>
</div>
</div>
</div>
<div class="wizard-input-section">
<label for="jellyfin_password">Jellyfin Password</label>
<div class="row">
<div class="col-xs-4">
<input type="password" class="form-control pms-settings" name="jellyfin_password"
id="jellyfin_password" value="" required>
</div>
</div>
</div>
<input type="hidden" id="pms_identifier" name="pms_identifier" value="${config['pms_identifier']}"> <input type="hidden" id="pms_identifier" name="pms_identifier" value="${config['pms_identifier']}">
<a class="btn btn-dark" id="verify-plex-server" href="#" role="button">Verify</a> <a class="btn btn-dark" id="verify-plex-server" href="#" role="button">Verify</a>
<span style="margin-left: 10px; display: none;" id="pms-verify-status"></span> <span style="margin-left: 10px; display: none;" id="pms-verify-status"></span>
</div> </div>
<div class="wizard-card" data-cardname="card4"> <div class="wizard-card" data-cardname="card5">
<h3>Activity Logging</h3> <h3>Activity Logging</h3>
<div class="wizard-input-section"> <div class="wizard-input-section">
<p class="help-block"> <p class="help-block">
@@ -157,38 +192,47 @@
<label for="logging_ignore_interval">Ignore Interval</label> <label for="logging_ignore_interval">Ignore Interval</label>
<div class="row"> <div class="row">
<div class="col-xs-4"> <div class="col-xs-4">
<input type="text" class="form-control pms-monitoring" id="logging_ignore_interval" name="logging_ignore_interval" placeholder="120" value="${config['logging_ignore_interval']}" data-validate="validateIgnoreInterval" required> <input type="text" class="form-control pms-monitoring" id="logging_ignore_interval"
name="logging_ignore_interval" placeholder="120"
value="${config['logging_ignore_interval']}"
data-validate="validateIgnoreInterval" required>
</div> </div>
<span style="margin-left: 10px; line-height: 35px; display: none;" id="ignore-int-status"></span> <span style="margin-left: 10px; line-height: 35px; display: none;"
id="ignore-int-status"></span>
</div> </div>
<p class="help-block">The interval (in seconds) an item must be in a playing state before logging it. 0 to disable.</p> <p class="help-block">The interval (in seconds) an item must be in a playing state before
logging it. 0 to disable.</p>
</div> </div>
<div class="wizard-input-section"> <div class="wizard-input-section">
<p class="help-block"> <p class="help-block">
Additional options to disable history logging for certain libraries or users can be found by editing them Additional options to disable history logging for certain libraries or users can be found by
editing them
on the <strong>Libraries</strong> or <strong>Users</strong> pages. on the <strong>Libraries</strong> or <strong>Users</strong> pages.
</p> </p>
</div> </div>
</div> </div>
<div class="wizard-card" data-cardname="card5"> <div class="wizard-card" data-cardname="card6">
<h3>Notifications</h3> <h3>Notifications</h3>
<div class="wizard-input-section"> <div class="wizard-input-section">
<p class="help-block"> <p class="help-block">
Tautulli can send a wide variety of notifications to alert you of activity on your Plex server. Tautulli can send a wide variety of notifications to alert you of activity on your Plex
server.
</p> </p>
<p class="help-block"> <p class="help-block">
To set up a notification agent, navigate to the <strong>Settings</strong> page To set up a notification agent, navigate to the <strong>Settings</strong> page
and to the <strong>Notification Agents</strong> tab after you have completed this setup wizard. and to the <strong>Notification Agents</strong> tab after you have completed this setup
wizard.
</p> </p>
</div> </div>
</div> </div>
<div class="wizard-card" data-cardname="card6"> <div class="wizard-card" data-cardname="card7">
<h3>Database Import</h3> <h3>Database Import</h3>
<div class="wizard-input-section"> <div class="wizard-input-section">
<p class="help-block"> <p class="help-block">
If you have an existing Tautulli, PlexWatch, or Plexivity database, you can import the data into Tautulli. If you have an existing Tautulli, PlexWatch, or Plexivity database, you can import the data
into Tautulli.
</p> </p>
<p class="help-block"> <p class="help-block">
To import a database, navigate to the <strong>Settings</strong> page To import a database, navigate to the <strong>Settings</strong> page
@@ -200,18 +244,23 @@
<div style="display: none;"> <div style="display: none;">
<input type="checkbox" name="first_run" id="first_run" value="1" checked> <input type="checkbox" name="first_run" id="first_run" value="1" checked>
<input type="checkbox" name="group_history_tables" id="group_history_tables" value="1" checked> <input type="checkbox" name="group_history_tables" id="group_history_tables" value="1" checked>
<input type="checkbox" name="history_table_activity" id="history_table_activity" value="1" checked> <input type="checkbox" name="history_table_activity" id="history_table_activity" value="1"
checked>
<input type="checkbox" name="sys_tray_icon" id="sys_tray_icon" value="1" checked> <input type="checkbox" name="sys_tray_icon" id="sys_tray_icon" value="1" checked>
<input type="checkbox" name="launch_startup" id="launch_startup" value="1" checked> <input type="checkbox" name="launch_startup" id="launch_startup" value="1" checked>
<input type="checkbox" name="launch_browser" id="launch_browser" value="1" checked> <input type="checkbox" name="launch_browser" id="launch_browser" value="1" checked>
<input type="checkbox" name="api_enabled" id="api_enabled" value="1" checked> <input type="checkbox" name="api_enabled" id="api_enabled" value="1" checked>
<input type="checkbox" name="refresh_users_on_startup" id="refresh_users_on_startup" value="1" checked> <input type="checkbox" name="refresh_users_on_startup" id="refresh_users_on_startup" value="1"
<input type="checkbox" name="refresh_libraries_on_startup" id="refresh_libraries_on_startup" value="1" checked> checked>
<input type="checkbox" name="refresh_libraries_on_startup" id="refresh_libraries_on_startup"
value="1" checked>
<input type="checkbox" name="check_github" id="check_github" value="1" checked> <input type="checkbox" name="check_github" id="check_github" value="1" checked>
<input type="checkbox" name="log_blacklist" id="log_blacklist" value="1" checked> <input type="checkbox" name="log_blacklist" id="log_blacklist" value="1" checked>
<input type="checkbox" name="cache_images" id="cache_images" value="1" checked> <input type="checkbox" name="cache_images" id="cache_images" value="1" checked>
<input type="checkbox" name="notify_group_recently_added_grandparent" id="notify_group_recently_added_grandparent" value="1" checked> <input type="checkbox" name="notify_group_recently_added_grandparent"
<input type="checkbox" name="notify_group_recently_added_parent" id="notify_group_recently_added_parent" value="1" checked> id="notify_group_recently_added_grandparent" value="1" checked>
<input type="checkbox" name="notify_group_recently_added_parent"
id="notify_group_recently_added_parent" value="1" checked>
<input type="checkbox" name="server_changed" id="server_changed" value="1" checked> <input type="checkbox" name="server_changed" id="server_changed" value="1" checked>
<input type="checkbox" name="first_run_complete" id="first_run_complete" value="1" checked> <input type="checkbox" name="first_run_complete" id="first_run_complete" value="1" checked>
<input type="text" name="home_stats_cards" id="home_stats_cards" value="first_run_wizard"> <input type="text" name="home_stats_cards" id="home_stats_cards" value="first_run_wizard">
@@ -224,9 +273,11 @@
<div class="wizard-success"> <div class="wizard-success">
<h3>Setup Complete!</h3> <h3>Setup Complete!</h3>
<br/> <br/>
<p>Setup is now complete. For more configuration options please visit the Settings menu on the home page.</p> <p>Setup is now complete. For more configuration options please visit the Settings menu on the home
page.</p>
<br/> <br/>
<i class="fa fa-refresh fa-spin"></i>&nbspWaiting <span class="countdown">5</span> seconds to ensure authentication token is registered... <i class="fa fa-refresh fa-spin"></i>&nbspWaiting <span class="countdown">5</span> seconds to ensure
authentication token is registered...
</div> </div>
</div> </div>
@@ -243,7 +294,6 @@
function validateAuthentication(el) { function validateAuthentication(el) {
var http_username = $("#http_username").val(); var http_username = $("#http_username").val();
var http_password = $("#http_password").val(); var http_password = $("#http_password").val();
var valid_authentication = el.val();
var retValue = {}; var retValue = {};
if (http_username === "" || http_password === "") { if (http_username === "" || http_password === "") {
@@ -310,13 +360,13 @@
return $.isNumeric(n) && (Math.floor(n) == n) && (n >= 0) return $.isNumeric(n) && (Math.floor(n) == n) && (n >= 0)
} }
$(document).ready(function() { $(document).ready(function () {
$.fn.wizard.logging = false; $.fn.wizard.logging = false;
var options = { var options = {
keyboard : false, keyboard: false,
contentHeight : 450, contentHeight: 450,
contentWidth : 700, contentWidth: 700,
backdrop: 'static', backdrop: 'static',
buttons: {submitText: 'Finish'}, buttons: {submitText: 'Finish'},
submitUrl: "configUpdate" submitUrl: "configUpdate"
@@ -326,14 +376,14 @@ $(document).ready(function() {
// Change button classes // Change button classes
wizard.find('.wizard-back').addClass('btn-dark'); wizard.find('.wizard-back').addClass('btn-dark');
wizard.on('incrementCard', function(wizard) { wizard.on('incrementCard', function (wizard) {
wizard.find('.wizard-next.btn-success').removeClass('btn-success').addClass('btn-bright'); wizard.find('.wizard-next.btn-success').removeClass('btn-success').addClass('btn-bright');
}); });
wizard.on('decrementCard', function(wizard) { wizard.on('decrementCard', function (wizard) {
wizard.find('.wizard-next').removeClass('btn-bright').text('Next'); wizard.find('.wizard-next').removeClass('btn-bright').text('Next');
}); });
wizard.on("submit", function(wizard) { wizard.on("submit", function (wizard) {
// Probably should not success before we know, but hopefully validation is good enough. // Probably should not success before we know, but hopefully validation is good enough.
wizard.submitSuccess(); wizard.submitSuccess();
$.ajax({ $.ajax({
@@ -342,7 +392,9 @@ $(document).ready(function() {
data: wizard.serialize(), data: wizard.serialize(),
dataType: "json", dataType: "json",
complete: function (data) { complete: function (data) {
$(".countdown").countdown(function () { location.reload(); }, 5, ""); $(".countdown").countdown(function () {
location.reload();
}, 5, "");
} }
}) })
}); });
@@ -350,9 +402,9 @@ $(document).ready(function() {
$('.checkbox-toggle').click(function () { $('.checkbox-toggle').click(function () {
var configToggle = $(this).data('id'); var configToggle = $(this).data('id');
if ($(this).is(':checked')) { if ($(this).is(':checked')) {
$('#'+configToggle).val(1); $('#' + configToggle).val(1);
} else { } else {
$('#'+configToggle).val(0); $('#' + configToggle).val(0);
} }
}); });
@@ -400,7 +452,7 @@ $(document).ready(function() {
'</div>'; '</div>';
} }
}, },
create: function(input) { create: function (input) {
return {label: '', value: input}; return {label: '', value: input};
}, },
onInitialize: function () { onInitialize: function () {
@@ -416,7 +468,6 @@ $(document).ready(function() {
var port = $(pms_ip_selected).data('port'); var port = $(pms_ip_selected).data('port');
var local = $(pms_ip_selected).data('local'); var local = $(pms_ip_selected).data('local');
var ssl = $(pms_ip_selected).data('ssl'); var ssl = $(pms_ip_selected).data('ssl');
var is_cloud = $(pms_ip_selected).data('is_cloud');
var value = $(pms_ip_selected).data('value'); var value = $(pms_ip_selected).data('value');
$("#pms_valid").val(identifier !== 'undefined' ? 'valid' : ''); $("#pms_valid").val(identifier !== 'undefined' ? 'valid' : '');
@@ -424,24 +475,18 @@ $(document).ready(function() {
$("#pms_identifier").val(identifier !== 'undefined' ? identifier : ''); $("#pms_identifier").val(identifier !== 'undefined' ? identifier : '');
$('#pms_ip').val(ip !== 'undefined' ? ip : value); $('#pms_ip').val(ip !== 'undefined' ? ip : value);
$('#pms_port').val(port !== 'undefined' ? port : 32400); $('#pms_port').val(port !== 'undefined' ? port : 8096);
$('#pms_is_remote_checkbox').prop('checked', (local !== 'undefined' && local === 0)); $('#pms_is_remote_checkbox').prop('checked', (local !== 'undefined' && local === 0));
$('#pms_is_remote').val(local !== 'undefined' && local === 0 ? 1 : 0); $('#pms_is_remote').val(local !== 'undefined' && local === 0 ? 1 : 0);
$('#pms_ssl_checkbox').prop('checked', (ssl !== 'undefined' && ssl === 1)); $('#pms_ssl_checkbox').prop('checked', (ssl !== 'undefined' && ssl === 1));
$('#pms_ssl').val(ssl !== 'undefined' && ssl === 1 ? 1 : 0); $('#pms_ssl').val(ssl !== 'undefined' && ssl === 1 ? 1 : 0);
$('#pms_is_cloud').val(is_cloud !== 'undefined' && is_cloud === true ? 1 : 0);
if (is_cloud === true) {
$('#pms_port').prop('readonly', true);
$('#pms_is_remote_checkbox').prop('disabled', true);
$('#pms_ssl_checkbox').prop('disabled', true);
} else {
$('#pms_port').prop('readonly', false); $('#pms_port').prop('readonly', false);
$('#pms_is_remote_checkbox').prop('disabled', false); $('#pms_is_remote_checkbox').prop('disabled', false);
$('#pms_ssl_checkbox').prop('disabled', false); $('#pms_ssl_checkbox').prop('disabled', false);
}
}, },
onDropdownOpen: function() { onDropdownOpen: function () {
this.clear(); this.clear();
} }
}); });
@@ -469,6 +514,7 @@ $(document).ready(function() {
} }
}) })
} }
var pms_verified = false; var pms_verified = false;
var authenticated = false; var authenticated = false;
@@ -498,7 +544,7 @@ $(document).ready(function() {
$("#pms-verify-status").html('<i class="fa fa-exclamation-circle"></i>&nbsp; Error verifying server: ' + textStatus); $("#pms-verify-status").html('<i class="fa fa-exclamation-circle"></i>&nbsp; Error verifying server: ' + textStatus);
$('#pms-verify-status').fadeIn('fast'); $('#pms-verify-status').fadeIn('fast');
}, },
success: function(xhr, status) { success: function (xhr, status) {
var result = xhr; var result = xhr;
var identifier = result.identifier; var identifier = result.identifier;
if (identifier) { if (identifier) {
@@ -520,30 +566,12 @@ $(document).ready(function() {
} }
}); });
$( ".pms-settings" ).change(function() { $(".pms-settings").change(function () {
pms_verified = false; pms_verified = false;
$("#pms_valid").val(""); $("#pms_valid").val("");
$("#pms-verify-status").html(""); $("#pms-verify-status").html("");
}); });
function OAuthPreFunction() {
$("#pms_token").val('');
$("#pms-token-status").html('<i class="fa fa-refresh fa-spin"></i>&nbsp; Waiting for authentication...').fadeIn('fast');
}
function OAuthSuccessCallback(authToken) {
$("#pms_token").val(authToken);
$("#pms-token-status").html('<i class="fa fa-check"></i>&nbsp; Authentication successful.').fadeIn('fast');
authenticated = true;
getServerOptions(authToken);
}
function OAuthErrorCallback() {
$("#pms-token-status").html('<i class="fa fa-exclamation-circle"></i>&nbsp; Error communicating with Plex.tv.').fadeIn('fast');
}
$('#sign-in-plex').click(function() {
PlexOAuth(OAuthSuccessCallback, OAuthErrorCallback, OAuthPreFunction);
}); });
});
</script> </script>
</body> </body>

View File

@@ -15,11 +15,9 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>. # along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
import json
from itertools import groupby from itertools import groupby
import jellypy import jellypy
from jellypy import common from jellypy import common
from jellypy import database from jellypy import database
from jellypy import datatables from jellypy import datatables

View File

@@ -37,15 +37,11 @@ from urllib.parse import urlencode
from xml.dom import minidom from xml.dom import minidom
import arrow import arrow
import cloudinary
import ipwhois import ipwhois
import ipwhois.exceptions import ipwhois.exceptions
import ipwhois.utils import ipwhois.utils
import xmltodict import xmltodict
from IPy import IP from IPy import IP
from cloudinary.api import delete_resources_by_tag
from cloudinary.uploader import upload
from cloudinary.utils import cloudinary_url
import jellypy import jellypy
from jellypy import common from jellypy import common
@@ -795,110 +791,6 @@ def delete_from_imgur(delete_hash, img_title='', fallback=''):
return False return False
def upload_to_cloudinary(img_data, img_title='', rating_key='', fallback=''):
""" Uploads an image to Cloudinary """
img_url = ''
if not jellypy.CONFIG.CLOUDINARY_CLOUD_NAME or not jellypy.CONFIG.CLOUDINARY_API_KEY or not jellypy.CONFIG.CLOUDINARY_API_SECRET:
logger.error(
"Tautulli Helpers :: Cannot upload image to Cloudinary. Cloudinary settings not specified in the settings.")
return img_url
cloudinary.config(
cloud_name=jellypy.CONFIG.CLOUDINARY_CLOUD_NAME,
api_key=jellypy.CONFIG.CLOUDINARY_API_KEY,
api_secret=jellypy.CONFIG.CLOUDINARY_API_SECRET
)
# Cloudinary library has very poor support for non-ASCII characters on Python 2
if jellypy.PYTHON2:
_img_title = latinToAscii(img_title, replace=True)
else:
_img_title = img_title
try:
response = upload((img_title, img_data),
public_id='{}_{}'.format(fallback, rating_key),
tags=['tautulli', fallback, str(rating_key)],
context={'title': _img_title, 'rating_key': str(rating_key), 'fallback': fallback})
logger.debug("Tautulli Helpers :: Image '{}' ({}) uploaded to Cloudinary.".format(img_title, fallback))
img_url = response.get('url', '')
except Exception as e:
logger.error(
"Tautulli Helpers :: Unable to upload image '{}' ({}) to Cloudinary: {}".format(img_title, fallback, e))
return img_url
def delete_from_cloudinary(rating_key=None, delete_all=False):
""" Deletes an image from Cloudinary """
if not jellypy.CONFIG.CLOUDINARY_CLOUD_NAME or not jellypy.CONFIG.CLOUDINARY_API_KEY or not jellypy.CONFIG.CLOUDINARY_API_SECRET:
logger.error(
"Tautulli Helpers :: Cannot delete image from Cloudinary. Cloudinary settings not specified in the settings.")
return False
cloudinary.config(
cloud_name=jellypy.CONFIG.CLOUDINARY_CLOUD_NAME,
api_key=jellypy.CONFIG.CLOUDINARY_API_KEY,
api_secret=jellypy.CONFIG.CLOUDINARY_API_SECRET
)
if delete_all:
delete_resources_by_tag('tautulli')
logger.debug("Tautulli Helpers :: Deleted all images from Cloudinary.")
elif rating_key:
delete_resources_by_tag(str(rating_key))
logger.debug("Tautulli Helpers :: Deleted images from Cloudinary with rating_key {}.".format(rating_key))
else:
logger.debug("Tautulli Helpers :: Unable to delete images from Cloudinary: No rating_key provided.")
return True
def cloudinary_transform(rating_key=None, width=1000, height=1500, opacity=100, background='000000', blur=0,
img_format='png', img_title='', fallback=None):
url = ''
if not jellypy.CONFIG.CLOUDINARY_CLOUD_NAME or not jellypy.CONFIG.CLOUDINARY_API_KEY or not jellypy.CONFIG.CLOUDINARY_API_SECRET:
logger.error(
"Tautulli Helpers :: Cannot transform image on Cloudinary. Cloudinary settings not specified in the settings.")
return url
cloudinary.config(
cloud_name=jellypy.CONFIG.CLOUDINARY_CLOUD_NAME,
api_key=jellypy.CONFIG.CLOUDINARY_API_KEY,
api_secret=jellypy.CONFIG.CLOUDINARY_API_SECRET
)
img_options = {'format': img_format,
'fetch_format': 'auto',
'quality': 'auto',
'version': timestamp(),
'secure': True}
if width != 1000:
img_options['width'] = str(width)
img_options['crop'] = 'fill'
if height != 1500:
img_options['height'] = str(height)
img_options['crop'] = 'fill'
if opacity != 100:
img_options['opacity'] = opacity
if background != '000000':
img_options['background'] = 'rgb:{}'.format(background)
if blur != 0:
img_options['effect'] = 'blur:{}'.format(blur * 100)
try:
url, options = cloudinary_url('{}_{}'.format(fallback, rating_key), **img_options)
logger.debug("Tautulli Helpers :: Image '{}' ({}) transformed on Cloudinary.".format(img_title, fallback))
except Exception as e:
logger.error(
"Tautulli Helpers :: Unable to transform image '{}' ({}) on Cloudinary: {}".format(img_title, fallback, e))
return url
def cache_image(url, image=None): def cache_image(url, image=None):
""" """
Saves an image to the cache directory. Saves an image to the cache directory.

View File

@@ -19,7 +19,7 @@ from jellyfin_apiclient_python import JellyfinClient
class Jellyfin(object): class Jellyfin(object):
def __init__(self, url, token): def __init__(self, url, token=None):
self.jf = JellyfinClient() self.jf = JellyfinClient()
def get_library(self, section_id): def get_library(self, section_id):
@@ -30,3 +30,6 @@ class Jellyfin(object):
def get_item(self, rating_key): def get_item(self, rating_key):
return self.jf.fetchItem(rating_key) return self.jf.fetchItem(rating_key)
def login(self, user, password):
pass