Jellycord is a highly configurable Discord bot designed as a companion app to integrate with JFA-GO for managing user invites to a Jellyfin media server. It empowers authorized Discord users to create trial and paid invite links, manage existing invites, and extend user plans directly within designated support channels or threads. All bot behaviors, settings, messages, and embed appearances are customizable through YAML and JSON configuration files.
Important Note / Current Limitations:
- Jellycord currently does not support migrating existing users from your JFA-GO database to the bot's database.
- Jellycord is best suited for new JFA-GO setups or if this limitation is not a major hurdle for your existing workflow.
- Configurable Invite Types:
- Trial Invites: Create temporary, single-use trial invites. Durations for the invite link and the resulting user account are configurable.
- Paid Invites: Generate invites linked to specific JFA-GO user profiles, with customizable account durations.
- Enhanced Invite Management:
/remove_invite [user_identifier]: Identifies a user by Discord mention/ID or Jellyfin username. Attempts to delete the user from JFA-GO, delete their associated JFA-GO invite code, and sets their invite status to 'disabled' in Jellycord's local database. It also attempts to revert their Discord roles.- Extend the expiry of existing JFA-GO user accounts.
- User Notifications: Automatically notify users via DM before their JFA-GO account expires, with configurable notification timings.
- Role-Based Access Control: Restrict command usage to users with specific Discord roles within designated support categories/channels.
- Comprehensive Admin Logging: Logs administrative actions (invite creation/removal, plan extensions) to a specified Discord channel and the local database. All log messages are configurable.
- Deep JFA-GO Integration: Communicates directly with the JFA-GO API for profile fetching, user lookup, invite creation/deletion, and plan extensions.
- Database Persistence: Stores invite information and admin actions in an SQLite database (filename configurable).
- Fully Configurable Messaging: All user-facing messages, embed titles, field names, colors, and footers are configurable via a
message_templates.jsonfile. - Centralized YAML Configuration: Primary bot settings (name, branding), JFA-GO connection details, Discord server specifics (IDs, roles, channels), command behaviors, and role mappings are managed through a central
config.yamlfile. - Modular Design: Code is structured into modules for better organization and maintainability.
- Docker Support: Includes a Dockerfile for easy containerization and deployment.
- Language: Python 3.12+
- Discord API Wrapper: discord.py
- HTTP Requests: requests
- Configuration: PyYAML for
config.yaml, python-dotenv for.env(secrets/overrides). - Database: SQLite 3
- JFA-GO: Interacts with a running JFA-GO instance API.
- Python 3.12 or higher
pip(Python package installer)- A running instance of JFA-GO accessible from where the bot runs.
- A Discord Bot Token and Application.
- Docker (Optional, for containerized deployment)
-
Clone the repository:
git clone <your-repository-url> # Replace with the actual URL cd Jellycord # Or your chosen directory name
-
Navigate to the source directory: This project now uses a
srcdirectory for its main codebase.cd src # Or your chosen directory name if you cloned into a subdirectory
-
Create a virtual environment (Recommended, from within the
srcdirectory or project root): If you are in the project root:python -m venv .venv # Activate the virtual environment # Windows (Command Prompt/PowerShell) .venv\Scripts\activate # Linux/macOS source .venv/bin/activate
If you
cd srcfirst, adjust paths accordingly or create venv in root. -
Install dependencies (from the project root where
requirements.txtis):pip install -r requirements.txt
-
Configure the Bot:
-
Configuration Directory: All configuration files now reside in the
config/directory in the project root. -
Example Files: Copy
config/config.yaml.exampletoconfig/config.yaml. Copyconfig/message_templates.json.exampletoconfig/message_templates.json. -
Primary Configuration (
config/config.yaml): Editconfig/config.yaml. Detailed comments withinconfig/config.yaml.exampleexplain each option. -
Secrets & Environment-Specific Overrides (
.envfile): Create a.envfile in the project root. Place critical secrets likeDISCORD_TOKEN,JFA_GO_USERNAME, andJFA_GO_PASSWORDin.env. -
Message Customization (
config/message_templates.json): Editconfig/message_templates.jsonto change any bot output. The path is set inconfig/config.yaml(message_settings.templates_file, which should default to or be set toconfig/message_templates.json).
-
Ensure your virtual environment is activated and config/config.yaml (and .env in the project root) are configured.
Run from the project root:
python src/main.pyDeploying Jellycord with Docker is a convenient way to manage the application and its dependencies. You can use a pre-built image from Docker Hub or build the image locally.
Recommended: Using the Pre-built Docker Image from Docker Hub
A pre-built image is available on Docker Hub: sidikulous/jellycord:latest.
-
Prepare your host environment:
- Create a dedicated directory for your Jellycord configuration and data. For example:
mkdir ~/jellycord_bot_data cd ~/jellycord_bot_data
- Inside this directory, create subdirectories for the database and logs if you plan to map them from the host:
Ensure these directories have the correct permissions for the Docker user/group to write to them.
mkdir my_bot_db mkdir my_bot_logs
- Place your
config.yamland.envfile (containing secrets) in the~/jellycord_bot_datadirectory. Create aconfigsubdirectory within~/jellycord_bot_dataand place yourconfig.yamlandmessage_templates.jsonthere.# Example structure in ~/jellycord_bot_data # . # |-- .env # |-- config/ # | |-- config.yaml # | `-- message_templates.json (if customized) # |-- my_bot_db/ # `-- my_bot_logs/
- Create a dedicated directory for your Jellycord configuration and data. For example:
-
Configure Paths in
config.yaml(inside~/jellycord_bot_data/config/config.yaml): Update yourconfig.yamlto reflect the paths inside the container. The Docker run command below mounts:- Host
~/jellycord_bot_data/config/config.yamlto Container/app/config/config.yaml - Host
~/jellycord_bot_data/config/message_templates.jsonto Container/app/config/message_templates.json - Host
~/jellycord_bot_data/my_bot_dbto Container/app/data/db - Host
~/jellycord_bot_data/my_bot_logsto Container/app/logs
Therefore, your
config.yaml(the one on your host at~/jellycord_bot_data/config/config.yaml) should use these container-relative paths:bot_settings: # ... other bot_settings ... db_file_name: "data/db/jellycord.db" # Path inside the container log_file_name: "logs/jellycord.log" # Path inside the container # ... message_settings: templates_file: "config/message_templates.json" # Path inside the container # ...
- Host
-
Run the Docker container: From your dedicated directory (
~/jellycord_bot_datain this example), run the following command:docker run -d \ --name jellycord \ --env-file .env \ -v "$(pwd)/config/config.yaml:/app/config/config.yaml:ro" \ -v "$(pwd)/config/message_templates.json:/app/config/message_templates.json:ro" \ -v "$(pwd)/my_bot_db:/app/data/db" \ -v "$(pwd)/my_bot_logs:/app/logs" \ sidikulous/jellycord:latest
--env-file .env: Passes your secrets from~/jellycord_bot_data/.envto the container.-v "$(pwd)/config/config.yaml:/app/config/config.yaml:ro": Mounts your hostconfig.yaml.-v "$(pwd)/config/message_templates.json:/app/config/message_templates.json:ro": Mounts your hostmessage_templates.json.-v "$(pwd)/my_bot_db:/app/data/db": Mounts your host database directory.-v "$(pwd)/my_bot_logs:/app/logs": Mounts your host logs directory.-d: Runs the container in detached mode.sidikulous/jellycord:latest: Specifies the image to use.
Alternative: Building the Docker image locally
-
Build the Docker image: From the root of the project directory (where the
Dockerfileis located):docker build -t jellycord-bot . -
Run the Docker container (using local build): Follow the same steps 1 and 2 from the "Pre-built Image" section to prepare your host environment and configure
config.yaml. Then, run the container using your locally built image name:# Ensure you are in your dedicated directory (e.g., ~/jellycord_bot_data) docker run -d \ --name jellycord \ --env-file .env \ -v "$(pwd)/config/config.yaml:/app/config/config.yaml:ro" \ -v "$(pwd)/config/message_templates.json:/app/config/message_templates.json:ro" \ -v "$(pwd)/my_bot_db:/app/data/db" \ -v "$(pwd)/my_bot_logs:/app/logs" \ jellycord-bot # Use your local image name
Common Docker Operations:
- To view logs:
docker logs jellycord -f
- To stop the container:
docker stop jellycord
- To remove the container (after stopping):
docker rm jellycord
Updating the Bot (Docker):
To update Jellycord to the latest version when using a pre-built Docker image:
-
Pull the latest image from Docker Hub:
docker pull sidikulous/jellycord:latest
-
Stop the currently running container:
docker stop jellycord
-
Remove the old container: This does not delete your data volumes.
docker rm jellycord
-
Run the new container using the same
docker runcommand as before. Ensure your volume mounts (-v) forconfig.yaml,message_templates.json(if used),bot_data_db, andbot_data_logsare identical to your initial setup. This will reconnect the new container to your existing data and configuration.Navigate to your dedicated bot directory (e.g.,
~/jellycord_bot_data) and execute:docker run -d \ --name jellycord \ --env-file .env \ -v "$(pwd)/config/config.yaml:/app/config/config.yaml:ro" \ -v "$(pwd)/config/message_templates.json:/app/config/message_templates.json:ro" \ -v "$(pwd)/my_bot_db:/app/data/db" \ -v "$(pwd)/my_bot_logs:/app/logs" \ sidikulous/jellycord:latest
Your existing database and logs will be used by the updated bot.
- Ensure the
db_file_name(data/db/your_database.db),log_file_name(logs/your_log.log), andtemplates_file(config/message_templates.json) paths in your host'sconfig/config.yamlcorrectly point to locations that align with the container's perspective, as configured by the volume mounts.
- Ensure the
Configuration is primarily managed via config/config.yaml. Environment variables can override these settings. Refer to config/config.yaml.example for a comprehensive list of options.
Key sections in config/config.yaml:
bot_settings: General bot settings (name, log file, database file, debug mode).discord: Discord-specific settings (token, guild ID, admin log channel, authorized roles/channels for commands, role for trial users, notification channel and timings).jfa_go: JFA-GO connection details (base URL, username, password - ideally set in.env, default trial profile).invite_settings: Global settings for invite generation (base URL for invite links, default link validity, trial account duration, label formats for trial/paid invites, JFA-GO profile to Discord role mapping for paid invites).message_settings: Path toconfig/message_templates.json, default embed colors, default embed footer text (can use{bot_name}placeholder), and the bot's display name used in messages.notification_settings: Configuration for user expiry notifications (how far ahead to check for expiries, how often to send the same notification, and on which specific days before expiry to notify).commands: Fine-grained settings for specific commands:create_trial_invite: Override JFA-GO user expiry, label format, and assigned Discord role for trial invites.create_user_invite: Override invite link validity, define the mapping from JFA-GO plans to Discord roles, and specify the trial role to remove when a user plan is given./remove_invite [user_identifier]: Identifies a user by Discord mention/ID or Jellyfin username. Attempts to delete the user from JFA-GO, delete their associated JFA-GO invite code, and sets their invite status to 'disabled' in Jellycord's local database. It also attempts to revert their Discord roles./extend-plan [user] [jfa_username] [months/days/hours/minutes (at least one required)] [reason (optional)] [notify (optional)]: Extends a user's JFA-GO plan.
The project is structured with a src/ directory containing the core application code.
src/main.py: Entry point; initializes logging, configuration, the bot instance, registers handlers, and runs the bot.src/modules/config.py: Loads and validates configuration fromconfig/config.yamland environment variables.src/modules/logging_setup.py: Configures application-wide logging (output tologs/).src/modules/messaging.py: Loadsconfig/message_templates.jsonand provides message/embed helpers.src/modules/models.py: Defines data classes.src/modules/database.py: Manages SQLite database interactions (database stored indata/db/).src/modules/jfa_client.py: Handles all communication with the JFA-GO API.src/modules/bot.py: Defines the mainJfaGoBotclass, event handling, command tree, and background tasks.src/modules/commands/: Sub-package for command definitions.auth.py: Authorization decorators.invite_commands.py: Logic for/create-trial-invite.user_invite_commands.py: Logic for/create-user-invite.admin_commands.py: Logic for/remove_inviteand/extend-plan.
Once the bot is running and configured:
- Invite the bot to your Discord server.
- Ensure commands are usable in channels/categories listed in
discord.command_channel_ids. - Ensure users who need to run commands have a role listed in
discord.command_authorized_roles. - Available slash commands (exact behavior and output are configurable):
/create-trial-invite: Creates a trial invite for a user in the current channel/thread (user is auto-detected)./create-user-invite [user] [plan_type] [months (optional)] [days (optional)]: Creates a user invite for a specified Discord user, assigning them to a JFA-GO plan./remove_invite [user_identifier]: Identifies a user by Discord mention/ID or Jellyfin username. Attempts to delete the user from JFA-GO, delete their associated JFA-GO invite code, and sets their invite status to 'disabled' in Jellycord's local database. It also attempts to revert their Discord roles./extend-plan [user] [jfa_username] [months/days/hours/minutes (at least one required)] [reason (optional)] [notify (optional)]: Extends a user's JFA-GO plan.
Contributions, issues, and feature requests are welcome!
This project is licensed under the GNU License. See the LICENSE file for details.




