Skip to content

Commit 4de43ea

Browse files
authored
Merge pull request #464 from plexguide/dev
Dev
2 parents dde303a + c36c8e5 commit 4de43ea

File tree

7 files changed

+131
-6
lines changed

7 files changed

+131
-6
lines changed

frontend/static/js/new-main.js

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
* Main JavaScript file for handling UI interactions and API communication
44
*/
55

6+
/**
7+
* Huntarr - New UI Implementation
8+
* Main JavaScript file for handling UI interactions and API communication
9+
*/
10+
611
let huntarrUI = {
712
// Current state
813
eventSources: {},
@@ -2064,6 +2069,38 @@ let huntarrUI = {
20642069
});
20652070
},
20662071

2072+
// Format large numbers with appropriate suffixes (K, MIL, BIL, TRI)
2073+
formatLargeNumber: function(num) {
2074+
if (num < 1000) {
2075+
// 0-999: Display as is
2076+
return num.toString();
2077+
} else if (num < 10000) {
2078+
// 1,000-9,999: Display with single decimal and K (e.g., 5.2K)
2079+
return (num / 1000).toFixed(1) + 'K';
2080+
} else if (num < 100000) {
2081+
// 10,000-99,999: Display with single decimal and K (e.g., 75.4K)
2082+
return (num / 1000).toFixed(1) + 'K';
2083+
} else if (num < 1000000) {
2084+
// 100,000-999,999: Display with K (no decimal) (e.g., 982K)
2085+
return Math.floor(num / 1000) + 'K';
2086+
} else if (num < 10000000) {
2087+
// 1,000,000-9,999,999: Display with single decimal and MIL (e.g., 9.7 MIL)
2088+
return (num / 1000000).toFixed(1) + ' MIL';
2089+
} else if (num < 100000000) {
2090+
// 10,000,000-99,999,999: Display with single decimal and MIL (e.g., 99.7 MIL)
2091+
return (num / 1000000).toFixed(1) + ' MIL';
2092+
} else if (num < 1000000000) {
2093+
// 100,000,000-999,999,999: Display with MIL (no decimal)
2094+
return Math.floor(num / 1000000) + ' MIL';
2095+
} else if (num < 1000000000000) {
2096+
// 1B - 999B: Display with single decimal and BIL
2097+
return (num / 1000000000).toFixed(1) + ' BIL';
2098+
} else {
2099+
// 1T+: Display with TRI
2100+
return (num / 1000000000000).toFixed(1) + ' TRI';
2101+
}
2102+
},
2103+
20672104
animateNumber: function(element, start, end) {
20682105
const duration = 1000; // Animation duration in milliseconds
20692106
const startTime = performance.now();
@@ -2076,12 +2113,15 @@ let huntarrUI = {
20762113
const easeOutQuad = progress * (2 - progress);
20772114

20782115
const currentValue = Math.floor(start + (end - start) * easeOutQuad);
2079-
element.textContent = currentValue;
2116+
2117+
// Format number for display
2118+
element.textContent = this.formatLargeNumber(currentValue);
20802119

20812120
if (progress < 1) {
20822121
requestAnimationFrame(updateNumber);
20832122
} else {
2084-
element.textContent = end; // Ensure we end with the exact target number
2123+
// Ensure we end with the exact formatted target number
2124+
element.textContent = this.formatLargeNumber(end);
20852125
}
20862126
};
20872127

frontend/static/js/settings_forms.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,11 @@ const SettingsForms = {
13211321
<input type="number" id="log_refresh_interval_seconds" min="5" value="${settings.log_refresh_interval_seconds !== undefined ? settings.log_refresh_interval_seconds : 30}">
13221322
<p class="setting-help" style="margin-left: -3ch !important;">How often Huntarr refreshes logs from apps (seconds)</p>
13231323
</div>
1324+
<div class="setting-item">
1325+
<label for="base_url"><a href="https://plexguide.github.io/Huntarr.io/settings/settings.html#base-url" class="info-icon" title="Learn more about reverse proxy base URL settings" target="_blank" rel="noopener"><i class="fas fa-info-circle"></i></a>&nbsp;&nbsp;&nbsp;Base URL:</label>
1326+
<input type="text" id="base_url" value="${settings.base_url || ''}" placeholder="/huntarr">
1327+
<p class="setting-help" style="margin-left: -3ch !important;">Base URL path for reverse proxy (e.g., '/huntarr'). Leave empty for root path. Requires restart.</p>
1328+
</div>
13241329
</div>
13251330
`;
13261331

frontend/static/js/utils.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,21 @@ const HuntarrUtils = {
3131
signal: controller.signal
3232
};
3333

34-
return fetch(url, fetchOptions)
34+
// Process URL to handle base URL for reverse proxy subpaths
35+
let processedUrl = url;
36+
37+
// Only process internal API requests (not external URLs)
38+
if (url && typeof url === 'string' && !url.startsWith('http') && !url.startsWith('//')) {
39+
// Handle base URL from window.HUNTARR_BASE_URL if available
40+
const baseUrl = window.HUNTARR_BASE_URL || '';
41+
if (baseUrl && !url.startsWith(baseUrl)) {
42+
// Ensure path starts with a slash
43+
const normalizedPath = url.startsWith('/') ? url : '/' + url;
44+
processedUrl = baseUrl + normalizedPath;
45+
}
46+
}
47+
48+
return fetch(processedUrl, fetchOptions)
3549
.then(response => {
3650
clearTimeout(timeoutId);
3751
return response;

frontend/templates/components/head.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
<link rel="preload" href="/static/logo/256.png" as="image" fetchpriority="high">
55
<!-- Preload theme script to prevent flashing -->
66
<script src="/static/js/theme-preload.js"></script>
7+
<!-- Pass base URL configuration to JavaScript -->
8+
<script>
9+
// Make base URL available to frontend JavaScript
10+
window.HUNTARR_BASE_URL = '{{ base_url|default("", true) }}';
11+
</script>
712
<link rel="stylesheet" href="/static/css/new-style.css">
813
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
914
<link rel="icon" href="/static/logo/16.png">

src/primary/default_configs/general.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@
1313
"command_wait_attempts": 600,
1414
"minimum_download_queue_size": -1,
1515
"api_timeout": 120,
16-
"ssl_verify": true
16+
"ssl_verify": true,
17+
"base_url": ""
1718
}

src/primary/web_server.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,60 @@
123123
if os.path.exists(template_dir):
124124
print(f"Template dir contents: {os.listdir(template_dir)}")
125125

126+
# Get base_url from settings (used for reverse proxy subpath configurations)
127+
def get_base_url():
128+
"""
129+
Get the configured base URL from general settings.
130+
This allows Huntarr to run under a subpath like /huntarr when behind a reverse proxy.
131+
132+
Returns:
133+
str: The configured base URL (e.g., '/huntarr') or empty string if not configured
134+
"""
135+
try:
136+
base_url = settings_manager.get_setting('general', 'base_url', '')
137+
# Ensure base_url always starts with a / if not empty
138+
if base_url and not base_url.startswith('/'):
139+
base_url = f'/{base_url}'
140+
# Remove trailing slash if present
141+
if base_url and base_url != '/' and base_url.endswith('/'):
142+
base_url = base_url.rstrip('/')
143+
return base_url
144+
except Exception as e:
145+
print(f"Error getting base_url from settings: {e}")
146+
return ''
147+
148+
# Define base_url at module level
149+
base_url = ''
150+
126151
# Create Flask app with additional debug logging
127152
app = Flask(__name__, template_folder=template_dir, static_folder=static_dir)
128153
print(f"Flask app created with template_folder: {app.template_folder}")
129154
print(f"Flask app created with static_folder: {app.static_folder}")
130155

156+
# Get and apply the base URL setting after app is created
157+
try:
158+
base_url = get_base_url()
159+
if base_url:
160+
print(f"Configuring base URL: {base_url}")
161+
app.config['APPLICATION_ROOT'] = base_url
162+
# Flask 1.x compatibility - needed for proper URL generation
163+
if not hasattr(app, 'wsgi_app') or not hasattr(app.wsgi_app, '__call__'):
164+
print("Warning: Unable to configure WSGI middleware for base URL")
165+
else:
166+
# This ensures static files and other routes respect the base URL
167+
from werkzeug.middleware.dispatcher import DispatcherMiddleware
168+
from werkzeug.exceptions import NotFound
169+
app.wsgi_app = DispatcherMiddleware(
170+
NotFound(), # Default 404 app when accessed without base URL
171+
{base_url: app.wsgi_app} # Main app mounted at base URL
172+
)
173+
print(f"WSGI middleware configured for base URL: {base_url}")
174+
else:
175+
print("Running at root URL path (no base URL)")
176+
except Exception as e:
177+
print(f"Error applying base URL setting: {e}")
178+
base_url = '' # Fallback to empty string on error
179+
131180
# Add debug logging for template rendering
132181
def debug_template_rendering():
133182
"""Additional logging for Flask template rendering"""
@@ -198,6 +247,12 @@ def get_source_wrapper(environment, template):
198247
# Register the authentication check to run before requests
199248
app.before_request(authenticate_request)
200249

250+
# Add base_url to template context so it can be used in templates
251+
@app.context_processor
252+
def inject_base_url():
253+
"""Add base_url to template context for use in templates"""
254+
return {'base_url': base_url}
255+
201256
# Removed MAIN_PID and signal-related code
202257

203258
# Lock for accessing the log files
@@ -219,14 +274,19 @@ def get_source_wrapper(environment, template):
219274

220275
ALL_APP_LOG_FILES = list(KNOWN_LOG_FILES.values()) # List of all individual log file paths
221276

277+
# Handle both root path and base URL root path
222278
@app.route('/')
223279
def home():
280+
"""Render the main index page"""
224281
return render_template('index.html')
225282

226283
@app.route('/user')
227284
def user():
228-
# User account screen
285+
"""Render the user account screen"""
229286
return render_template('user.html')
287+
288+
# This section previously contained code for redirecting paths to include the base URL
289+
# It has been removed as Flask's APPLICATION_ROOT setting provides this functionality
230290

231291
# Removed /settings and /logs routes if handled by index.html and JS routing
232292
# Keep /logs if it's the actual SSE endpoint

version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
7.0.2
1+
7.0.3

0 commit comments

Comments
 (0)