ytmusic-hub · git:20260312.babbb60 · 2026-03-12 · sha256 e5a7590c4cddab4f
ytmusic-hub git:20260312.babbb60A
Immutable. This exact content is served forever at /api/v1/blob/e5a7590c4cddab4f.
---
name: ytmusic-hub
description: Read and write YouTube Music data using Python + ytmusicapi, authenticated via browser cookies obtained automatically with browser_use get_cookies — no manual copying required. Supports fetching playlists, liked songs, playlist details, creating/editing/deleting playlists, searching and adding songs, recommendations, charts, and lyrics. Trigger this skill whenever the user mentions "YouTube Music", "YT Music", "ytmusic", "ytmusic-hub", "get YouTube playlists", "create YouTube Music playlist", "my liked songs", "YTM playlist", or any scenario requiring programmatic read/write access to YouTube Music data.
---
# ytmusic-hub
Interact with YouTube Music using the `ytmusicapi` library, authenticated via browser cookies. Supports full playlist management, search, liked songs, and more.
---
## Setup
### Install dependency
```bash
pip install ytmusicapi
```
### Auth file path
```
/var/minis/workspace/ytmusic_headers.json
```
---
## Authentication (run before first use or when cookies expire)
Two steps: **get cookies** → **generate auth file**.
### Step 1: Get cookies
Navigate to YouTube Music and get cookies via `browser_use`:
```
browser_use navigate: https://music.youtube.com
browser_use get_cookies -> save env file path
```
Confirm the page is logged in (avatar visible in top-right), then call `get_cookies` and note the env file path.
### Step 2: Generate auth file
Load the env file and run the auth setup script:
```bash
. /var/minis/offloads/env_cookies_youtube_com_xxx.sh
python3 /var/minis/skills/ytmusic-hub/scripts/setup_auth.py
```
The script reads all Cookie env vars and writes a browser-auth file with SAPISIDHASH to `/var/minis/workspace/ytmusic_headers.json`.
### Step 3: Initialize YTMusic client
Use the unified client module — it automatically handles DNS pollution and SSL issues:
```python
import sys
sys.path.insert(0, "/var/minis/skills/ytmusic-hub/scripts")
from ytmusic_client import get_client
yt = get_client()
```
`get_client()` will automatically:
1. Patch urllib3 to disable SSL certificate verification (required in iSH)
2. Detect if local DNS is polluted
3. If polluted, resolve the real IP via Google DoH and patch `socket.getaddrinfo`
4. Return a ready-to-use YTMusic instance, or raise `RuntimeError` with a clear message
---
## API Reference
### 📋 Playlist Management
```python
# Get all my playlists
playlists = yt.get_library_playlists(limit=25)
# Returns: [{playlistId, title, count, ...}, ...]
# Get playlist contents (all tracks)
playlist = yt.get_playlist(playlistId, limit=100)
# Returns: {title, description, trackCount, tracks: [{videoId, title, artists, ...}]}
# Create a new playlist
playlistId = yt.create_playlist(
title="Playlist name",
description="Description",
privacy_status="PRIVATE" # PUBLIC / PRIVATE / UNLISTED
)
# Edit playlist metadata
yt.edit_playlist(playlistId, title="New name", description="New description")
# Delete a playlist
yt.delete_playlist(playlistId)
# Add songs to a playlist
yt.add_playlist_items(playlistId, videoIds=["videoId1", "videoId2"])
# Remove songs from a playlist
# setVideoId is the track's unique ID within the playlist (different from videoId)
tracks = yt.get_playlist(playlistId)["tracks"]
yt.remove_playlist_items(playlistId, tracks=[
{"videoId": t["videoId"], "setVideoId": t["setVideoId"]}
for t in tracks if t["title"] == "Target song"
])
```
### ❤️ Liked Songs & Library
```python
# Get liked songs
liked = yt.get_liked_songs(limit=100)
tracks = liked["tracks"] # [{videoId, title, artists, album, ...}]
# Get library songs / albums / artists
songs = yt.get_library_songs(limit=25)
albums = yt.get_library_albums(limit=25)
artists = yt.get_library_artists(limit=25)
# Like / unlike a song
yt.rate_song(videoId, "LIKE") # LIKE / DISLIKE / INDIFFERENT
```
### 🔍 Search
```python
# General search (mixed results)
results = yt.search("Jay Chou")
# Filter by type
songs = yt.search("Jay Chou", filter="songs")
videos = yt.search("Jay Chou", filter="videos")
albums = yt.search("Jay Chou", filter="albums")
artists = yt.search("Jay Chou", filter="artists")
# Get videoId for adding to playlist
videoId = songs[0]["videoId"]
```
### 🎵 Browse & Recommendations
```python
# Home feed
home = yt.get_home()
# Charts (global or by country)
charts = yt.get_charts(country="US") # TW / HK / CN / JP / KR etc.
# Mood playlists
moods = yt.get_mood_categories()
mood_playlists = yt.get_mood_playlists(params=moods["Moods & moments"][0]["params"])
# Lyrics
watch = yt.get_watch_playlist(videoId="videoId")
lyrics_id = watch.get("lyrics")
if lyrics_id:
lyrics = yt.get_lyrics(lyrics_id)
print(lyrics["lyrics"])
```
### 🎤 Artists & Albums
```python
artist = yt.get_artist(channelId)
album = yt.get_album(browseId)
user = yt.get_user(channelId)
user_playlists = yt.get_user_playlists(channelId, params)
```
---
## Common Workflows
### Workflow A: Search and add a song to a playlist
```python
results = yt.search("Gao Wu Ren - Love Missed", filter="songs")
videoId = results[0]["videoId"]
playlists = yt.get_library_playlists()
for i, pl in enumerate(playlists):
print(f"{i+1}. {pl['title']} [{pl['playlistId']}]")
yt.add_playlist_items(playlistId, videoIds=[videoId])
print("✅ Added to playlist")
```
### Workflow B: Create a playlist from liked songs
```python
new_id = yt.create_playlist("My Favorites", "Picked from liked songs", "PRIVATE")
liked = yt.get_liked_songs(limit=50)
ids = [t["videoId"] for t in liked["tracks"][:20]]
yt.add_playlist_items(new_id, videoIds=ids)
print(f"✅ Created playlist with {len(ids)} songs")
```
### Workflow C: Export a playlist as Markdown
```python
playlist = yt.get_playlist(playlistId, limit=200)
lines = [f"# {playlist['title']}", f"> {playlist.get('description', '')}", ""]
for i, t in enumerate(playlist["tracks"], 1):
artists = ", ".join(a["name"] for a in t.get("artists", []))
lines.append(f"{i}. **{t['title']}** — {artists}")
print("\n".join(lines))
```
---
## Notes
- **Cookie expiry**: Cookies typically last days to weeks. Re-run the auth flow when they expire.
- **Auth file security**: `ytmusic_headers.json` contains login credentials — do not share it.
- **Rate limits**: ytmusicapi is unofficial. Avoid bulk operations that may trigger Google's rate limiting.
- **Network**: Requires access to `music.youtube.com`. The client module handles DNS pollution and SSL issues automatically.
- **videoId vs setVideoId**: When removing tracks from a playlist, you must use `setVideoId` (the track's position-specific ID), not `videoId`.