Pikeuli's picture
Update app.py
3f840a3 verified
Raw
History Blame Contribute Delete
7.12 kB
import reverse_geocoder as rg
import os, time, math, requests, threading
from http.server import HTTPServer, BaseHTTPRequestHandler
from datetime import datetime
from zoneinfo import ZoneInfo
# --- CONFIG ---
KL_TZ = ZoneInfo('Asia/Kuala_Lumpur')
WEBHOOK_URL = os.getenv("DISCORD_WEBHOOK")
MY_DISCORD_ID = os.getenv("MY_DISCORD_ID")
GAMBAR_BOT = "https://i.ibb.co/KpyqyjPg/20251224-130538.jpg"
NAMA_BOT = "Kapten ISS Pikeuli (Terkini)"
# Koordinat Selayang Kau
MY_LAT, MY_LON = 3.2350656, 101.6604678
ALERT_RADIUS = 350 # KM
# --- DUMMY SERVER (UNTUK KEEP-ALIVE) ---
class KeepAliveServer(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/html; charset=utf-8")
self.end_headers()
waktu = datetime.now(KL_TZ).strftime('%d %b %Y %H:%M:%S')
html = f"""
<html>
<body style="font-family: sans-serif; text-align: center; margin-top: 50px;">
<h2>πŸš€ {NAMA_BOT} SEDANG AKTIF</h2>
<p><b>Waktu Tempatan (KL):</b> {waktu}</p>
<p style="color: green;">Status: Menjejak data langsung ISS & Kru Ekspedisi Terkini</p>
</body>
</html>
"""
self.wfile.write(html.encode('utf-8'))
def log_message(self, format, *args): return
def run_server():
try:
server = HTTPServer(('0.0.0.0', 7860), KeepAliveServer)
server.serve_forever()
except Exception as e:
print(f"Ralat Server: {e}")
# --- FUNGSI LOKASI & KRU (LIVE DATA) ---
def get_location_name(lat, lon):
try:
results = rg.search((lat, lon))
bandar = results[0].get('name', '')
negeri = results[0].get('admin1', '')
negara = results[0].get('cc', '')
return f"{bandar}, {negeri} ({negara})"
except:
return "Atas Lautan / Kawasan Terpencil"
def get_current_crew():
"""Tarik data live siapa yang ada di ISS sekarang (Ekspedisi Semasa)"""
try:
r = requests.get("http://api.open-notify.org/astros.json", timeout=10)
if r.status_code == 200:
data = r.json()
# Tapis untuk kru ISS sahaja
iss_crew = [p["name"] for p in data.get("people",[]) if p.get("craft") == "ISS"]
return iss_crew
except:
pass
return[]
# --- FUNGSI PENGIRAAN ---
def get_distance(lat1, lon1, lat2, lon2):
R = 6371
dlat, dlon = math.radians(lat2-lat1), math.radians(lon2-lon1)
a = math.sin(dlat/2)**2 + math.cos(math.radians(lat1))*math.cos(math.radians(lat2))*math.sin(dlon/2)**2
return R * (2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)))
def get_bearing(lat1, lon1, lat2, lon2):
lat1, lon1, lat2, lon2 = map(math.radians,[lat1, lon1, lat2, lon2])
dLon = lon2 - lon1
y = math.sin(dLon) * math.cos(lat2)
x = math.cos(lat1) * math.sin(lat2) - math.sin(lat1) * math.cos(lat2) * math.cos(dLon)
bearing = math.degrees(math.atan2(y, x))
return (bearing + 360) % 360
def get_compass(bearing):
directions =["Utara", "Timur Laut", "Timur", "Tenggara", "Selatan", "Barat Daya", "Barat", "Barat Laut"]
idx = int((bearing + 22.5) / 45) % 8
return directions[idx]
def send_discord(content, embed=None):
if not WEBHOOK_URL: return
url = WEBHOOK_URL.replace("discord.com", "discordapp.com")
payload = {"content": content, "embeds": [embed] if embed else[], "username": NAMA_BOT, "avatar_url": GAMBAR_BOT}
try:
requests.post(url, json=payload, timeout=15)
except:
pass
# --- LOOP UTAMA ---
def tracking_loop():
print("πŸ›°οΈ Menjejak ISS menggunakan data API Terkini...", flush=True)
last_hour = -1
is_overhead = False
while True:
try:
# Tetap gunakan wheretheiss untuk ketepatan Altitud/Kelajuan
r = requests.get("https://api.wheretheiss.at/v1/satellites/25544", timeout=10)
if r.status_code == 200:
data = r.json()
lat, lon = float(data['latitude']), float(data['longitude'])
dist = get_distance(MY_LAT, MY_LON, lat, lon)
bearing = get_bearing(MY_LAT, MY_LON, lat, lon)
velocity = data['velocity']
altitude = data['altitude']
now = datetime.now(KL_TZ)
# 1. Update Hourly (Laporan Jam + Update Kru ISS)
if now.hour != last_hour:
nama_lokasi = get_location_name(lat, lon)
kru_sebenar = get_current_crew()
jumlah_kru = len(kru_sebenar) if kru_sebenar else "Tidak diketahui"
nama_kru = ", ".join(kru_sebenar) if kru_sebenar else "Gagal menyemak nama kru"
embed = {
"title": f"πŸ“Š Laporan Jam ISS ({now.strftime('%H:%M')})",
"description": f"ISS sekarang berada di atas:\n**🌍 {nama_lokasi}**",
"color": 3447003,
"fields":[
{"name": "πŸ“ Jarak ke Selayang", "value": f"{dist:.2f} km", "inline": True},
{"name": "🧭 Arah", "value": f"{get_compass(bearing)}", "inline": True},
{"name": "πŸ‘¨β€πŸš€ Senarai Angkasawan di ISS", "value": f"**{jumlah_kru} Orang:**\n_{nama_kru}_", "inline": False}
],
"footer": {"text": f"Kemas kini: {now.strftime('%d %b %Y')}"}
}
send_discord(None, embed)
last_hour = now.hour
# 2. Alert Ping (Radius < 350km)
if dist <= ALERT_RADIUS:
if not is_overhead:
nama_lokasi = get_location_name(lat, lon)
ping = f"<@{MY_DISCORD_ID}>" if MY_DISCORD_ID else "Bro"
embed = {
"title": "πŸš€ ISS MASUK RADAR SELAYANG!",
"description": f"Lokasi Sekarang: **🌍 {nama_lokasi}**",
"color": 15158332,
"fields":[
{"name": "🧭 Arah Mata Angin", "value": f"{get_compass(bearing)} ({bearing:.0f}°)", "inline": True},
{"name": "πŸ“ Jarak", "value": f"{dist:.2f} km", "inline": True},
{"name": "πŸ’¨ Kelajuan", "value": f"{velocity:.0f} km/j", "inline": True},
{"name": "πŸ”οΈ Altitud", "value": f"{altitude:.0f} km", "inline": True}
],
"footer": {"text": f"Masa Pintasan: {now.strftime('%H:%M:%S')}"}
}
send_discord(f"🚨 {ping} ISS TENGAH LALU!", embed)
is_overhead = True
else:
is_overhead = False
except Exception as e:
pass
time.sleep(60)
if __name__ == "__main__":
threading.Thread(target=run_server, daemon=True).start()
tracking_loop()