JKT48Connect

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 key
  • channel (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