let currentItem = null; let currentLinks = []; let currentPosts = []; // Get URI parameter from URL function getQueryParam(param) { const urlParams = new URLSearchParams(window.location.search); return urlParams.get(param); } // Load featured items data async function loadFeaturedData() { try { const response = await fetch(Config.featured); return await response.json(); } catch (error) { console.error('Error loading featured data:', error); return []; } } // Fetch GitHub repository data async function fetchGitHubRepo(owner, repo) { try { const response = await fetch(`https://api.github.com/repos/${owner}/${repo}`); return await response.json(); } catch (error) { console.error('Error fetching GitHub repo:', error); return null; } } // Fetch pinokio_meta.json for additional data async function fetchPinokioMeta(repoFullName) { try { console.log('Fetching pinokio_meta.json for:', repoFullName); const response = await fetch(`https://raw.githubusercontent.com/${repoFullName}/main/pinokio_meta.json`); const meta = await response.json(); console.log('Pinokio meta data:', meta); // Extract tweet IDs from posts if (meta.posts) { const tweetIds = []; for (const post of meta.posts) { // Reset regex for each iteration const tweetRegex = /.*(twitter|x)\.com\/.+\/([0-9]+)/i; const matches = post.match(tweetRegex); if (matches && matches.length > 2) { tweetIds.push(matches[2]); console.log('Found tweet ID:', matches[2], 'from:', post); } } currentPosts = tweetIds; console.log('Extracted tweet IDs:', tweetIds); } if (meta.links) { currentLinks = meta.links; } return meta; } catch (error) { console.error('Error fetching pinokio meta:', error); return null; } } // Create author section HTML function createAuthorSection(item) { console.log("createAuthorSection", { item }) if (item.author_username) { return `
Author
Verified Script Publisher:
@${item.author_username}
${createTipSection()} `; } else { return `
Script Publisher:
Not Verified
${createTipSection()} `; } } // Create tip/donation section function createTipSection() { if (!currentLinks || currentLinks.length === 0) { return ''; } return `
${currentLinks.map(link => { if (link.links) { return `
${link.title || ''}
${createNestedLinks(link.links)}
`; } else if (link.type === 'bitcoin') { return createBitcoinLink(link); } else { return createRegularLink(link); } }).join('')}
`; } function createNestedLinks(links) { return links.map(link => { if (link.type === 'bitcoin') { return createBitcoinLink(link); } else { return createRegularLink(link); } }).join(''); } function createBitcoinLink(item) { const title = item.title || 'Bitcoin donation'; return `
`; } function createRegularLink(item) { const url = item.value || item.url; const title = item.title || url; const favicon = getFaviconUrl(url); return `
favicon
${title}
`; } function getFaviconUrl(url) { try { const parsed = new URL(url); const origin = parsed.origin; return { primary: `${origin}/favicon.ico`, fallback: `https://www.google.com/s2/favicons?domain=${parsed.hostname}&sz=32` }; } catch { return { primary: '', fallback: 'data:image/svg+xml,' }; } } function showBitcoinModal(address, title) { // Create modal overlay const modal = document.createElement('div'); modal.className = 'modal-overlay'; modal.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); display: flex; justify-content: center; align-items: center; z-index: 10000; `; modal.innerHTML = ` `; // Close modal when clicking overlay modal.addEventListener('click', (e) => { if (e.target === modal) { modal.remove(); } }); document.body.appendChild(modal); // Generate QR code generateBitcoinQR(`bitcoin:${address}`, 'qr-container'); } function generateBitcoinQR(bitcoinUri, containerId) { // Use QR Server API to generate QR code const qrContainer = document.getElementById(containerId); const size = 200; const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=${size}x${size}&data=${encodeURIComponent(bitcoinUri)}&margin=2`; qrContainer.innerHTML = ` Bitcoin QR Code
QR code could not be generated
`; } // Render item profile function renderItemProfile(item) { const profileSection = document.getElementById('profileSection'); profileSection.innerHTML = `
App Icon
${item.title}
${item.url}
${item.description}
One-Click Install with Pinokio
${createAuthorSection(item)}
`; } // Main function to load item details async function loadItemDetails() { const uri = getQueryParam('uri'); const display = getQueryParam('display'); const parent_frame = getQueryParam('parent_frame'); const theme = getQueryParam('theme'); // Hide navigation if display mode is set if (display) { let nav = document.querySelector("#navigation") if (nav) { nav.style.display = 'none'; } } if (!uri) { document.getElementById('profileSection').innerHTML = `
No Item Selected
Please select an item from the home page.
`; return; } // Reset state currentLinks = []; currentPosts = []; try { // Load featured data const featuredItems = await loadFeaturedData(); // Check if it's a GitHub URL const githubRegex = /github\.com\/(.+)\/(.+)/i; const match = githubRegex.exec(uri); let item = {}; if (match && match.length > 0) { // It's a GitHub URL - fetch repo data const owner = match[1]; const repo = match[2]; const repoData = await fetchGitHubRepo(owner, repo); if (repoData) { let downloadURL if (parent_frame) { downloadURL = `${parent_frame}?mode=download&uri=${repoData.html_url}` } else { downloadURL = `pinokio://download?uri=${repoData.html_url}` } item = { title: repoData.name, description: repoData.description, image: repoData.owner.avatar_url, url: repoData.html_url, path: repoData.full_name, download: repoData.html_url, downloadURL, id: repoData.full_name }; // Fetch additional metadata await fetchPinokioMeta(repoData.full_name); } } // Check if this item is in featured list and override with featured data for (const featuredItem of featuredItems) { if (featuredItem.url.toLowerCase() === uri.toLowerCase() || (item.url && featuredItem.url.toLowerCase() === item.url.toLowerCase())) { // Override with featured data if (featuredItem.title) item.title = featuredItem.title; if (featuredItem.image) item.image = featuredItem.image; if (featuredItem.url) item.url = featuredItem.url; if (featuredItem.path) item.path = featuredItem.path; if (featuredItem.description) item.description = featuredItem.description; if (featuredItem.download) item.download = featuredItem.download; if (featuredItem.version) item.version = featuredItem.version; if (featuredItem.branch) item.branch = featuredItem.branch; if (featuredItem.author_avatar) item.author_avatar = featuredItem.author_avatar; if (featuredItem.author_url) item.author_url = featuredItem.author_url; if (featuredItem.author_username) item.author_username = featuredItem.author_username; if (featuredItem.links && Array.isArray(featuredItem.links)) { currentLinks = featuredItem.links; } // Update download URL if (parent_frame) { item.downloadURL = `${parent_frame}?mode=download&uri=${item.download}` } else { item.downloadURL = `pinokio://download?uri=${item.download}` } if (item.branch) { item.downloadURL += "&branch=" + item.branch; } break; } } // If no GitHub match, check featured items directly if (!match) { for (const featuredItem of featuredItems) { if (featuredItem.url.toLowerCase() === uri.toLowerCase()) { item = { ...featuredItem }; if (parent_frame) { item.downloadURL = `${parent_frame}?mode=download&uri=${item.download}` } else { item.downloadURL = `pinokio://download?uri=${item.download}` } if (item.branch) { item.downloadURL += "&branch=" + item.branch; } if (item.links && Array.isArray(item.links)) { currentLinks = item.links; } break; } } } currentItem = item; // Render the UI based on display mode if (!display || display === 'profile') { renderItemProfile(item); } if (!display || display === 'feed') { const container = document.getElementById('tweetsContainer'); renderTweets(container, currentPosts); } } catch (error) { console.error('Error loading item details:', error); document.getElementById('profileSection').innerHTML = `
Error Loading Item
There was an error loading the item details.
`; } } function updateTheme() { const theme = getQueryParam('theme'); document.querySelector("body").classList.add(theme) document.querySelector("body").setAttribute("data-theme", theme) } // Initialize when page loads document.addEventListener('DOMContentLoaded', function() { updateTheme() loadItemDetails(); });