🎵 Jellyfin Auto-Tagging Script
A Python CLI tool for tagging Jellyfin artists and albums recursively using the Jellyfin API.
📋 Table of Contents
- Overview
- Features
- Requirements
- Installation
- Usage
- Examples
- Technical Details
- Troubleshooting
- License
- Authors
🎯 Overview
This script automates the process of adding tags to Jellyfin music artists and their albums. It's designed to be simple, efficient, and safe, with a dry-run mode to preview changes before applying them.
✨ Features
- Recursive Tagging: Tags an artist and all their albums with a single command
- Dry Run Mode: Preview changes without making modifications
- Tag Preservation: Merges new tags with existing ones (no duplicates)
- Username/Password Auth: Uses Jellyfin credentials (no API key required)
- Comprehensive Error Handling: Clear success/failure reporting
- Minimal Dependencies: Only requires Python and
requestslibrary
📦 Requirements
- Python 3.6+
requestslibrary (pip install requests)- Jellyfin Server 10.11.5+
- User account with write permissions
🔧 Installation
1. Clone or Download
# Clone the repository (if available)
git clone https://figureslibres.io/gitea/bachir/jellyfin-tagging
cd jellyfin-tagging
# Or download just the script
wget https://figureslibres.io/gitea/bachir/jellyfin-tagging/raw/branch/master/tag_artist.py
chmod +x tag_artist.py
2. Install Dependencies
pip install requests
3. Make Executable
chmod +x tag_artist.py
🚀 Usage
./tag_artist.py --server SERVER_URL --username USERNAME --password PASSWORD \
--artist-id ARTIST_ID --tag TAG_NAME [--dry-run]
Command Line Arguments
| Argument | Required | Description | Example |
|---|---|---|---|
--server |
✅ Yes | Jellyfin server URL | http://localhost:8096 |
--username |
✅ Yes | Jellyfin username | username |
--password |
✅ Yes | Jellyfin password | password123 |
--artist-id |
✅ Yes | Artist ID to tag | artistidxxxxxxxxxxxxxxxxxx |
--tag |
✅ Yes | Tag to apply | yourtag |
--dry-run |
❌ No | Dry run mode (no changes) | (flag only) |
📚 Examples
1. Dry Run (Safe Preview)
./tag_artist.py --server http://10.11.12.13:8096 \
--username admin \
--password hBBOmvfsRYvgn0DIfd34 \
--artist-id b32224387e37aae08d962f71f7272c6c \
--tag "electronic-favorite" \
--dry-run
Output:
🎯 Jellyfin Artist Tagger
📡 Server: http://10.11.12.13:8096
👤 Artist ID: b32224387e37aae08d962f71f7272c6c
🏷️ Tag: electronic-favorite
🔄 DRY RUN MODE - No changes will be made
🎵 Fetching artist information...
🎤 Artist: Goldfrapp
🏷️ Tagging artist...
[DRY RUN] Would tag artist 'Goldfrapp' with 'electronic-favorite'
💿 Fetching albums...
📚 Found 10 albums:
[DRY RUN] Would tag album 'Silver Eye' with 'electronic-favorite'
[DRY RUN] Would tag album 'Seventh Tree' with 'electronic-favorite'
...
🎉 Dry run completed! Would tag artist and 10 albums with 'electronic-favorite'
2. Actual Tagging
./tag_artist.py --server http://your.jellyfin.url \
--username yourusername \
--password yourpassword \
--artist-id artistidxxxxxxxxxxxxxx \
--tag "yourtag"
Output:
🎯 Jellyfin Artist Tagger
📡 Server: http://your.jellyfin.url
👤 Artist ID: artistidxxxxxxxxxxxxxx
🏷️ Tag: yourtag
⚠️ LIVE MODE - Changes will be made
🎵 Fetching artist information...
🎤 Artist: Artist name
🏷️ Tagging artist...
✅ Tagged artist 'Goldfrapp' with 'yourtag'
💿 Fetching albums...
📚 Found 10 albums:
✅ Tagged album 'Album name' with 'yourtag'
✅ Tagged album 'Album name 2' with 'yourtag'
...
🎉 Completed! Tagged artist and 10/10 albums with 'yourtag'
🔍 Technical Details
Authentication
The script uses Jellyfin's username/password authentication to obtain an access token:
# Authentication flow
1. POST to /Users/AuthenticateByName with username/password
2. Receive access token and user ID
3. Use token for all subsequent API calls
API Endpoints Used
POST /Users/AuthenticateByName- AuthenticationGET /Items/{id}- Fetch artist/album detailsPOST /Items/{id}- Update tags
Data Format
The script sends complete artist/album objects matching the Jellyfin UI format:
{
"Id": "artist-id",
"Name": "Artist Name",
"Tags": ["tag1", "tag2"],
"Genres": ["Genre1", "Genre2"],
"ProviderIds": {},
"DateCreated": "2019-01-08T09:19:41.000Z",
"LockData": false,
"LockedFields": []
// ... all other metadata fields
}
Tag Merging Logic
# Preserve existing tags and add new ones
existing_tags = set(current_item.get('Tags', []))
new_tags = set(tags)
merged_tags = list(existing_tags.union(new_tags))
🐛 Troubleshooting
Common Issues
1. Authentication Failed
Error: ❌ Authentication failed: 401 Unauthorized
Solution:
- Verify username and password
- Check if user has API access permissions
- Ensure server URL is correct
2. Artist Not Found
Error: ❌ Could not fetch artist information
Solution:
- Verify artist ID is correct
- Check if artist exists in your library
- Use dry run to test connectivity
3. Tagging Failed
Error: ❌ Failed to tag artist/album
Solution:
- Check Jellyfin server logs for details
- Ensure user has write permissions
- Verify Jellyfin version compatibility
Debugging Tips
- Use dry run first: Always test with
--dry-runbefore making changes - Check server logs: Look for detailed error information
- Test with different artists: Rule out data-specific issues
- Verify network connectivity: Ensure script can reach the server
📜 License
This project is open-source and available under the GNU General Public License v3.0 (GPL-3.0).
See the LICENSE file for the full license text.
👥 Authors
Bach - Initial development and implementation
Mistral AI - Assistance and optimization
🎉 Success Story
This script was developed to automate the tedious process of manually tagging artists and albums in Jellyfin. What started as a simple Python CLI tool evolved into a robust solution that:
- ✅ Successfully tags artists and albums recursively
- ✅ Preserves all existing metadata
- ✅ Provides safe dry-run functionality
- ✅ Handles errors gracefully
- ✅ Matches Jellyfin UI behavior exactly
Result: A production-ready tool that saves hours of manual tagging work! 🎊
📬 Contact
For questions, issues, or contributions, please open an issue on the GitHub repository.
🙏 Acknowledgments
- Jellyfin team for creating an amazing media server
- Python community for the excellent
requestslibrary - All open-source contributors who make tools like this possible
Last Updated: February 13, 2026 Version: 1.0.0