update web version to use new format

This commit is contained in:
fynks 2025-09-30 09:34:25 +05:00
parent 393a30bbd7
commit 19462698c9
5 changed files with 136 additions and 142 deletions

View file

@ -54,14 +54,16 @@ Debrid ("multi-hoster") services act as paid aggregation layers between you and
| 💡 Tip | Think of a debrid service as a “premium proxy” between you and file-hosting sites like Rapidgator, Mediafire, or Uptobox. |
| ------ | ---------------------------------------------------------------------------------------------- |
---
## Getting Started
<div align="center">
### Support This Project
> ✨ This guide is **free, open-source, and community-run**. If it helped: starring, reporting corrections, or using a referral link helps sustain maintenance (at no extra cost to you).
| Service | Referral | Direct Signup |
| :------ | :------- | :------------ |
| AllDebrid | [Referral](https://alldebrid.com/?uid=3wvya&lang=en) | [Signup](https://alldebrid.com/register/) |
@ -75,6 +77,8 @@ Debrid ("multi-hoster") services act as paid aggregation layers between you and
| Offcloud | [Referral](https://offcloud.com/?=c44b1fa5) | [Signup](https://offcloud.com/register) |
| High-Way | | [Signup](https://high-way.me/login/login) |
</div>
> [!NOTE]
> No financial ties to services. Referrals offset hosting & data validation costs only.

109
dist/index.html vendored
View file

@ -240,10 +240,111 @@
<div class="pricing-container">
<div id="pricing-table-container" class="data-table-container" role="region"
aria-live="polite" aria-label="Pricing table">
<div class="loading-state" aria-busy="true">
<div class="loading-spinner" aria-hidden="true"></div>
<p>Loading pricing data...</p>
</div>
<table class="data-table pricing-table" aria-label="Pricing comparison table">
<thead>
<tr>
<th scope="col">Plan</th>
<th scope="col">AllDebrid</th>
<th scope="col">Premiumize</th>
<th scope="col">Real-Debrid</th>
<th scope="col">TorBox</th>
<th scope="col">Debrid-Link</th>
<th scope="col">LinkSnappy</th>
<th scope="col">Mega-Debrid</th>
<th scope="col">Deepbrid</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Free/Trial</th>
<td>7 days*</td>
<td>-</td>
<td>-</td>
<td>$0/month</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>Limited Hosts</td>
</tr>
<tr>
<th scope="row">7 Days</th>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>$4.99 USD</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<th scope="row">15 Days</th>
<td>€2.99</td>
<td>-</td>
<td>€3</td>
<td>-</td>
<td>€3</td>
<td>-</td>
<td>-</td>
<td>€4.50</td>
</tr>
<tr>
<th scope="row">30 Days</th>
<td>€2.99/mo (Recur) / €3.99 (One-time)</td>
<td>€11.99</td>
<td>€4</td>
<td>Starts from $3.0</td>
<td>€4</td>
<td>$12.99 USD</td>
<td>€4</td>
<td>€4.99</td>
</tr>
<tr>
<th scope="row">90 Days</th>
<td>€8.99(One-time)</td>
<td>$29.99</td>
<td>€9</td>
<td>-</td>
<td>€9</td>
<td>$29.99 USD</td>
<td>€9</td>
<td>€12.99</td>
</tr>
<tr>
<th scope="row">180 Days</th>
<td>€15.99(One-time)</td>
<td>-</td>
<td>€16</td>
<td>-</td>
<td>€16</td>
<td>$54.99</td>
<td>€16</td>
<td>€19.99</td>
</tr>
<tr>
<th scope="row">300 Days</th>
<td>€24.99(One-time)</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>€25</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<th scope="row">365 Days</th>
<td>-</td>
<td>$79.99</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>€32.99</td>
</tr>
</tbody>
</table>
</div>
<div class="alert alert-info" role="alert">

159
dist/js/app.js vendored
View file

@ -1,7 +1,7 @@
/**
* Debrid Services Comparison - Improved App JS
* - Data loading (file hosts, adult hosts, pricing)
* - Tables, comparison, pricing interactions
* - Data loading (file hosts, adult hosts)
* - Tables, comparison interactions with / format
* - Age verification overlay (focus trap + inert)
* - Back-to-top, nav highlight, animations, offline detection
* - Performance-minded DOM updates and event delegation
@ -167,13 +167,22 @@ class TableManager {
// New method to transform indexed data to regular format
_transformIndexedData(indexedData) {
// Check if data is in the new direct format (host -> service -> ✅/❌)
const firstHost = Object.values(indexedData)[0];
if (firstHost && typeof firstHost === 'object' && !firstHost.hasOwnProperty('services') && !firstHost.hasOwnProperty('supported')) {
// Data is already in the new direct format
this.state.isIndexedFormat = false;
return indexedData;
}
// Handle indexed format
const { services, supported } = indexedData;
const transformed = {};
for (const [host, supportedIndices] of Object.entries(supported)) {
transformed[host] = {};
services.forEach((service, index) => {
transformed[host][service] = supportedIndices.includes(index) ? "yes" : "no";
transformed[host][service] = supportedIndices.includes(index) ? "✅" : "❌";
});
}
@ -272,7 +281,7 @@ class TableManager {
</div>
</td>
${columns.map(column => {
const isSupported = hostData[column] === "yes";
const isSupported = hostData[column] === "";
return `
<td class="status-cell" role="gridcell" data-status="${hostData[column]}">
<span class="status-indicator ${isSupported ? "supported" : "not-supported"}" aria-label="${isSupported ? "Supported" : "Not supported"}">
@ -399,9 +408,9 @@ class TableManager {
valueA = hostA.toLowerCase();
valueB = hostB.toLowerCase();
} else {
// Convert "yes"/"no" to numeric values for sorting
valueA = dataA[column] === "yes" ? 1 : 0;
valueB = dataB[column] === "yes" ? 1 : 0;
// Convert "✅"/"❌" to numeric values for sorting
valueA = dataA[column] === "" ? 1 : 0;
valueB = dataB[column] === "" ? 1 : 0;
}
let comparison = 0;
@ -496,11 +505,11 @@ class ComparisonManager {
const supportedIndices = this.data.supported[hostName] || [];
const hostData = {};
this.services.forEach((service, index) => {
hostData[service] = supportedIndices.includes(index) ? "yes" : "no";
hostData[service] = supportedIndices.includes(index) ? "✅" : "❌";
});
return hostData;
} else {
// Return data as-is for regular format
// Return data as-is for regular format (already using ✅/❌)
return this.data[hostName] || {};
}
}
@ -605,8 +614,8 @@ class ComparisonManager {
for (const host of hosts) {
const hostData = this._getHostData(host);
const supported1 = hostData[service1] === "yes";
const supported2 = hostData[service2] === "yes";
const supported1 = hostData[service1] === "";
const supported2 = hostData[service2] === "";
let statusClass = "neither-supported";
let statusText = "Neither";
@ -653,8 +662,8 @@ class ComparisonManager {
for (const host of hosts) {
const hostData = this._getHostData(host);
const supported1 = hostData[service1] === "yes";
const supported2 = hostData[service2] === "yes";
const supported1 = hostData[service1] === "";
const supported2 = hostData[service2] === "";
if (supported1 && supported2) {
shared++;
@ -739,120 +748,6 @@ class ComparisonManager {
this.elements.container.style.display = "block";
}
}
/* ==============================
Pricing Manager
============================== */
class PricingManager {
constructor(containerId) {
this.container = document.getElementById(`${containerId}-table-container`);
this.currentData = null;
this._onMouseOver = this._onMouseOver.bind(this);
this._onMouseOut = this._onMouseOut.bind(this);
this._onMouseLeaveContainer = this._onMouseLeaveContainer.bind(this);
}
generatePricingTable(data = {}) {
if (!this.container) return;
if (!data.plans?.length) {
this.container.innerHTML = '<div class="error-state"><p>Error: Invalid pricing data structure.</p></div>';
return;
}
this.currentData = data;
const services = Object.keys(data.plans[0]).filter(key => key !== 'name');
const fragment = document.createDocumentFragment();
const wrapper = document.createElement('div');
wrapper.className = 'table-wrapper';
const table = document.createElement('table');
table.id = 'pricing-table';
table.className = 'pricing-table';
table.setAttribute('aria-label', 'Service Pricing Table');
const thead = document.createElement('thead');
thead.innerHTML = `
<tr>
<th>Plans</th>
${services.map(service => `
<th class="service-column">
<div class="service-header">
<span class="service-name">${service}</span>
</div>
</th>
`).join('')}
</tr>
`;
const tbody = document.createElement('tbody');
tbody.innerHTML = data.plans.map((plan, index) => `
<tr class="pricing-row ${index % 2 === 0 ? 'even' : 'odd'}">
<td class="plan-name"><strong>${plan.name}</strong></td>
${services.map(service => {
const price = plan[service];
const isNumeric = !isNaN(parseFloat(price));
return `
<td class="price-cell ${isNumeric ? 'numeric-price' : 'text-price'}">
<div class="price-content">
<span class="price-value">${price}</span>
${isNumeric ? '<span class="price-period">/month</span>' : ''}
</div>
</td>
`;
}).join('')}
</tr>
`).join('');
table.appendChild(thead);
table.appendChild(tbody);
wrapper.appendChild(table);
fragment.appendChild(wrapper);
this.container.innerHTML = '';
this.container.appendChild(fragment);
this._setupPricingFeatures();
}
_setupPricingFeatures() {
// Use mouseover/mouseout for delegation; mouseenter doesn't bubble
this.container.addEventListener('mouseover', this._onMouseOver);
this.container.addEventListener('mouseout', this._onMouseOut);
this.container.addEventListener('mouseleave', this._onMouseLeaveContainer);
}
_onMouseOver(e) {
const cell = e.target.closest('.price-cell');
if (!cell || !this.container.contains(cell)) return;
const index = Array.from(cell.parentNode.children).indexOf(cell);
if (index >= 0) this._highlightColumn(index + 1); // nth-child is 1-based
}
_onMouseOut(e) {
const toElement = e.relatedTarget;
if (!toElement || !this.container.contains(toElement)) {
this._removeColumnHighlight();
}
}
_onMouseLeaveContainer() {
this._removeColumnHighlight();
}
_highlightColumn(columnIndex) {
const table = this.container.querySelector('table');
if (!table) return;
// Plans column is 1; services start at 2; columnIndex is the index within row (including plan col)
const cells = table.querySelectorAll(`tbody td:nth-child(${columnIndex + 1}), thead th:nth-child(${columnIndex + 1})`);
this._removeColumnHighlight();
cells.forEach(cell => cell.classList.add('highlighted'));
}
_removeColumnHighlight() {
this.container.querySelectorAll('.highlighted').forEach(cell => cell.classList.remove('highlighted'));
}
}
/* ==============================
Performance Monitor (light)
============================== */
@ -1075,12 +970,10 @@ document.addEventListener('DOMContentLoaded', async () => {
try {
const fileHostsTable = new TableManager('file-hosts-table-container', 'host-search-input', 'clear-host-search');
const adultHostsTable = new TableManager('adult-hosts-table-container', 'adult-host-search-input', 'clear-adult-host-search');
const pricingManager = new PricingManager('pricing');
const loaders = [
loadingManager.show('#file-hosts-table-container', 'Loading file hosts...'),
loadingManager.show('#adult-hosts-table-container', 'Loading adult hosts...'),
loadingManager.show('#pricing-table-container', 'Loading pricing data...')
loadingManager.show('#adult-hosts-table-container', 'Loading adult hosts...')
];
// Helper: fetch with timeout and graceful fallbacks
@ -1117,7 +1010,7 @@ document.addEventListener('DOMContentLoaded', async () => {
const results = await Promise.allSettled(fetchPromises);
results.forEach((result, index) => {
const containers = ['#file-hosts-table-container', '#adult-hosts-table-container', '#pricing-table-container'];
const containers = ['#file-hosts-table-container', '#adult-hosts-table-container'];
loadingManager.hide(containers[index], loaders[index]);
if (result.status === 'fulfilled') {
@ -1131,10 +1024,6 @@ document.addEventListener('DOMContentLoaded', async () => {
adultHostsTable.generateTable(result.value);
break;
}
case 2: {
pricingManager.generatePricingTable(result.value);
break;
}
}
} else {
console.error('Error loading data set:', result.reason);

View file

@ -1 +1 @@
{"Beeg":{"AllDebrid":"yes","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"no"},"Coomer":{"AllDebrid":"no","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"no"},"Drtuber":{"AllDebrid":"yes","TorBox":"yes","Premiumize":"yes","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"no"},"Eporner":{"AllDebrid":"no","TorBox":"no","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"yes"},"Hanime":{"AllDebrid":"no","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"no"},"Hentai foundry":{"AllDebrid":"no","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"no"},"Kemono":{"AllDebrid":"no","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"no"},"Nhentai":{"AllDebrid":"no","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"no"},"Pornhub":{"AllDebrid":"yes","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"yes"},"Redgifs":{"AllDebrid":"no","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"no"},"Redtube":{"AllDebrid":"yes","TorBox":"yes","Premiumize":"no","RealDebrid":"yes","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"yes","High-Way":"no","Offcloud":"yes"},"Rule34":{"AllDebrid":"no","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"no"},"Spankbang":{"AllDebrid":"yes","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"yes"},"Stripchat":{"AllDebrid":"no","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"no"},"Sunporno":{"AllDebrid":"no","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"yes","Deepbrid":"no","High-Way":"no","Offcloud":"no"},"Xhamster":{"AllDebrid":"yes","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"yes"},"Xnxx":{"AllDebrid":"yes","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"no"},"Xvideos":{"AllDebrid":"yes","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"yes"},"Xxxymovies":{"AllDebrid":"yes","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"no"},"Youjizz":{"AllDebrid":"yes","TorBox":"yes","Premiumize":"no","RealDebrid":"no","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"yes"},"Youporn":{"AllDebrid":"no","TorBox":"yes","Premiumize":"no","RealDebrid":"yes","Debrid-Link":"no","LinkSnappy":"no","Mega-Debrid":"no","Deepbrid":"no","High-Way":"no","Offcloud":"yes"}}
{"Beeg":{"AllDebrid":"✅","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"❌"},"Coomer":{"AllDebrid":"❌","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"❌"},"Drtuber":{"AllDebrid":"✅","TorBox":"✅","Premiumize":"✅","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"❌"},"Eporner":{"AllDebrid":"❌","TorBox":"❌","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"✅"},"Hanime":{"AllDebrid":"❌","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"❌"},"Hentai foundry":{"AllDebrid":"❌","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"❌"},"Kemono":{"AllDebrid":"❌","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"❌"},"Nhentai":{"AllDebrid":"❌","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"❌"},"Pornhub":{"AllDebrid":"✅","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"✅"},"Redgifs":{"AllDebrid":"❌","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"❌"},"Redtube":{"AllDebrid":"✅","TorBox":"✅","Premiumize":"❌","Real-Debrid":"✅","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"✅","High-Way":"❌","Offcloud":"✅"},"Rule34":{"AllDebrid":"❌","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"❌"},"Spankbang":{"AllDebrid":"✅","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"✅"},"Stripchat":{"AllDebrid":"❌","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"❌"},"Sunporno":{"AllDebrid":"❌","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"✅","Deepbrid":"❌","High-Way":"❌","Offcloud":"❌"},"Xhamster":{"AllDebrid":"✅","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"✅"},"Xnxx":{"AllDebrid":"✅","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"❌"},"Xvideos":{"AllDebrid":"✅","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"✅"},"Xxxymovies":{"AllDebrid":"✅","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"❌"},"Youjizz":{"AllDebrid":"✅","TorBox":"✅","Premiumize":"❌","Real-Debrid":"❌","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"✅"},"Youporn":{"AllDebrid":"❌","TorBox":"✅","Premiumize":"❌","Real-Debrid":"✅","Debrid-Link":"❌","LinkSnappy":"❌","Mega-Debrid":"❌","Deepbrid":"❌","High-Way":"❌","Offcloud":"✅"}}

File diff suppressed because one or more lines are too long