YouTube Videos
Get latest JKT48 official YouTube videos using JKT48Connect API
Introduction
The JKT48Connect YouTube API provides access to latest videos from official JKT48 YouTube channels including @jkt48 and @jkt48tv. Use this endpoint to fetch recent uploads, music videos, variety shows, and other official content.
Official Videos
Access latest uploads from JKT48 official channels.
Multiple Channels
Get content from @jkt48 and @jkt48tv channels.
Real-time Updates
Track new video releases and channel activity.
Quick Start
Basic Request
curl "https://v2.jkt48connect.my.id/api/jkt48/youtube?apikey=YOUR_API_KEY"
Process Response
const youtubeData = await getYouTubeVideos();
console.log(youtubeData.jkt48_channel);
console.log(youtubeData.jkt48tv_channel);
Filter Content
Filter by channel, date, or video type.
Endpoint Details
Base URL: https://v2.jkt48connect.my.id
Endpoint: /api/jkt48/youtube
Method: GET
Authentication: API Key required
Query Parameters:
apikey
(required): Your API authentication keychannel
(optional): Filter by channel (@jkt48 or @jkt48tv)limit
(optional): Number of videos per channel (default: 10)date
(optional): Filter videos after specific date (YYYY-MM-DD)
Example:
GET /api/jkt48/youtube?apikey=YOUR_API_KEY&limit=20 HTTP/1.1
Host: v2.jkt48connect.my.id
Returns latest videos from official JKT48 YouTube channels:
{
"jkt48_channel": [
{
"video_id": "dQw4w9WgXcQ",
"title": "JKT48 - Rapsodi (Official Music Video)",
"description": "Official Music Video JKT48 - Rapsodi...",
"thumbnail": "https://img.youtube.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
"duration": "04:23",
"published_at": "2025-06-28T12:00:00.000Z",
"view_count": 125430,
"like_count": 8320,
"comment_count": 456,
"youtube_url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"channel": "@jkt48",
"tags": ["JKT48", "Music Video", "Rapsodi"]
}
],
"jkt48tv_channel": [
{
"video_id": "abc123xyz",
"title": "JKT48 Variety Show - Episode 15",
"description": "Episode terbaru variety show JKT48...",
"thumbnail": "https://img.youtube.com/vi/abc123xyz/maxresdefault.jpg",
"duration": "45:12",
"published_at": "2025-06-27T19:00:00.000Z",
"view_count": 67890,
"like_count": 3210,
"comment_count": 189,
"youtube_url": "https://youtube.com/watch?v=abc123xyz",
"channel": "@jkt48tv",
"tags": ["JKT48TV", "Variety", "Entertainment"]
}
],
"total_videos": 20,
"last_updated": "2025-06-29T10:30:00.000Z"
}
Implementation Examples
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://v2.jkt48connect.my.id';
async function getYouTubeVideos(options = {}) {
const params = new URLSearchParams({
apikey: API_KEY,
...options
});
try {
const response = await fetch(`${BASE_URL}/api/jkt48/youtube?${params}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error('Failed to fetch YouTube videos:', error);
throw error;
}
}
// Get videos from specific channel
async function getChannelVideos(channel, limit = 10) {
const data = await getYouTubeVideos({ channel, limit });
return channel === '@jkt48' ? data.jkt48_channel : data.jkt48tv_channel;
}
// Get all latest videos
async function getLatestVideos(limit = 20) {
const data = await getYouTubeVideos({ limit });
return [
...(data.jkt48_channel || []),
...(data.jkt48tv_channel || [])
].sort((a, b) => new Date(b.published_at) - new Date(a.published_at));
}
// Format video data
function formatVideoData(video) {
const publishDate = new Date(video.published_at);
const isRecent = Date.now() - publishDate.getTime() < 24 * 60 * 60 * 1000; // 24 hours
return {
id: video.video_id,
title: video.title,
channel: video.channel,
duration: video.duration,
publishDate: publishDate.toLocaleDateString('id-ID'),
publishTime: publishDate.toLocaleTimeString('id-ID'),
viewCount: formatNumber(video.view_count),
likeCount: formatNumber(video.like_count),
commentCount: formatNumber(video.comment_count),
thumbnail: video.thumbnail,
watchUrl: video.youtube_url,
isRecent: isRecent,
tags: video.tags || []
};
}
function formatNumber(num) {
if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M';
if (num >= 1000) return (num / 1000).toFixed(1) + 'K';
return num.toString();
}
// Display YouTube feed
async function displayYouTubeFeed() {
try {
const data = await getYouTubeVideos({ limit: 15 });
console.log('=== JKT48 YOUTUBE FEED ===');
console.log(`Last updated: ${new Date(data.last_updated).toLocaleString('id-ID')}`);
console.log(`Total videos: ${data.total_videos}\n`);
if (data.jkt48_channel?.length > 0) {
console.log('🎵 JKT48 Main Channel (@jkt48):');
data.jkt48_channel.forEach(video => {
const formatted = formatVideoData(video);
console.log(`• ${formatted.title}`);
console.log(` 📅 ${formatted.publishDate} | ⏱️ ${formatted.duration}`);
console.log(` 👁️ ${formatted.viewCount} views | 👍 ${formatted.likeCount} likes`);
console.log(` 🔗 ${formatted.watchUrl}\n`);
});
}
if (data.jkt48tv_channel?.length > 0) {
console.log('📺 JKT48TV Channel (@jkt48tv):');
data.jkt48tv_channel.forEach(video => {
const formatted = formatVideoData(video);
console.log(`• ${formatted.title}`);
console.log(` 📅 ${formatted.publishDate} | ⏱️ ${formatted.duration}`);
console.log(` 👁️ ${formatted.viewCount} views | 👍 ${formatted.likeCount} likes`);
console.log(` 🔗 ${formatted.watchUrl}\n`);
});
}
} catch (error) {
console.error('Error displaying YouTube feed:', error);
}
}
// Get trending videos (high engagement)
async function getTrendingVideos() {
const data = await getYouTubeVideos({ limit: 20 });
const allVideos = [
...(data.jkt48_channel || []),
...(data.jkt48tv_channel || [])
];
return allVideos
.map(video => ({
...video,
engagementScore: (video.like_count + video.comment_count) / video.view_count
}))
.sort((a, b) => b.engagementScore - a.engagementScore)
.slice(0, 10);
}
// Search videos by title
function searchVideos(videos, query) {
const searchTerm = query.toLowerCase();
return videos.filter(video =>
video.title.toLowerCase().includes(searchTerm) ||
video.description.toLowerCase().includes(searchTerm) ||
video.tags.some(tag => tag.toLowerCase().includes(searchTerm))
);
}
import requests
from datetime import datetime, timedelta
API_KEY = 'YOUR_API_KEY'
BASE_URL = 'https://v2.jkt48connect.my.id'
def get_youtube_videos(options=None):
"""Fetch YouTube videos from JKT48 channels"""
params = {'apikey': API_KEY}
if options:
params.update(options)
try:
response = requests.get(f"{BASE_URL}/api/jkt48/youtube", params=params)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error fetching YouTube videos: {e}")
raise
def get_channel_videos(channel, limit=10):
"""Get videos from specific channel"""
data = get_youtube_videos({'channel': channel, 'limit': limit})
return data.get('jkt48_channel' if channel == '@jkt48' else 'jkt48tv_channel', [])
def get_latest_videos(limit=20):
"""Get all latest videos sorted by publish date"""
data = get_youtube_videos({'limit': limit})
all_videos = (data.get('jkt48_channel', []) +
data.get('jkt48tv_channel', []))
return sorted(all_videos,
key=lambda x: datetime.fromisoformat(x['published_at'].replace('Z', '+00:00')),
reverse=True)
def format_video_data(video):
"""Format video data for display"""
publish_date = datetime.fromisoformat(video['published_at'].replace('Z', '+00:00'))
is_recent = datetime.now() - publish_date < timedelta(days=1)
return {
'id': video['video_id'],
'title': video['title'],
'channel': video['channel'],
'duration': video['duration'],
'publish_date': publish_date.strftime('%d %B %Y'),
'publish_time': publish_date.strftime('%H:%M'),
'view_count': format_number(video['view_count']),
'like_count': format_number(video['like_count']),
'comment_count': format_number(video['comment_count']),
'thumbnail': video['thumbnail'],
'watch_url': video['youtube_url'],
'is_recent': is_recent,
'tags': video.get('tags', [])
}
def format_number(num):
"""Format numbers with K/M suffix"""
if num >= 1000000:
return f"{num/1000000:.1f}M"
elif num >= 1000:
return f"{num/1000:.1f}K"
else:
return str(num)
def display_youtube_feed():
"""Display YouTube feed"""
try:
data = get_youtube_videos({'limit': 15})
print("=== JKT48 YOUTUBE FEED ===")
last_updated = datetime.fromisoformat(data['last_updated'].replace('Z', '+00:00'))
print(f"Last updated: {last_updated.strftime('%d %B %Y %H:%M')}")
print(f"Total videos: {data['total_videos']}\n")
if data.get('jkt48_channel'):
print("🎵 JKT48 Main Channel (@jkt48):")
for video in data['jkt48_channel']:
formatted = format_video_data(video)
print(f"• {formatted['title']}")
print(f" 📅 {formatted['publish_date']} | ⏱️ {formatted['duration']}")
print(f" 👁️ {formatted['view_count']} views | 👍 {formatted['like_count']} likes")
print(f" 🔗 {formatted['watch_url']}\n")
if data.get('jkt48tv_channel'):
print("📺 JKT48TV Channel (@jkt48tv):")
for video in data['jkt48tv_channel']:
formatted = format_video_data(video)
print(f"• {formatted['title']}")
print(f" 📅 {formatted['publish_date']} | ⏱️ {formatted['duration']}")
print(f" 👁️ {formatted['view_count']} views | 👍 {formatted['like_count']} likes")
print(f" 🔗 {formatted['watch_url']}\n")
except Exception as e:
print(f"Error displaying YouTube feed: {e}")
def get_trending_videos():
"""Get trending videos based on engagement"""
data = get_youtube_videos({'limit': 20})
all_videos = (data.get('jkt48_channel', []) +
data.get('jkt48tv_channel', []))
# Calculate engagement score
for video in all_videos:
engagement = (video['like_count'] + video['comment_count']) / max(video['view_count'], 1)
video['engagement_score'] = engagement
return sorted(all_videos, key=lambda x: x['engagement_score'], reverse=True)[:10]
def search_videos(videos, query):
"""Search videos by title, description, or tags"""
query_lower = query.lower()
return [video for video in videos
if (query_lower in video['title'].lower() or
query_lower in video['description'].lower() or
any(query_lower in tag.lower() for tag in video.get('tags', [])))]
# Usage example
if __name__ == "__main__":
display_youtube_feed()
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"sort"
"time"
)
const (
APIKey = "YOUR_API_KEY"
BaseURL = "https://v2.jkt48connect.my.id"
)
type YouTubeData struct {
JKT48Channel []Video `json:"jkt48_channel"`
JKT48TVChannel []Video `json:"jkt48tv_channel"`
TotalVideos int `json:"total_videos"`
LastUpdated string `json:"last_updated"`
}
type Video struct {
VideoID string `json:"video_id"`
Title string `json:"title"`
Description string `json:"description"`
Thumbnail string `json:"thumbnail"`
Duration string `json:"duration"`
PublishedAt string `json:"published_at"`
ViewCount int `json:"view_count"`
LikeCount int `json:"like_count"`
CommentCount int `json:"comment_count"`
YouTubeURL string `json:"youtube_url"`
Channel string `json:"channel"`
Tags []string `json:"tags"`
}
func getYouTubeVideos(options map[string]string) (*YouTubeData, error) {
params := url.Values{}
params.Add("apikey", APIKey)
for key, value := range options {
params.Add(key, value)
}
url := fmt.Sprintf("%s/api/jkt48/youtube?%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 YouTubeData
err = json.NewDecoder(resp.Body).Decode(&data)
return &data, err
}
func getChannelVideos(channel string, limit int) ([]Video, error) {
options := map[string]string{
"channel": channel,
"limit": fmt.Sprintf("%d", limit),
}
data, err := getYouTubeVideos(options)
if err != nil {
return nil, err
}
if channel == "@jkt48" {
return data.JKT48Channel, nil
}
return data.JKT48TVChannel, nil
}
func getLatestVideos(limit int) ([]Video, error) {
options := map[string]string{
"limit": fmt.Sprintf("%d", limit),
}
data, err := getYouTubeVideos(options)
if err != nil {
return nil, err
}
allVideos := append(data.JKT48Channel, data.JKT48TVChannel...)
// Sort by published date (newest first)
sort.Slice(allVideos, func(i, j int) bool {
timeI, _ := time.Parse(time.RFC3339, allVideos[i].PublishedAt)
timeJ, _ := time.Parse(time.RFC3339, allVideos[j].PublishedAt)
return timeI.After(timeJ)
})
return allVideos, nil
}
func formatNumber(num int) string {
if num >= 1000000 {
return fmt.Sprintf("%.1fM", float64(num)/1000000)
} else if num >= 1000 {
return fmt.Sprintf("%.1fK", float64(num)/1000)
}
return fmt.Sprintf("%d", num)
}
func displayYouTubeFeed() {
options := map[string]string{"limit": "15"}
data, err := getYouTubeVideos(options)
if err != nil {
fmt.Printf("Error fetching YouTube videos: %v\n", err)
return
}
fmt.Println("=== JKT48 YOUTUBE FEED ===")
lastUpdated, _ := time.Parse(time.RFC3339, data.LastUpdated)
fmt.Printf("Last updated: %s\n", lastUpdated.Format("02 January 2006 15:04"))
fmt.Printf("Total videos: %d\n\n", data.TotalVideos)
if len(data.JKT48Channel) > 0 {
fmt.Println("🎵 JKT48 Main Channel (@jkt48):")
for _, video := range data.JKT48Channel {
publishDate, _ := time.Parse(time.RFC3339, video.PublishedAt)
fmt.Printf("• %s\n", video.Title)
fmt.Printf(" 📅 %s | ⏱️ %s\n", publishDate.Format("02 January 2006"), video.Duration)
fmt.Printf(" 👁️ %s views | 👍 %s likes\n", formatNumber(video.ViewCount), formatNumber(video.LikeCount))
fmt.Printf(" 🔗 %s\n\n", video.YouTubeURL)
}
}
if len(data.JKT48TVChannel) > 0 {
fmt.Println("📺 JKT48TV Channel (@jkt48tv):")
for _, video := range data.JKT48TVChannel {
publishDate, _ := time.Parse(time.RFC3339, video.PublishedAt)
fmt.Printf("• %s\n", video.Title)
fmt.Printf(" 📅 %s | ⏱️ %s\n", publishDate.Format("02 January 2006"), video.Duration)
fmt.Printf(" 👁️ %s views | 👍 %s likes\n", formatNumber(video.ViewCount), formatNumber(video.LikeCount))
fmt.Printf(" 🔗 %s\n\n", video.YouTubeURL)
}
}
}
func main() {
displayYouTubeFeed()
}
Filtering Options
// Get only JKT48 main channel videos
const mainChannelVideos = await getYouTubeVideos({
channel: '@jkt48',
limit: 15
});
// Get only JKT48TV videos
const tvChannelVideos = await getYouTubeVideos({
channel: '@jkt48tv',
limit: 15
});
// Compare channel activity
const channelStats = {
jkt48: mainChannelVideos.jkt48_channel?.length || 0,
jkt48tv: tvChannelVideos.jkt48tv_channel?.length || 0
};
// Get videos from last week
const lastWeek = new Date();
lastWeek.setDate(lastWeek.getDate() - 7);
const recentVideos = await getYouTubeVideos({
date: lastWeek.toISOString().split('T')[0]
});
// Get today's videos
const today = new Date().toISOString().split('T')[0];
const todayVideos = await getYouTubeVideos({ date: today });
// Get more videos per request
const moreVideos = await getYouTubeVideos({ limit: 30 });
// Get just latest uploads
const latestUploads = await getYouTubeVideos({ limit: 5 });
Common Use Cases
// YouTube feed widget
async function createYouTubeFeed() {
const data = await getYouTubeVideos({ limit: 12 });
return {
musicVideos: data.jkt48_channel?.filter(v =>
v.tags.includes('Music Video') || v.title.includes('MV')
) || [],
varietyShows: data.jkt48tv_channel?.filter(v =>
v.tags.includes('Variety') || v.duration > '20:00'
) || [],
recent: getLatestVideos(6),
trending: await getTrendingVideos()
};
}
// Video recommendation system
function getRecommendedVideos(videos, userPreferences) {
return videos.filter(video => {
const matchesTags = video.tags.some(tag =>
userPreferences.tags.includes(tag)
);
const matchesChannel = userPreferences.channels.includes(video.channel);
return matchesTags || matchesChannel;
});
}
// Notification for new uploads
async function checkNewUploads(lastCheckTime) {
const data = await getYouTubeVideos();
const allVideos = [
...(data.jkt48_channel || []),
...(data.jkt48tv_channel || [])
];
return allVideos.filter(video =>
new Date(video.published_at) > new Date(lastCheckTime)
);
}
Error Handling
async function safeGetYouTubeVideos(options = {}) {
try {
const data = await getYouTubeVideos(options);
return {
jkt48_channel: data.jkt48_channel || [],
jkt48tv_channel: data.jkt48tv_channel || [],
total_videos: data.total_videos || 0,
last_updated: data.last_updated || new Date().toISOString(),
status: 'success'
};
} catch (error) {
console.error('Failed to fetch YouTube videos:', error);
return {
jkt48_channel: [],
jkt48tv_channel: [],
total_videos: 0,
last_updated: new Date().toISOString(),
status: 'error',
error: error.message
};
}
}
Get your API key from JKT48Connect and start building YouTube video applications!
How is this guide?
Last updated on