Video Call Schedule
Get JKT48 video call schedule data with real-time status updates using JKT48Connect API
Introduction
The JKT48Connect Video Call Schedule API provides access to real-time video call schedule data for JKT48 members. Track upcoming video call sessions, monitor ongoing sessions, and get detailed information about member schedules with live status updates.
Live Schedule
Access real-time video call schedules with session status tracking.
Session Status
Monitor preparation, ongoing, upcoming, and finished sessions.
Member Filter
Filter schedules by specific JKT48 members and sessions.
Quick Start
Get All Video Call Schedules
Fetch complete video call schedule data for the current month.
const scheduleData = await getVideoCallSchedule();
console.log(scheduleData.statistics.total_sessions);
Filter by Date or Session
curl "https://v2.jkt48connect.my.id/api/jkt48/videocall?date=18&apikey=YOUR_API_KEY"
Get Today's Schedule
Fetch video call schedule specifically for today with real-time status.
curl "https://v2.jkt48connect.my.id/api/jkt48/videocall/today?apikey=YOUR_API_KEY"
Endpoint Details
Base URL: https://v2.jkt48connect.my.id
Endpoint: /api/jkt48/videocall
Method: GET
Authentication: API Key required
Query Parameters:
sesi
: Filter by session number (1, 2, 3, etc.)date
: Filter by date (13, 14, 15, etc.)member
: Filter by member name (partial match)
Base URL: https://v2.jkt48connect.my.id
Endpoint: /api/jkt48/videocall/today
Method: GET
Authentication: API Key required
Shows video call schedule specifically for today with real-time session status updates.
Available Filters:
- Session Filter:
?sesi=1
- Get all session 1 schedules - Date Filter:
?date=16
- Get schedules for the 16th - Member Filter:
?member=Adeline
- Get schedules with Adeline - Combined:
?date=18&sesi=2&member=Freya
- Multiple filters
Session Status Types:
upcoming
: Session will startpreparation
: Currently in preparation phaseongoing
: Session is currently livefinished
: Session has ended
API Response Examples
Request: GET /api/jkt48/videocall
{
"success": true,
"author": "JKT48ConnectCORP - Valzyy",
"current_time": "2025-08-17T09:50:08.117Z",
"timezone": "GMT+7 (Indonesia)",
"data_month": "Agustus",
"data_year": "2025",
"is_data_outdated": false,
"statistics": {
"total_sessions": 15,
"ongoing_sessions": 0,
"finished_sessions": 3,
"upcoming_sessions": 12,
"preparation_sessions": 0
},
"filters": {
"date": null,
"session": null,
"member": null
},
"available_dates": [
{
"date": "2025-08-18",
"day": "Senin",
"total_sessions": 3
},
{
"date": "2025-08-19",
"day": "Selasa",
"total_sessions": 3
}
],
"data": [
{
"date": "2025-08-18",
"day": "Senin",
"sessions": [
{
"session": 1,
"preparation": "16:15 - 16:30 WIB",
"waktu": "16:30 - 17:30 WIB",
"members": [
"Aulia Riza",
"Bong Aprilla",
"Hagia Sopia",
"Astrella Virgiananda",
"Humaira Ramadhani",
"Shabilqis Naila",
"Abigail Rachel",
"Nina Tutachia",
"Jazzlyn Trisha"
],
"session_status": {
"status": "upcoming",
"message": "Sesi akan dimulai",
"is_ongoing": false,
"is_finished": false,
"is_preparation": false
}
}
]
}
]
}
Request: GET /api/jkt48/videocall?date=18
{
"success": true,
"author": "JKT48ConnectCORP - Valzyy",
"current_time": "2025-08-17T09:50:08.117Z",
"timezone": "GMT+7 (Indonesia)",
"data_month": "Agustus",
"data_year": "2025",
"is_data_outdated": false,
"statistics": {
"total_sessions": 3,
"ongoing_sessions": 0,
"finished_sessions": 0,
"upcoming_sessions": 3,
"preparation_sessions": 0
},
"filters": {
"date": "18",
"session": null,
"member": null
},
"available_dates": [
{
"date": "2025-08-18",
"day": "Senin",
"total_sessions": 3
}
],
"data": [
{
"date": "2025-08-18",
"day": "Senin",
"sessions": [
{
"session": 1,
"preparation": "16:15 - 16:30 WIB",
"waktu": "16:30 - 17:30 WIB",
"members": [
"Aulia Riza",
"Bong Aprilla",
"Hagia Sopia"
],
"session_status": {
"status": "upcoming",
"message": "Sesi akan dimulai",
"is_ongoing": false,
"is_finished": false,
"is_preparation": false
}
},
{
"session": 2,
"preparation": "17:45 - 18:00 WIB",
"waktu": "18:00 - 19:00 WIB",
"members": [
"Aulia Riza",
"Bong Aprilla",
"Hagia Sopia"
],
"session_status": {
"status": "upcoming",
"message": "Sesi akan dimulai",
"is_ongoing": false,
"is_finished": false,
"is_preparation": false
}
}
]
}
]
}
Request: GET /api/jkt48/videocall?member=Adeline
{
"success": true,
"author": "JKT48ConnectCORP - Valzyy",
"member_name": "Adeline",
"total_sessions": 6,
"data_month": "Agustus",
"data_year": "2025",
"is_data_outdated": false,
"schedule": [
{
"date": "2025-08-18",
"day": "Senin",
"session": 1,
"preparation": "16:15 - 16:30 WIB",
"waktu": "16:30 - 17:30 WIB",
"session_status": {
"status": "upcoming",
"message": "Sesi akan dimulai",
"is_ongoing": false,
"is_finished": false,
"is_preparation": false
},
"other_members": [
"Aulia Riza",
"Bong Aprilla",
"Hagia Sopia"
]
},
{
"date": "2025-08-19",
"day": "Selasa",
"session": 2,
"preparation": "17:45 - 18:00 WIB",
"waktu": "18:00 - 19:00 WIB",
"session_status": {
"status": "upcoming",
"message": "Sesi akan dimulai",
"is_ongoing": false,
"is_finished": false,
"is_preparation": false
},
"other_members": [
"Freya Jayawardana",
"Shania Gracia"
]
}
],
"raw_data": [...]
}
Request: GET /api/jkt48/videocall/today
{
"success": true,
"author": "JKT48ConnectCORP - Valzyy",
"current_time": "2025-08-17T14:25:00.000Z",
"timezone": "GMT+7 (Indonesia)",
"data_month": "Agustus",
"data_year": "2025",
"is_data_outdated": false,
"date": "2025-08-17",
"day": "Sabtu",
"total_sessions": 2,
"sessions": [
{
"session": 1,
"preparation": "16:15 - 16:30 WIB",
"waktu": "16:30 - 17:30 WIB",
"members": [
"Freya Jayawardana",
"Shania Gracia",
"Adeline Wijaya"
],
"session_status": {
"status": "preparation",
"message": "Sedang masa persiapan",
"is_ongoing": false,
"is_finished": false,
"is_preparation": true,
"time_until_session": 5
}
},
{
"session": 2,
"preparation": "19:15 - 19:30 WIB",
"waktu": "19:30 - 20:30 WIB",
"members": [
"Christy Lyn",
"Fiony Alveria",
"Greesel Anastasia"
],
"session_status": {
"status": "upcoming",
"message": "Sesi akan dimulai",
"is_ongoing": false,
"is_finished": false,
"is_preparation": false,
"time_until_start": 290
}
}
]
}
Implementation Examples
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://v2.jkt48connect.my.id';
async function getVideoCallSchedule(options = {}) {
const params = new URLSearchParams({
apikey: API_KEY,
...options
});
try {
const response = await fetch(
`${BASE_URL}/api/jkt48/videocall?${params}`
);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error('Failed to fetch video call schedule:', error);
throw error;
}
}
async function getTodayVideoCallSchedule() {
const params = new URLSearchParams({ apikey: API_KEY });
try {
const response = await fetch(
`${BASE_URL}/api/jkt48/videocall/today?${params}`
);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error('Failed to fetch today video call schedule:', error);
throw error;
}
}
// Get video call schedule by date
async function getVideoCallByDate(date) {
return await getVideoCallSchedule({ date });
}
// Get video call schedule by session
async function getVideoCallBySession(sessionNumber) {
return await getVideoCallSchedule({ sesi: sessionNumber });
}
// Get video call schedule by member
async function getVideoCallByMember(memberName) {
return await getVideoCallSchedule({ member: memberName });
}
// Format session status for display
function formatSessionStatus(session) {
const status = session.session_status;
const icons = {
upcoming: '⏰',
preparation: '🔄',
ongoing: '🔴',
finished: '✅'
};
return `${icons[status.status]} ${status.message}`;
}
// Display video call schedule
async function displayVideoCallSchedule(options = {}) {
try {
const data = await getVideoCallSchedule(options);
if (!data.success) {
console.log('❌ Failed to get video call schedule');
return;
}
console.log(`📅 VIDEO CALL SCHEDULE - ${data.data_month} ${data.data_year}`);
console.log(`📊 Statistics: ${data.statistics.total_sessions} total, ${data.statistics.ongoing_sessions} ongoing, ${data.statistics.upcoming_sessions} upcoming`);
if (data.is_data_outdated) {
console.log(`⚠️ ${data.message}`);
return;
}
console.log('\n--- SCHEDULE DETAILS ---');
data.data.forEach(day => {
console.log(`\n📆 ${day.day}, ${day.date}`);
day.sessions.forEach(session => {
console.log(` 📱 Session ${session.session}`);
console.log(` ⏱️ Preparation: ${session.preparation}`);
console.log(` 🎥 Video Call: ${session.waktu}`);
console.log(` 👥 Members: ${session.members.join(', ')}`);
console.log(` ${formatSessionStatus(session)}`);
});
});
} catch (error) {
console.error('Error displaying video call schedule:', error);
}
}
// Display today's video call schedule
async function displayTodayVideoCallSchedule() {
try {
const data = await getTodayVideoCallSchedule();
if (!data.success || !data.sessions) {
console.log('📅 No video call sessions today');
return;
}
console.log(`📅 TODAY'S VIDEO CALL SCHEDULE - ${data.day}, ${data.date}`);
console.log(`📊 Total Sessions: ${data.total_sessions}`);
console.log('');
data.sessions.forEach(session => {
console.log(`📱 Session ${session.session}`);
console.log(` ⏱️ Preparation: ${session.preparation}`);
console.log(` 🎥 Video Call: ${session.waktu}`);
console.log(` 👥 Members: ${session.members.join(', ')}`);
console.log(` ${formatSessionStatus(session)}`);
// Show countdown for upcoming sessions
if (session.session_status.time_until_start) {
const minutes = session.session_status.time_until_start;
const hours = Math.floor(minutes / 60);
const mins = minutes % 60;
console.log(` ⏰ Starts in: ${hours}h ${mins}m`);
}
if (session.session_status.time_remaining) {
const minutes = session.session_status.time_remaining;
console.log(` ⏱️ Ends in: ${minutes} minutes`);
}
console.log('');
});
} catch (error) {
console.error('Error displaying today video call schedule:', error);
}
}
// Monitor live video call sessions
async function monitorVideoCallSessions() {
console.log('🔄 Starting video call session monitor...');
setInterval(async () => {
try {
const data = await getTodayVideoCallSchedule();
if (data.success && data.sessions) {
const ongoingSessions = data.sessions.filter(s => s.session_status.is_ongoing);
const preparationSessions = data.sessions.filter(s => s.session_status.is_preparation);
if (ongoingSessions.length > 0) {
console.log(`🔴 LIVE NOW: ${ongoingSessions.length} video call session(s)`);
ongoingSessions.forEach(session => {
console.log(` 📱 Session ${session.session} with ${session.members.join(', ')}`);
});
}
if (preparationSessions.length > 0) {
console.log(`🔄 PREPARING: ${preparationSessions.length} session(s) in preparation`);
preparationSessions.forEach(session => {
console.log(` 📱 Session ${session.session} starting soon`);
});
}
}
} catch (error) {
console.error('Monitor error:', error);
}
}, 60000); // Check every minute
}
// Get member schedule analysis
async function getMemberScheduleAnalysis(memberName) {
try {
const data = await getVideoCallByMember(memberName);
if (!data.success || data.total_sessions === 0) {
console.log(`❌ No video call sessions found for ${memberName}`);
return;
}
console.log(`📊 ${memberName.toUpperCase()} VIDEO CALL ANALYSIS`);
console.log(`📅 Total Sessions: ${data.total_sessions}`);
console.log(`📆 Month: ${data.data_month} ${data.data_year}`);
console.log('');
// Group by date
const sessionsByDate = {};
data.schedule.forEach(session => {
if (!sessionsByDate[session.date]) {
sessionsByDate[session.date] = [];
}
sessionsByDate[session.date].push(session);
});
Object.entries(sessionsByDate).forEach(([date, sessions]) => {
console.log(`📆 ${sessions[0].day}, ${date}`);
sessions.forEach(session => {
console.log(` 📱 Session ${session.session}: ${session.waktu}`);
console.log(` 👥 With: ${session.other_members.join(', ')}`);
console.log(` ${formatSessionStatus(session)}`);
});
console.log('');
});
} catch (error) {
console.error('Error analyzing member schedule:', error);
}
}
// Schedule reminder system
class VideoCallReminder {
constructor() {
this.reminders = new Map();
}
async setReminders() {
try {
const data = await getTodayVideoCallSchedule();
if (data.success && data.sessions) {
data.sessions.forEach(session => {
if (session.session_status.status === 'upcoming') {
const timeUntilStart = session.session_status.time_until_start;
// Set reminder 10 minutes before
if (timeUntilStart > 10) {
const reminderTime = (timeUntilStart - 10) * 60 * 1000;
const timerId = setTimeout(() => {
console.log(`🔔 REMINDER: Session ${session.session} starts in 10 minutes!`);
console.log(`👥 Members: ${session.members.join(', ')}`);
}, reminderTime);
this.reminders.set(`session_${session.session}`, timerId);
}
}
});
}
} catch (error) {
console.error('Error setting reminders:', error);
}
}
clearReminders() {
this.reminders.forEach(timerId => clearTimeout(timerId));
this.reminders.clear();
}
}
// Usage examples
async function examples() {
// Display all video call schedules
await displayVideoCallSchedule();
// Display today's schedule
await displayTodayVideoCallSchedule();
// Get specific date schedule
await displayVideoCallSchedule({ date: '18' });
// Get specific session
await displayVideoCallSchedule({ sesi: '2' });
// Get member specific schedule
await getMemberScheduleAnalysis('Adeline');
// Start monitoring
monitorVideoCallSessions();
// Set up reminders
const reminder = new VideoCallReminder();
await reminder.setReminders();
}
import requests
import time
from datetime import datetime, timedelta
from typing import Optional, Dict, List, Any
API_KEY = 'YOUR_API_KEY'
BASE_URL = 'https://v2.jkt48connect.my.id'
def get_video_call_schedule(**options) -> Dict[str, Any]:
"""Fetch video call schedule data"""
params = {'apikey': API_KEY, **options}
url = f"{BASE_URL}/api/jkt48/videocall"
try:
response = requests.get(url, params=params)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error fetching video call schedule: {e}")
raise
def get_today_video_call_schedule() -> Dict[str, Any]:
"""Fetch today's video call schedule"""
params = {'apikey': API_KEY}
url = f"{BASE_URL}/api/jkt48/videocall/today"
try:
response = requests.get(url, params=params)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error fetching today's video call schedule: {e}")
raise
def get_video_call_by_date(date: str) -> Dict[str, Any]:
"""Get video call schedule by date"""
return get_video_call_schedule(date=date)
def get_video_call_by_session(session: int) -> Dict[str, Any]:
"""Get video call schedule by session number"""
return get_video_call_schedule(sesi=str(session))
def get_video_call_by_member(member_name: str) -> Dict[str, Any]:
"""Get video call schedule by member name"""
return get_video_call_schedule(member=member_name)
def format_session_status(session: Dict[str, Any]) -> str:
"""Format session status for display"""
status = session['session_status']
icons = {
'upcoming': '⏰',
'preparation': '🔄',
'ongoing': '🔴',
'finished': '✅'
}
return f"{icons.get(status['status'], '❓')} {status['message']}"
def display_video_call_schedule(**options):
"""Display video call schedule"""
try:
data = get_video_call_schedule(**options)
if not data['success']:
print('❌ Failed to get video call schedule')
return
print(f"📅 VIDEO CALL SCHEDULE - {data['data_month']} {data['data_year']}")
stats = data['statistics']
print(f"📊 Statistics: {stats['total_sessions']} total, {stats['ongoing_sessions']} ongoing, {stats['upcoming_sessions']} upcoming")
if data['is_data_outdated']:
print(f"⚠️ {data['message']}")
return
print('\n--- SCHEDULE DETAILS ---')
for day in data['data']:
print(f"\n📆 {day['day']}, {day['date']}")
for session in day['sessions']:
print(f" 📱 Session {session['session']}")
print(f" ⏱️ Preparation: {session['preparation']}")
print(f" 🎥 Video Call: {session['waktu']}")
print(f" 👥 Members: {', '.join(session['members'])}")
print(f" {format_session_status(session)}")
except Exception as e:
print(f"Error displaying video call schedule: {e}")
def display_today_video_call_schedule():
"""Display today's video call schedule"""
try:
data = get_today_video_call_schedule()
if not data['success'] or not data.get('sessions'):
print('📅 No video call sessions today')
return
print(f"📅 TODAY'S VIDEO CALL SCHEDULE - {data['day']}, {data['date']}")
print(f"📊 Total Sessions: {data['total_sessions']}")
print()
for session in data['sessions']:
print(f"📱 Session {session['session']}")
print(f" ⏱️ Preparation: {session['preparation']}")
print(f" 🎥 Video Call: {session['waktu']}")
print(f" 👥 Members: {', '.join(session['members'])}")
print(f" {format_session_status(session)}")
# Show countdown for upcoming sessions
if 'time_until_start' in session['session_status']:
minutes = session['session_status']['time_until_start']
hours = minutes // 60
mins = minutes % 60
print(f" ⏰ Starts in: {hours}h {mins}m")
if 'time_remaining' in session['session_status']:
minutes = session['session_status']['time_remaining']
print(f" ⏱️ Ends in: {minutes} minutes")
print()
except Exception as e:
print(f"Error displaying today's video call schedule: {e}")
def monitor_video_call_sessions(duration_minutes: int = 60):
"""Monitor live video call sessions"""
print('🔄 Starting video call session monitor...')
start_time = time.time()
while time.time() - start_time < duration_minutes * 60:
try:
data = get_today_video_call_schedule()
if data['success'] and data.get('sessions'):
ongoing_sessions = [s for s in data['sessions'] if s['session_status']['is_ongoing']]
prep_sessions = [s for s in data['sessions'] if s['session_status']['is_preparation']]
if ongoing_sessions:
print(f"🔴 LIVE NOW: {len(ongoing_sessions)} video call session(s)")
for session in ongoing_sessions:
print(f" 📱 Session {session['session']} with {', '.join(session['members'])}")
if prep_sessions:
print(f"🔄 PREPARING: {len(prep_sessions)} session(s) in preparation")
for session in prep_sessions:
print(f" 📱 Session {session['session']} starting soon")
time.sleep(60) # Check every minute
except Exception as e:
print(f"Monitor error: {e}")
time.sleep(60)
def get_member_schedule_analysis(member_name: str):
"""Get member schedule analysis"""
try:
data = get_video_call_by_member(member_name)
if not data['success'] or data.get('total_sessions', 0) == 0:
print(f"❌ No video call sessions found for {member_name}")
return
print(f"📊 {member_name.upper()} VIDEO CALL ANALYSIS")
print(f"📅 Total Sessions: {data['total_sessions']}")
print(f"📆 Month: {data['data_month']} {data['data_year']}")
print()
# Group by date
sessions_by_date = {}
for session in data['schedule']:
date = session['date']
if date not in sessions_by_date:
sessions_by_date[date] = []
sessions_by_date[date].append(session)
for date, sessions in sessions_by_date.items():
print(f"📆 {sessions[0]['day']}, {date}")
for session in sessions:
print(f" 📱 Session {session['session']}: {session['waktu']}")
print(f" 👥 With: {', '.join(session['other_members'])}")
print(f" {format_session_status(session)}")
print()
except Exception as e:
print(f"Error analyzing member schedule: {e}")
# Schedule reminder system
class VideoCallReminder:
def __init__(self):
self.reminders = []
def set_reminders(self):
"""Set reminders for upcoming sessions"""
try:
data = get_today_video_call_schedule()
if data['success'] and data.get('sessions'):
for session in data['sessions']:
if session['session_status']['status'] == 'upcoming':
time_until_start = session['session_status'].get('time_until_start', 0)
# Set reminder 10 minutes before
if time_until_start > 10:
reminder_time = (time_until_start - 10) * 60
print(f"🔔 Reminder set for Session {session['session']} in {reminder_time//60} minutes")
except Exception as e:
print(f"Error setting reminders: {e}")
# Usage examples
if __name__ == "__main__":
# Display all video call schedules
display_video_call_schedule()
# Display today's schedule
display_today_video_call_schedule()
# Get specific date schedule
display_video_call_schedule(date='18')
# Get specific session
display_video_call_schedule(sesi='2')
# Get member specific schedule
get_member_schedule_analysis('Adeline')
# Start monitoring for 30 minutes
# monitor_video_call_sessions(30)
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
const (
APIKey = "YOUR_API_KEY"
BaseURL = "https://v2.jkt48connect.my.id"
)
type VideoCallScheduleData struct {
Success bool `json:"success"`
Author string `json:"author"`
CurrentTime string `json:"current_time"`
Timezone string `json:"timezone"`
DataMonth string `json:"data_month"`
DataYear string `json:"data_year"`
IsDataOutdated bool `json:"is_data_outdated"`
Statistics VideoCallStats `json:"statistics"`
Filters map[string]*string `json:"filters"`
AvailableDates []AvailableDate `json:"available_dates"`
Data []VideoCallDay `json:"data"`
Message string `json:"message,omitempty"`
}
type TodayVideoCallData struct {
Success bool `json:"success"`
Author string `json:"author"`
CurrentTime string `json:"current_time"`
Timezone string `json:"timezone"`
DataMonth string `json:"data_month"`
DataYear string `json:"data_year"`
IsDataOutdated bool `json:"is_data_outdated"`
Date string `json:"date"`
Day string `json:"day"`
TotalSessions int `json:"total_sessions"`
Sessions []VideoCallSession `json:"sessions"`
}
type MemberVideoCallData struct {
Success bool `json:"success"`
Author string `json:"author"`
MemberName string `json:"member_name"`
TotalSessions int `json:"total_sessions"`
DataMonth string `json:"data_month"`
DataYear string `json:"data_year"`
Schedule []MemberScheduleItem `json:"schedule"`
RawData []VideoCallDay `json:"raw_data"`
}
type VideoCallStats struct {
TotalSessions int `json:"total_sessions"`
OngoingSessions int `json:"ongoing_sessions"`
FinishedSessions int `json:"finished_sessions"`
UpcomingSessions int `json:"upcoming_sessions"`
PreparationSessions int `json:"preparation_sessions"`
}
type AvailableDate struct {
Date string `json:"date"`
Day string `json:"day"`
TotalSessions int `json:"total_sessions"`
}
type VideoCallDay struct {
Date string `json:"date"`
Day string `json:"day"`
Sessions []VideoCallSession `json:"sessions"`
}
type VideoCallSession struct {
Session int `json:"session"`
Preparation string `json:"preparation"`
Waktu string `json:"waktu"`
Members []string `json:"members"`
SessionStatus SessionStatus `json:"session_status"`
}
type SessionStatus struct {
Status string `json:"status"`
Message string `json:"message"`
IsOngoing bool `json:"is_ongoing"`
IsFinished bool `json:"is_finished"`
IsPreparation bool `json:"is_preparation"`
TimeUntilStart *int `json:"time_until_start,omitempty"`
TimeRemaining *int `json:"time_remaining,omitempty"`
}
type MemberScheduleItem struct {
Date string `json:"date"`
Day string `json:"day"`
Session int `json:"session"`
Preparation string `json:"preparation"`
Waktu string `json:"waktu"`
SessionStatus SessionStatus `json:"session_status"`
OtherMembers []string `json:"other_members"`
}
func getVideoCallSchedule(options map[string]string) (*VideoCallScheduleData, error) {
params := url.Values{}
params.Add("apikey", APIKey)
for key, value := range options {
params.Add(key, value)
}
url := fmt.Sprintf("%s/api/jkt48/videocall?%s", BaseURL, params.Encode())
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API request failed with status: %d", resp.StatusCode)
}
var data VideoCallScheduleData
err = json.NewDecoder(resp.Body).Decode(&data)
return &data, err
}
func getTodayVideoCallSchedule() (*TodayVideoCallData, error) {
params := url.Values{}
params.Add("apikey", APIKey)
url := fmt.Sprintf("%s/api/jkt48/videocall/today?%s", BaseURL, params.Encode())
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API request failed with status: %d", resp.StatusCode)
}
var data TodayVideoCallData
err = json.NewDecoder(resp.Body).Decode(&data)
return &data, err
}
func getVideoCallByDate(date string) (*VideoCallScheduleData, error) {
return getVideoCallSchedule(map[string]string{"date": date})
}
func getVideoCallBySession(session int) (*VideoCallScheduleData, error) {
return getVideoCallSchedule(map[string]string{"sesi": strconv.Itoa(session)})
}
func getVideoCallByMember(member string) (*MemberVideoCallData, error) {
params := url.Values{}
params.Add("apikey", APIKey)
params.Add("member", member)
url := fmt.Sprintf("%s/api/jkt48/videocall?%s", BaseURL, params.Encode())
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API request failed with status: %d", resp.StatusCode)
}
var data MemberVideoCallData
err = json.NewDecoder(resp.Body).Decode(&data)
return &data, err
}
func formatSessionStatus(status SessionStatus) string {
icons := map[string]string{
"upcoming": "⏰",
"preparation": "🔄",
"ongoing": "🔴",
"finished": "✅",
}
icon, exists := icons[status.Status]
if !exists {
icon = "❓"
}
return fmt.Sprintf("%s %s", icon, status.Message)
}
func displayVideoCallSchedule(options map[string]string) {
data, err := getVideoCallSchedule(options)
if err != nil {
fmt.Printf("Error fetching video call schedule: %v\n", err)
return
}
if !data.Success {
fmt.Println("❌ Failed to get video call schedule")
return
}
fmt.Printf("📅 VIDEO CALL SCHEDULE - %s %s\n", data.DataMonth, data.DataYear)
fmt.Printf("📊 Statistics: %d total, %d ongoing, %d upcoming\n",
data.Statistics.TotalSessions,
data.Statistics.OngoingSessions,
data.Statistics.UpcomingSessions)
if data.IsDataOutdated {
fmt.Printf("⚠️ %s\n", data.Message)
return
}
fmt.Println("\n--- SCHEDULE DETAILS ---")
for _, day := range data.Data {
fmt.Printf("\n📆 %s, %s\n", day.Day, day.Date)
for _, session := range day.Sessions {
fmt.Printf(" 📱 Session %d\n", session.Session)
fmt.Printf(" ⏱️ Preparation: %s\n", session.Preparation)
fmt.Printf(" 🎥 Video Call: %s\n", session.Waktu)
fmt.Printf(" 👥 Members: %s\n", strings.Join(session.Members, ", "))
fmt.Printf(" %s\n", formatSessionStatus(session.SessionStatus))
}
}
}
func displayTodayVideoCallSchedule() {
data, err := getTodayVideoCallSchedule()
if err != nil {
fmt.Printf("Error fetching today's video call schedule: %v\n", err)
return
}
if !data.Success || len(data.Sessions) == 0 {
fmt.Println("📅 No video call sessions today")
return
}
fmt.Printf("📅 TODAY'S VIDEO CALL SCHEDULE - %s, %s\n", data.Day, data.Date)
fmt.Printf("📊 Total Sessions: %d\n", data.TotalSessions)
fmt.Println()
for _, session := range data.Sessions {
fmt.Printf("📱 Session %d\n", session.Session)
fmt.Printf(" ⏱️ Preparation: %s\n", session.Preparation)
fmt.Printf(" 🎥 Video Call: %s\n", session.Waktu)
fmt.Printf(" 👥 Members: %s\n", strings.Join(session.Members, ", "))
fmt.Printf(" %s\n", formatSessionStatus(session.SessionStatus))
// Show countdown for upcoming sessions
if session.SessionStatus.TimeUntilStart != nil {
minutes := *session.SessionStatus.TimeUntilStart
hours := minutes / 60
mins := minutes % 60
fmt.Printf(" ⏰ Starts in: %dh %dm\n", hours, mins)
}
if session.SessionStatus.TimeRemaining != nil {
minutes := *session.SessionStatus.TimeRemaining
fmt.Printf(" ⏱️ Ends in: %d minutes\n", minutes)
}
fmt.Println()
}
}
func monitorVideoCallSessions(durationMinutes int) {
fmt.Println("🔄 Starting video call session monitor...")
ticker := time.NewTicker(1 * time.Minute)
defer ticker.Stop()
timeout := time.After(time.Duration(durationMinutes) * time.Minute)
for {
select {
case <-timeout:
fmt.Println("🔄 Monitor stopped")
return
case <-ticker.C:
data, err := getTodayVideoCallSchedule()
if err != nil {
fmt.Printf("Monitor error: %v\n", err)
continue
}
if data.Success && len(data.Sessions) > 0 {
ongoingSessions := []VideoCallSession{}
prepSessions := []VideoCallSession{}
for _, session := range data.Sessions {
if session.SessionStatus.IsOngoing {
ongoingSessions = append(ongoingSessions, session)
}
if session.SessionStatus.IsPreparation {
prepSessions = append(prepSessions, session)
}
}
if len(ongoingSessions) > 0 {
fmt.Printf("🔴 LIVE NOW: %d video call session(s)\n", len(ongoingSessions))
for _, session := range ongoingSessions {
fmt.Printf(" 📱 Session %d with %s\n", session.Session, strings.Join(session.Members, ", "))
}
}
if len(prepSessions) > 0 {
fmt.Printf("🔄 PREPARING: %d session(s) in preparation\n", len(prepSessions))
for _, session := range prepSessions {
fmt.Printf(" 📱 Session %d starting soon\n", session.Session)
}
}
}
}
}
}
func getMemberScheduleAnalysis(memberName string) {
data, err := getVideoCallByMember(memberName)
if err != nil {
fmt.Printf("Error analyzing member schedule: %v\n", err)
return
}
if !data.Success || data.TotalSessions == 0 {
fmt.Printf("❌ No video call sessions found for %s\n", memberName)
return
}
fmt.Printf("📊 %s VIDEO CALL ANALYSIS\n", strings.ToUpper(memberName))
fmt.Printf("📅 Total Sessions: %d\n", data.TotalSessions)
fmt.Printf("📆 Month: %s %s\n", data.DataMonth, data.DataYear)
fmt.Println()
// Group by date
sessionsByDate := make(map[string][]MemberScheduleItem)
for _, session := range data.Schedule {
date := session.Date
sessionsByDate[date] = append(sessionsByDate[date], session)
}
for date, sessions := range sessionsByDate {
fmt.Printf("📆 %s, %s\n", sessions[0].Day, date)
for _, session := range sessions {
fmt.Printf(" 📱 Session %d: %s\n", session.Session, session.Waktu)
fmt.Printf(" 👥 With: %s\n", strings.Join(session.OtherMembers, ", "))
fmt.Printf(" %s\n", formatSessionStatus(session.SessionStatus))
}
fmt.Println()
}
}
func main() {
// Example usage
fmt.Println("=== JKT48 VIDEO CALL SCHEDULE API EXAMPLES ===\n")
// Display all video call schedules
fmt.Println("1. All Video Call Schedules:")
displayVideoCallSchedule(nil)
fmt.Println()
// Display today's schedule
fmt.Println("2. Today's Video Call Schedule:")
displayTodayVideoCallSchedule()
fmt.Println()
// Get specific date schedule
fmt.Println("3. Video Call Schedule for Date 18:")
displayVideoCallSchedule(map[string]string{"date": "18"})
fmt.Println()
// Get member specific schedule
fmt.Println("4. Adeline's Video Call Analysis:")
getMemberScheduleAnalysis("Adeline")
fmt.Println()
// Uncomment to start monitoring
// fmt.Println("5. Starting Monitor (30 minutes):")
// monitorVideoCallSessions(30)
}
Real-time Status Monitoring
// Session status monitoring
function getSessionStatusInfo(session) {
const status = session.session_status;
switch (status.status) {
case 'upcoming':
return {
icon: '⏰',
color: '#FFA500',
description: 'Session will start soon',
action: 'Set reminder'
};
case 'preparation':
return {
icon: '🔄',
color: '#FFD700',
description: 'Members are preparing',
action: 'Get ready'
};
case 'ongoing':
return {
icon: '🔴',
color: '#FF0000',
description: 'Video call is live',
action: 'Join now'
};
case 'finished':
return {
icon: '✅',
color: '#32CD32',
description: 'Session completed',
action: 'Check highlights'
};
default:
return {
icon: '❓',
color: '#808080',
description: 'Unknown status',
action: 'Refresh'
};
}
}
// Real-time video call session monitor
class VideoCallLiveMonitor {
constructor(options = {}) {
this.updateInterval = options.updateInterval || 60000; // 1 minute
this.callbacks = {
onSessionStart: options.onSessionStart || (() => {}),
onSessionEnd: options.onSessionEnd || (() => {}),
onPreparation: options.onPreparation || (() => {}),
onStatusChange: options.onStatusChange || (() => {})
};
this.previousSessions = new Map();
this.isMonitoring = false;
}
async start() {
if (this.isMonitoring) return;
this.isMonitoring = true;
console.log('🎥 Starting video call live monitor...');
this.monitorLoop();
}
async monitorLoop() {
while (this.isMonitoring) {
try {
const data = await getTodayVideoCallSchedule();
if (data.success && data.sessions) {
this.checkForStatusChanges(data.sessions);
}
await new Promise(resolve => setTimeout(resolve, this.updateInterval));
} catch (error) {
console.error('Monitor error:', error);
await new Promise(resolve => setTimeout(resolve, 30000)); // Wait 30s on error
}
}
}
checkForStatusChanges(sessions) {
sessions.forEach(session => {
const sessionKey = `session_${session.session}`;
const currentStatus = session.session_status.status;
const previousStatus = this.previousSessions.get(sessionKey);
if (previousStatus !== currentStatus) {
this.callbacks.onStatusChange(session, previousStatus, currentStatus);
if (currentStatus === 'ongoing' && previousStatus !== 'ongoing') {
this.callbacks.onSessionStart(session);
}
if (currentStatus === 'finished' && previousStatus === 'ongoing') {
this.callbacks.onSessionEnd(session);
}
if (currentStatus === 'preparation' && previousStatus !== 'preparation') {
this.callbacks.onPreparation(session);
}
this.previousSessions.set(sessionKey, currentStatus);
}
});
}
stop() {
this.isMonitoring = false;
console.log('🛑 Video call monitor stopped');
}
}
// Usage
const monitor = new VideoCallLiveMonitor({
onSessionStart: (session) => {
console.log(`🔴 LIVE: Session ${session.session} started!`);
console.log(`👥 Members: ${session.members.join(', ')}`);
},
onPreparation: (session) => {
console.log(`🔄 PREP: Session ${session.session} in preparation`);
},
onSessionEnd: (session) => {
console.log(`✅ END: Session ${session.session} finished`);
}
});
// monitor.start();
// Advanced reminder system
class VideoCallReminderSystem {
constructor() {
this.activeReminders = new Map();
this.notificationMethods = [];
}
addNotificationMethod(method) {
this.notificationMethods.push(method);
}
async setupTodayReminders() {
try {
const data = await getTodayVideoCallSchedule();
if (data.success && data.sessions) {
data.sessions.forEach(session => {
if (session.session_status.status === 'upcoming') {
this.setSessionReminders(session);
}
});
}
} catch (error) {
console.error('Error setting up reminders:', error);
}
}
setSessionReminders(session) {
const timeUntilStart = session.session_status.time_until_start;
if (!timeUntilStart) return;
// Reminder intervals (in minutes before start)
const reminderIntervals = [30, 15, 5, 1];
reminderIntervals.forEach(minutes => {
if (timeUntilStart > minutes) {
const delay = (timeUntilStart - minutes) * 60 * 1000;
const timerId = setTimeout(() => {
this.sendReminder(session, minutes);
}, delay);
this.activeReminders.set(`session_${session.session}_${minutes}min`, timerId);
}
});
}
sendReminder(session, minutesUntilStart) {
const reminderData = {
session: session.session,
members: session.members,
startTime: session.waktu,
minutesUntilStart,
message: `Video call session ${session.session} starts in ${minutesUntilStart} minute(s)!`
};
this.notificationMethods.forEach(method => {
try {
method(reminderData);
} catch (error) {
console.error('Notification method error:', error);
}
});
}
clearAllReminders() {
this.activeReminders.forEach(timerId => clearTimeout(timerId));
this.activeReminders.clear();
}
}
// Notification methods
const consoleNotification = (data) => {
console.log(`🔔 REMINDER: ${data.message}`);
console.log(`👥 Members: ${data.members.join(', ')}`);
console.log(`⏰ Time: ${data.startTime}`);
};
const desktopNotification = (data) => {
if ('Notification' in window && Notification.permission === 'granted') {
new Notification(`JKT48 Video Call Reminder`, {
body: data.message,
icon: '/jkt48-icon.png'
});
}
};
// Usage
const reminderSystem = new VideoCallReminderSystem();
reminderSystem.addNotificationMethod(consoleNotification);
reminderSystem.addNotificationMethod(desktopNotification);
// reminderSystem.setupTodayReminders();
Error Handling & Edge Cases
// Comprehensive error handling
async function safeGetVideoCallSchedule(options = {}) {
try {
const data = await getVideoCallSchedule(options);
// Check for outdated data
if (data.is_data_outdated) {
return {
...data,
warning: 'Schedule data is from a previous month',
isEmpty: true
};
}
// Validate response structure
if (!data.data || !Array.isArray(data.data)) {
throw new Error('Invalid schedule data structure');
}
// Check for empty results with filters
if (data.data.length === 0 && Object.values(data.filters).some(f => f !== null)) {
return {
...data,
warning: 'No sessions found matching the specified filters',
isEmpty: true
};
}
return {
...data,
isEmpty: false
};
} catch (error) {
console.error('Video call schedule error:', error);
return {
success: false,
error: error.message,
isEmpty: true,
data: [],
statistics: {
total_sessions: 0,
ongoing_sessions: 0,
finished_sessions: 0,
upcoming_sessions: 0
}
};
}
}
// Connection retry logic
async function getVideoCallScheduleWithRetry(options = {}, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await getVideoCallSchedule(options);
} catch (error) {
if (attempt === maxRetries) {
throw error;
}
console.log(`Attempt ${attempt} failed, retrying in ${attempt * 1000}ms...`);
await new Promise(resolve => setTimeout(resolve, attempt * 1000));
}
}
}
Usage Examples
Basic Examples:
# Get all video call schedules
curl "https://v2.jkt48connect.my.id/api/jkt48/videocall?apikey=YOUR_API_KEY"
# Get schedules for date 16
curl "https://v2.jkt48connect.my.id/api/jkt48/videocall?date=16&apikey=YOUR_API_KEY"
# Get all session 1 schedules
curl "https://v2.jkt48connect.my.id/api/jkt48/videocall?sesi=1&apikey=YOUR_API_KEY"
# Get schedules with Adeline
curl "https://v2.jkt48connect.my.id/api/jkt48/videocall?member=Adeline&apikey=YOUR_API_KEY"
# Get today's schedule only
curl "https://v2.jkt48connect.my.id/api/jkt48/videocall/today?apikey=YOUR_API_KEY"
# Combined filters
curl "https://v2.jkt48connect.my.id/api/jkt48/videocall?date=18&sesi=2&apikey=YOUR_API_KEY"
Advanced Integration:
// Complete video call dashboard
async function createVideoCallDashboard() {
const today = await getTodayVideoCallSchedule();
const all = await getVideoCallSchedule();
return {
today: today.sessions || [],
upcoming: all.data || [],
statistics: all.statistics || {},
liveStatus: {
hasLiveSessions: today.sessions?.some(s => s.session_status.is_ongoing) || false,
preparingSessions: today.sessions?.filter(s => s.session_status.is_preparation) || [],
nextSession: today.sessions?.find(s => s.session_status.status === 'upcoming') || null
}
};
}
Get your API key from JKT48Connect and start building video call schedule applications!
How is this guide?
Last updated on