mirror of
https://github.com/himanshu8443/providers.git
synced 2026-06-19 14:07:45 +00:00
Compare commits
25 Commits
1ad8250666
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 11b0fc424d | |||
| b5e0532875 | |||
| d2d835ed65 | |||
| d6d5e2e902 | |||
| 1e01c32f33 | |||
| e8870b383e | |||
| 6386c0b02f | |||
| 0b12d095a5 | |||
| dd4e468991 | |||
| 129f671ae2 | |||
| 53d12fe6a1 | |||
| 48f1e3472d | |||
| cb9cb22c70 | |||
| 38fd128eaa | |||
| bfe80ce95a | |||
| 55d79974db | |||
| 68dd646b90 | |||
| 1d39a56cc0 | |||
| 0081034e35 | |||
| a3be4c3f10 | |||
| 5bf0d4418e | |||
| 8c3b254d05 | |||
| bc7989ed11 | |||
| adcd64d8d7 | |||
| d5e64ad6a2 |
+219
-196
@@ -1,196 +1,219 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
|
|
||||||
const FILE_PATH = 'modflix.json';
|
const FILE_PATH = 'modflix.json';
|
||||||
const updatedProviders = []; // Track updated providers for Discord notification
|
const updatedProviders = []; // Track updated providers for Discord notification
|
||||||
|
|
||||||
// Read the modflix.json file
|
const DEFAULT_HEADERS = {
|
||||||
function readModflixJson() {
|
'User-Agent':
|
||||||
try {
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36',
|
||||||
const data = fs.readFileSync(FILE_PATH, 'utf8');
|
Accept:
|
||||||
return JSON.parse(data);
|
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
|
||||||
} catch (error) {
|
'Accept-Language': 'en-US,en;q=0.9',
|
||||||
console.error(`Error reading ${FILE_PATH}:`, error);
|
'Accept-Encoding': 'gzip, deflate, br',
|
||||||
process.exit(1);
|
Connection: 'keep-alive',
|
||||||
}
|
'Upgrade-Insecure-Requests': '1'
|
||||||
}
|
};
|
||||||
|
|
||||||
// Extract domain (origin) from URL without trailing slash
|
// Read the modflix.json file
|
||||||
function getDomain(url) {
|
function readModflixJson() {
|
||||||
try {
|
try {
|
||||||
const urlObj = new URL(url);
|
const data = fs.readFileSync(FILE_PATH, 'utf8');
|
||||||
return urlObj.origin;
|
return JSON.parse(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error parsing URL ${url}:`, error);
|
console.error(`Error reading ${FILE_PATH}:`, error);
|
||||||
return url;
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if original URL has a trailing slash in path
|
// Extract domain (origin) from URL without trailing slash
|
||||||
function hasTrailingSlash(url) {
|
function getDomain(url) {
|
||||||
return url.endsWith('/') && !url.endsWith('://');
|
try {
|
||||||
}
|
const urlObj = new URL(url);
|
||||||
|
return urlObj.origin;
|
||||||
// Check URL and return new URL if domain redirected
|
} catch (error) {
|
||||||
async function checkUrl(url) {
|
console.error(`Error parsing URL ${url}:`, error);
|
||||||
try {
|
return url;
|
||||||
// Set timeout to 10 seconds to avoid hanging
|
}
|
||||||
const response = await axios.head(url, {
|
}
|
||||||
maxRedirects: 0,
|
|
||||||
timeout: 10000,
|
// Check if original URL has a trailing slash in path
|
||||||
validateStatus: status => true
|
function hasTrailingSlash(url) {
|
||||||
});
|
return url.endsWith('/') && !url.endsWith('://');
|
||||||
|
}
|
||||||
// If status is 200, no change needed
|
|
||||||
if (response.status === 200) {
|
function getFinalUrl(response, originalUrl) {
|
||||||
console.log(`✅ ${url} is valid (200 OK)`);
|
return (
|
||||||
return null;
|
response?.request?.res?.responseUrl ||
|
||||||
} else if (response.status >= 300 && response.status < 400) {
|
response?.request?._redirectable?._currentUrl ||
|
||||||
// Handle redirects
|
response?.config?.url ||
|
||||||
const newLocation = response.headers.location;
|
originalUrl
|
||||||
if (newLocation) {
|
);
|
||||||
// If it's a relative redirect, construct the full URL
|
}
|
||||||
let fullRedirectUrl = newLocation;
|
|
||||||
if (!newLocation.startsWith('http')) {
|
function normalizeOrigin(url) {
|
||||||
const baseUrl = new URL(url);
|
try {
|
||||||
fullRedirectUrl = new URL(newLocation, baseUrl.origin).toString();
|
return new URL(url).origin;
|
||||||
}
|
} catch {
|
||||||
|
return url;
|
||||||
console.log(`🔄 ${url} redirects to ${fullRedirectUrl}`);
|
}
|
||||||
|
}
|
||||||
// Get the new domain
|
|
||||||
const newDomain = getDomain(fullRedirectUrl);
|
async function requestUrl(method, url) {
|
||||||
|
return axios({
|
||||||
// Check if original URL had a trailing slash
|
method,
|
||||||
const needsTrailingSlash = hasTrailingSlash(url);
|
url,
|
||||||
|
maxRedirects: 5,
|
||||||
// Create new URL: new domain + trailing slash if the original had one
|
timeout: 10000,
|
||||||
let finalUrl = newDomain;
|
validateStatus: status => true,
|
||||||
if (needsTrailingSlash) {
|
headers: DEFAULT_HEADERS
|
||||||
finalUrl += '/';
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Will update to: ${finalUrl} (preserved trailing slash: ${needsTrailingSlash})`);
|
function logVerboseResult(url, response, finalUrl) {
|
||||||
return finalUrl;
|
const status = response?.status ?? 'unknown';
|
||||||
}
|
const locationHeader = response?.headers?.location;
|
||||||
} else {
|
console.log(
|
||||||
console.log(`⚠️ ${url} returned status ${response.status}`);
|
`ℹ️ ${url} -> status=${status} final=${finalUrl}` +
|
||||||
}
|
(locationHeader ? ` location=${locationHeader}` : '')
|
||||||
} catch (error) {
|
);
|
||||||
// Try GET request if HEAD fails
|
}
|
||||||
try {
|
|
||||||
const response = await axios.get(url, {
|
function shouldUpdateFromFinalUrl(originalUrl, finalUrl) {
|
||||||
maxRedirects: 0,
|
const originalDomain = getDomain(originalUrl);
|
||||||
timeout: 10000,
|
const finalDomain = getDomain(finalUrl);
|
||||||
validateStatus: status => true
|
return finalDomain && finalDomain !== originalDomain;
|
||||||
});
|
}
|
||||||
|
|
||||||
if (response.status === 200) {
|
// Check URL and return new URL if domain redirected or resolved elsewhere
|
||||||
console.log(`✅ ${url} is valid (200 OK)`);
|
async function checkUrl(url) {
|
||||||
return null;
|
try {
|
||||||
} else if (response.status >= 300 && response.status < 400) {
|
const response = await requestUrl('get', url);
|
||||||
// Handle redirects
|
const finalUrl = getFinalUrl(response, url);
|
||||||
const newLocation = response.headers.location;
|
logVerboseResult(url, response, finalUrl);
|
||||||
if (newLocation) {
|
|
||||||
console.log(`🔄 ${url} redirects to ${newLocation}`);
|
if (shouldUpdateFromFinalUrl(url, finalUrl)) {
|
||||||
|
const updatedUrl = normalizeOrigin(finalUrl) + (hasTrailingSlash(url) ? '/' : '');
|
||||||
let fullRedirectUrl = newLocation;
|
console.log(`🔄 ${url} resolved to ${finalUrl}`);
|
||||||
if (!newLocation.startsWith('http')) {
|
console.log(`Will update to: ${updatedUrl} (preserved trailing slash: ${hasTrailingSlash(url)})`);
|
||||||
const baseUrl = new URL(url);
|
return updatedUrl;
|
||||||
fullRedirectUrl = new URL(newLocation, baseUrl.origin).toString();
|
}
|
||||||
}
|
|
||||||
|
if (response.status === 200) {
|
||||||
// Get the new domain
|
console.log(`✅ ${url} is valid (200 OK)`);
|
||||||
const newDomain = getDomain(fullRedirectUrl);
|
return null;
|
||||||
|
}
|
||||||
// Check if original URL had a trailing slash
|
|
||||||
const needsTrailingSlash = hasTrailingSlash(url);
|
if (response.status >= 300 && response.status < 400) {
|
||||||
|
const newLocation = response.headers.location;
|
||||||
// Create new URL: new domain + trailing slash if the original had one
|
if (newLocation) {
|
||||||
let finalUrl = newDomain;
|
let fullRedirectUrl = newLocation;
|
||||||
if (needsTrailingSlash) {
|
if (!newLocation.startsWith('http')) {
|
||||||
finalUrl += '/';
|
const baseUrl = new URL(url);
|
||||||
}
|
fullRedirectUrl = new URL(newLocation, baseUrl.origin).toString();
|
||||||
|
}
|
||||||
console.log(`Will update to: ${finalUrl} (preserved trailing slash: ${needsTrailingSlash})`);
|
|
||||||
return finalUrl;
|
if (shouldUpdateFromFinalUrl(url, fullRedirectUrl)) {
|
||||||
}
|
const newDomain = normalizeOrigin(fullRedirectUrl);
|
||||||
} else {
|
const needsTrailingSlash = hasTrailingSlash(url);
|
||||||
console.log(`⚠️ ${url} returned status ${response.status}`);
|
const finalUrlForUpdate = newDomain + (needsTrailingSlash ? '/' : '');
|
||||||
}
|
console.log(`🔄 ${url} redirects to ${fullRedirectUrl}`);
|
||||||
} catch (getError) {
|
console.log(
|
||||||
if (getError.response) {
|
`Will update to: ${finalUrlForUpdate} (preserved trailing slash: ${needsTrailingSlash})`
|
||||||
console.log(`⚠️ ${url} returned status ${getError.response.status}`);
|
);
|
||||||
} else if (getError.code === 'ECONNABORTED') {
|
return finalUrlForUpdate;
|
||||||
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}`);
|
console.log(`⚠️ ${url} returned status ${response.status}`);
|
||||||
}
|
} catch (error) {
|
||||||
}
|
if (error.response) {
|
||||||
}
|
const finalUrl = getFinalUrl(error.response, url);
|
||||||
|
logVerboseResult(url, error.response, finalUrl);
|
||||||
// Return null if no change or error
|
|
||||||
return null;
|
// If the request resolves to a different origin even with a non-2xx status,
|
||||||
}
|
// use that as an update signal. This keeps existing behavior intact while
|
||||||
|
// allowing sites that block HEAD/GET with 403 but still resolve elsewhere.
|
||||||
// Main function
|
if (shouldUpdateFromFinalUrl(url, finalUrl)) {
|
||||||
async function main() {
|
const updatedUrl = normalizeOrigin(finalUrl) + (hasTrailingSlash(url) ? '/' : '');
|
||||||
const providers = readModflixJson();
|
console.log(`🔄 ${url} resolved to ${finalUrl}`);
|
||||||
let hasChanges = false;
|
console.log(
|
||||||
|
`Will update to: ${updatedUrl} (preserved trailing slash: ${hasTrailingSlash(url)})`
|
||||||
// Process each provider
|
);
|
||||||
for (const [key, provider] of Object.entries(providers)) {
|
return updatedUrl;
|
||||||
const url = provider.url;
|
}
|
||||||
console.log(`Checking ${provider.name} (${url})...`);
|
|
||||||
|
console.log(`⚠️ ${url} returned status ${error.response.status}`);
|
||||||
try {
|
} else if (error.code === 'ECONNABORTED') {
|
||||||
const newUrl = await checkUrl(url);
|
console.log(`⌛ ${url} request timed out`);
|
||||||
if (newUrl && newUrl !== url) {
|
} else if (error.code === 'ENOTFOUND') {
|
||||||
// Store the old URL before updating
|
console.log(`❌ ${url} domain not found`);
|
||||||
const oldUrl = provider.url;
|
} else {
|
||||||
|
console.log(`❌ Error checking ${url}: ${error.message}`);
|
||||||
// Update the provider URL
|
}
|
||||||
provider.url = newUrl;
|
}
|
||||||
hasChanges = true;
|
|
||||||
console.log(`Updated ${provider.name} URL from ${oldUrl} to ${newUrl}`);
|
// Return null if no change or error
|
||||||
|
return null;
|
||||||
// Track updated provider for Discord notification
|
}
|
||||||
updatedProviders.push({
|
|
||||||
name: provider.name,
|
// Main function
|
||||||
oldUrl: oldUrl,
|
async function main() {
|
||||||
newUrl: newUrl
|
const providers = readModflixJson();
|
||||||
});
|
let hasChanges = false;
|
||||||
}
|
|
||||||
} catch (error) {
|
// Process each provider
|
||||||
console.log(`❌ Error processing ${url}: ${error.message}`);
|
for (const [key, provider] of Object.entries(providers)) {
|
||||||
}
|
const url = provider.url;
|
||||||
}
|
console.log(`Checking ${provider.name} (${url})...`);
|
||||||
|
|
||||||
// Write changes back to file if needed
|
try {
|
||||||
if (hasChanges) {
|
const newUrl = await checkUrl(url);
|
||||||
// Use a space-efficient JSON format but with proper formatting
|
if (newUrl && newUrl !== url) {
|
||||||
const jsonString = JSON.stringify(providers, null, 2);
|
// Store the old URL before updating
|
||||||
fs.writeFileSync(FILE_PATH, jsonString);
|
const oldUrl = provider.url;
|
||||||
console.log(`✅ Updated ${FILE_PATH} with new URLs`);
|
|
||||||
|
// Update the provider URL
|
||||||
// Output updated providers for Discord notification in a clean format
|
provider.url = newUrl;
|
||||||
if (updatedProviders.length > 0) {
|
hasChanges = true;
|
||||||
console.log("\n### UPDATED_PROVIDERS_START ###");
|
console.log(`Updated ${provider.name} URL from ${oldUrl} to ${newUrl}`);
|
||||||
for (const provider of updatedProviders) {
|
|
||||||
// Format: name|oldUrl|newUrl (pipe-delimited for easy parsing)
|
// Track updated provider for Discord notification
|
||||||
console.log(`${provider.name}|${provider.oldUrl}|${provider.newUrl}`);
|
updatedProviders.push({
|
||||||
}
|
name: provider.name,
|
||||||
console.log("### UPDATED_PROVIDERS_END ###");
|
oldUrl: oldUrl,
|
||||||
}
|
newUrl: newUrl
|
||||||
} else {
|
});
|
||||||
console.log(`ℹ️ No changes needed for ${FILE_PATH}`);
|
}
|
||||||
}
|
} catch (error) {
|
||||||
}
|
console.log(`❌ Error processing ${url}: ${error.message}`);
|
||||||
|
}
|
||||||
// Execute main function with error handling
|
}
|
||||||
main().catch(error => {
|
|
||||||
console.error('Unhandled error:', error);
|
// Write changes back to file if needed
|
||||||
process.exit(1);
|
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);
|
||||||
|
});
|
||||||
|
|||||||
@@ -27,20 +27,26 @@ jobs:
|
|||||||
|
|
||||||
- name: Run URL checker
|
- name: Run URL checker
|
||||||
id: url_checker
|
id: url_checker
|
||||||
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
# Run the URL checker and save output
|
set -o pipefail
|
||||||
node .github/scripts/url-checker.js > checker_output.log 2>&1
|
# Run the URL checker and show output in the job logs while also saving it
|
||||||
|
node .github/scripts/url-checker.js 2>&1 | tee checker_output.log
|
||||||
|
|
||||||
# Check if there are updated providers
|
# Check if there are updated providers
|
||||||
if grep -q "### UPDATED_PROVIDERS_START ###" checker_output.log; then
|
if grep -q "### UPDATED_PROVIDERS_START ###" checker_output.log; then
|
||||||
echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
|
echo "CHANGES_DETECTED=true" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
# Extract only the updated provider lines between the markers
|
# Extract only the updated provider lines between the markers
|
||||||
sed -n '/### UPDATED_PROVIDERS_START ###/,/### UPDATED_PROVIDERS_END ###/p' checker_output.log |
|
sed -n '/### UPDATED_PROVIDERS_START ###/,/### UPDATED_PROVIDERS_END ###/p' checker_output.log | \
|
||||||
grep -v "###" > updated_providers.txt
|
grep -v "###" > updated_providers.txt
|
||||||
else
|
else
|
||||||
echo "CHANGES_DETECTED=false" >> $GITHUB_ENV
|
echo "CHANGES_DETECTED=false" >> "$GITHUB_ENV"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "--- checker_output.log ---"
|
||||||
|
cat checker_output.log
|
||||||
|
echo "--- end checker_output.log ---"
|
||||||
|
|
||||||
- name: Commit changes if any
|
- name: Commit changes if any
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
+15
-15
@@ -9,11 +9,11 @@
|
|||||||
},
|
},
|
||||||
"Topmovies": {
|
"Topmovies": {
|
||||||
"name": "Topmovies",
|
"name": "Topmovies",
|
||||||
"url": "https://moviesleech.link"
|
"url": "https://moviesleech.bar"
|
||||||
},
|
},
|
||||||
"UhdMovies": {
|
"UhdMovies": {
|
||||||
"name": "UhdMovies",
|
"name": "UhdMovies",
|
||||||
"url": "https://uhdmovies.pink"
|
"url": "https://uhdmovies.food"
|
||||||
},
|
},
|
||||||
"filepress": {
|
"filepress": {
|
||||||
"name": "filepress",
|
"name": "filepress",
|
||||||
@@ -21,23 +21,23 @@
|
|||||||
},
|
},
|
||||||
"Vega": {
|
"Vega": {
|
||||||
"name": "vegamovies",
|
"name": "vegamovies",
|
||||||
"url": "https://vegamovies.vodka"
|
"url": "https://vegamovies.mq"
|
||||||
},
|
},
|
||||||
"lux": {
|
"lux": {
|
||||||
"name": "luxmovies",
|
"name": "luxmovies",
|
||||||
"url": "https://rogmovies.vip"
|
"url": "https://rogmovies.work"
|
||||||
},
|
},
|
||||||
"drive": {
|
"drive": {
|
||||||
"name": "moviesDrive",
|
"name": "moviesDrive",
|
||||||
"url": "https://new2.moviesdrives.my/"
|
"url": "https://new3.moviesdrives.my/"
|
||||||
},
|
},
|
||||||
"multi": {
|
"multi": {
|
||||||
"name": "multimovies",
|
"name": "multimovies",
|
||||||
"url": "https://multimovies.autos"
|
"url": "https://multimovies.fyi"
|
||||||
},
|
},
|
||||||
"w4u": {
|
"w4u": {
|
||||||
"name": "world4ufree",
|
"name": "world4ufree",
|
||||||
"url": "https://world4ufree.tw"
|
"url": "https://world4ufree.cl"
|
||||||
},
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
"name": "extraMovies",
|
"name": "extraMovies",
|
||||||
@@ -45,11 +45,11 @@
|
|||||||
},
|
},
|
||||||
"hdhub": {
|
"hdhub": {
|
||||||
"name": "hdhub4u",
|
"name": "hdhub4u",
|
||||||
"url": "https://new4.hdhub4u.fo"
|
"url": "https://new1.hdhub4u.cl"
|
||||||
},
|
},
|
||||||
"kat": {
|
"kat": {
|
||||||
"name": "katmovieshd",
|
"name": "katmovieshd",
|
||||||
"url": "https://katmoviehd.pictures"
|
"url": "https://new1.katmoviehd.cymru"
|
||||||
},
|
},
|
||||||
"dc": {
|
"dc": {
|
||||||
"name": "dramacool",
|
"name": "dramacool",
|
||||||
@@ -141,11 +141,11 @@
|
|||||||
},
|
},
|
||||||
"4khdhub": {
|
"4khdhub": {
|
||||||
"name": "4khdhub",
|
"name": "4khdhub",
|
||||||
"url": "https://4khdhub.dad"
|
"url": "https://4khdhub.one"
|
||||||
},
|
},
|
||||||
"moviezwap": {
|
"moviezwap": {
|
||||||
"name": "moviezwap",
|
"name": "moviezwap",
|
||||||
"url": "https://www.moviezwap.date/"
|
"url": "https://www.moviezwap.onl/"
|
||||||
},
|
},
|
||||||
"9xflix": {
|
"9xflix": {
|
||||||
"name": "9xflix",
|
"name": "9xflix",
|
||||||
@@ -173,7 +173,7 @@
|
|||||||
},
|
},
|
||||||
"movies4u": {
|
"movies4u": {
|
||||||
"name": "movies4u",
|
"name": "movies4u",
|
||||||
"url": "https://movies4u.tl"
|
"url": "https://movies4u.as"
|
||||||
},
|
},
|
||||||
"joya9tv": {
|
"joya9tv": {
|
||||||
"name": "joya9tv1",
|
"name": "joya9tv1",
|
||||||
@@ -181,10 +181,10 @@
|
|||||||
},
|
},
|
||||||
"skymovieshd": {
|
"skymovieshd": {
|
||||||
"name": "skyMovesHd",
|
"name": "skyMovesHd",
|
||||||
"url": "https://skymovieshd.fast"
|
"url": "https://skymovieshd.spot"
|
||||||
},
|
},
|
||||||
"1cinevood": {
|
"1cinevood": {
|
||||||
"name": "cinewood",
|
"name": "cinewood",
|
||||||
"url": "https://proxy01.cvproxy.workers.dev"
|
"url": "https://1cinevood.in"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user