| |
| |
|
|
| const { createClient } = require('@supabase/supabase-js'); |
| const { Octokit } = require('octokit'); |
| const fs = require('fs'); |
| const path = require('path'); |
| const axios = require('axios'); |
| const { execSync } = require('child_process'); |
| const mime = require('mime-types'); |
|
|
| |
| const SUPABASE_URL = "https://ajeukqjcqweuofclpdjo.supabase.co"; |
| const SUPABASE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFqZXVrcWpjcXdldW9mY2xwZGpvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzA5MTA5NjMsImV4cCI6MjA4NjQ4Njk2M30.DfSpKC2u3u3MKynG9gkZsG_a4M5_AtQbs9QI1OYpwZQ"; |
|
|
| |
| const GH_TOKEN = "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"; |
| const GH_OWNER = "yanzzv520-cyber"; |
| const GH_REPO = "mikunime"; |
|
|
| |
| const supabase = createClient(SUPABASE_URL, SUPABASE_KEY); |
| const octokit = new Octokit({ auth: GH_TOKEN }); |
|
|
| |
| const PROJEK_REPO_URL = "https://github.com/Yanzz15/Projek.git"; |
| const TEMP_DIR = "./temp_projek"; |
| const JSON_DIR = path.join(TEMP_DIR, "anime_json"); |
|
|
| async function main() { |
| console.log("π Memulai Migrasi Anime (GITHUB RELEASES)..."); |
|
|
| |
| try { |
| await octokit.request('GET /repos/{owner}/{repo}/contents/{path}', { |
| owner: GH_OWNER, |
| repo: GH_REPO, |
| path: 'README.md' |
| }); |
| console.log("β
Repo GitHub sudah siap (ada README.md)."); |
| } catch (err) { |
| if (err.status === 404) { |
| console.log("β οΈ Repo GitHub kosong! Membuat README.md..."); |
| try { |
| await octokit.request('PUT /repos/{owner}/{repo}/contents/{path}', { |
| owner: GH_OWNER, |
| repo: GH_REPO, |
| path: 'README.md', |
| message: 'Initial commit for Anime Vault', |
| content: Buffer.from('# Anime Vault\n\nTempat penyimpanan video anime.').toString('base64') |
| }); |
| console.log("β
Berhasil inisialisasi Repo GitHub!"); |
| } catch (createErr) { |
| console.error("β Gagal Init Repo:", createErr.message); |
| process.exit(1); |
| } |
| } else { |
| console.error("β Gagal Cek Repo GitHub:", err.message); |
| } |
| } |
|
|
| |
| if (!fs.existsSync(TEMP_DIR)) { |
| console.log("π₯ Cloning Repo Projek..."); |
| try { execSync(`git clone ${PROJEK_REPO_URL} ${TEMP_DIR}`); } |
| catch (e) { console.error("β Gagal Clone:", e.message); process.exit(1); } |
| } |
|
|
| |
| const files = fs.readdirSync(JSON_DIR).filter(f => f.endsWith('.json')); |
| console.log(`π Total Anime: ${files.length}`); |
|
|
| |
| for (const file of files) { |
| try { |
| const rawData = fs.readFileSync(path.join(JSON_DIR, file), 'utf-8'); |
| const animeData = JSON.parse(rawData); |
|
|
| const cleanTitle = cleanMetadata(animeData.title); |
| const cleanSlug = cleanMetadataSlug(animeData.slug); |
|
|
| console.log(` |
| π¬ [${cleanTitle}] (${cleanSlug})`); |
|
|
| |
| const { data: existingAnime } = await supabase |
| .from('animes') |
| .select('id') |
| .eq('slug', cleanSlug) |
| .maybeSingle(); |
|
|
| if (existingAnime) { |
| console.log(`βοΈ Anime sudah ada di DB, skip.`); |
| continue; |
| } |
|
|
| |
| |
| |
| |
| let releaseData; |
| try { |
| |
| releaseData = await octokit.request('GET /repos/{owner}/{repo}/releases/tags/{tag}', { |
| owner: GH_OWNER, |
| repo: GH_REPO, |
| tag: cleanSlug |
| }); |
| console.log(`π·οΈ Release '${cleanSlug}' sudah ada, pakai yang lama.`); |
| releaseData = releaseData.data; |
| } catch (err) { |
| if (err.status === 404) { |
| |
| console.log(`β¨ Membuat Release Baru: ${cleanSlug}`); |
| const newRelease = await octokit.request('POST /repos/{owner}/{repo}/releases', { |
| owner: GH_OWNER, |
| repo: GH_REPO, |
| tag_name: cleanSlug, |
| name: cleanTitle, |
| body: `Video streaming untuk anime ${cleanTitle}`, |
| draft: false, |
| prerelease: false |
| }); |
| releaseData = newRelease.data; |
| } else { |
| console.error(`β Gagal Cek Release: ${err.message}`); |
| continue; |
| } |
| } |
|
|
| |
| let allEpisodes = []; |
| const episodes = animeData.episodes || []; |
|
|
| for (const ep of episodes) { |
| console.log(`πΉ Processing Ep ${ep.episode}...`); |
| |
| let epMetadata = { |
| number: ep.episode, |
| title: cleanMetadata(ep.title), |
| streams: { "480p": null, "720p": null } |
| }; |
|
|
| |
| if (ep.streams?.["480p"]) { |
| epMetadata.streams["480p"] = await uploadToGithub(ep.streams["480p"], releaseData, `ep${ep.episode}-480p.mp4`); |
| } |
| if (ep.streams?.["720p"]) { |
| epMetadata.streams["720p"] = await uploadToGithub(ep.streams["720p"], releaseData, `ep${ep.episode}-720p.mp4`); |
| } |
|
|
| allEpisodes.push(epMetadata); |
| } |
|
|
| |
| const { error: insertError } = await supabase |
| .from('animes') |
| .insert({ |
| slug: cleanSlug, |
| title: cleanTitle, |
| poster: animeData.poster, |
| synopsis: animeData.synopsis, |
| metadata: { original_url: animeData.url }, |
| episodes: allEpisodes |
| }); |
|
|
| if (insertError) console.error(`β Gagal Insert DB: ${insertError.message}`); |
| else console.log(`πΎ Anime & Episodes tersimpan di DB!`); |
|
|
| } catch (err) { |
| console.error(`β Error File ${file}:`, err.message); |
| } |
| } |
| console.log("π SELESAI SEMUA!"); |
| } |
|
|
| |
|
|
| function cleanMetadata(str) { |
| if (!str) return ""; |
| return str.replace(/Subtitle Indonesia/gi, '').replace(/Sub Indo/gi, '').replace(/\(END\)/gi, '').trim(); |
| } |
|
|
| function cleanMetadataSlug(str) { |
| if (!str) return ""; |
| return str.replace(/-subtitle-indonesia/gi, '').replace(/-sub-indo/gi, '').replace(/-end-/gi, '-').replace(/-$/gi, '').trim(); |
| } |
|
|
| async function uploadToGithub(url, release, filename) { |
| |
| const existingAsset = release.assets?.find(a => a.name === filename); |
| if (existingAsset) { |
| |
| return existingAsset.browser_download_url; |
| } |
|
|
| try { |
| |
| const response = await axios({ |
| method: 'get', |
| url: url, |
| responseType: 'arraybuffer', |
| timeout: 60000, |
| headers: { |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', |
| 'Referer': 'https://x3.sokuja.uk/' |
| } |
| }); |
|
|
| |
| |
| |
| const upload = await octokit.request('POST ' + release.upload_url, { |
| headers: { |
| 'content-type': 'video/mp4', |
| 'content-length': response.data.byteLength |
| }, |
| name: filename, |
| data: response.data |
| }); |
|
|
| return upload.data.browser_download_url; |
|
|
| } catch (error) { |
| console.error(`β οΈ Gagal Upload GitHub ${filename}: ${error.message}`); |
| return null; |
| } |
| } |
|
|
| main(); |