buttons to configure plex or view the current configuration

pull/342/head
elmerohueso 4 weeks ago
parent 919cd1a2b2
commit 6344f250fc

@ -0,0 +1,104 @@
#!/usr/bin/env python3
"""
Test script to authenticate with Plex using PIN-based login.
This mimics the app's /api/plex/pin/start and /api/plex/pin/status flows.
"""
import sys
import time
import traceback
from plexapi.myplex import MyPlexAccount, MyPlexPinLogin
def main():
print('Starting Plex PIN login flow...')
try:
pinlogin = MyPlexPinLogin(oauth=False)
except Exception as exc:
print(f'Failed to create MyPlexPinLogin: {exc}', file=sys.stderr)
traceback.print_exc()
return 1
pin = getattr(pinlogin, 'pin', None)
if not pin:
print('Failed to obtain PIN from Plex', file=sys.stderr)
return 1
print(f'\nPlease go to the following URL in your browser and enter the PIN: {pin}')
print(f' https://plex.tv/link')
print('Then return here and wait for authentication to complete.')
while True:
if getattr(pinlogin, 'expired', False):
print('\nPIN has expired. Please rerun this script to start again.', file=sys.stderr)
return 2
try:
if pinlogin.checkLogin():
token = getattr(pinlogin, 'token', None)
if not token:
print('Login succeeded but no token was returned.', file=sys.stderr)
return 3
print('\nLogin complete!')
print(f'Plex token: {token}')
try:
account = MyPlexAccount(token=token)
except Exception as exc:
print(f'Failed to create MyPlexAccount: {exc}', file=sys.stderr)
traceback.print_exc()
return 4
print(f'Authenticated Plex username: {getattr(account, "username", None)}')
print(f'Authenticated Plex title: {getattr(account, "title", None)}')
print('\nFetching available Plex resources...')
try:
resources = account.resources()
except Exception as exc:
print(f'Failed to fetch resources: {exc}', file=sys.stderr)
traceback.print_exc()
return 5
server_resources = [r for r in resources if 'server' in (getattr(r, 'provides', '') or '')]
if server_resources:
print(f'Found {len(server_resources)} Plex server resource(s):')
for idx, resource in enumerate(server_resources, 1):
print(f'[{idx}] {getattr(resource, "name", None)} ({getattr(resource, "product", None)})')
connections = getattr(resource, 'connections', []) or []
for conn in connections:
uri = getattr(conn, 'uri', None)
local = getattr(conn, 'local', False)
relay = getattr(conn, 'relay', False)
print(f' - {uri} {'(LOCAL)' if local else ''}{' (RELAY)' if relay else ''}')
local_conn = None
for resource in server_resources:
for conn in getattr(resource, 'connections', []) or []:
if getattr(conn, 'local', False):
local_conn = conn
break
if local_conn:
break
if local_conn:
print(f'\nSelected local server URI: {getattr(local_conn, "uri", None)}')
else:
print('\nNo local server connection found. Use one of the above URIs manually.')
else:
print('No Plex server resources were found for this account.')
return 0
print('PIN not yet authorized. Polling again in 5 seconds...')
except Exception as exc:
print(f'Error checking PIN login status: {exc}', file=sys.stderr)
traceback.print_exc()
return 6
time.sleep(5)
if __name__ == '__main__':
sys.exit(main())

