const express = require('express'); const puppeteer = require('puppeteer'); const axios = require('axios'); const cors = require('cors'); const fs = require('fs'); const https = require('https'); const app = express(); const path = './checkedLinksCache.json'; const cheerio = require('cheerio'); app.use(cors()); const clientId = 'yourClientId'; const clientSecret = 'yourClientSecret'; const authString = Buffer.from(`${clientId}:${clientSecret}`).toString('base64'); let accessToken = ''; const options = { key: fs.readFileSync('ssl/178.254.39.146.key'), cert: fs.readFileSync('ssl/178.254.39.146.crt'), ca: [ fs.readFileSync('ssl/178.254.39.146.crt') ] }; async function getAccessToken() { try { const response = await axios.post('https://accounts.spotify.com/api/token', 'grant_type=client_credentials', { headers: { 'Authorization': `Basic ${authString}`, 'Content-Type': 'application/x-www-form-urlencoded' } }); accessToken = response.data.access_token; console.log('Access token retrieved:', accessToken); } catch (error) { console.error('Error fetching access token:', error); } } app.get('/token', async (req, res) => { await getAccessToken(); res.json({ accessToken }); }); async function loadCookies(page, filePath = 'cookies.json') { if (fs.existsSync(filePath)) { const cookies = JSON.parse(fs.readFileSync(filePath)); await page.setCookie(...cookies); console.log("Cookies loaded from", filePath); } } async function saveCookies(page, filePath = 'cookies.json') { const cookies = await page.cookies(); fs.writeFileSync(filePath, JSON.stringify(cookies, null, 2)); console.log("Cookies saved to", filePath); } let checkedLinksCache = {}; if (fs.existsSync(path)) { const data = fs.readFileSync(path, 'utf8'); checkedLinksCache = JSON.parse(data); } async function handleYouTubeConsentAndSpotifyVerification(page, url) { await loadCookies(page); const consentUrl = "consent.youtube.com"; if (page.url().includes(consentUrl)) { try { await page.waitForSelector('button[aria-label="Accept all"]', { timeout: 5000 }); await page.click('button[aria-label="Accept all"]'); console.log("Clicked 'Accept all' on consent prompt."); await new Promise(resolve => setTimeout(resolve, 2000)); await saveCookies(page); await page.waitForNavigation({ waitUntil: 'domcontentloaded' }); console.log("Handled YouTube consent page."); } catch (error) { console.log("Could not handle YouTube consent page:", error); } } let isVerified = false; if (url.includes('spotify.com')) { isVerified = await checkSpotifyVerification(page); } return { finalUrl: page.url(), isVerified }; } async function checkSpotifyVerification(page) { try { await page.waitForSelector('.Svg-sc-ytk21e-0.ZxtYq.b0NcxAbHvRbqgs2S8QDg', { timeout: 5000 }); return await page.evaluate(() => !!document.querySelector('.Svg-sc-ytk21e-0.ZxtYq.b0NcxAbHvRbqgs2S8QDg')); } catch (error) { console.error("Error checking Spotify verification:", error); return false; } } async function fetchMusicLinks(query) { const artistName = query.toLowerCase(); if (checkedLinksCache[artistName]) { console.log("Returning cached links for:", artistName); return checkedLinksCache[artistName]; } const browser = await puppeteer.launch({ headless: false, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu', '--window-size=1280x800', '--user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"' ] }); const page = await browser.newPage(); const musicLinks = new Set(); let isVerified = false; const url = `https://www.google.com/search?q=${query}+listen&oq=${query}+listen&sourceid=chrome&ie=UTF-8`; await page.goto(url, { waitUntil: 'networkidle2' }); try { await page.waitForSelector('.TzHB6b'); const allLinks = await page.evaluate(() => { const links = []; document.querySelectorAll('.TzHB6b .PZPZlf a').forEach(anchor => { const url = anchor.href; if (url && (url.includes('youtube.com') || url.includes('spotify.com') || url.includes('music.apple.com') || url.includes('deezer.com') || url.includes('amazon.com'))) { links.push(url); } }); return links; }); allLinks.forEach(url => { if (url.includes('artist') || url.includes('channel')) { musicLinks.add(url); } }); } catch (error) { console.log("Knowledge Panel not found or failed to load within the timeout."); } if (musicLinks.size === 0) { console.log("No Knowledge Panel links found. Attempting general search."); const fallbackUrl = `https://www.google.com/search?q=${query}+"artist"&oq=${query}+"artist"&sourceid=chrome&ie=UTF-8`; await page.goto(fallbackUrl, { waitUntil: 'networkidle2' }); await page.waitForSelector('#search'); await page.evaluate(() => window.scrollBy(0, 100)); await new Promise(resolve => setTimeout(resolve, 2000)); const allLinks = await page.evaluate(() => { const links = []; document.querySelectorAll('#search [data-hveid] a').forEach(anchor => { const url = anchor.href; if (url && (url.includes('youtube.com') || url.includes('spotify.com') || url.includes('music.apple.com') || url.includes('deezer.com') || url.includes('amazon.com'))) { links.push(url); } }); return links; }); allLinks.forEach(url => { if (url.includes('artist') || url.includes('channel')) { musicLinks.add(url); } }); } const uniqueMusicLinks = Array.from(musicLinks); const filteredMusicLinks = []; for (let url of uniqueMusicLinks) { const match = url.match(/\/(artist|channel)\/([a-zA-Z0-9]+)/); if (match) { const id = match[2]; const linkPage = await browser.newPage(); await loadCookies(linkPage); await linkPage.goto(url, { waitUntil: 'domcontentloaded' }); const { finalUrl, isVerified: verifiedStatus } = await handleYouTubeConsentAndSpotifyVerification(linkPage, url); const title = await linkPage.title(); if (title.toLowerCase().includes(artistName) && !filteredMusicLinks.some(link => link.url.includes(id))) { filteredMusicLinks.push({ url: finalUrl }); if (url.includes('spotify.com')) isVerified = verifiedStatus; } await linkPage.close(); } } await browser.close(); checkedLinksCache[artistName] = { links: filteredMusicLinks, isVerified }; fs.writeFileSync(path, JSON.stringify(checkedLinksCache, null, 2), 'utf8'); return { links: filteredMusicLinks, isVerified }; } app.get('/api/search/', async (req, res) => { const artist = req.query.artist; if (!artist) { return res.status(400).send({ error: "Please provide an artist name as a query parameter" }); } try { const data = await fetchMusicLinks(artist); res.json({ artist, ...data }); } catch (error) { console.error("Error fetching music links:", error); res.status(500).send({ error: "Failed to fetch music links" }); } }); setInterval(getAccessToken, 3600 * 1000); const PORT = process.env.PORT || 300; https.createServer(options, app).listen(PORT, () => { console.log(`Server running at https://178.254.39.146:${PORT}/`); getAccessToken(); });