Automatically scrobble songs to Last.fm by listening to your environment and identifying music with Shazam. Useful for when you are playing music from a source without a digital integration (vinyl, tape deck, vintage CD player, etc.).
- Passive audio scrobbling: Listens to your microphone, identifies music, and scrobbles to Last.fm automatically.
- Duplicate prevention: Automatically checks Last.fm to ensure the same song isn't scrobbled twice in a row.
- Shazam integration: Uses Shazam for robust song identification.
- Customizable duty cycle: Control how often the program listens and scrobbles.
- Flexible credentials: Easily specify your credentials file location.
- Python 3.13+
- uv (for running and installing dependencies)
- Microphone/input device
- Clone the repository
git clone [email protected]:guillochon/autoscrobbler.git cd autoscrobbler
- Install dependencies
uv sync
Create a credentials.json file in the project root or specify its path with --credentials. Instructions on how to get your last.fm credentials available here.
Example credentials.json:
{
"lastfm": {
"api_key": "YOUR_LASTFM_API_KEY",
"api_secret": "YOUR_LASTFM_API_SECRET",
"username": "YOUR_LASTFM_USERNAME",
"password": "YOUR_LASTFM_PASSWORD"
}
}Run the program using uv run:
uv run -m autoscrobblerNote: You may see some harmless warnings from the pydub library (used by Shazam). These are SyntaxWarnings about regex patterns and don't affect functionality. They are automatically suppressed in the latest version.
-c,--credentials <path>: Path to yourcredentials.jsonfile (optional if in project root or package directory)-d,--duty-cycle <seconds>: Time in seconds between each listening/scrobbling attempt (default: 60)-i,--input-source <source>: Input source for recording. Can be:auto: Use the first available input device- Device index (number): Use the ith device in the list
- Device name (string): Use the device whose name contains the string (case-insensitive)
- If not set, you will be prompted to select a device at startup
- Run with default settings:
uv run -m autoscrobbler
- Specify a custom credentials file:
uv run -m autoscrobbler --credentials /path/to/credentials.json
- Change the duty cycle to 30 seconds:
uv run -m autoscrobbler --duty-cycle 30
- Use the first available input device automatically:
uv run -m autoscrobbler --input-source auto
- Use the 2nd device in the list (index 1):
uv run -m autoscrobbler -i 1
- Use a device by (partial) name:
uv run -m autoscrobbler -i "USB Microphone" - Combine all options:
uv run -m autoscrobbler -c /path/to/credentials.json -d 45 -i auto
- At startup, all available input devices will be listed with their index and name.
- If
--input-sourceis not set, you will be prompted to select a device interactively. - The program will print information about your selected input device and status messages for each scrobble attempt.
- If the credentials file is missing or invalid, you'll get a helpful error message.
- The actual interval between attempts is always as close as possible to your specified duty cycle, accounting for processing time.
- The program automatically checks Last.fm before scrobbling to prevent duplicate scrobbles of the same song.
Run autoscrobbler in a Docker container (Linux/macOS only):
# Build the image
docker build -t autoscrobbler .
# Run with your credentials file
docker run --rm -it --device /dev/snd \
-v /path/to/credentials.json:/app/credentials.json:ro \
autoscrobbler# Run with custom duty cycle and input device
docker run --rm -it --device /dev/snd \
-v /path/to/credentials.json:/app/credentials.json:ro \
autoscrobbler --duty-cycle 30 --input-source "USB Microphone"- Docker installed on your system
- Audio device access (the
--device /dev/sndflag) - Your
credentials.jsonfile mounted into the container
- The container uses Python 3.13+ and includes all necessary audio dependencies
- Your credentials file must be mounted at runtime for security
- Audio input requires access to the host's sound devices
If you see "No input devices found" error:
-
Check audio device access:
# Run the audio check script inside the container docker run --rm -it --device /dev/snd autoscrobbler /app/check_audio.sh -
Verify host audio setup:
# On the host system, check if ALSA is working aplay -l arecord -l -
Common solutions:
- Linux host: Ensure ALSA is installed and working
- Windows host: Use WSL2 with audio forwarding enabled
- macOS host: Use Docker Desktop with audio device sharing
- Raspberry Pi: Add user to audio group:
sudo usermod -a -G audio $USER
-
Alternative Docker run commands:
# For Linux with PulseAudio docker run --rm -it --device /dev/snd --group-add audio \ -v /path/to/credentials.json:/app/credentials.json:ro \ autoscrobbler # For systems with specific audio device docker run --rm -it --device /dev/snd \ -v /path/to/credentials.json:/app/credentials.json:ro \ -e PULSE_SERVER=unix:${XDG_RUNTIME_DIR}/pulse/native \ autoscrobbler
-
Test audio manually:
# Test recording inside container docker run --rm -it --device /dev/snd autoscrobbler \ uv run python -c "import sounddevice as sd; print(sd.query_devices())" # Run comprehensive audio test docker run --rm -it --device /dev/snd autoscrobbler \ uv run python test_docker_audio.py
For continuous operation, you can install autoscrobbler as a systemd service on a Raspberry Pi. This allows it to run automatically on boot and restart if it crashes.
- Raspberry Pi with Raspberry Pi OS (or similar Linux distribution)
- Python 3.13+ installed
- USB microphone or audio input device connected
- Internet connection for Shazam and Last.fm API access
-
Install required system dependencies
sudo apt-get update && sudo apt-get install -y portaudio19-dev -
Clone and install the project
git clone [email protected]:guillochon/autoscrobbler.git cd autoscrobbler curl -LsSf https://astral.sh/uv/install.sh | sh source ~/.bashrc uv sync
Note: The uv installer places the binary in
~/.local/bin/uv. Make sure this directory is in your PATH. -
Create credentials file
sudo mkdir -p /opt/autoscrobbler sudo chown -R pi:pi /opt/autoscrobbler sudo cp credentials.example.json /opt/autoscrobbler/credentials.json
Edit the newly created file to add your last.fm API credentials.
-
Run the setup script
chmod +x setup_audio_service.sh ./setup_audio_service.sh
This script will:
- Add your user to the audio group (if not already added)
- Create the necessary service directory
- Copy the service file to the user space
- Enable the service
- Test audio device access
Note: If the script adds you to the audio group, you'll need to log out and log back in for the changes to take effect.
If the service fails to start:
- Check the logs:
journalctl --user -u autoscrobbler.service -n 50 - Verify audio device permissions:
groups(should include audio) - Test audio manually:
uv run -m autoscrobbler --input-source auto - Check credentials file permissions and content
- Verify uv is installed in the correct location:
which uv(should show/home/pi/.local/bin/uv) - Ensure the project is cloned to
/home/pi/autoscrobbleras expected by the service
Audio device issues:
- Ensure your microphone is properly connected and recognized
- Test with:
arecord -lto list audio devices - Check volume levels:
alsamixer
Network connectivity:
- Ensure the Pi has internet access
- Test Shazam API connectivity manually
- Check firewall settings if applicable
You can modify the service file at ~/.config/systemd/user/autoscrobbler.service to customize:
- Duty cycle: Change
--duty-cycle 60to your preferred interval - Input device: Replace
--input-source autowith a specific device - Credentials path: Update the path if you store credentials elsewhere
- Working directory: Change the
WorkingDirectorypath if your project is located elsewhere
pylastsounddevicesoundfileshazamio- (see
pyproject.tomlfor full list)
-
Install development dependencies
uv sync --extras dev
-
Install pre-commit hooks
pre-commit install
The project uses pytest for testing with comprehensive unit and integration tests.
Run all tests:
uv run pytestRun tests with verbose output:
uv run pytest -vRun specific test file:
uv run pytest tests/test_credentials.pyRun specific test function:
uv run pytest tests/test_credentials.py::TestLoadCredentials::test_load_credentials_successRun tests by marker:
uv run pytest -m unit # Run only unit tests
uv run pytest -m integration # Run only integration tests
uv run pytest -m "not slow" # Run all tests except slow onesRun tests with coverage:
uv run pytest --cov=autoscrobbler --cov-report=htmlThe project uses pre-commit hooks to ensure code quality. These hooks will run automatically on each commit:
- Ruff: Lints and formats Python code
- Ruff format: Ensures consistent code formatting
- Basic checks: Trailing whitespace, end-of-file fixer, YAML validation, and large file detection
You can run the pre-commit hooks manually:
pre-commit run --all-filesMIT