diff --git a/.github/scripts/url-checker.js b/.github/scripts/url-checker.js index 47852b9..5574df0 100644 --- a/.github/scripts/url-checker.js +++ b/.github/scripts/url-checker.js @@ -1,13 +1,13 @@ -const fs = require("fs"); -const axios = require("axios"); -const path = require("path"); +const fs = require('fs'); +const axios = require('axios'); +const path = require('path'); -const FILE_PATH = "modflix.json"; +const FILE_PATH = 'modflix.json'; // Read the modflix.json file -async function readModflixJson() { +function readModflixJson() { try { - const data = fs.readFileSync(FILE_PATH, "utf8"); + const data = fs.readFileSync(FILE_PATH, 'utf8'); return JSON.parse(data); } catch (error) { console.error(`Error reading ${FILE_PATH}:`, error); @@ -33,97 +33,140 @@ function getPath(url) { return urlObj.pathname + urlObj.search + urlObj.hash; } catch (error) { console.error(`Error extracting path from ${url}:`, error); - return ""; + return ''; } } // Check URL and return new URL if redirected async function checkUrl(url) { try { - const response = await axios.get(url, { + // Set timeout to 10 seconds to avoid hanging + const response = await axios.head(url, { maxRedirects: 0, - validateStatus: (status) => status >= 200 && status < 400, + timeout: 10000, + validateStatus: status => true // Accept all status codes to handle them manually }); - + // If status is 200, no change needed if (response.status === 200) { console.log(`✅ ${url} is valid (200 OK)`); return null; - } - } catch (error) { - // Handle redirects - if ( - error.response && - (error.response.status === 301 || - error.response.status === 302 || - error.response.status === 307 || - error.response.status === 308) - ) { - const newLocation = error.response.headers.location; + } else if (response.status >= 300 && response.status < 400) { + // Handle redirects + const newLocation = response.headers.location; if (newLocation) { // If it's a relative redirect, construct the full URL let fullRedirectUrl = newLocation; - if (!newLocation.startsWith("http")) { + if (!newLocation.startsWith('http')) { const baseUrl = new URL(url); fullRedirectUrl = new URL(newLocation, baseUrl.origin).toString(); } - + console.log(`🔄 ${url} redirects to ${fullRedirectUrl}`); - + // Get new domain but keep original path const newDomain = getDomain(fullRedirectUrl); const originalPath = getPath(url); - + // Construct new URL with original path let finalUrl = newDomain; - if (originalPath && originalPath !== "/") { + if (originalPath && originalPath !== '/') { finalUrl += originalPath; } - + return finalUrl; } - } else if (error.response) { - console.log(`âš ī¸ ${url} returned status ${error.response.status}`); - } else if (error.request) { - console.log(`❌ ${url} failed to respond`); } else { - console.log(`❌ Error checking ${url}: ${error.message}`); + console.log(`âš ī¸ ${url} returned status ${response.status}`); + } + } catch (error) { + // Try GET request if HEAD fails (some servers don't properly support HEAD) + try { + const response = await axios.get(url, { + maxRedirects: 0, + timeout: 10000, + validateStatus: status => true + }); + + if (response.status === 200) { + console.log(`✅ ${url} is valid (200 OK)`); + return null; + } else if (response.status >= 300 && response.status < 400) { + // Handle redirects + const newLocation = response.headers.location; + if (newLocation) { + console.log(`🔄 ${url} redirects to ${newLocation}`); + + // Process redirect similar to above + let fullRedirectUrl = newLocation; + if (!newLocation.startsWith('http')) { + const baseUrl = new URL(url); + fullRedirectUrl = new URL(newLocation, baseUrl.origin).toString(); + } + + const newDomain = getDomain(fullRedirectUrl); + const originalPath = getPath(url); + + let finalUrl = newDomain; + if (originalPath && originalPath !== '/') { + finalUrl += originalPath; + } + + return finalUrl; + } + } else { + console.log(`âš ī¸ ${url} returned status ${response.status}`); + } + } catch (getError) { + if (getError.response) { + console.log(`âš ī¸ ${url} returned status ${getError.response.status}`); + } else if (getError.code === 'ECONNABORTED') { + console.log(`⌛ ${url} request timed out`); + } else if (getError.code === 'ENOTFOUND') { + console.log(`❌ ${url} domain not found`); + } else { + console.log(`❌ Error checking ${url}: ${getError.message}`); + } } } - + // Return null if no change or error return null; } // Main function async function main() { - const providers = await readModflixJson(); + const providers = readModflixJson(); let hasChanges = false; - + // Process each provider for (const [key, provider] of Object.entries(providers)) { const url = provider.url; console.log(`Checking ${provider.name} (${url})...`); - - const newUrl = await checkUrl(url); - if (newUrl && newUrl !== url) { - provider.url = newUrl; - hasChanges = true; - console.log(`Updated ${provider.name} URL to ${newUrl}`); + + try { + const newUrl = await checkUrl(url); + if (newUrl && newUrl !== url) { + provider.url = newUrl; + hasChanges = true; + console.log(`Updated ${provider.name} URL from ${url} to ${newUrl}`); + } + } catch (error) { + console.log(`❌ Error processing ${url}: ${error.message}`); } } - + // Write changes back to file if needed if (hasChanges) { fs.writeFileSync(FILE_PATH, JSON.stringify(providers, null, 2)); - console.log(`Updated ${FILE_PATH} with new URLs`); + console.log(`✅ Updated ${FILE_PATH} with new URLs`); } else { - console.log(`No changes needed for ${FILE_PATH}`); + console.log(`â„šī¸ No changes needed for ${FILE_PATH}`); } } -// Execute main function -main().catch((error) => { - console.error("Unhandled error:", error); +// Execute main function with error handling +main().catch(error => { + console.error('Unhandled error:', error); process.exit(1); });