Fix autosync toggle disable functionality
- Fix service instance management to use global instance for stopping autosync - Add automatic saving when toggle is changed (no manual save required) - Fix validation issue where custom sync type without cron expression caused 400 error - Add comprehensive debugging and error handling - Ensure .env file is properly updated with AUTO_SYNC_ENABLED value - Improve service lifecycle management with proper state cleanup - Add fallback logic for invalid sync interval configurations Resolves issue where disabling autosync in GUI didn't update .env file or stop service
This commit is contained in:
@@ -27,3 +27,12 @@ AUTH_ENABLED=false
|
||||
AUTH_SETUP_COMPLETED=false
|
||||
JWT_SECRET=
|
||||
DATABASE_URL="file:/opt/ProxmoxVE-Local/data/settings.db"
|
||||
AUTO_SYNC_ENABLED=false
|
||||
SYNC_INTERVAL_TYPE=
|
||||
SYNC_INTERVAL_PREDEFINED=
|
||||
AUTO_DOWNLOAD_NEW=
|
||||
AUTO_UPDATE_EXISTING=
|
||||
NOTIFICATION_ENABLED=
|
||||
APPRISE_URLS=
|
||||
LAST_AUTO_SYNC=
|
||||
SYNC_INTERVAL_CRON=
|
||||
@@ -12,7 +12,7 @@
|
||||
"documentation": "https://docs.bunkerweb.io/latest/",
|
||||
"website": "https://www.bunkerweb.io/",
|
||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/bunkerweb.webp",
|
||||
"config_path": "/opt/bunkerweb/variables.env",
|
||||
"config_path": "/etc/bunkerweb/variables.env",
|
||||
"description": "BunkerWeb is a security-focused web server that enhances web application protection. It guards against common web vulnerabilities like SQL injection, XSS, and CSRF. It features simple setup and configuration using a YAML file, customizable security rules, and provides detailed logs for traffic monitoring and threat detection.",
|
||||
"install_methods": [
|
||||
{
|
||||
|
||||
48
scripts/json/execute.json
Normal file
48
scripts/json/execute.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "PVE LXC Execute Command",
|
||||
"slug": "lxc-execute",
|
||||
"categories": [
|
||||
1
|
||||
],
|
||||
"date_created": "2025-09-18",
|
||||
"type": "pve",
|
||||
"updateable": false,
|
||||
"privileged": false,
|
||||
"interface_port": null,
|
||||
"documentation": null,
|
||||
"website": null,
|
||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/proxmox.webp",
|
||||
"config_path": "",
|
||||
"description": "This script allows administrators to execute a custom command inside one or multiple LXC containers on a Proxmox VE node. Containers can be selectively excluded via an interactive checklist. If a container is stopped, the script will automatically start it, run the command, and then shut it down again. Only Debian and Ubuntu based containers are supported.",
|
||||
"install_methods": [
|
||||
{
|
||||
"type": "default",
|
||||
"script": "tools/pve/execute.sh",
|
||||
"resources": {
|
||||
"cpu": null,
|
||||
"ram": null,
|
||||
"hdd": null,
|
||||
"os": null,
|
||||
"version": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"default_credentials": {
|
||||
"username": null,
|
||||
"password": null
|
||||
},
|
||||
"notes": [
|
||||
{
|
||||
"text": "Execute within the Proxmox shell.",
|
||||
"type": "info"
|
||||
},
|
||||
{
|
||||
"text": "Non-Debian/Ubuntu containers will be skipped automatically.",
|
||||
"type": "info"
|
||||
},
|
||||
{
|
||||
"text": "Stopped containers will be started temporarily to run the command, then shut down again.",
|
||||
"type": "warning"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
"ram": 2048,
|
||||
"hdd": 10,
|
||||
"os": "debian",
|
||||
"version": "12"
|
||||
"version": "13"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"documentation": "https://github.com/HydroshieldMKII/Guardian/blob/main/README.md",
|
||||
"config_path": "/opt/guardian/.env",
|
||||
"website": "https://github.com/HydroshieldMKII/Guardian",
|
||||
"logo": null,
|
||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/guardian-plex.webp",
|
||||
"description": "Guardian is a lightweight companion app for Plex that lets you monitor, approve or block devices in real time. It helps you enforce per-user or global policies, stop unwanted sessions automatically and grant temporary access - all through a simple web interface.",
|
||||
"install_methods": [
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"resources": {
|
||||
"cpu": 2,
|
||||
"ram": 2048,
|
||||
"hdd": 8,
|
||||
"hdd": 16,
|
||||
"os": "ubuntu",
|
||||
"version": "24.04"
|
||||
}
|
||||
|
||||
40
scripts/json/jotty.json
Normal file
40
scripts/json/jotty.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "jotty",
|
||||
"slug": "jotty",
|
||||
"categories": [
|
||||
12
|
||||
],
|
||||
"date_created": "2025-10-21",
|
||||
"type": "ct",
|
||||
"updateable": true,
|
||||
"privileged": false,
|
||||
"interface_port": 3000,
|
||||
"documentation": "https://github.com/fccview/jotty/blob/main/README.md",
|
||||
"website": "https://github.com/fccview/jotty",
|
||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/jotty.webp",
|
||||
"config_path": "/opt/jotty/.env",
|
||||
"description": "A simple, self-hosted app for your checklists and notes. Tired of bloated, cloud-based to-do apps? jotty is a lightweight alternative for managing your personal checklists and notes. It's built with Next.js 14, is easy to deploy, and keeps all your data on your own server.",
|
||||
"install_methods": [
|
||||
{
|
||||
"type": "default",
|
||||
"script": "ct/jotty.sh",
|
||||
"resources": {
|
||||
"cpu": 2,
|
||||
"ram": 3072,
|
||||
"hdd": 6,
|
||||
"os": "debian",
|
||||
"version": "13"
|
||||
}
|
||||
}
|
||||
],
|
||||
"default_credentials": {
|
||||
"username": null,
|
||||
"password": null
|
||||
},
|
||||
"notes": [
|
||||
{
|
||||
"text": "jotty was previously named rwMarkable",
|
||||
"type": "info"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
"ram": 2048,
|
||||
"hdd": 8,
|
||||
"os": "debian",
|
||||
"version": "12"
|
||||
"version": "13"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1,186 +1,186 @@
|
||||
{
|
||||
"categories": [
|
||||
{
|
||||
"name": "Proxmox & Virtualization",
|
||||
"id": 1,
|
||||
"sort_order": 1.0,
|
||||
"description": "Tools and scripts to manage Proxmox VE and virtualization platforms effectively.",
|
||||
"icon": "server"
|
||||
},
|
||||
{
|
||||
"name": "Operating Systems",
|
||||
"id": 2,
|
||||
"sort_order": 2.0,
|
||||
"description": "Scripts for deploying and managing various operating systems.",
|
||||
"icon": "monitor"
|
||||
},
|
||||
{
|
||||
"name": "Containers & Docker",
|
||||
"id": 3,
|
||||
"sort_order": 3.0,
|
||||
"description": "Solutions for containerization using Docker and related technologies.",
|
||||
"icon": "box"
|
||||
},
|
||||
{
|
||||
"name": "Network & Firewall",
|
||||
"id": 4,
|
||||
"sort_order": 4.0,
|
||||
"description": "Enhance network security and configure firewalls with ease.",
|
||||
"icon": "shield"
|
||||
},
|
||||
{
|
||||
"name": "Adblock & DNS",
|
||||
"id": 5,
|
||||
"sort_order": 5.0,
|
||||
"description": "Optimize your network with DNS and ad-blocking solutions.",
|
||||
"icon": "ban"
|
||||
},
|
||||
{
|
||||
"name": "Authentication & Security",
|
||||
"id": 6,
|
||||
"sort_order": 6.0,
|
||||
"description": "Secure your infrastructure with authentication and security tools.",
|
||||
"icon": "lock"
|
||||
},
|
||||
{
|
||||
"name": "Backup & Recovery",
|
||||
"id": 7,
|
||||
"sort_order": 7.0,
|
||||
"description": "Reliable backup and recovery scripts to protect your data.",
|
||||
"icon": "archive"
|
||||
},
|
||||
{
|
||||
"name": "Databases",
|
||||
"id": 8,
|
||||
"sort_order": 8.0,
|
||||
"description": "Deploy and manage robust database systems with ease.",
|
||||
"icon": "database"
|
||||
},
|
||||
{
|
||||
"name": "Monitoring & Analytics",
|
||||
"id": 9,
|
||||
"sort_order": 9.0,
|
||||
"description": "Monitor system performance and analyze data seamlessly.",
|
||||
"icon": "bar-chart"
|
||||
},
|
||||
{
|
||||
"name": "Dashboards & Frontends",
|
||||
"id": 10,
|
||||
"sort_order": 10.0,
|
||||
"description": "Create interactive dashboards and user-friendly frontends.",
|
||||
"icon": "layout"
|
||||
},
|
||||
{
|
||||
"name": "Files & Downloads",
|
||||
"id": 11,
|
||||
"sort_order": 11.0,
|
||||
"description": "Manage file sharing and downloading solutions efficiently.",
|
||||
"icon": "download"
|
||||
},
|
||||
{
|
||||
"name": "Documents & Notes",
|
||||
"id": 12,
|
||||
"sort_order": 12.0,
|
||||
"description": "Organize and manage documents and note-taking tools.",
|
||||
"icon": "file-text"
|
||||
},
|
||||
{
|
||||
"name": "Media & Streaming",
|
||||
"id": 13,
|
||||
"sort_order": 13.0,
|
||||
"description": "Stream and manage media effortlessly across devices.",
|
||||
"icon": "play"
|
||||
},
|
||||
{
|
||||
"name": "*Arr Suite",
|
||||
"id": 14,
|
||||
"sort_order": 14.0,
|
||||
"description": "Automated media management with the popular *Arr suite tools.",
|
||||
"icon": "tv"
|
||||
},
|
||||
{
|
||||
"name": "NVR & Cameras",
|
||||
"id": 15,
|
||||
"sort_order": 15.0,
|
||||
"description": "Manage network video recorders and camera setups.",
|
||||
"icon": "camera"
|
||||
},
|
||||
{
|
||||
"name": "IoT & Smart Home",
|
||||
"id": 16,
|
||||
"sort_order": 16.0,
|
||||
"description": "Control and automate IoT devices and smart home systems.",
|
||||
"icon": "home"
|
||||
},
|
||||
{
|
||||
"name": "ZigBee, Z-Wave & Matter",
|
||||
"id": 17,
|
||||
"sort_order": 17.0,
|
||||
"description": "Solutions for ZigBee, Z-Wave, and Matter-based device management.",
|
||||
"icon": "radio"
|
||||
},
|
||||
{
|
||||
"name": "MQTT & Messaging",
|
||||
"id": 18,
|
||||
"sort_order": 18.0,
|
||||
"description": "Set up reliable messaging and MQTT-based communication systems.",
|
||||
"icon": "message-circle"
|
||||
},
|
||||
{
|
||||
"name": "Automation & Scheduling",
|
||||
"id": 19,
|
||||
"sort_order": 19.0,
|
||||
"description": "Automate tasks and manage scheduling with powerful tools.",
|
||||
"icon": "clock"
|
||||
},
|
||||
{
|
||||
"name": "AI / Coding & Dev-Tools",
|
||||
"id": 20,
|
||||
"sort_order": 20.0,
|
||||
"description": "Leverage AI and developer tools for smarter coding workflows.",
|
||||
"icon": "code"
|
||||
},
|
||||
{
|
||||
"name": "Webservers & Proxies",
|
||||
"id": 21,
|
||||
"sort_order": 21.0,
|
||||
"description": "Deploy and configure web servers and proxy solutions.",
|
||||
"icon": "globe"
|
||||
},
|
||||
{
|
||||
"name": "Bots & ChatOps",
|
||||
"id": 22,
|
||||
"sort_order": 22.0,
|
||||
"description": "Enhance collaboration with bots and ChatOps integrations.",
|
||||
"icon": "bot"
|
||||
},
|
||||
{
|
||||
"name": "Finance & Budgeting",
|
||||
"id": 23,
|
||||
"sort_order": 23.0,
|
||||
"description": "Track expenses and manage budgets efficiently.",
|
||||
"icon": "dollar-sign"
|
||||
},
|
||||
{
|
||||
"name": "Gaming & Leisure",
|
||||
"id": 24,
|
||||
"sort_order": 24.0,
|
||||
"description": "Scripts for gaming servers and leisure-related tools.",
|
||||
"icon": "gamepad-2"
|
||||
},
|
||||
{
|
||||
"name": "Business & ERP",
|
||||
"id": 25,
|
||||
"sort_order": 25.0,
|
||||
"description": "Streamline business operations with ERP and management tools.",
|
||||
"icon": "building"
|
||||
},
|
||||
{
|
||||
"name": "Miscellaneous",
|
||||
"id": 0,
|
||||
"sort_order": 99.0,
|
||||
"description": "General scripts and tools that don't fit into other categories.",
|
||||
"icon": "more-horizontal"
|
||||
}
|
||||
]
|
||||
}
|
||||
"categories": [
|
||||
{
|
||||
"name": "Proxmox & Virtualization",
|
||||
"id": 1,
|
||||
"sort_order": 1.0,
|
||||
"description": "Tools and scripts to manage Proxmox VE and virtualization platforms effectively.",
|
||||
"icon": "server"
|
||||
},
|
||||
{
|
||||
"name": "Operating Systems",
|
||||
"id": 2,
|
||||
"sort_order": 2.0,
|
||||
"description": "Scripts for deploying and managing various operating systems.",
|
||||
"icon": "monitor"
|
||||
},
|
||||
{
|
||||
"name": "Containers & Docker",
|
||||
"id": 3,
|
||||
"sort_order": 3.0,
|
||||
"description": "Solutions for containerization using Docker and related technologies.",
|
||||
"icon": "box"
|
||||
},
|
||||
{
|
||||
"name": "Network & Firewall",
|
||||
"id": 4,
|
||||
"sort_order": 4.0,
|
||||
"description": "Enhance network security and configure firewalls with ease.",
|
||||
"icon": "shield"
|
||||
},
|
||||
{
|
||||
"name": "Adblock & DNS",
|
||||
"id": 5,
|
||||
"sort_order": 5.0,
|
||||
"description": "Optimize your network with DNS and ad-blocking solutions.",
|
||||
"icon": "ban"
|
||||
},
|
||||
{
|
||||
"name": "Authentication & Security",
|
||||
"id": 6,
|
||||
"sort_order": 6.0,
|
||||
"description": "Secure your infrastructure with authentication and security tools.",
|
||||
"icon": "lock"
|
||||
},
|
||||
{
|
||||
"name": "Backup & Recovery",
|
||||
"id": 7,
|
||||
"sort_order": 7.0,
|
||||
"description": "Reliable backup and recovery scripts to protect your data.",
|
||||
"icon": "archive"
|
||||
},
|
||||
{
|
||||
"name": "Databases",
|
||||
"id": 8,
|
||||
"sort_order": 8.0,
|
||||
"description": "Deploy and manage robust database systems with ease.",
|
||||
"icon": "database"
|
||||
},
|
||||
{
|
||||
"name": "Monitoring & Analytics",
|
||||
"id": 9,
|
||||
"sort_order": 9.0,
|
||||
"description": "Monitor system performance and analyze data seamlessly.",
|
||||
"icon": "bar-chart"
|
||||
},
|
||||
{
|
||||
"name": "Dashboards & Frontends",
|
||||
"id": 10,
|
||||
"sort_order": 10.0,
|
||||
"description": "Create interactive dashboards and user-friendly frontends.",
|
||||
"icon": "layout"
|
||||
},
|
||||
{
|
||||
"name": "Files & Downloads",
|
||||
"id": 11,
|
||||
"sort_order": 11.0,
|
||||
"description": "Manage file sharing and downloading solutions efficiently.",
|
||||
"icon": "download"
|
||||
},
|
||||
{
|
||||
"name": "Documents & Notes",
|
||||
"id": 12,
|
||||
"sort_order": 12.0,
|
||||
"description": "Organize and manage documents and note-taking tools.",
|
||||
"icon": "file-text"
|
||||
},
|
||||
{
|
||||
"name": "Media & Streaming",
|
||||
"id": 13,
|
||||
"sort_order": 13.0,
|
||||
"description": "Stream and manage media effortlessly across devices.",
|
||||
"icon": "play"
|
||||
},
|
||||
{
|
||||
"name": "*Arr Suite",
|
||||
"id": 14,
|
||||
"sort_order": 14.0,
|
||||
"description": "Automated media management with the popular *Arr suite tools.",
|
||||
"icon": "tv"
|
||||
},
|
||||
{
|
||||
"name": "NVR & Cameras",
|
||||
"id": 15,
|
||||
"sort_order": 15.0,
|
||||
"description": "Manage network video recorders and camera setups.",
|
||||
"icon": "camera"
|
||||
},
|
||||
{
|
||||
"name": "IoT & Smart Home",
|
||||
"id": 16,
|
||||
"sort_order": 16.0,
|
||||
"description": "Control and automate IoT devices and smart home systems.",
|
||||
"icon": "home"
|
||||
},
|
||||
{
|
||||
"name": "ZigBee, Z-Wave & Matter",
|
||||
"id": 17,
|
||||
"sort_order": 17.0,
|
||||
"description": "Solutions for ZigBee, Z-Wave, and Matter-based device management.",
|
||||
"icon": "radio"
|
||||
},
|
||||
{
|
||||
"name": "MQTT & Messaging",
|
||||
"id": 18,
|
||||
"sort_order": 18.0,
|
||||
"description": "Set up reliable messaging and MQTT-based communication systems.",
|
||||
"icon": "message-circle"
|
||||
},
|
||||
{
|
||||
"name": "Automation & Scheduling",
|
||||
"id": 19,
|
||||
"sort_order": 19.0,
|
||||
"description": "Automate tasks and manage scheduling with powerful tools.",
|
||||
"icon": "clock"
|
||||
},
|
||||
{
|
||||
"name": "AI / Coding & Dev-Tools",
|
||||
"id": 20,
|
||||
"sort_order": 20.0,
|
||||
"description": "Leverage AI and developer tools for smarter coding workflows.",
|
||||
"icon": "code"
|
||||
},
|
||||
{
|
||||
"name": "Webservers & Proxies",
|
||||
"id": 21,
|
||||
"sort_order": 21.0,
|
||||
"description": "Deploy and configure web servers and proxy solutions.",
|
||||
"icon": "globe"
|
||||
},
|
||||
{
|
||||
"name": "Bots & ChatOps",
|
||||
"id": 22,
|
||||
"sort_order": 22.0,
|
||||
"description": "Enhance collaboration with bots and ChatOps integrations.",
|
||||
"icon": "bot"
|
||||
},
|
||||
{
|
||||
"name": "Finance & Budgeting",
|
||||
"id": 23,
|
||||
"sort_order": 23.0,
|
||||
"description": "Track expenses and manage budgets efficiently.",
|
||||
"icon": "dollar-sign"
|
||||
},
|
||||
{
|
||||
"name": "Gaming & Leisure",
|
||||
"id": 24,
|
||||
"sort_order": 24.0,
|
||||
"description": "Scripts for gaming servers and leisure-related tools.",
|
||||
"icon": "gamepad-2"
|
||||
},
|
||||
{
|
||||
"name": "Business & ERP",
|
||||
"id": 25,
|
||||
"sort_order": 25.0,
|
||||
"description": "Streamline business operations with ERP and management tools.",
|
||||
"icon": "building"
|
||||
},
|
||||
{
|
||||
"name": "Miscellaneous",
|
||||
"id": 0,
|
||||
"sort_order": 99.0,
|
||||
"description": "General scripts and tools that don't fit into other categories.",
|
||||
"icon": "more-horizontal"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"ram": 1024,
|
||||
"hdd": 4,
|
||||
"os": "debian",
|
||||
"version": "13"
|
||||
"version": "12"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"ram": 2048,
|
||||
"hdd": 8,
|
||||
"os": "debian",
|
||||
"version": "13"
|
||||
"version": "12"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"ram": 2048,
|
||||
"hdd": 6,
|
||||
"os": "debian",
|
||||
"version": "13"
|
||||
"version": "12"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"ram": 1024,
|
||||
"hdd": 4,
|
||||
"os": "debian",
|
||||
"version": "13"
|
||||
"version": "12"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
40
scripts/json/open-archiver.json
Normal file
40
scripts/json/open-archiver.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "Open-Archiver",
|
||||
"slug": "open-archiver",
|
||||
"categories": [
|
||||
7
|
||||
],
|
||||
"date_created": "2025-10-18",
|
||||
"type": "ct",
|
||||
"updateable": true,
|
||||
"privileged": false,
|
||||
"interface_port": 3000,
|
||||
"documentation": "https://docs.openarchiver.com/",
|
||||
"config_path": "/opt/openarchiver/.env",
|
||||
"website": "https://openarchiver.com/",
|
||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/open-archiver.webp",
|
||||
"description": "Open Archiver is a secure, self-hosted email archiving solution, and it's completely open source. Get an email archiver that enables full-text search across email and attachments. Create a permanent, searchable, and compliant mail archive from Google Workspace, Microsoft 35, and any IMAP server.",
|
||||
"install_methods": [
|
||||
{
|
||||
"type": "default",
|
||||
"script": "ct/open-archiver.sh",
|
||||
"resources": {
|
||||
"cpu": 2,
|
||||
"ram": 3072,
|
||||
"hdd": 8,
|
||||
"os": "debian",
|
||||
"version": "13"
|
||||
}
|
||||
}
|
||||
],
|
||||
"default_credentials": {
|
||||
"username": null,
|
||||
"password": null
|
||||
},
|
||||
"notes": [
|
||||
{
|
||||
"text": "Data directory is: `/opt/openarchiver-data`. If you have a lot of email, you might consider mounting external storage to this directory.",
|
||||
"type": "info"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
"ram": 8192,
|
||||
"hdd": 25,
|
||||
"os": "debian",
|
||||
"version": "13"
|
||||
"version": "12"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
"type": "default",
|
||||
"script": "ct/paperless-ai.sh",
|
||||
"resources": {
|
||||
"cpu": 2,
|
||||
"ram": 2048,
|
||||
"cpu": 4,
|
||||
"ram": 4096,
|
||||
"hdd": 20,
|
||||
"os": "debian",
|
||||
"version": "13"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"ram": 1024,
|
||||
"hdd": 4,
|
||||
"os": "debian",
|
||||
"version": "13"
|
||||
"version": "12"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"ram": 512,
|
||||
"hdd": 2,
|
||||
"os": "debian",
|
||||
"version": "13"
|
||||
"version": "12"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@
|
||||
"ram": 2048,
|
||||
"hdd": 5,
|
||||
"os": "Debian",
|
||||
"version": "12"
|
||||
"version": "13"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -322,31 +322,18 @@ export function GeneralSettingsModal({ isOpen, onClose }: GeneralSettingsModalPr
|
||||
setIsSaving(true);
|
||||
setMessage(null);
|
||||
|
||||
console.log('Saving auto-sync settings:', {
|
||||
autoSyncEnabled,
|
||||
syncIntervalType,
|
||||
syncIntervalPredefined,
|
||||
syncIntervalCron,
|
||||
autoDownloadNew,
|
||||
autoUpdateExisting,
|
||||
notificationEnabled,
|
||||
appriseUrls
|
||||
});
|
||||
|
||||
try {
|
||||
// Validate cron expression if custom
|
||||
if (syncIntervalType === 'custom' && syncIntervalCron) {
|
||||
const response = await fetch('/api/settings/auto-sync', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
autoSyncEnabled,
|
||||
syncIntervalType,
|
||||
syncIntervalPredefined,
|
||||
syncIntervalCron,
|
||||
autoDownloadNew,
|
||||
autoUpdateExisting,
|
||||
notificationEnabled,
|
||||
appriseUrls: appriseUrls
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
setMessage({ type: 'error', text: errorData.error ?? 'Failed to save auto-sync settings' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const response = await fetch('/api/settings/auto-sync', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -362,11 +349,16 @@ export function GeneralSettingsModal({ isOpen, onClose }: GeneralSettingsModalPr
|
||||
})
|
||||
});
|
||||
|
||||
console.log('API response status:', response.status);
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json();
|
||||
console.log('API response data:', result);
|
||||
setMessage({ type: 'success', text: 'Auto-sync settings saved successfully!' });
|
||||
setTimeout(() => setMessage(null), 3000);
|
||||
} else {
|
||||
const errorData = await response.json();
|
||||
console.error('API error:', errorData);
|
||||
setMessage({ type: 'error', text: errorData.error ?? 'Failed to save auto-sync settings' });
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -824,7 +816,46 @@ export function GeneralSettingsModal({ isOpen, onClose }: GeneralSettingsModalPr
|
||||
</div>
|
||||
<Toggle
|
||||
checked={autoSyncEnabled}
|
||||
onCheckedChange={setAutoSyncEnabled}
|
||||
onCheckedChange={async (checked) => {
|
||||
console.log('Toggle changed to:', checked);
|
||||
setAutoSyncEnabled(checked);
|
||||
|
||||
// Auto-save when toggle changes
|
||||
try {
|
||||
// If syncIntervalType is custom but no cron expression, fallback to predefined
|
||||
const effectiveSyncIntervalType = (syncIntervalType === 'custom' && !syncIntervalCron)
|
||||
? 'predefined'
|
||||
: syncIntervalType;
|
||||
|
||||
const response = await fetch('/api/settings/auto-sync', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
autoSyncEnabled: checked,
|
||||
syncIntervalType: effectiveSyncIntervalType,
|
||||
syncIntervalPredefined: effectiveSyncIntervalType === 'predefined' ? syncIntervalPredefined : undefined,
|
||||
syncIntervalCron: effectiveSyncIntervalType === 'custom' ? syncIntervalCron : undefined,
|
||||
autoDownloadNew,
|
||||
autoUpdateExisting,
|
||||
notificationEnabled,
|
||||
appriseUrls: appriseUrls
|
||||
})
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
console.log('Auto-sync toggle saved successfully');
|
||||
// Update local state to reflect the effective sync interval type
|
||||
if (effectiveSyncIntervalType !== syncIntervalType) {
|
||||
setSyncIntervalType(effectiveSyncIntervalType);
|
||||
}
|
||||
} else {
|
||||
const errorData = await response.json();
|
||||
console.error('Failed to save auto-sync toggle:', errorData);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error saving auto-sync toggle:', error);
|
||||
}
|
||||
}}
|
||||
disabled={isSaving}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { isValidCron } from 'cron-validator';
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const settings = await request.json();
|
||||
console.log('Received auto-sync settings:', settings);
|
||||
|
||||
if (!settings || typeof settings !== 'object') {
|
||||
return NextResponse.json(
|
||||
@@ -45,11 +46,14 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
// Validate sync interval type
|
||||
if (!['predefined', 'custom'].includes(settings.syncIntervalType)) {
|
||||
console.log('Invalid syncIntervalType:', settings.syncIntervalType);
|
||||
return NextResponse.json(
|
||||
{ error: 'syncIntervalType must be "predefined" or "custom"' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
console.log('Sync interval validation - type:', settings.syncIntervalType, 'cron:', settings.syncIntervalCron);
|
||||
|
||||
// Validate predefined interval
|
||||
if (settings.syncIntervalType === 'predefined') {
|
||||
@@ -64,14 +68,13 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
// Validate custom cron expression
|
||||
if (settings.syncIntervalType === 'custom') {
|
||||
if (!settings.syncIntervalCron || typeof settings.syncIntervalCron !== 'string') {
|
||||
return NextResponse.json(
|
||||
{ error: 'Custom cron expression is required when syncIntervalType is "custom"' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
if (!isValidCron(settings.syncIntervalCron, { seconds: false })) {
|
||||
if (!settings.syncIntervalCron || typeof settings.syncIntervalCron !== 'string' || settings.syncIntervalCron.trim() === '') {
|
||||
console.log('Custom sync interval type but no cron expression provided, falling back to predefined');
|
||||
// Fallback to predefined if custom is selected but no cron expression
|
||||
settings.syncIntervalType = 'predefined';
|
||||
settings.syncIntervalPredefined = settings.syncIntervalPredefined || '1hour';
|
||||
settings.syncIntervalCron = '';
|
||||
} else if (!isValidCron(settings.syncIntervalCron, { seconds: false })) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid cron expression' },
|
||||
{ status: 400 }
|
||||
@@ -156,23 +159,33 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
|
||||
// Write back to .env file
|
||||
console.log('Writing to .env file:', envPath);
|
||||
console.log('New .env content:', envContent);
|
||||
fs.writeFileSync(envPath, envContent);
|
||||
console.log('Successfully wrote to .env file');
|
||||
|
||||
// Reschedule auto-sync service with new settings
|
||||
try {
|
||||
const { getAutoSyncService } = await import('../../../../server/lib/autoSyncInit.js');
|
||||
const { getAutoSyncService, setAutoSyncService } = await import('../../../../server/lib/autoSyncInit.js');
|
||||
let autoSyncService = getAutoSyncService();
|
||||
|
||||
// If no global instance exists, create one
|
||||
if (!autoSyncService) {
|
||||
const { AutoSyncService } = await import('../../../../server/services/autoSyncService.js');
|
||||
autoSyncService = new AutoSyncService();
|
||||
setAutoSyncService(autoSyncService);
|
||||
}
|
||||
|
||||
// Update the global service instance with new settings
|
||||
console.log('Updating global service instance with settings:', settings);
|
||||
autoSyncService.saveSettings(settings);
|
||||
|
||||
if (settings.autoSyncEnabled) {
|
||||
console.log('Enabling auto-sync...');
|
||||
autoSyncService.scheduleAutoSync();
|
||||
console.log('Auto-sync rescheduled with new settings');
|
||||
} else {
|
||||
console.log('Disabling auto-sync...');
|
||||
autoSyncService.stopAutoSync();
|
||||
console.log('Auto-sync stopped');
|
||||
}
|
||||
|
||||
@@ -504,22 +504,26 @@ export const scriptsRouter = createTRPCRouter({
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
// Use the global auto-sync service instance
|
||||
const { getAutoSyncService } = await import('~/server/lib/autoSyncInit');
|
||||
const { getAutoSyncService, setAutoSyncService } = await import('~/server/lib/autoSyncInit');
|
||||
let autoSyncService = getAutoSyncService();
|
||||
|
||||
// If no global instance exists, create one
|
||||
if (!autoSyncService) {
|
||||
const { AutoSyncService } = await import('~/server/services/autoSyncService');
|
||||
autoSyncService = new AutoSyncService();
|
||||
setAutoSyncService(autoSyncService);
|
||||
}
|
||||
|
||||
// Save settings to both .env file and service instance
|
||||
autoSyncService.saveSettings(input);
|
||||
|
||||
// Reschedule auto-sync if enabled
|
||||
if (input.autoSyncEnabled) {
|
||||
autoSyncService.scheduleAutoSync();
|
||||
console.log('Auto-sync rescheduled with new settings');
|
||||
} else {
|
||||
autoSyncService.stopAutoSync();
|
||||
console.log('Auto-sync stopped');
|
||||
}
|
||||
|
||||
return { success: true, message: 'Auto-sync settings saved successfully' };
|
||||
|
||||
@@ -9,13 +9,16 @@ export function initializeAutoSync() {
|
||||
try {
|
||||
console.log('Initializing auto-sync service...');
|
||||
autoSyncService = new AutoSyncService();
|
||||
console.log('AutoSyncService instance created');
|
||||
|
||||
// Load settings and schedule if enabled
|
||||
const settings = autoSyncService.loadSettings();
|
||||
console.log('Settings loaded:', settings);
|
||||
|
||||
if (settings.autoSyncEnabled) {
|
||||
console.log('Auto-sync is enabled, scheduling cron job...');
|
||||
autoSyncService.scheduleAutoSync();
|
||||
console.log('Cron job scheduled');
|
||||
} else {
|
||||
console.log('Auto-sync is disabled');
|
||||
}
|
||||
@@ -23,6 +26,7 @@ export function initializeAutoSync() {
|
||||
console.log('Auto-sync service initialized successfully');
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize auto-sync service:', error);
|
||||
console.error('Error stack:', error.stack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +53,13 @@ export function getAutoSyncService() {
|
||||
return autoSyncService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the auto-sync service instance (for external management)
|
||||
*/
|
||||
export function setAutoSyncService(service) {
|
||||
autoSyncService = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Graceful shutdown handler
|
||||
*/
|
||||
|
||||
@@ -49,6 +49,13 @@ export function getAutoSyncService(): AutoSyncService | null {
|
||||
return autoSyncService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the auto-sync service instance (for external management)
|
||||
*/
|
||||
export function setAutoSyncService(service: AutoSyncService | null): void {
|
||||
autoSyncService = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Graceful shutdown handler
|
||||
*/
|
||||
|
||||
@@ -173,6 +173,7 @@ export class AutoSyncService {
|
||||
const key = trimmedLine.substring(0, equalIndex).trim();
|
||||
if (key && key in settingsMap) {
|
||||
// Replace existing setting
|
||||
// @ts-ignore - Dynamic property access is safe here
|
||||
newLines.push(`${key}=${settingsMap[key]}`);
|
||||
existingKeys.add(key);
|
||||
} else {
|
||||
@@ -256,7 +257,10 @@ export class AutoSyncService {
|
||||
if (this.cronJob) {
|
||||
this.cronJob.stop();
|
||||
this.cronJob = null;
|
||||
this.isRunning = false;
|
||||
console.log('Auto-sync cron job stopped');
|
||||
} else {
|
||||
console.log('No active cron job to stop');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,8 +289,8 @@ export class AutoSyncService {
|
||||
|
||||
const results = {
|
||||
jsonSync: syncResult,
|
||||
newScripts: /** @type {string[]} */ ([]),
|
||||
updatedScripts: /** @type {string[]} */ ([]),
|
||||
newScripts: /** @type {any[]} */ ([]),
|
||||
updatedScripts: /** @type {any[]} */ ([]),
|
||||
errors: /** @type {string[]} */ ([])
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user