🎵 akuibots-musical (Python)
Plugin musik untuk bot — bukan bot-nya. Kirim judul atau link (YouTube / Spotify), plugin balas metadata lengkap: thumbnail, judul, durasi, pembuat — plus audio stream yang siap diputar di voice bot.
🟢 Versi Node.js:
akuibots-musicaldi npm — API-nya sengaja dibuat mirip, tinggal pindah bahasa.
from akuibots_musical import Musical
music = Musical()
track = music.play("a!p alan walker faded") # judul → dicari otomatis di YouTube
track = music.play("https://youtu.be/60ItHLz5WEA") # link YouTube
track = music.play("https://open.spotify.com/track/4uLU6hMCjMI75M1A2tKUQC") # link Spotify
print(track.title) # Alan Walker - Faded
print(track.author) # Alan Walker
print(track.duration_text) # 3:33
print(track.thumbnail) # https://i.ytimg.com/vi/.../hqdefault.jpg
handle = music.get_stream(track)
print(handle.url) # URL audio → pipa ke ffmpeg (voice bot)
✨ Fitur
- 🔎 Kirim judul → dicari otomatis di YouTube (kayak
ytsearch), ambil hasil teratas - 🔗 Kirim link → YouTube (watch / youtu.be / shorts / live / music) & Spotify (track / album / playlist / artist) langsung dikenali
- 🖼️ Data lengkap: thumbnail, judul, durasi, pembuat (uploader), views, status live
- 🔊 Audio stream siap dipipa ke ffmpeg — discord.py, py-cord, Telegram, CLI, apa saja
- ⚡ Tanpa Lavalink, tanpa API key, tanpa browser headless
- 🧹 Pembersih perintah otomatis:
a!p faded,!play faded,music-bot!p faded→faded - 🌐 Spotify tanpa API key (token anonim embed + fallback oEmbed) → dicocokkan ke YouTube untuk audionya
- 🐍 Dependency minimal:
yt-dlp+requests— Python ≥ 3.8 - 🌀 Async ready:
play_async()dkk. untuk bot berbasis asyncio (discord.py, dll)
📦 Instalasi
pip install akuibots-musical
Untuk memutar audio di voice bot kamu juga butuh ffmpeg terpasang di server
(apt install ffmpeg / brew install ffmpeg).
🚀 Quick Start
1 — Instal:
pip install akuibots-musical
2 — Play dari judul (alur a!p):
from akuibots_musical import Musical
music = Musical()
track = music.play("a!p alan walker faded")
# prefix 'a!p' otomatis dibuang → dicari 'alan walker faded' di YouTube
3 — Play dari link (YouTube / Spotify):
track = music.play("https://www.youtube.com/watch?v=60ItHLz5WEA")
track = music.play("https://open.spotify.com/track/4uLU6hMCjMI75M1A2tKUQC")
# Spotify → metadata diambil tanpa API key, lalu dicocokkan ke YouTube
4 — Ambil audio untuk voice:
handle = music.get_stream(track) # atau music.get_stream("a!p faded")
print(handle.url) # URL audio langsung (m4a/opus)
📦 Isi Track
| Field | Tipe | Contoh | Keterangan |
|---|---|---|---|
id |
str |
60ItHLz5WEA |
video ID YouTube |
title |
str |
Alan Walker - Faded |
judul |
author |
str |
Alan Walker |
pembuat / uploader |
duration |
int | None |
213 |
durasi dalam detik (None kalau live) |
duration_text |
str |
"3:33" / "Live" |
durasi siap tampil |
duration_ms |
property | 213000 |
durasi dalam milidetik |
thumbnail |
str |
https://i.ytimg.com/vi/... |
gambar thumbnail |
url |
str |
https://www.youtube.com/watch?v=... |
halaman YouTube |
is_live |
bool |
False |
sedang live? |
view_count |
int | None |
3500000000 |
jumlah views |
source |
str |
"youtube" / "spotify" |
asal track |
spotify_url |
str | None |
link Spotify asal (kalau dari Spotify) | |
spotify_title |
str | None |
judul asli di Spotify | |
spotify_author |
str | None |
artis asli di Spotify | |
query |
str | None |
alan walker faded |
judul yang diketik user |
to_dict() |
→ dict |
semua field sebagai dict |
🔊 Isi StreamHandle
| Field / Method | Keterangan |
|---|---|
handle.url |
URL audio langsung (m4a/opus; live = HLS m3u8) → pipa ke ffmpeg |
handle.ext / handle.abr / handle.format_id |
info format audio |
handle.is_live |
True kalau live stream |
handle.track |
objek Track asalnya |
handle.iter_chunks(size=65536) |
generator byte audio (untuk relay manual) |
handle.save(path) |
unduh audio ke file |
handle.popen() |
subprocess yt-dlp → byte audio mentah di proc.stdout (paling tahan bot-check) |
handle.pcm_popen() |
yt-dlp → ffmpeg → PCM siap discord.PCMAudio; return (proc_ytdlp, proc_ffmpeg) |
handle.read_all() |
semua byte sekaligus (hati-hati memori) |
URL audio berlaku ± 6 jam dan terikat IP — ambil ulang (get_stream) setiap
kali memutar, jangan simpan lama.
🔎 Cara kerja — alur a!p
User : a!p faded
└─> bot memanggil music.play("a!p faded")
└─> buang prefix 'a!p' → 'faded'
└─> bukan link → cari di YouTube (ytsearch)
└─> ambil hasil teratas → Track {title, author, duration, thumbnail, url}
└─> bot balas embed (thumbnail + judul + durasi + channel)
└─> music.get_stream(track) → URL audio → ffmpeg → voice channel
Link dikenali otomatis: YouTube → ambil langsung; Spotify → ambil metadata
lalu cocokkan ke YouTube; link lain → error UNSUPPORTED_SOURCE.
📖 API Reference
Musical(strip_prefix=True, default_limit=5, ytdlp_options=None)
| Option | Default | Keterangan |
|---|---|---|
strip_prefix |
True |
buang prefix perintah (a!p, !play, bot!p, ...) otomatis |
default_limit |
5 |
jumlah hasil default search() |
ytdlp_options |
None |
opsi yt-dlp tambahan, mis. {"cookiefile": "cookies.txt"} |
Metode
| Metode | Input | Return |
|---|---|---|
search(query, limit=None) |
judul | list[Track] |
resolve(text) |
judul / link (boleh berprefix a!p) |
Track |
play(text) |
sama dengan resolve |
Track |
get_stream(x) |
Track / judul / link |
StreamHandle |
play_stream(x) |
Track / judul / link |
(Track, StreamHandle) |
search_async, resolve_async, play_async, get_stream_async, play_stream_async |
sama | coroutine (asyncio) |
Fungsi standalone (instance default)
from akuibots_musical import play, resolve, search, get_stream, play_stream
track = play("a!p faded")
Helper
parse_command, strip_command_prefix, is_url, detect_source,
format_duration, extract_youtube_id, resolve_spotify — dan
MusicalError dengan .code: INVALID_INPUT, NOT_FOUND, SEARCH_FAILED,
UNSUPPORTED_SOURCE, SPOTIFY_FAILED, STREAM_FAILED.
🤖 Contoh: Bot Discord (discord.py)
import discord
from discord.ext import commands
from akuibots_musical import Musical
music = Musical()
intents = discord.Intents.default()
intents.message_content = True
bot = commands.Bot(command_prefix="a!", intents=intents)
@bot.event
async def on_ready():
print("Bot siap:", bot.user)
@bot.command()
async def p(ctx, *, query: str):
"""a!p <judul/link> → play musik di voice channel."""
if not ctx.author.voice:
return await ctx.send("Masuk voice channel dulu ya 🎧")
await ctx.send(f"🔍 Mencari: `{query}`")
track = await music.play_async(query) # judul ATAU link
handle = await music.get_stream_async(track) # metadata + audio
if ctx.voice_client is None:
await ctx.author.voice.channel.connect()
# ✅ Pola paling awet (2025+): yt-dlp yang mengunduh audionya
# (headers & PO token diurus yt-dlp), lalu dipipa ke ffmpeg.
# URL mentah handle.url langsung ke ffmpeg sering DITOLAK YouTube
# (bot jalan tapi tanpa suara).
ytdlp_proc, ff_proc = handle.pcm_popen()
source = discord.PCMAudio(ff_proc.stdout)
def selesai(e):
for p in (ytdlp_proc, ff_proc):
try:
p.kill()
except Exception:
pass
if e:
print("FFmpeg error:", e)
ctx.voice_client.stop()
ctx.voice_client.play(source, after=selesai)
embed = discord.Embed(title=track.title, url=track.url, color=0x2B6CB0)
embed.set_thumbnail(url=track.thumbnail)
embed.add_field(name="Durasi", value=track.duration_text, inline=True)
embed.add_field(name="Channel", value=track.author, inline=True)
embed.set_footer(text=f"Sumber: {track.source}")
await ctx.send(embed=embed)
bot.run("TOKEN_BOT")
✈️ Contoh: Bot Telegram (python-telegram-bot)
from telegram.ext import Application, CommandHandler, ContextTypes
from telegram import Update
from akuibots_musical import Musical
music = Musical()
async def p(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = " ".join(context.args or [])
if not query:
return await update.message.reply_text("Kirim judul atau link: /p faded")
msg = await update.message.reply_text(f"🔍 Mencari: {query}")
track, handle = await music.play_stream_async(query)
await msg.edit_text(
f"🎵 {track.title}\n"
f"👤 {track.author}\n"
f"⏱ {track.duration_text}\n"
f"🔗 {track.url}"
)
# opsional — kirim file audionya juga:
# handle.save("lagu.m4a") lalu reply_audio
app = Application.builder().token("TOKEN_BOT").build()
app.add_handler(CommandHandler("p", p))
app.run_polling()
🖥️ Contoh: CLI
#!/usr/bin/env python3
import subprocess, sys
from akuibots_musical import music
track, handle = music.play_stream(" ".join(sys.argv[1:]))
print(f"▶ {track.title} — {track.author} [{track.duration_text}]")
subprocess.run(["ffplay", "-nodisp", "-autoexit", "-loglevel", "quiet", handle.url])
python player.py "a!p alan walker faded"
⚙️ Opsi yt-dlp & cookies
Semua opsi yt-dlp bisa diteruskan lewat ytdlp_options:
music = Musical(ytdlp_options={
"cookiefile": "cookies.txt", # cookies browser (Netscape)
"extractor_args": {"youtube": {"player_client": ["ios", "web"]}},
})
🆘 Troubleshooting
| Masalah | Penyebab & solusi |
|---|---|
Sign in to confirm you're not a bot |
YouTube menandai IP server/VPS. Export cookies.txt dari browser (format Netscape) lalu Musical(ytdlp_options={"cookiefile": "cookies.txt"}). Di IP rumah biasanya langsung jalan. |
ffmpeg not found |
Pasang ffmpeg: apt install ffmpeg / brew install ffmpeg. |
| URL audio 403 setelah lama | URL kadaluarsa (±6 jam) & terikat IP. Panggil get_stream() ulang sebelum tiap memutar. |
| Bot jalan, embed muncul, tapi tidak ada suara | URL audio mentah ditolak YouTube saat diambil ffmpeg langsung (PO token/SABR — aturan baru YouTube 2025+). Solusi: ① pip install -U yt-dlp dan pasang Deno, ② pakai pola pipe handle.pcm_popen() pada contoh Discord (yt-dlp yang mengunduh audionya, bukan ffmpeg), ③ tes dengan script diagnosis di bawah. |
SPOTIFY_FAILED |
Link privat/regional atau diblokir. Coba link track langsung dari aplikasi Spotify (Share → Copy link). |
UNSUPPORTED_SOURCE |
Link bukan YouTube/Spotify. Plugin ini hanya menerima keduanya + judul. |
| Hasil pencarian kurang pas | Beri judul lebih spesifik, mis. a!p alan walker faded bukan a!p faded. |
❓ FAQ
Ini bot Discord?
Bukan. Ini plugin/library yang dipasang di bot kamu (Discord, Telegram,
WhatsApp, CLI, apa saja). Bot yang memproses perintah a!p, plugin ini yang
mengerjakan musiknya.
Sama kayak Lavalink?
Gak perlu server Lavalink, gak perlu Java, gak perlu API key. Cukup
pip install akuibots-musical — pencarian & stream langsung jalan.
Kenapa Spotify cuma dapat metadata?
Spotify tidak menyediakan audio untuk pihak ketiga. Plugin mengambil metadata
Spotify (judul + artis), lalu otomatis mencocokkannya ke YouTube — jadi
music.play_stream(<link spotify>) tetap menghasilkan audio.
Bisa buat download mp3?
Bisa — handle.save("lagu.m4a"), atau konversi pakai ffmpeg ke mp3.
Bedanya dengan versi npm?
| npm (Node.js) | PyPI (Python) |
|---|---|
new Musical({...}) |
Musical(strip_prefix=True, ...) |
await music.play(text) |
music.play(text) / await music.play_async(text) |
await music.getStream(x) |
music.get_stream(x) |
track.durationText |
track.duration_text |
Node Readable stream |
StreamHandle (url, iter_chunks(), save()) |
Pakai yt-dlp? Ya — mesin pencarian & ekstraksi memakai yt-dlp
yang aktif dirawat, jadi jauh lebih tahan perubahan YouTube daripada
library ytdl-core lama.
📄 Lisensi
MIT — © 2026 Akuibots. Versi npm: akuibots-musical.
Metadata
Release files for akuibots-musical 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| akuibots_musical-1.0.1.tar.gz | 24.4 kB | Without provenance | Details for akuibots_musical-1.0.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| akuibots_musical-1.0.1-py3-none-any.whl | Python 3 | none | any | Details for akuibots_musical-1.0.1-py3-none-any.whl |
Total release size: 44.7 kB
Release files / akuibots_musical-1.0.1.tar.gz
| Download URL | akuibots_musical-1.0.1.tar.gz |
|---|---|
| Size | 24.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a59b25d99b136e80237a6f60f13bc478c554ed824e9b6e92d478958de91b64d7
|
|
BLAKE2b-256 checksum How to use checksums |
2189fddec60c6c7100f60ef1db98e62583df80c4fe5c5b19cf3772f24c66202b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.16
|
Release files / akuibots_musical-1.0.1-py3-none-any.whl
| Download URL | akuibots_musical-1.0.1-py3-none-any.whl |
|---|---|
| Size | 20.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e91023f548bce0a9630c6209558aa9ae6cdd0b341bbe752cabb2519d294d5e87
|
|
BLAKE2b-256 checksum How to use checksums |
6793bc5190100f83e76d9ba1255337e7500bd5d02b7e55f8e053c354bc14d724
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.16
|
Security for akuibots-musical 1.0.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.