Skip to content

Commit 3135261

Browse files
Major Improvements: Subpath, Database Support & Logging (#115)
Features 🚀 SUBPATH Configuration: Added support for subpath configuration and updated routing logic. Database Support: Introduced support for MySQL and PostgreSQL, with error handling and configuration improvements. Toast Notifications: Implemented notifications for configuration save success. UI Refactoring: Updated configuration forms to use v-slot in router-view. Improvements 🔧 Docker: Refactored Dockerfile to simplify user and permission management. Logging: Enhanced logging system and added log level configuration via environment variable. Error Handling: Improved robustness in database error handling and media request processing. README & UI: Updated documentation, added Discord link to the footer, and improved UX. Fixes 🛠️ Fixed incorrect logging statement in the save_metadata method. Added duplicate request handling in media requests.
1 parent 26af7d4 commit 3135261

39 files changed

Lines changed: 4320 additions & 3230 deletions

.github/FUNDING.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# These are supported funding model platforms
22

33
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4-
patreon: # Replace with a single Patreon username
4+
patreon: suggestarr
55
open_collective: # Replace with a single Open Collective username
66
ko_fi: # Replace with a single Ko-fi username
77
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel

README.md

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,10 @@
1010
![Platform Support](https://img.shields.io/badge/platforms-linux%2Famd64%20|%20linux%2Farm64-blue?logo=linux)
1111
![Docker Pulls](https://img.shields.io/docker/pulls/ciuse99/suggestarr?label=Docker%20Pulls&logo=docker)
1212

13-
[![GitHub Discussions](https://img.shields.io/badge/Community-GitHub%20Discussions-blue?logo=github)](https://github.com/giuseppe99barchetta/suggestarr/discussions)
14-
![GitHub Stars](https://img.shields.io/github/stars/giuseppe99barchetta/suggestarr?label=Stars&logo=github)
15-
![Contributors](https://img.shields.io/github/contributors/giuseppe99barchetta/suggestarr?label=Contributors&logo=github)
1613
[![Buy Me a Coffee](https://img.shields.io/badge/Donate-Buy%20Me%20a%20Coffee-orange?logo=buy-me-a-coffee)](https://buymeacoffee.com/suggestarr)
1714
[![Reddit Upvotes](https://img.shields.io/badge/Reddit-Upvotes-ff4500?logo=reddit)](https://www.reddit.com/r/selfhosted/comments/1gb4swg/release_major_update_for_suggestarr_now/)
1815
![Last Commit](https://img.shields.io/github/last-commit/giuseppe99barchetta/suggestarr?label=Last%20Commit&logo=github)
19-
16+
[![](https://dcbadge.limes.pink/api/server/https://discord.gg/JXwFd3PnXY?style=flat)](https://discord.gg/JXwFd3PnXY)
2017
</div>
2118

2219
SuggestArr is a project designed to automate media content recommendations and download requests based on user activity in media servers like **Jellyfin**, **Plex**, and now **Emby**. It retrieves recently watched content, searches for similar titles using the TMDb API, and sends automated download requests to **Jellyseer** or **Overseer**.
@@ -30,12 +27,15 @@ SuggestArr is a project designed to automate media content recommendations and d
3027
- **User Selection**: Choose specific users to initiate requests, allowing management and approval of auto-requested content.
3128
- **Cron Job Management**: Update the cron job schedule directly from the web interface.
3229
- **Configuration Pre-testing**: Automatically validates API keys and URLs during setup.
30+
- **Content Filtering**: Exclude requests for content already available on streaming platforms in your country.
31+
- **External Database Support**: Use external databases (PostgreSQL, MySQL) in addition to SQLite for improved scalability and performance.
3332

3433
## Prerequisites
3534
- **Python 3.x** or **Docker**
3635
- **[TMDb API Key](https://www.themoviedb.org/documentation/api)**
3736
- Configured **[Jellyfin](https://jellyfin.org/)**, **[Plex](https://www.plex.tv/)**, or **[Emby](https://emby.media/)**
3837
- Configured **[Jellyseer](https://github.com/Fallenbagel/jellyseerr)** or **[Overseer](https://github.com/sct/overseerr)**
38+
- (Optional) External database (PostgreSQL or MySQL) for improved performance
3939

4040
## Docker Usage
4141

@@ -53,6 +53,9 @@ services:
5353
- "5000:5000"
5454
volumes:
5555
- ./config_files:/app/config/config_files
56+
environment:
57+
# Optional: Only needed if something goes wrong and you need to inspect deeper
58+
- LOG_LEVEL=${LOG_LEVEL:-info}
5659
```
5760
To start the container with Docker Compose:
5861
@@ -77,22 +80,10 @@ If you'd like to use a specific Jellyseer user to make media requests, follow th
7780
Note: Currently, only local Jellyseer users are supported.
7881

7982
## Running Without Docker
80-
You can also run the project locally by installing the dependencies and setting the environment variables.
81-
82-
### Steps:
83-
1. Install Python dependencies:
84-
85-
```bash
86-
pip install -r requirements.txt
87-
```
88-
2. Run the project:
89-
90-
```bash
91-
python app.py
92-
```
83+
For detailed instructions on setting up SuggestArr withouth Docker or as a system service, please refer to our [Installation Guide](https://github.com/giuseppe99barchetta/SuggestArr/wiki/Installation#documentation-to-run-the-project-without-docker).
9384

94-
3. Access to the web interface
95-
The web interface will be available at: [http://localhost:5000](http://localhost:5000).
85+
## Join Our Discord Community
86+
Feel free to join our Discord community to share ideas, ask questions, or get help with SuggestArr: [Join here](https://discord.gg/cpjBJ5sK).
9687

9788
## Contribute
9889
Contributions are highly welcome! Feel free to open issues, submit pull requests, or provide any feedback that can improve the project. Whether you're fixing bugs, improving documentation, or adding new features, all contributions are greatly appreciated.

api_service/app.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
from api_service.utils.utils import AppUtils
1313
from api_service.config.logger_manager import LoggerManager
14+
from api_service.config.config import load_env_vars
1415

1516
from api_service.blueprints.jellyfin.routes import jellyfin_bp
1617
from api_service.blueprints.seer.routes import seer_bp
@@ -20,7 +21,8 @@
2021
from api_service.blueprints.config.routes import config_bp
2122

2223
executor = ThreadPoolExecutor(max_workers=3)
23-
logger = LoggerManager().get_logger(__name__)
24+
logger = LoggerManager.get_logger("APP")
25+
logger.info(f"Current log level: {logging.getLevelName(logger.getEffectiveLevel())}")
2426

2527
# App Factory Pattern for modularity and testability
2628
def create_app():
@@ -69,6 +71,10 @@ def serve_frontend(path):
6971

7072
app = create_app()
7173
asgi_app = WsgiToAsgi(app)
74+
env_vars = load_env_vars()
75+
if env_vars.get('CRON_TIMES'):
76+
from api_service.config.cron_jobs import start_cron_job
77+
start_cron_job(env_vars)
7278

7379
def close_log_handlers():
7480
for handler in logging.root.handlers[:]:

api_service/automate_process.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import asyncio
2-
31
from api_service.config.config import load_env_vars
42
from api_service.config.logger_manager import LoggerManager
53
from api_service.handler.jellyfin_handler import JellyfinHandler

api_service/blueprints/automation/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from api_service.config.logger_manager import LoggerManager
44
from api_service.db.database_manager import DatabaseManager
55

6-
logger = LoggerManager().get_logger(__name__)
6+
logger = LoggerManager().get_logger("AutomationRoute")
77
automation_bp = Blueprint('automation', __name__)
88

99
@automation_bp.route('/force_run', methods=['POST'])

api_service/blueprints/config/routes.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
import os
12
from flask import Blueprint, request, jsonify
3+
import yaml
24
from api_service.config.config import load_env_vars, save_env_vars, clear_env_vars
35
from api_service.config.logger_manager import LoggerManager
6+
from api_service.db.database_manager import DatabaseManager
47

5-
logger = LoggerManager().get_logger(__name__)
8+
logger = LoggerManager().get_logger("ConfigRoute")
69
config_bp = Blueprint('config', __name__)
710

811
@config_bp.route('/fetch', methods=['GET'])
@@ -25,6 +28,7 @@ def save_config():
2528
try:
2629
config_data = request.json
2730
save_env_vars(config_data)
31+
DatabaseManager().initialize_db()
2832
return jsonify({'message': 'Configuration saved successfully!', 'status': 'success'}), 200
2933
except Exception as e:
3034
logger.error(f'Error saving configuration: {str(e)}')
@@ -41,3 +45,30 @@ def reset_config():
4145
except Exception as e:
4246
logger.error(f'Error clearing configuration: {str(e)}')
4347
return jsonify({'message': f'Error clearing configuration: {str(e)}', 'status': 'error'}), 500
48+
49+
@config_bp.route('/test-db-connection', methods=['POST'])
50+
def test_db_connection():
51+
"""
52+
Test database connection.
53+
"""
54+
try:
55+
# Extract DB configuration data from the request
56+
db_config = request.json
57+
58+
# Check if the necessary data has been provided
59+
required_keys = ['DB_TYPE', 'DB_HOST', 'DB_PORT', 'DB_USER', 'DB_PASSWORD', 'DB_NAME']
60+
if any(key not in db_config for key in required_keys):
61+
return jsonify({'message': 'Missing required database configuration parameters.', 'status': 'error'}), 400
62+
63+
# Create an instance of the DatabaseManager
64+
db_manager = DatabaseManager()
65+
66+
# Call the connection test method
67+
result = db_manager.test_connection(db_config)
68+
69+
# Respond with the test result
70+
return jsonify(result), 200 if result['status'] == 'success' else 500
71+
72+
except Exception as e:
73+
logger.error(f'Error testing database connection: {str(e)}')
74+
return jsonify({'message': f'Error testing database connection: {str(e)}', 'status': 'error'}), 500

api_service/blueprints/jellyfin/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from api_service.services.jellyfin.jellyfin_client import JellyfinClient
33
from api_service.config.logger_manager import LoggerManager
44

5-
logger = LoggerManager().get_logger(__name__)
5+
logger = LoggerManager().get_logger("JellyfinRoute")
66
jellyfin_bp = Blueprint('jellyfin', __name__)
77

88
@jellyfin_bp.route('/libraries', methods=['POST'])

api_service/blueprints/logs/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from flask import Blueprint, jsonify
22
from api_service.config.logger_manager import LoggerManager
33

4-
logger = LoggerManager().get_logger(__name__)
4+
logger = LoggerManager().get_logger("LogsRoute")
55
logs_bp = Blueprint('logs', __name__)
66

77
@logs_bp.route('/logs', methods=['GET'])

api_service/blueprints/plex/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from api_service.services.plex.plex_client import PlexClient
66
from api_service.config.logger_manager import LoggerManager
77

8-
logger = LoggerManager().get_logger(__name__)
8+
logger = LoggerManager().get_logger("PlexRoute")
99
plex_bp = Blueprint('plex', __name__)
1010
client_id = os.getenv('PLEX_CLIENT_ID', str(uuid.uuid4()))
1111

api_service/blueprints/seer/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from api_service.services.jellyseer.seer_client import SeerClient
33
from api_service.config.logger_manager import LoggerManager
44

5-
logger = LoggerManager().get_logger(__name__)
5+
logger = LoggerManager().get_logger("SeerRoute")
66
seer_bp = Blueprint('seer', __name__)
77

88
@seer_bp.route('/get_users', methods=['POST'])

0 commit comments

Comments
 (0)