Membangun Downloader Telegram Otomatis: Tinggal Forward, Server yang Kerja

Membangun Downloader Telegram Otomatis: Tinggal Forward, Server yang Kerja

Ada satu masalah klasik kalau sudah punya server media sendiri.

Media berseliweran di Telegram.

IYKWIM. 😏

Kadang ada video, kadang ada foto, kadang ada file yang rasanya:

β€œHmm... ini kayaknya harus masuk koleksi Jellyfin.”

Sebenarnya cara manualnya gampang.

Download di HP β†’ pindahkan ke komputer β†’ upload ke server β†’ rapikan folder β†’ tunggu Jellyfin scan.

Secara teknis tidak sulit.

Masalahnya cuma satu:

You know how lazy I am laaa.

Kalau cuma satu file, masih oke.

Tapi kalau harus dilakukan berkali-kali, mulai muncul kalimat:

β€œNanti aja.”

Dan biasanya β€œnanti” itu tidak pernah datang.

Akhirnya kepikiran:

Kenapa nggak Telegram saja yang mengantarkan medianya ke server?

Jadi daripada download di HP lalu upload manual ke Jellyfin, saya cukup forward media dari nomor A ke nomor B.

Sisanya biar homelab yang kerja.


1. Memanfaatkan Git

Daripada membuat downloader Telegram sendiri dari nol, saya mencari project yang sudah mengerjakan bagian yang merepotkan tersebut.

Pilihan yang digunakan adalah:

Dineshkarthik/telegram_media_downloader di GitHub

Repository tersebut kemudian di-clone ke homelab:

cd /home/serverkamu/PYTHON

git clone https://github.com/Dineshkarthik/telegram_media_downloader.git

cd telegram_media_downloader

Kenapa pakai Git?

Ya karena kalau nanti project-nya mau di-update, dicek perubahannya, atau sekadar ingin tahu source code yang sedang digunakan, semuanya sudah rapi.

Tidak perlu:

β€œIni file Python bikinan siapa ya?”

2. Python Virtual Environment

Karena ini Python project, dependency-nya dipisahkan dari Python sistem.

python3 -m venv .venv
source .venv/bin/activate

Kemudian:

make install

Sekarang downloader punya lingkungan Python sendiri.

telegram_media_downloader/
β”œβ”€β”€ .venv/
β”œβ”€β”€ media_downloader.py
β”œβ”€β”€ config.yaml
β”œβ”€β”€ media_downloader.session
└── DOWNLOADS/

Virtual environment ini nantinya juga penting ketika program dijalankan oleh systemd.


3. Nomor B Menjadi Downloader

Saya tidak menggunakan Telegram Bot API.

Tidak ada bot token.

Tidak ada:

A β†’ Bot β†’ Server

Yang digunakan adalah akun Telegram biasa.

Misalnya:

Nomor A = sumber media
Nomor B = akun downloader

Jadi workflow-nya:

Nomor A
    β”‚
    β”‚ forward media
    β–Ό
Nomor B

Nomor B login menggunakan Telegram API dan Telethon.

API ID dan API Hash dibuat melalui:

my.telegram.org/apps

Setelah login pertama kali, Telethon membuat session:

media_downloader.session

Session inilah yang menyimpan autentikasi akun B.

Jadi setelah login pertama:

Nomor B
   ↓
Telethon
   ↓
media_downloader.session

program tidak perlu meminta OTP setiap kali dijalankan.


4. Menentukan Chat yang Dipantau

Downloader perlu tahu percakapan mana yang harus dipantau.

Dari akun B, chat dengan nomor A mempunyai ID:

169172416

Kemudian dimasukkan ke config.yaml:

chats:
  - chat_id: 169172416
    last_read_message_id: 0
    ids_to_retry: []
    download_directory: ./DOWNLOADS

Sekarang server tahu:

Chat yang perlu diperiksa adalah 169172416.

5. Checkpoint Supaya Tidak Download Ulang

Bagian yang sangat penting adalah:

last_read_message_id

Anggap saja downloader sudah memproses:

message ID = 500

Maka config menyimpan:

last_read_message_id: 500

Saat program dijalankan lagi, dia tidak mengulang semuanya dari awal.

Dia tahu:

β€œSaya sudah sampai message 500.”

Ini juga terbukti ketika downloader dijalankan kembali: media yang sudah diproses tidak di-download ulang.

Dengan kata lain, restart server bukan berarti download ulang semua isi chat.


6. Downloader Ternyata Bukan Daemon

Pada awalnya saya kira tinggal menjalankan:

python3 media_downloader.py

dan membiarkannya hidup.

Ternyata tidak.

Downloader bekerja seperti ini:

connect
   ↓
check messages
   ↓
download
   ↓
update checkpoint
   ↓
disconnect
   ↓
exit

Jadi dia bukan proses yang terus menunggu pesan baru.

Kalau ada pesan baru lima menit kemudian, downloader yang sudah exit tentu tidak tahu.

Maka dibutuhkan watcher.


7. Watcher: Cek Setiap 30 Detik

Watcher dibuat sangat sederhana.

Setiap 30 detik, dia:

  1. membaca config.yaml,
  2. mengambil last_read_message_id,
  3. mengambil message terbaru dari chat A β†’ B,
  4. membandingkan ID,
  5. kalau sama β†’ tidak melakukan apa-apa,
  6. kalau berbeda β†’ menjalankan downloader.

Konsepnya:

                 setiap 30 detik
                       β”‚
                       β–Ό
                message terbaru
                       β”‚
                       β–Ό
             current ID == last ID?
                  β”‚           β”‚
                 YES          NO
                  β”‚           β”‚
                  β–Ό           β–Ό
                skip      downloader

