mirror of
https://github.com/plexguide/Huntarr.io.git
synced 2026-04-19 17:17:05 -04:00
222 lines
8.7 KiB
Python
222 lines
8.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Concatenate JS files into bundles. Reduces HTTP requests from 60+ to ~15.
|
|
Run from repo root: python scripts/build_js_bundles.py
|
|
|
|
Bundles preserve original load order. Requestarr type=module files stay separate
|
|
(they use import/export; concatenation would break them).
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
|
FRONTEND = os.path.join(REPO_ROOT, "frontend")
|
|
STATIC_JS = os.path.join(FRONTEND, "static", "js")
|
|
DIST_DIR = os.path.join(STATIC_JS, "dist")
|
|
|
|
# Groups: (output_filename, [list of paths relative to STATIC_JS])
|
|
BUNDLES = [
|
|
(
|
|
"bundle-core.js",
|
|
[
|
|
"modules/core/utils.js",
|
|
"modules/core/helpers.js",
|
|
"modules/core/dom.js",
|
|
"modules/core/notifications.js",
|
|
"modules/core/confirm-modal.js",
|
|
"modules/core/navigation.js",
|
|
"modules/core/theme.js",
|
|
"modules/core/version.js",
|
|
"modules/core/auth.js",
|
|
"modules/core/ui-handlers.js",
|
|
"modules/core/initialization.js",
|
|
],
|
|
),
|
|
(
|
|
"bundle-app.js",
|
|
["app.js", "app-sections.js"],
|
|
),
|
|
(
|
|
"bundle-settings.js",
|
|
[
|
|
"modules/features/settings/core.js",
|
|
"modules/features/settings/instance-editor.js",
|
|
"modules/features/settings/sonarr.js",
|
|
"modules/features/settings/radarr.js",
|
|
"modules/features/settings/lidarr.js",
|
|
"modules/features/settings/readarr.js",
|
|
"modules/features/settings/whisparr.js",
|
|
"modules/features/settings/prowlarr.js",
|
|
"modules/features/settings/swaparr.js",
|
|
"modules/features/settings/indexer-editor.js",
|
|
"modules/features/settings/indexers.js",
|
|
"modules/features/settings/media-hunt-profiles.js",
|
|
"modules/features/settings/profile-editor.js",
|
|
"modules/features/settings/movie-management.js",
|
|
"modules/features/settings/tv-management.js",
|
|
"modules/features/settings/client-editor.js",
|
|
"modules/features/settings/clients.js",
|
|
"modules/features/settings/import-lists.js",
|
|
"modules/features/settings/media-hunt-import-media.js",
|
|
"modules/features/settings/root-folders.js",
|
|
"modules/features/settings/remote-mappings.js",
|
|
"modules/features/settings/custom-formats.js",
|
|
"modules/features/settings/media-hunt-instance-management.js",
|
|
"modules/features/settings/media-hunt-instance-editor.js",
|
|
"modules/features/settings/logs.js",
|
|
"modules/features/settings/notifications.js",
|
|
"modules/features/settings/general.js",
|
|
],
|
|
),
|
|
(
|
|
"bundle-features.js",
|
|
[
|
|
"modules/features/apps/apps-main.js",
|
|
"modules/features/logs/logs-main.js",
|
|
"modules/features/logs/logs-core.js",
|
|
"modules/features/instances.js",
|
|
"modules/features/stateful.js",
|
|
"modules/features/backup-restore.js",
|
|
"modules/features/hunt_manager.js",
|
|
"modules/features/scheduling.js",
|
|
"modules/features/history.js",
|
|
"modules/features/user.js",
|
|
"modules/features/new-user.js",
|
|
"modules/features/community-resources.js",
|
|
"modules/features/github-sponsors.js",
|
|
"modules/features/app-sponsor-rotation.js",
|
|
"modules/features/swaparr-card.js",
|
|
"modules/features/prowlarr.js",
|
|
"modules/features/setup-wizard.js",
|
|
"modules/features/huntarr-chat.js",
|
|
],
|
|
),
|
|
(
|
|
"bundle-media.js",
|
|
[
|
|
"modules/features/media-utils.js",
|
|
"modules/features/media-hunt-instance-dropdown.js",
|
|
"modules/features/media-hunt.js",
|
|
"modules/features/media-hunt-filters.js",
|
|
"modules/features/media-hunt-activity.js",
|
|
"modules/features/media-hunt-card-delete-modal.js",
|
|
"modules/features/media-hunt-collection-movies.js",
|
|
"modules/features/media-hunt-collection-tv.js",
|
|
"modules/features/media-hunt-collection.js",
|
|
"modules/features/media-hunt-calendar.js",
|
|
"modules/features/settings/media-hunt-custom-formats.js",
|
|
"modules/features/settings/media-hunt-root-folders.js",
|
|
"modules/utils/tmdb-image-cache-standalone.js",
|
|
],
|
|
),
|
|
(
|
|
"requestarr-bundle.js",
|
|
[
|
|
"modules/features/requestarr/requestarr-core-utils.js",
|
|
"modules/features/requestarr/requestarr-filters.js",
|
|
"modules/features/requestarr/requestarr-tv-filters.js",
|
|
"modules/features/requestarr/requestarr-search.js",
|
|
"modules/features/requestarr/requestarr-settings.js",
|
|
"modules/features/requestarr/requestarr-content.js",
|
|
"modules/features/requestarr/requestarr-modal.js",
|
|
"modules/features/requestarr/requestarr-core.js",
|
|
"modules/features/requestarr/requestarr-smarthunt.js",
|
|
"modules/features/requestarr/requestarr-controller.js",
|
|
"modules/features/requestarr/requestarr-home.js",
|
|
"modules/features/requestarr/requestarr-users.js",
|
|
"modules/features/requestarr/requestarr-bundles.js",
|
|
"modules/features/requestarr/requestarr-requests.js",
|
|
],
|
|
),
|
|
(
|
|
"bundle-misc.js",
|
|
[
|
|
"modules/features/requestarr/requestarr-detail.js",
|
|
"modules/features/requestarr/requestarr-tv-detail.js",
|
|
"modules/features/nzb-hunt.js",
|
|
"modules/features/nzb-hunt-settings.js",
|
|
"modules/features/indexer-hunt.js",
|
|
"modules/features/indexer-hunt-home.js",
|
|
"modules/features/indexer-hunt-stats.js",
|
|
"modules/features/indexer-hunt-history.js",
|
|
"modules/features/apps/sonarr.js",
|
|
"modules/features/apps/radarr.js",
|
|
"modules/features/apps/lidarr.js",
|
|
"modules/features/apps/readarr.js",
|
|
"modules/features/apps/whisparr.js",
|
|
"modules/features/apps/eros.js",
|
|
"modules/features/apps/swaparr-view.js",
|
|
"modules/ui/stats.js",
|
|
"modules/ui/api-progress.js",
|
|
"modules/ui/cycle-countdown.js",
|
|
"modules/ui/apps-scroll-fix.js",
|
|
"modules/ui/card-hover-effects.js",
|
|
"modules/ui/circular-progress.js",
|
|
"modules/ui/background-pattern.js",
|
|
"modules/ui/hourly-cap.js",
|
|
],
|
|
),
|
|
]
|
|
|
|
|
|
import re
|
|
|
|
|
|
def strip_es_module_syntax(content: str) -> str:
|
|
"""Strip import/export so concatenated bundle works as non-module script."""
|
|
lines = content.split('\n')
|
|
out = []
|
|
for line in lines:
|
|
stripped = line.strip()
|
|
# Remove import statements
|
|
if stripped.startswith('import '):
|
|
continue
|
|
# Remove export { X, Y }; or export { X as Y };
|
|
if re.match(r'^export\s+\{[^}]*\}\s*;?\s*$', stripped):
|
|
continue
|
|
# Strip 'export ' prefix from declarations
|
|
if stripped.startswith('export default '):
|
|
out.append(re.sub(r'^export\s+default\s+', '', line))
|
|
elif stripped.startswith('export '):
|
|
out.append(re.sub(r'^(\s*)export\s+', r'\1', line))
|
|
else:
|
|
out.append(line)
|
|
return '\n'.join(out)
|
|
|
|
|
|
def concat_bundle(output_name: str, files: list[str], strip_modules: bool = False) -> bool:
|
|
"""Concatenate files into one bundle. Returns True on success."""
|
|
os.makedirs(DIST_DIR, exist_ok=True)
|
|
out_path = os.path.join(DIST_DIR, output_name)
|
|
parts = []
|
|
for rel_path in files:
|
|
full_path = os.path.join(STATIC_JS, rel_path)
|
|
if not os.path.exists(full_path):
|
|
print(f" WARNING: missing {rel_path}", file=sys.stderr)
|
|
continue
|
|
with open(full_path, "r", encoding="utf-8", errors="replace") as f:
|
|
content = f.read()
|
|
if strip_modules:
|
|
content = strip_es_module_syntax(content)
|
|
parts.append(f"\n/* === {rel_path} === */\n{content}")
|
|
result = "\n".join(parts)
|
|
with open(out_path, "w", encoding="utf-8") as f:
|
|
f.write(result)
|
|
size_kb = len(result.encode("utf-8")) / 1024
|
|
print(f" {output_name}: {len(files)} files, {size_kb:.1f} KB")
|
|
return True
|
|
|
|
|
|
def main():
|
|
print("Building JS bundles...")
|
|
for output_name, files in BUNDLES:
|
|
strip_modules = output_name == "requestarr-bundle.js"
|
|
concat_bundle(output_name, files, strip_modules=strip_modules)
|
|
print("Done. Bundles written to frontend/static/js/dist/")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|