Jellyfin Login ✓

This commit is contained in:
2021-02-06 18:41:24 +01:00
parent 6e1067e43e
commit 3852275b74
5 changed files with 85 additions and 117 deletions

View File

@@ -19,10 +19,10 @@ not well documented (read as: not documented at all).
## Major Differences compared to Tautulli ## Major Differences compared to Tautulli
* No Plex/PMS Support * Dropped Plex/PMS Support
* Removed Google Analytics * Dropped Google Analytics
* Removed Python2 support * Dropped Python2 support
* Removed import feature from varius abondonded projects * Dropped import from varius abondonded projects
## Installation & Support ## Installation & Support

View File

@@ -176,8 +176,7 @@ from jellypy import common, helpers
</div> </div>
</div> </div>
</div> </div>
<input type="hidden" id="jellyfin_identifier" name="jellyfin_identifier" value="${config['jellyfin_identifier']}"> <a class="btn btn-dark" id="verify-jellyfin-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="jellyfin-verify-status"></span> <span style="margin-left: 10px; display: none;" id="jellyfin-verify-status"></span>
</div> </div>
@@ -185,7 +184,7 @@ from jellypy import common, helpers
<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">
Tautulli will keep a history of all streaming activity on your Plex server. JellyPy will keep a history of all streaming activity on your Jellyfin server.
</p> </p>
</div> </div>
<div class="wizard-input-section"> <div class="wizard-input-section">
@@ -216,7 +215,7 @@ from jellypy import common, helpers
<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 JellyPy can send a wide variety of notifications to alert you of activity on your Jellyfin
server. server.
</p> </p>
<p class="help-block"> <p class="help-block">
@@ -225,20 +224,6 @@ from jellypy import common, helpers
wizard. wizard.
</p> </p>
</div> </div>
</div>
<div class="wizard-card" data-cardname="card7">
<h3>Database Import</h3>
<div class="wizard-input-section">
<p class="help-block">
If you have an existing Tautulli, PlexWatch, or Plexivity database, you can import the data
into Tautulli.
</p>
<p class="help-block">
To import a database, navigate to the <strong>Settings</strong> page
and to the <strong>Import & Backups</strong> tab after you have completed this setup wizard.
</p>
</div>
<!-- Required fields but hidden --> <!-- Required fields but hidden -->
<div style="display: none;"> <div style="display: none;">
@@ -266,7 +251,6 @@ from jellypy import common, helpers
<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">
<input type="text" name="home_library_cards" id="home_library_cards" value="first_run_wizard"> <input type="text" name="home_library_cards" id="home_library_cards" value="first_run_wizard">
</div> </div>
</div> </div>
</form> </form>
@@ -308,7 +292,7 @@ from jellypy import common, helpers
return retValue; return retValue;
} }
function validatejellyfinip(el) { function validateJellyfinIp(el) {
var valid_jellyfin_ip = el.val(); var valid_jellyfin_ip = el.val();
var retValue = {}; var retValue = {};
@@ -324,7 +308,7 @@ from jellypy import common, helpers
return retValue; return retValue;
} }
function validatejellyfintoken(el) { function validateJellyfinToken(el) {
var valid_jellyfin_token = el.val(); var valid_jellyfin_token = el.val();
var retValue = {}; var retValue = {};
@@ -518,24 +502,27 @@ from jellypy import common, helpers
var jellyfin_verified = false; var jellyfin_verified = false;
var authenticated = false; var authenticated = false;
$("#verify-plex-server").click(function () { $("#verify-jellyfin-server").click(function () {
if (!(jellyfin_verified)) { if (!(jellyfin_verified)) {
var jellyfin_ip = $("#jellyfin_ip").val().trim(); var jellyfin_ip = $("#jellyfin_ip").val().trim();
var jellyfin_port = $("#jellyfin_port").val().trim(); var jellyfin_port = $("#jellyfin_port").val().trim();
var jellyfin_identifier = $("#jellyfin_identifier").val();
var jellyfin_ssl = $("#jellyfin_ssl").val(); var jellyfin_ssl = $("#jellyfin_ssl").val();
var jellyfin_is_remote = $("#jellyfin_is_remote").val(); var jellyfin_is_remote = $("#jellyfin_is_remote").val();
var jellyfin_user = $("#jellyfin_user").val().trim();
var jellyfin_password = $("#jellyfin_password").val();
if ((jellyfin_ip !== '') || (jellyfin_port !== '')) { if ((jellyfin_ip !== '') || (jellyfin_port !== '')) {
$("#jellyfin-verify-status").html('<i class="fa fa-refresh fa-spin"></i>&nbsp; Verifying server...'); $("#jellyfin-verify-status").html('<i class="fa fa-refresh fa-spin"></i>&nbsp; Verifying server...');
$('#jellyfin-verify-status').fadeIn('fast'); $('#jellyfin-verify-status').fadeIn('fast');
$.ajax({ $.ajax({
url: 'get_server_id', url: 'check_login',
data: { data: {
hostname: jellyfin_ip, hostname: jellyfin_ip,
port: jellyfin_port, port: jellyfin_port,
identifier: jellyfin_identifier,
ssl: jellyfin_ssl, ssl: jellyfin_ssl,
remote: jellyfin_is_remote remote: jellyfin_is_remote,
user: jellyfin_user,
password: jellyfin_password
}, },
cache: true, cache: true,
async: true, async: true,
@@ -549,12 +536,12 @@ from jellypy import common, helpers
var identifier = result.identifier; var identifier = result.identifier;
if (identifier) { if (identifier) {
$("#jellyfin_identifier").val(identifier); $("#jellyfin_identifier").val(identifier);
$("#jellyfin-verify-status").html('<i class="fa fa-check"></i>&nbsp; Server found!'); $("#jellyfin-verify-status").html('<i class="fa fa-check"></i>&nbsp; Login successfull!');
$('#jellyfin-verify-status').fadeIn('fast'); $('#jellyfin-verify-status').fadeIn('fast');
jellyfin_verified = true; jellyfin_verified = true;
$("#jellyfin_valid").val("valid"); $("#jellyfin_valid").val("valid");
} else { } else {
$("#jellyfin-verify-status").html('<i class="fa fa-exclamation-circle"></i>&nbsp; This is not a Plex Server!'); $("#jellyfin-verify-status").html('<i class="fa fa-exclamation-circle"></i>&nbsp; This is not a Jellyfin Server!');
$('#jellyfin-verify-status').fadeIn('fast'); $('#jellyfin-verify-status').fadeIn('fast');
} }
} }

View File

@@ -653,19 +653,6 @@ def is_public_ip(host):
return False return False
def get_ip(host):
ip_address = ''
if is_valid_ip(host):
return host
elif not re.match(r'^[0-9]+(?:\.[0-9]+){3}(?!\d*-[a-z0-9]{6})$', host):
try:
ip_address = socket.getaddrinfo(host, None)[0][4][0]
logger.debug("IP Checker :: Resolved %s to %s." % (host, ip_address))
except:
logger.error("IP Checker :: Bad IP or hostname provided: %s." % host)
return ip_address
def is_valid_ip(address): def is_valid_ip(address):
try: try:
return IP(address) return IP(address)

View File

@@ -35,11 +35,13 @@ class Jellyfin(object):
PRODUCT, RELEASE, PRODUCT, jellypy.CONFIG.JELLYFIN_CLIENT_UUID PRODUCT, RELEASE, PRODUCT, jellypy.CONFIG.JELLYFIN_CLIENT_UUID
) )
self.jf.config.data["http.user_agent"] = PRODUCT self.jf.config.data["http.user_agent"] = PRODUCT
self.jf.config.data["auth.ssl"] = not jellypy.CONFIG.JELLYFIN_SSL self.jf.config.data["auth.ssl"] = jellypy.CONFIG.JELLYFIN_SSL
self.url = url self.url = url
self.id = None
self.token = token
if token: if self.token:
self.login(token=token) self.login()
def get_library(self, section_id): def get_library(self, section_id):
return self.jf.library.sectionByID(str(section_id)) return self.jf.library.sectionByID(str(section_id))
@@ -50,22 +52,23 @@ 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=None, password=None, token=None) -> bool: def login(self, user=None, password=None) -> bool:
if user and password: if user and password and self.url:
self.jf.auth.connect_to_address(self.url) self.jf.auth.connect_to_address(self.url)
result = self.jf.auth.login(self.url, user, password) result = self.jf.auth.login(self.url, user, password)
if "AccessToken" in result: if "AccessToken" in result:
credentials = self.jf.auth.credentials.get_credentials() credentials = self.jf.auth.credentials.get_credentials()
pprint.pprint(credentials) pprint.pprint(credentials)
server = credentials["Servers"][0] self.id = credentials["Servers"][0]["Id"]
server["uuid"] = server["Id"]
server["username"] = user
# jellypy.CONFIG.JELLYFIN_TOKEN = # jellypy.CONFIG.JELLYFIN_TOKEN =
# #
# self._connect_client(server) # self._connect_client(server)
# self.credentials.append(server) # self.credentials.append(server)
# self.save_credentials() # self.save_credentials()
return True return True
return False if self.token and self.url:
# TODO: Add token auth
pass
return False

View File

@@ -20,6 +20,7 @@ import csv
import json import json
import linecache import linecache
import os import os
import re
import shutil import shutil
import sys import sys
import threading import threading
@@ -30,7 +31,6 @@ from urllib.parse import urlencode
import cherrypy import cherrypy
import mako.exceptions import mako.exceptions
import mako.template import mako.template
import websocket
from cherrypy import NotFound from cherrypy import NotFound
from cherrypy.lib.static import serve_file, serve_fileobj, serve_download from cherrypy.lib.static import serve_file, serve_fileobj, serve_download
from mako.lookup import TemplateLookup from mako.lookup import TemplateLookup
@@ -57,6 +57,7 @@ from jellypy import versioncheck
from jellypy import webstart from jellypy import webstart
from jellypy.api2 import API2 from jellypy.api2 import API2
from jellypy.helpers import checked, addtoapi, create_https_certificates, build_datatables_json, sanitize_out from jellypy.helpers import checked, addtoapi, create_https_certificates, build_datatables_json, sanitize_out
from jellypy.jellyfin import Jellyfin
from jellypy.password import make_hash from jellypy.password import make_hash
from jellypy.session import get_session_info, get_session_user_id, allow_session_user, allow_session_library from jellypy.session import get_session_info, get_session_user_id, allow_session_user, allow_session_library
from jellypy.webauth import AuthController, requireAuth, member_of, check_auth from jellypy.webauth import AuthController, requireAuth, member_of, check_auth
@@ -4035,14 +4036,16 @@ class WebInterface(object):
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
@addtoapi() @addtoapi()
def get_server_id(self, hostname=None, port=None, identifier=None, ssl=0, remote=0, manual=0, def check_login(self, hostname=None, port=None, ssl=0, remote=0, manual=0, user=None, password=None,
get_url=False, test_websocket=False, **kwargs): get_url=False, test_websocket=False, **kwargs):
""" Get the JELLYFIN server identifier. """ Try Jellyfin Login.
``` ```
Required parameters: Required parameters:
hostname (str): 'localhost' or '192.160.0.10' hostname (str): 'localhost' or '192.160.0.10'
port (int): 32400 port (int): 8096
user (str): Jellyfin user
password (str): Jellyfin password
Optional parameters: Optional parameters:
ssl (int): 0 or 1 ssl (int): 0 or 1
@@ -4054,66 +4057,54 @@ class WebInterface(object):
``` ```
""" """
# Attempt to get the pms_identifier from plex.tv if the server is published # Attempt to get the pms_identifier from plex.tv if the server is published
# Works for all JELLYFIN SSL settings # Works for all Jellyfin SSL settings
if not identifier and hostname and port: result = {"identifier": None}
pass if hostname and port and user and password:
# TODO: Jellyfin path_regex = re.compile("^(https?://)?([^/:]+)(:[0-9]+)?(/.*)?$")
# plex_tv = plextv.PlexTV()
# servers = plex_tv.discover() protocol, host, port, path = path_regex.match(hostname + ":" + port).groups()
# ip_address = get_ip(hostname)
if not protocol:
protocol = "http://"
if protocol == "http://" and not port:
port = "8096"
server = "".join(filter(bool, (protocol, host, port, path)))
jf = Jellyfin(server)
if jf.login(user, password):
result = {'identifier': jf.id}
# if identifier:
# if helpers.bool_true(get_url):
# server = self.get_server_resources(jellyfin_ip=hostname,
# jellyfin_port=port,
# jellyfin_ssl=ssl,
# jellyfin_is_remote=remote,
# jellyfin_url_manual=manual,
# jellyfin_identifier=identifier)
# result['url'] = server['jellyfin_url']
# result['ws'] = None
# #
# for server in servers: # if helpers.bool_true(test_websocket):
# if (server['ip'] == hostname or server['ip'] == ip_address) and server['port'] == port: # # Quick test websocket connection
# identifier = server['clientIdentifier'] # ws_url = result['url'].replace('http', 'ws', 1) + '/:/websockets/notifications'
# break # header = ['X-Plex-Token: %s' % jellypy.CONFIG.JELLYFIN_TOKEN]
# #
# # Fallback to checking /identity endpoint if the server is unpublished # logger.debug("Testing websocket connection...")
# # Cannot set SSL settings on the JELLYFIN if unpublished so 'http' is okay # try:
# if not identifier: # test_ws = websocket.create_connection(ws_url, header=header)
# scheme = 'https' if helpers.cast_to_int(ssl) else 'http' # test_ws.close()
# url = '{scheme}://{hostname}:{port}'.format(scheme=scheme, hostname=hostname, port=port) # logger.debug("Websocket connection test successful.")
# uri = '/identity' # result['ws'] = True
# # except (websocket.WebSocketException, IOError, Exception) as e:
# request_handler = http_handler.HTTPHandler(urls=url, # logger.error("Websocket connection test failed: %s" % e)
# ssl_verify=False) # result['ws'] = False
# request = request_handler.make_request(uri=uri,
# request_type='GET',
# output_format='xml')
# if request:
# xml_head = request.getElementsByTagName('MediaContainer')[0]
# identifier = xml_head.getAttribute('machineIdentifier')
result = {'identifier': identifier}
if identifier:
if helpers.bool_true(get_url):
server = self.get_server_resources(jellyfin_ip=hostname,
jellyfin_port=port,
jellyfin_ssl=ssl,
jellyfin_is_remote=remote,
jellyfin_url_manual=manual,
jellyfin_identifier=identifier)
result['url'] = server['jellyfin_url']
result['ws'] = None
if helpers.bool_true(test_websocket):
# Quick test websocket connection
ws_url = result['url'].replace('http', 'ws', 1) + '/:/websockets/notifications'
header = ['X-Plex-Token: %s' % jellypy.CONFIG.JELLYFIN_TOKEN]
logger.debug("Testing websocket connection...")
try:
test_ws = websocket.create_connection(ws_url, header=header)
test_ws.close()
logger.debug("Websocket connection test successful.")
result['ws'] = True
except (websocket.WebSocketException, IOError, Exception) as e:
logger.error("Websocket connection test failed: %s" % e)
result['ws'] = False
return result return result
else: else:
logger.warn('Unable to retrieve the JELLYFIN identifier.') logger.warn('Unable to retrieve the Jellyfin identifier.')
return result return result
@cherrypy.expose @cherrypy.expose
@@ -4480,8 +4471,8 @@ class WebInterface(object):
@addtoapi('jellyfin_image_proxy') @addtoapi('jellyfin_image_proxy')
def real_jellyfin_image_proxy(self, img=None, rating_key=None, width=750, height=1000, def real_jellyfin_image_proxy(self, img=None, rating_key=None, width=750, height=1000,
opacity=100, background='000000', blur=0, img_format='png', opacity=100, background='000000', blur=0, img_format='png',
fallback=None, refresh=False, clip=False, **kwargs): fallback=None, refresh=False, clip=False, **kwargs):
""" Gets an image from the JELLYFIN and saves it to the image cache directory. """ Gets an image from the JELLYFIN and saves it to the image cache directory.
``` ```