Watcher tidak mengubah checkpoint.

Yang mengubah:

last_read_message_id

tetap downloader.

Dengan begitu hanya downloader yang bertanggung jawab terhadap status message yang sudah diproses.


8. Kenapa Pakai systemd?

Kalau watcher harus dijalankan manual setiap kali server boot:

python3 telegram_watcher.py

berarti kita belum benar-benar otomatis.

Maka watcher dijadikan systemd service.

File:

/etc/systemd/system/telegram-watcher.service

Konfigurasinya:

[Unit]
Description=Telegram Media Watcher
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=serverkamu
WorkingDirectory=/home/serverkamu/PYTHON/telegram_media_downloader
ExecStart=/home/serverkamu/PYTHON/telegram_media_downloader/.venv/bin/python telegram_watcher.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Kemudian:

sudo systemctl daemon-reload
sudo systemctl enable --now telegram-watcher

Sekarang setiap server boot:

server boot
    ↓
systemd
    ↓
telegram-watcher
    ↓
check Telegram
    ↓
setiap 30 detik

Tidak perlu menjalankan apa-apa secara manual.

Kalau watcher crash, systemd juga bisa menjalankannya kembali.

Untuk melihat status:

systemctl status telegram-watcher

Untuk melihat aktivitas secara live:

journalctl -u telegram-watcher -f

9. Ada Sedikit Drama dengan Python 3.14

Tentu saja tidak mungkin proyek homelab berjalan mulus tanpa sedikit drama.

Server menggunakan:

CPython 3.14.4

Sementara downloader masih menggunakan pola asyncio lama.

Saat pertama dijalankan muncul:

RuntimeError:
There is no current event loop in thread 'MainThread'.

Untungnya masalahnya cukup lokal.

Event loop dibuat terlebih dahulu sebelum main() dijalankan.

Setelah patch kecil tersebut:

Telegram connection β†’ OK
chat β†’ OK
download β†’ OK
checkpoint β†’ OK
disconnect β†’ OK

Lanjut.


10. Watcher Juga Sempat Salah Python

Setelah watcher berjalan, muncul error:

ModuleNotFoundError: No module named 'telethon'

Padahal Telethon sudah terinstall.

Ternyata watcher menggunakan Python dari .venv, tetapi ketika menjalankan downloader dia memanggil:

python3 media_downloader.py

yang mengarah ke Python sistem.

Solusinya adalah menggunakan interpreter yang sedang menjalankan watcher:

subprocess.run(
    [sys.executable, "media_downloader.py"],
    check=True,
)

Sekarang watcher dan downloader sama-sama menggunakan Python dari .venv.


11. Dan Akhirnya: Tinggal Forward

Setelah semua bagian selesai, workflow sehari-hari menjadi sangat sederhana.

Misalnya ada sebuah film yang mau ditangkap.

Tidak perlu:

download ke HP
     ↓
upload ke komputer
     ↓
copy ke server
     ↓
rapikan folder
     ↓
tunggu Jellyfin

Cukup:

Telegram
   β”‚
   β”‚ forward film
   β–Ό
Nomor B

Kemudian server akan melakukan sisanya.

Nomor B
   ↓
watcher cek setiap 30 detik
   ↓
ada message baru
   ↓
media_downloader.py
   ↓
download
   ↓
update last_read_message_id
   ↓
storage
   ↓
Jellyfin

Jadi dari sisi saya:

Film yang mau ditangkap? Forward ke nomor B.

Sudah.

Server akan mengecek maksimal sekitar 30 detik kemudian, menjalankan downloader, dan mengambil medianya sendiri.


12. Berikutnya: Caption Sebagai Routing

Setelah mekanisme download stabil, sistem masih bisa dibuat lebih malas lagi.

Misalnya nomor A forward film dengan caption:

indonesia

Watcher bisa membaca caption tersebut dan menjadikannya routing key.

Misalnya:

indonesia β†’ /home/serverkamu//MEDIA/indonesia/
jepang    β†’ /home/serverkamu/DATA/CLOUD/MEDIA/jepang/
korea     β†’ /home/serverkamu/DATA/CLOUD/MEDIA/korea/

Maka caption tidak lagi hanya menjadi keterangan.

Dia menjadi instruksi:

caption
   ↓
routing
   ↓
folder tujuan

Untuk tahap awal, semuanya bahkan bisa diarahkan statis ke:

/home/serverkamu//MEDIA/indonesia/

Baru nanti kalau sudah terbukti stabil, caption bisa digunakan untuk memilih folder secara otomatis.


Penutup

Pada akhirnya, tujuan sistem ini sebenarnya bukan membuat sesuatu yang canggih.

Tujuannya justru sebaliknya:

mengurangi sebanyak mungkin pekerjaan manual.

Awalnya:

Telegram
 ↓
download HP
 ↓
upload
 ↓
copy
 ↓
rapikan
 ↓
Jellyfin

Sekarang:

Telegram
 ↓
forward ke B
 ↓
selesai.

Sementara di belakang layar:

Nomor B
    ↓
Telethon session
    ↓
Watcher
    ↓
cek setiap 30 detik
    ↓
Downloader
    ↓
Checkpoint
    ↓
Storage
    ↓
Jellyfin

Dan itulah inti homelab ini.

Bukan supaya saya bisa melakukan lebih banyak pekerjaan.

Tapi supaya server melakukan pekerjaan yang sebenarnya tidak ingin saya lakukan.

Kalau ada film yang mau ditangkap:

forward ke nomor B.

Sisanya?

Biar server yang capek. 😌