@ -4318,26 +4318,35 @@
<!-- Plex Settings -->
<div class="server-config-container" id="plex-container">
<div class="form-group">
<label>Plex Server URL:</label>
<input type="url" id="plex-url" placeholder="http://localhost:32400">
</div>
<div class="form-group">
<label>Plex Token:</label>
<input type="password" id="plex-token" placeholder="X-Plex-Token">
</div>
<div class="form-group" id="plex-library-selector-container" style="display: none;">
<label>Music Library:</label>
<select id="plex-music-library" onchange="selectPlexLibrary()">
<option value="">Loading...</option>
</select>
<small style="color: #999; font-size: 0.9em; display: block; margin-top: 5px;">
Select which music library to use (doesn't affect config file)
</small>
<div id="plex-configuration">
<div class="form-group">
<label>Plex Server URL:</label>
<input type="url" id="plex-url" placeholder="http://localhost:32400">
</div>
<div class="form-group">
<label>Plex Token:</label>
<input type="password" id="plex-token" placeholder="X-Plex-Token">
</div>
<div class="form-group" id="plex-library-selector-container" style="display: none;">
<label>Music Library:</label>
<select id="plex-music-library" onchange="selectPlexLibrary()">
<option value="">Loading...</option>
</select>
<small style="color: #999; font-size: 0.9em; display: block; margin-top: 5px;">
Select which music library to use (doesn't affect config file)
</small>
</div>
<div class="form-actions">
<button class="detect-button" onclick="autoDetectPlex()">Auto-detect</button>
<button class="test-button" onclick="testConnection('plex')">Test</button>
<button class="detect-button" onclick="clearPlexConfiguration()">Clear Configuration</button>
</div>
</div>
<div class="form-actions">
<button class="detect-button" onclick="autoDetectPlex()">Auto-detect</button>
<button class="test-button" onclick="testConnection('plex')">Test</button>
<div id="plex-setup">
<div class="form-actions">
<button id="plex-configure-button" class="detect-button configure-button">Configure</button>
<button id="plex-view-config-button" class="detect-button view-config-button" onclick="showPlexConfiguration()">View Configuration</button>
</div>
</div>
</div>

@ -6026,6 +6026,15 @@ async function loadSettingsData() {
// Populate Plex settings
document.getElementById('plex-url').value = settings.plex?.base_url || '';
document.getElementById('plex-token').value = settings.plex?.token || '';
const hasPlexConfig = Boolean(settings.plex?.base_url || settings.plex?.token);
const plexViewConfigButton = document.getElementById('plex-view-config-button');
const plexConfigureButton = document.getElementById('plex-configure-button');
if (plexViewConfigButton) {
plexViewConfigButton.style.display = hasPlexConfig ? '' : 'none';
}
if (plexConfigureButton) {
plexConfigureButton.style.display = hasPlexConfig ? 'none' : '';
}
// Populate Jellyfin settings
document.getElementById('jellyfin-url').value = settings.jellyfin?.base_url || '';
@ -6416,6 +6425,36 @@ function updateMediaServerFields() {
}
}
function showPlexConfiguration() {
const plexConfig = document.getElementById('plex-configuration');
const plexSetup = document.getElementById('plex-setup');
if (plexConfig) plexConfig.style.display = '';
if (plexSetup) plexSetup.style.display = 'none';
}
function clearPlexConfiguration() {
const plexUrl = document.getElementById('plex-url');
const plexToken = document.getElementById('plex-token');
const plexConfig = document.getElementById('plex-configuration');
const plexSetup = document.getElementById('plex-setup');
const plexViewConfigButton = document.getElementById('plex-view-config-button');
const plexConfigureButton = document.getElementById('plex-configure-button');
if (plexUrl) plexUrl.value = '';
if (plexToken) plexToken.value = '';
if (plexConfig) plexConfig.style.display = 'none';
if (plexSetup) plexSetup.style.display = '';
if (plexViewConfigButton) plexViewConfigButton.style.display = 'none';
if (plexConfigureButton) plexConfigureButton.style.display = '';
if (typeof saveSettings === 'function') {
saveSettings(true);
}
if (typeof showToast === 'function') {
showToast('Plex configuration cleared', 'success');
}
}
function toggleServer(serverType) {
// Update toggle buttons
document.getElementById('plex-toggle').classList.remove('active');
@ -6430,6 +6469,12 @@ function toggleServer(serverType) {
document.getElementById('navidrome-container').classList.toggle('hidden', serverType !== 'navidrome');
document.getElementById('soulsync-container')?.classList.toggle('hidden', serverType !== 'soulsync');
// Show Plex setup when Plex is selected; otherwise hide both Plex panels
const plexConfig = document.getElementById('plex-configuration');
const plexSetup = document.getElementById('plex-setup');
if (plexConfig) plexConfig.style.display = serverType === 'plex' ? 'none' : '';
if (plexSetup) plexSetup.style.display = serverType === 'plex' ? '' : 'none';
// Load Plex music libraries when switching to Plex
if (serverType === 'plex') {
loadPlexMusicLibraries();

Loading…
Cancel
Save