Files
providers/.github/scripts/url-checker.js
T

192 lines
5.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const fs = require('fs');
const axios = require('axios');
const FILE_PATH = 'modflix.json';
const updatedProviders = []; // Track updated providers for Discord notification
const DEFAULT_HEADERS = {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36',
Accept:
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
Connection: 'keep-alive',
'Upgrade-Insecure-Requests': '1'
};
// Read the modflix.json file
function readModflixJson() {
try {
const data = fs.readFileSync(FILE_PATH, 'utf8');
return JSON.parse(data);
} catch (error) {
console.error(`Error reading ${FILE_PATH}:`, error);
process.exit(1);
}
}
// Extract domain (origin) from URL without trailing slash
function getDomain(url) {
try {
const urlObj = new URL(url);
return urlObj.origin;
} catch (error) {
console.error(`Error parsing URL ${url}:`, error);
return url;
}
}
// Check if original URL has a trailing slash in path
function hasTrailingSlash(url) {
return url.endsWith('/') && !url.endsWith('://');
}
function getFinalUrl(response, originalUrl) {
return (
response?.request?.res?.responseUrl ||
response?.request?._redirectable?._currentUrl ||
response?.config?.url ||
originalUrl
);
}
async function requestUrl(method, url) {
return axios({
method,
url,
maxRedirects: 5,
timeout: 10000,
validateStatus: status => true,
headers: DEFAULT_HEADERS
});
}
// Check URL and return new URL if domain redirected
async function checkUrl(url) {
try {
const response = await requestUrl('get', url);
const finalUrl = getFinalUrl(response, url);
if (response.status === 200) {
const originalDomain = getDomain(url);
const finalDomain = getDomain(finalUrl);
if (finalDomain !== originalDomain) {
console.log(`🔄 ${url} resolved to ${finalUrl}`);
const needsTrailingSlash = hasTrailingSlash(url);
let updatedUrl = finalDomain;
if (needsTrailingSlash) {
updatedUrl += '/';
}
console.log(
`Will update to: ${updatedUrl} (preserved trailing slash: ${needsTrailingSlash})`
);
return updatedUrl;
}
console.log(`${url} is valid (200 OK)`);
return null;
}
if (response.status >= 300 && response.status < 400) {
const newLocation = response.headers.location;
if (newLocation) {
let fullRedirectUrl = newLocation;
if (!newLocation.startsWith('http')) {
const baseUrl = new URL(url);
fullRedirectUrl = new URL(newLocation, baseUrl.origin).toString();
}
console.log(`🔄 ${url} redirects to ${fullRedirectUrl}`);
const newDomain = getDomain(fullRedirectUrl);
const needsTrailingSlash = hasTrailingSlash(url);
let finalUrlForUpdate = newDomain;
if (needsTrailingSlash) {
finalUrlForUpdate += '/';
}
console.log(
`Will update to: ${finalUrlForUpdate} (preserved trailing slash: ${needsTrailingSlash})`
);
return finalUrlForUpdate;
}
}
console.log(`⚠️ ${url} returned status ${response.status}`);
} catch (error) {
if (error.response) {
console.log(`⚠️ ${url} returned status ${error.response.status}`);
} else if (error.code === 'ECONNABORTED') {
console.log(`${url} request timed out`);
} else if (error.code === 'ENOTFOUND') {
console.log(`${url} domain not found`);
} else {
console.log(`❌ Error checking ${url}: ${error.message}`);
}
}
// Return null if no change or error
return null;
}
// Main function
async function main() {
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})...`);
try {
const newUrl = await checkUrl(url);
if (newUrl && newUrl !== url) {
// Store the old URL before updating
const oldUrl = provider.url;
// Update the provider URL
provider.url = newUrl;
hasChanges = true;
console.log(`Updated ${provider.name} URL from ${oldUrl} to ${newUrl}`);
// Track updated provider for Discord notification
updatedProviders.push({
name: provider.name,
oldUrl: oldUrl,
newUrl: newUrl
});
}
} catch (error) {
console.log(`❌ Error processing ${url}: ${error.message}`);
}
}
// Write changes back to file if needed
if (hasChanges) {
// Use a space-efficient JSON format but with proper formatting
const jsonString = JSON.stringify(providers, null, 2);
fs.writeFileSync(FILE_PATH, jsonString);
console.log(`✅ Updated ${FILE_PATH} with new URLs`);
// Output updated providers for Discord notification in a clean format
if (updatedProviders.length > 0) {
console.log("\n### UPDATED_PROVIDERS_START ###");
for (const provider of updatedProviders) {
// Format: name|oldUrl|newUrl (pipe-delimited for easy parsing)
console.log(`${provider.name}|${provider.oldUrl}|${provider.newUrl}`);
}
console.log("### UPDATED_PROVIDERS_END ###");
}
} else {
console.log(`️ No changes needed for ${FILE_PATH}`);
}
}
// Execute main function with error handling
main().catch(error => {
console.error('Unhandled error:', error);
process.exit(1);
});