revert to old web version
|
|
@ -1,9 +1,3 @@
|
|||
---
|
||||
layout: home
|
||||
title: Adult Hosts
|
||||
titleTemplate: Debrid Compare
|
||||
description: "Detailed adult hoster support comparison for leading debrid/multi-hoster services."
|
||||
---
|
||||
|
||||
### Adult Hosts
|
||||
|
||||
38
README.md
|
|
@ -1,6 +1,6 @@
|
|||
<div align="center">
|
||||
<h1>
|
||||
<img src="./docs/public/favicon.svg" alt="Logo" style="height:1em; width:1em; vertical-align:middle"> Debrid Services Comparison
|
||||
<img src="./dist/favicon.svg" alt="Logo" style="height:1em; width:1em; vertical-align:middle"> Debrid Services Comparison
|
||||
</h1>
|
||||
|
||||
<p><strong>Community‑maintained, up-to-date comparison</strong> of leading debrid / multi-hoster services for pricing, host coverage, policies & tools etc.</p>
|
||||
|
|
@ -13,9 +13,9 @@
|
|||
|
||||
<p><a href="https://debrid-services-comparison.netlify.app/"><em>▶ Open the interactive version (search • filter • compare)</em></a></p>
|
||||
|
||||
<a href="https://debrid-services-comparison.netlify.app/"><img src="./docs/public/images/og.png" alt="Screenshot of interactive comparison web app" width="880" loading="lazy"></a>
|
||||
<a href="https://debrid-services-comparison.netlify.app/"><img src="./dist/image.png" alt="Screenshot of interactive comparison web app" width="880" loading="lazy"></a>
|
||||
|
||||
<p><strong>Quick Jump:</strong> <a href="#pricing-comparison">Pricing</a> · <a href="#available-hosts">Hosts</a> · <a href="#policies-and-legal">Policies</a> · <a href="#tools-and-community">Tools</a></p>
|
||||
<p><a href="#pricing-comparison">Pricing</a> · <a href="#available-hosts">Hosts</a> · <a href="#policies-and-legal">Policies</a> · <a href="#tools-and-community">Tools</a></p>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
|
@ -58,8 +58,6 @@ Debrid ("multi-hoster") services act as paid aggregation layers between you and
|
|||
|
||||
## Getting Started
|
||||
|
||||
<div class="support">
|
||||
|
||||
### 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).
|
||||
|
|
@ -84,9 +82,7 @@ Debrid ("multi-hoster") services act as paid aggregation layers between you and
|
|||
|
||||
[(↑ Back to Top)](#table-of-contents)
|
||||
|
||||
</div></div>
|
||||
|
||||
<div class="pricing">
|
||||
</div>
|
||||
|
||||
## Pricing Comparison
|
||||
|
||||
|
|
@ -141,9 +137,7 @@ Debrid ("multi-hoster") services act as paid aggregation layers between you and
|
|||
|
||||
[(↑ Back to Top)](#table-of-contents)
|
||||
|
||||
</div></div>
|
||||
|
||||
<div class="hosts">
|
||||
</div>
|
||||
|
||||
## Available Hosts
|
||||
|
||||
|
|
@ -151,7 +145,7 @@ Debrid ("multi-hoster") services act as paid aggregation layers between you and
|
|||
|
||||
<br />
|
||||
|
||||
<div align="center" class="web-app-note">
|
||||
<div align="center">
|
||||
|
||||
| ⚡ For faster exploration (search + filter + side-by-side), use the <a href="https://debridcompare.pages.dev" target="_blank" rel="noopener">interactive web app</a>. |
|
||||
|------------------------------------------|
|
||||
|
|
@ -464,7 +458,7 @@ Debrid ("multi-hoster") services act as paid aggregation layers between you and
|
|||
|
||||
> Support varies. Some services exclude adult content for legal/policy reasons.
|
||||
|
||||
👉 [See Detailed Adult Host Support](./docs/Adult-hosts.md)
|
||||
👉 [See Detailed Adult Host Support](./Adult-hosts.md)
|
||||
|
||||
### Live Status
|
||||
|
||||
|
|
@ -493,9 +487,7 @@ Service availability and host support can change in real time. Use these officia
|
|||
|
||||
[(↑ Back to Top)](#table-of-contents)
|
||||
|
||||
</div></div>
|
||||
|
||||
<div class="policies">
|
||||
</div>
|
||||
|
||||
## Policies and Legal
|
||||
|
||||
|
|
@ -520,9 +512,7 @@ Service availability and host support can change in real time. Use these officia
|
|||
|
||||
[(↑ Back to Top)](#table-of-contents)
|
||||
|
||||
</div></div>
|
||||
|
||||
<div class="speedtest">
|
||||
</div>
|
||||
|
||||
## Speed Test
|
||||
|
||||
|
|
@ -571,7 +561,7 @@ For a more accurate assessment, follow these steps:
|
|||
|
||||
[(↑ Back to Top)](#table-of-contents)
|
||||
|
||||
</div></div>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -597,8 +587,6 @@ This project aims to provide accurate and up-to-date information, but the debrid
|
|||
|
||||
---
|
||||
|
||||
<div class="tools">
|
||||
|
||||
## Tools and Community
|
||||
|
||||
Enhance your debrid experience with these trusted tools, guides, and communities:
|
||||
|
|
@ -622,7 +610,7 @@ Enhance your debrid experience with these trusted tools, guides, and communities
|
|||
|
||||
[(↑ Back to Top)](#table-of-contents)
|
||||
|
||||
</div></div>
|
||||
</div>
|
||||
|
||||
## Contributing
|
||||
Help keep this guide accurate! We welcome:
|
||||
|
|
@ -632,10 +620,10 @@ Help keep this guide accurate! We welcome:
|
|||
- ✅ Policy clarifications
|
||||
- ✅ UX/UI suggestions
|
||||
|
||||
**[See Contribution Guidelines →](./CONTRIBUTING.md)**
|
||||
|
||||
> 🛡️ All PRs are verified against official sources before merging.
|
||||
|
||||
**[See Contribution Guidelines →](./CONTRIBUTING.md)**
|
||||
|
||||
<div align="right">
|
||||
|
||||
[(↑ Back to Top)](#table-of-contents)
|
||||
|
|
|
|||
0
docs/_redirects → dist/_redirects
vendored
3438
dist/css/styles.css
vendored
Normal file
0
docs/public/favicon.ico → dist/favicon.ico
vendored
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
0
docs/public/favicon.svg → dist/favicon.svg
vendored
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
0
docs/public/images/og.png → dist/image.png
vendored
|
Before Width: | Height: | Size: 321 KiB After Width: | Height: | Size: 321 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 410 B After Width: | Height: | Size: 410 B |
|
Before Width: | Height: | Size: 924 B After Width: | Height: | Size: 924 B |
1353
dist/index.html
vendored
Normal file
1
dist/json/adult-hosts.json
vendored
Normal file
|
|
@ -0,0 +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"}}
|
||||
1
dist/json/file-hosts.json
vendored
Normal file
1
dist/json/pricing.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"plans":[{"name":"Free/Trial","AllDebrid":"7 days*","Premiumize":"-","Real-Debrid":"-","TorBox":"$0/month","Debrid-Link":"-","Linksnappy":"-","Mega-Debrid":"-","Deepbrid":"Limited Hosts"},{"name":"7 Days","AllDebrid":"-","Premiumize":"-","Real-Debrid":"-","TorBox":"-","Debrid-Link":"-","Linksnappy":"$4.99 USD","Mega-Debrid":"-","Deepbrid":"-"},{"name":"15 Days","AllDebrid":"€2.99","Premiumize":"-","Real-Debrid":"€3","TorBox":"-","Debrid-Link":"€3","Linksnappy":"-","Mega-Debrid":"-","Deepbrid":"€4.50"},{"name":"30 Days","AllDebrid":"€2.99/mo (Recur) / €3.99 (One-time)","Premiumize":"€11.99","Real-Debrid":"€4","TorBox":"Starts from $3.0","Debrid-Link":"€4","Linksnappy":"$12.99 USD","Mega-Debrid":"€4","Deepbrid":"€4.99"},{"name":"90 Days","AllDebrid":"€8.99(One-time)","Premiumize":"$29.99","Real-Debrid":"€9","TorBox":"-","Debrid-Link":"€9","Linksnappy":"$29.99 USD","Mega-Debrid":"€9","Deepbrid":"€12.99"},{"name":"180 Days","AllDebrid":"€15.99(One-time)","Premiumize":"-","Real-Debrid":"€16","TorBox":"-","Debrid-Link":"€16","Linksnappy":"$54.99","Mega-Debrid":"€16","Deepbrid":"€19.99"},{"name":"300 Days","AllDebrid":"€24.99(One-time)","Premiumize":"-","Real-Debrid":"-","TorBox":"-","Debrid-Link":"€25","Linksnappy":"-","Mega-Debrid":"-","Deepbrid":"-"},{"name":"365 Days","AllDebrid":"-","Premiumize":"$79.99","Real-Debrid":"-","TorBox":"-","Debrid-Link":"-","Linksnappy":"-","Mega-Debrid":"-","Deepbrid":"€32.99"}]}
|
||||
0
docs/public/robots.txt → dist/robots.txt
vendored
0
docs/public/sitemap.xml → dist/sitemap.xml
vendored
|
|
@ -1,165 +0,0 @@
|
|||
import { defineConfig } from 'vitepress'
|
||||
|
||||
export default defineConfig({
|
||||
lang: 'en-US',
|
||||
title: 'Debrid Services Comparison',
|
||||
description: 'Community-maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools.',
|
||||
ignoreDeadLinks: true,
|
||||
cleanUrls: true,
|
||||
lastUpdated: true,
|
||||
|
||||
markdown: {
|
||||
lineNumbers: true
|
||||
},
|
||||
|
||||
head: [
|
||||
['link', { rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' }],
|
||||
['link', { rel: 'shortcut icon', href: '/favicon.ico' }],
|
||||
['link', { rel: 'apple-touch-icon', sizes: '180x180', href: '/images/apple-touch-icon.png' }],
|
||||
['meta', { name: 'theme-color', content: '#ffffff', media: '(prefers-color-scheme: light)' }],
|
||||
['meta', { name: 'theme-color', content: '#0b0b0c', media: '(prefers-color-scheme: dark)' }],
|
||||
['meta', { name: 'viewport', content: 'width=device-width, initial-scale=1.0, viewport-fit=cover' }],
|
||||
['meta', { name: 'author', content: 'Fynks' }],
|
||||
['meta', { name: 'robots', content: 'index, follow, max-image-preview:large, max-snippet:-1' }],
|
||||
['meta', { property: 'og:title', content: 'Debrid Services Comparison' }],
|
||||
['meta', { property: 'og:description', content: 'Community-maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools.' }],
|
||||
['meta', { property: 'og:type', content: 'website' }],
|
||||
['meta', { property: 'og:image', content: '/images/og.png' }],
|
||||
['meta', { name: 'twitter:card', content: 'summary_large_image' }],
|
||||
['meta', { name: 'twitter:title', content: 'Debrid Services Comparison' }],
|
||||
['meta', { name: 'twitter:description', content: 'Community-maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools.' }],
|
||||
['meta', { name: 'twitter:image', content: '/images/og.png' }]
|
||||
],
|
||||
|
||||
themeConfig: {
|
||||
logo: {
|
||||
light: 'favicon.svg',
|
||||
dark: 'favicon.svg',
|
||||
alt: 'Debrid Services Comparison Logo'
|
||||
},
|
||||
|
||||
search: {
|
||||
provider: 'local',
|
||||
options: {
|
||||
detailedView: true
|
||||
}
|
||||
},
|
||||
|
||||
nav: [
|
||||
{ text: 'Home', link: '/' },
|
||||
{ text: 'Pricing', link: '/pricing' },
|
||||
{ text: 'Hosts', link: '/hosts' },
|
||||
{ text: 'Adult Hosts', link: '/Adult-hosts' },
|
||||
{ text: 'Policies', link: '/policies' },
|
||||
{ text: 'Tools', link: '/tools' }
|
||||
],
|
||||
|
||||
sidebar: {
|
||||
'/': [
|
||||
{
|
||||
text: 'Getting Started',
|
||||
items: [
|
||||
{ text: 'What are Debrid Services?', link: '/#what-are-debrid-services' },
|
||||
{ text: 'Support This Project', link: '/#support-this-project' },
|
||||
{ text: 'Interactive Comparison', link: 'https://debridcompare.pages.dev' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Service Comparison',
|
||||
items: [
|
||||
{ text: 'Pricing Comparison', link: '/pricing' },
|
||||
{ text: 'Available Hosts', link: '/hosts' },
|
||||
{ text: 'Adult Hosts', link: '/Adult-hosts' },
|
||||
{ text: 'Policies & Legal', link: '/policies' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Tools & Resources',
|
||||
items: [
|
||||
{ text: 'Tools & Community', link: '/tools' },
|
||||
{ text: 'Speed Testing', link: '/tools#speed-test' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Community',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Contributing', link: 'https://github.com/fynks/debrid-services-comparison/blob/main/CONTRIBUTING.md' },
|
||||
{ text: 'Report Issues', link: 'https://github.com/fynks/debrid-services-comparison/issues' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
'/pricing': [
|
||||
{
|
||||
text: 'Pricing Information',
|
||||
items: [
|
||||
{ text: 'Overview', link: '/pricing' },
|
||||
{ text: 'Detailed Pricing Analysis', link: '/pricing#detailed-pricing-and-value-analysis' },
|
||||
{ text: 'Official Pricing Pages', link: '/pricing#up-to-date-pricing' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
'/hosts': [
|
||||
{
|
||||
text: 'File Hosting Services',
|
||||
items: [
|
||||
{ text: 'Complete Host List', link: '/hosts' },
|
||||
{ text: 'Interactive Comparison', link: 'https://debridcompare.pages.dev' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
'/Adult-hosts': [
|
||||
{
|
||||
text: 'Adult Content Hosts',
|
||||
items: [
|
||||
{ text: 'Supported Hosts', link: '/Adult-hosts' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
'/policies': [
|
||||
{
|
||||
text: 'Service Policies',
|
||||
items: [
|
||||
{ text: 'Policies & Legal', link: '/policies' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
'/tools': [
|
||||
{
|
||||
text: 'Tools & Community',
|
||||
items: [
|
||||
{ text: 'Recommended Tools', link: '/tools#recommended-tools' },
|
||||
{ text: 'Communities', link: '/tools#communities' },
|
||||
{ text: 'Speed Testing', link: '/tools#speed-test' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
footer: {
|
||||
message: 'Made with ❤️ by Fynks',
|
||||
copyright: 'Copyright © 2025 Debrid Services Comparison'
|
||||
},
|
||||
|
||||
outline: {
|
||||
level: [2, 3],
|
||||
label: 'On this page'
|
||||
},
|
||||
|
||||
lastUpdated: {
|
||||
text: 'Updated at',
|
||||
formatOptions: {
|
||||
dateStyle: 'short',
|
||||
timeStyle: 'medium'
|
||||
}
|
||||
},
|
||||
socialLinks: [
|
||||
{ icon: 'github', link: 'https://github.com/fynks/debrid-services-comparison' }
|
||||
]
|
||||
}
|
||||
})
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
// https://vitepress.dev/guide/custom-theme
|
||||
import { h } from 'vue'
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import './style.css'
|
||||
|
||||
/** @type {import('vitepress').Theme} */
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
Layout: () => {
|
||||
return h(DefaultTheme.Layout, null, {
|
||||
// Use default VitePress layout slots
|
||||
})
|
||||
},
|
||||
enhanceApp({ app, router, siteData }) {
|
||||
// Performance optimization: Add image loading attributes
|
||||
if (typeof window !== 'undefined') {
|
||||
let observer = null;
|
||||
|
||||
const setupImageOptimization = () => {
|
||||
// Clean up existing observer
|
||||
if (observer) {
|
||||
observer.disconnect();
|
||||
}
|
||||
|
||||
// Add loading="lazy" to images after mount
|
||||
observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
mutation.addedNodes.forEach((node) => {
|
||||
if (node.nodeType === 1) { // Element node
|
||||
// Add loading attributes to shields.io images
|
||||
const images = node.querySelectorAll?.('img[src*="img.shields.io"], img[src*="shields.io"]') || [];
|
||||
images.forEach(img => {
|
||||
if (!img.hasAttribute('loading')) {
|
||||
img.setAttribute('loading', 'eager'); // Keep badges as eager loading
|
||||
img.setAttribute('decoding', 'async');
|
||||
}
|
||||
});
|
||||
|
||||
// Add loading attributes to other images
|
||||
const otherImages = node.querySelectorAll?.('img:not([src*="shields.io"])') || [];
|
||||
otherImages.forEach(img => {
|
||||
if (!img.hasAttribute('loading')) {
|
||||
img.setAttribute('loading', 'lazy');
|
||||
img.setAttribute('decoding', 'async');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (document.body) {
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Setup on initial load
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', setupImageOptimization);
|
||||
} else {
|
||||
setupImageOptimization();
|
||||
}
|
||||
|
||||
// Clean up observer on route change and setup again
|
||||
router.onAfterRouteChanged = () => {
|
||||
if (observer) {
|
||||
observer.disconnect();
|
||||
}
|
||||
// Small delay to allow new content to render
|
||||
setTimeout(setupImageOptimization, 100);
|
||||
};
|
||||
|
||||
// Clean up on beforeunload
|
||||
window.addEventListener('beforeunload', () => {
|
||||
if (observer) {
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
|
||||
// Table enhancements
|
||||
const enhanceTables = () => {
|
||||
const tables = document.querySelectorAll('.vp-doc table');
|
||||
tables.forEach(table => {
|
||||
// Wrap tables for horizontal scrolling on mobile
|
||||
if (!table.parentElement.classList.contains('table-wrapper')) {
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'table-wrapper';
|
||||
wrapper.style.overflowX = 'auto';
|
||||
wrapper.style.webkitOverflowScrolling = 'touch';
|
||||
table.parentNode.insertBefore(wrapper, table);
|
||||
wrapper.appendChild(table);
|
||||
}
|
||||
|
||||
// Enhance table cells with better styling based on content
|
||||
const cells = table.querySelectorAll('td');
|
||||
cells.forEach(cell => {
|
||||
const content = cell.textContent.trim();
|
||||
|
||||
// Style success/failure indicators
|
||||
if (content === '✅' || content.toLowerCase().includes('yes')) {
|
||||
cell.classList.add('cell-success');
|
||||
cell.setAttribute('aria-label', 'Supported');
|
||||
} else if (content === '❌' || content.toLowerCase().includes('no')) {
|
||||
cell.classList.add('cell-danger');
|
||||
cell.setAttribute('aria-label', 'Not supported');
|
||||
}
|
||||
|
||||
// Style pricing cells
|
||||
if (content.includes('€') || content.includes('$')) {
|
||||
cell.classList.add('cell-price');
|
||||
}
|
||||
|
||||
// Style trial/free cells
|
||||
if (content.toLowerCase().includes('trial') || content.toLowerCase().includes('free')) {
|
||||
cell.classList.add('cell-trial');
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Run table enhancements
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', enhanceTables);
|
||||
} else {
|
||||
enhanceTables();
|
||||
}
|
||||
|
||||
// Re-enhance tables on route change
|
||||
const originalRouteHandler = router.onAfterRouteChanged;
|
||||
router.onAfterRouteChanged = () => {
|
||||
if (originalRouteHandler) originalRouteHandler();
|
||||
if (observer) {
|
||||
observer.disconnect();
|
||||
}
|
||||
setTimeout(() => {
|
||||
setupImageOptimization();
|
||||
enhanceTables();
|
||||
}, 100);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
.web-app-note{
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
layout: home
|
||||
title: Hosts
|
||||
titleTemplate: Debrid Compare
|
||||
description: "Comprehensive hoster support comparison for leading debrid/multi-hoster services including file and torrent hosters."
|
||||
---
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
---
|
||||
layout: home
|
||||
title: Best Debrid Compare
|
||||
description: "Community‑maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools etc."
|
||||
head:
|
||||
- - meta
|
||||
- name: robots
|
||||
content: "index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1"
|
||||
- - meta
|
||||
- property: og:type
|
||||
content: "website"
|
||||
- - meta
|
||||
- property: og:url
|
||||
content: "https://debridcompare.pages.dev"
|
||||
- - meta
|
||||
- property: og:image
|
||||
content: "https://debridcompare.pages.dev/images/og.png"
|
||||
- - meta
|
||||
- property: og:title
|
||||
content: "Debrid Compare"
|
||||
- - meta
|
||||
- property: og:description
|
||||
content: "Community‑maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools etc."
|
||||
- - meta
|
||||
- property: og:image:secure_url
|
||||
content: "https://debridcompare.pages.dev/images/og.png"
|
||||
- - meta
|
||||
- property: og:image:alt
|
||||
content: "Debrid Compare"
|
||||
- - meta
|
||||
- property: og:image:width
|
||||
content: "1200"
|
||||
- - meta
|
||||
- property: og:image:height
|
||||
content: "630"
|
||||
- - meta
|
||||
- property: og:image:type
|
||||
content: "image/png"
|
||||
- - meta
|
||||
- property: og:site_name
|
||||
content: "Debrid Compare"
|
||||
- - meta
|
||||
- property: og:locale
|
||||
content: "en_US"
|
||||
- - meta
|
||||
- property: og:updated_time
|
||||
content: "2025-09-19T00:00:00Z"
|
||||
- - link
|
||||
- rel: canonical
|
||||
href: "https://debridcompare.pages.dev"
|
||||
- - link
|
||||
- rel: alternate
|
||||
hreflang: "en"
|
||||
href: "https://debridcompare.pages.dev"
|
||||
hero:
|
||||
name: "Debrid Compare"
|
||||
tagline: "Community‑maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools etc."
|
||||
image:
|
||||
src: favicon.svg
|
||||
alt: Debrid Compare Logo
|
||||
actions:
|
||||
- theme: brand
|
||||
text: 🚀 Supported Hosts
|
||||
link: /hosts
|
||||
size: large
|
||||
- theme: alt
|
||||
text: 📚 Pricing
|
||||
link: /pricing
|
||||
- theme: alt
|
||||
text: ⭐ GitHub
|
||||
link: https://github.com/fynks/debrid-services-comparison
|
||||
target: _blank
|
||||
features:
|
||||
- icon: ⚡
|
||||
title: Performance & Gaming
|
||||
details: "Supercharge your device with performance optimization, gaming enhancements, CPU/GPU tuning, and intelligent automation."
|
||||
link: /android-root-apps/#performance-tweaks-and-optimizations
|
||||
|
||||
- icon: 🌐
|
||||
title: Network & Connectivity Control
|
||||
details: "Master network management with firewall tools, DNS control, Wi-Fi optimization, and advanced connectivity features."
|
||||
link: /android-root-apps/#network-and-connectivity
|
||||
|
||||
- icon: 🛠️
|
||||
title: Root Management & Hiding
|
||||
details: "Manage root access, hide root from banking apps, ensure integrity checks pass, and maintain system security."
|
||||
link: /android-root-apps/#root-management
|
||||
|
||||
---
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
layout: home
|
||||
title: Policies
|
||||
titleTemplate: Debrid Compare
|
||||
description: "Refund, privacy, and usage policies for leading debrid/multi-hoster services."
|
||||
---
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
layout: home
|
||||
title: Pricing
|
||||
titleTemplate: Debrid Compare
|
||||
description: "Comprehensive pricing comparison of leading debrid/multi-hoster services including plans, costs, and value analysis."
|
||||
---
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
layout: home
|
||||
title: Tools
|
||||
titleTemplate: Debrid Compare
|
||||
description: "Tools and integrations for leading debrid/multi-hoster services including browser extensions, download managers, and media center plugins."
|
||||
---
|
||||
40
package.json
|
|
@ -1,30 +1,24 @@
|
|||
{
|
||||
"name": "debrid-services-comparison",
|
||||
"version": "1.1.0",
|
||||
"description": "Community‑maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools etc.",
|
||||
"private": true,
|
||||
"homepage": "https://awesome-android-root.org",
|
||||
"name": "@fynks/debrid-service-comparison",
|
||||
"version": "2.0.1",
|
||||
"description": "A concise comparison of pricing and supported hosts for popular debrid services including AllDebrid, Real-Debrid, LinkSnappy, Premiumize, Debrid-Link, TorBox, and Mega-Debrid.",
|
||||
"main": "index.js",
|
||||
"homepage": "",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fynks/debrid-services-comparison.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/fynks/debrid-services-comparison/issues"
|
||||
"url": ""
|
||||
},
|
||||
"scripts": {
|
||||
"docs:dev": "vitepress dev docs",
|
||||
"docs:build": "scripts/build-docs.sh && vitepress build docs",
|
||||
"docs:preview": "vitepress preview docs"
|
||||
"minify:css": "cleancss -o dist/css/styles-min.css dist/css/styles.css",
|
||||
"minify:js": "terser dist/js/app.js -o dist/js/app-min.js --compress --mangle",
|
||||
"optimize-json": "chmod +x scripts/json-optimizer.sh && scripts/json-optimizer.sh dist/json/file-hosts.json dist/json/file-hosts-optimized.json && scripts/json-optimizer.sh dist/json/adult-hosts.json dist/json/adult-hosts-optimized.json",
|
||||
"build": "npm run minify:css && npm run minify:js && npm run optimize-json && workbox generateSW workbox-config.js",
|
||||
"postbuild": "node scripts/replace-assets.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vitepress": "^1.6.4",
|
||||
"terser": "^5.44.0"
|
||||
},
|
||||
"keywords": [
|
||||
],
|
||||
"author": {
|
||||
"name": "debrid-services-comparison",
|
||||
"url": "https://debridcompare.pages.dev"
|
||||
},
|
||||
"license": "MIT"
|
||||
"author": "fynks",
|
||||
"dependencies": {
|
||||
"clean-css-cli": "^5.6.3",
|
||||
"terser": "^5.44.0",
|
||||
"workbox-cli": "^7.3.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Exit on any error and treat unset variables as errors
|
||||
set -euo pipefail
|
||||
|
||||
# Colors for output
|
||||
readonly GREEN='\033[0;32m'
|
||||
readonly NC='\033[0m' # No Color
|
||||
readonly RED='\033[0;31m'
|
||||
readonly BLUE='\033[0;34m'
|
||||
readonly YELLOW='\033[1;33m'
|
||||
|
||||
# Script info
|
||||
readonly SCRIPT_NAME="$(basename "$0")"
|
||||
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Error handling function with line number
|
||||
handle_error() {
|
||||
local line_number="${2:-unknown}"
|
||||
echo -e "${RED}Error on line ${line_number}: $1${NC}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Trap errors and show line number
|
||||
trap 'handle_error "Script failed" ${LINENO}' ERR
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo -e "${GREEN}✓ $1${NC}"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}⚠ $1${NC}"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}✗ $1${NC}" >&2
|
||||
}
|
||||
|
||||
echo -e "${GREEN}Starting build-docs process...${NC}"
|
||||
|
||||
# 1. Check required files and directories
|
||||
[ ! -d "docs" ] && handle_error "'docs' directory not found."
|
||||
[ ! -f "README.md" ] && handle_error "'README.md' not found."
|
||||
|
||||
# 2. Function to extract div content with specific class from README.md
|
||||
extract_div_content() {
|
||||
local class_name="$1"
|
||||
local start_line end_line
|
||||
|
||||
# Find the start line of the div with the specified class
|
||||
start_line=$(grep -n "<div[^>]*class=\"${class_name}\"" README.md | head -1 | cut -d: -f1)
|
||||
|
||||
if [ -z "$start_line" ]; then
|
||||
log_warn "No div with class '${class_name}' found in README.md"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Find the corresponding closing </div></div> after the start line
|
||||
end_line=$(tail -n +$((start_line + 1)) README.md | grep -n "</div></div>" | head -1 | cut -d: -f1)
|
||||
|
||||
if [ -z "$end_line" ]; then
|
||||
log_warn "No closing </div></div> found for class '${class_name}'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Calculate the actual end line number
|
||||
end_line=$((start_line + end_line))
|
||||
|
||||
# Extract the content between start and end lines
|
||||
sed -n "${start_line},${end_line}p" README.md
|
||||
}
|
||||
|
||||
# 3. Function to copy div content to docs file
|
||||
copy_div_to_docs() {
|
||||
local class_name="$1"
|
||||
local target_file="$2"
|
||||
local content
|
||||
|
||||
content=$(extract_div_content "$class_name")
|
||||
|
||||
if [ $? -eq 0 ] && [ -n "$content" ]; then
|
||||
if [ -f "$target_file" ]; then
|
||||
# Append to existing file with separator
|
||||
{
|
||||
cat "$target_file"
|
||||
echo ""
|
||||
echo "$content"
|
||||
} > "${target_file}.tmp" && mv "${target_file}.tmp" "$target_file" || handle_error "Failed appending content to $target_file"
|
||||
log_info "Appended '$class_name' div content to $target_file"
|
||||
else
|
||||
# Create new file with content
|
||||
echo "$content" > "$target_file" || handle_error "Failed creating $target_file"
|
||||
log_info "Created $target_file with '$class_name' div content"
|
||||
fi
|
||||
|
||||
# Adjust relative links for docs directory structure
|
||||
adjust_links_for_docs "$target_file"
|
||||
else
|
||||
log_warn "Failed to extract content for class '$class_name'"
|
||||
fi
|
||||
}
|
||||
|
||||
# 4. Function to adjust links for docs directory structure
|
||||
adjust_links_for_docs() {
|
||||
local file="$1"
|
||||
|
||||
# Adjust relative links (skip absolute URLs)
|
||||
sed -i '/http[s]*:\/\/\//! s|\.\/docs/|\.\/|g' "$file" || handle_error "Failed adjusting links in $file"
|
||||
|
||||
# Adjust image paths
|
||||
sed -i 's|docs/public/images/|public/images/|g' "$file" || handle_error "Failed adjusting image paths in $file"
|
||||
sed -i 's|\./dist/|public/images/|g' "$file" || handle_error "Failed adjusting dist image paths in $file"
|
||||
|
||||
log_info "Adjusted links and image paths in $file"
|
||||
}
|
||||
|
||||
# 5. Function to create pricing.md with support section first, then pricing section
|
||||
create_pricing_with_support() {
|
||||
local target_file="docs/pricing.md"
|
||||
local support_content pricing_content
|
||||
|
||||
# Extract both sections
|
||||
support_content=$(extract_div_content "support")
|
||||
pricing_content=$(extract_div_content "pricing")
|
||||
|
||||
if [ $? -eq 0 ] && [ -n "$support_content" ] && [ -n "$pricing_content" ]; then
|
||||
# Create file with frontmatter + support + pricing
|
||||
{
|
||||
# Keep the original frontmatter
|
||||
head -7 "$target_file"
|
||||
echo ""
|
||||
echo "$support_content"
|
||||
echo ""
|
||||
echo "$pricing_content"
|
||||
} > "${target_file}.tmp" && mv "${target_file}.tmp" "$target_file" || handle_error "Failed creating $target_file with support and pricing content"
|
||||
log_info "Created $target_file with support section before pricing section"
|
||||
adjust_links_for_docs "$target_file"
|
||||
else
|
||||
log_warn "Failed to extract support or pricing content"
|
||||
fi
|
||||
}
|
||||
|
||||
# Copy div sections to respective docs files
|
||||
create_pricing_with_support
|
||||
copy_div_to_docs "hosts" "docs/hosts.md"
|
||||
copy_div_to_docs "policies" "docs/policies.md"
|
||||
copy_div_to_docs "tools" "docs/tools.md"
|
||||
|
||||
# 6. Append speedtest content to the bottom of tools.md
|
||||
speedtest_content=$(extract_div_content "speedtest")
|
||||
if [ $? -eq 0 ] && [ -n "$speedtest_content" ]; then
|
||||
{
|
||||
cat "docs/tools.md"
|
||||
echo ""
|
||||
echo "---"
|
||||
echo ""
|
||||
echo "$speedtest_content"
|
||||
} > "docs/tools.md.tmp" && mv "docs/tools.md.tmp" "docs/tools.md" || handle_error "Failed appending speedtest content to docs/tools.md"
|
||||
log_info "Appended speedtest content to bottom of docs/tools.md"
|
||||
adjust_links_for_docs "docs/tools.md"
|
||||
else
|
||||
log_warn "Failed to extract speedtest content"
|
||||
fi
|
||||
|
||||
# 7. Remove standalone speedtest.md file if it exists
|
||||
if [ -f "docs/speedtest.md" ]; then
|
||||
rm "docs/speedtest.md" || handle_error "Failed removing docs/speedtest.md"
|
||||
log_info "Removed standalone docs/speedtest.md file"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Documentation build process completed successfully.${NC}"
|
||||
191
scripts/json-optimizer.sh
Executable file
|
|
@ -0,0 +1,191 @@
|
|||
#!/bin/bash
|
||||
|
||||
# JSON Optimizer Script - Converts host data to indexed format
|
||||
# Usage: ./scripts/json-optimizer.sh file-hosts.json
|
||||
# ./scripts/json-optimizer.sh adult-hosts.json
|
||||
# ./scripts/json-optimizer.sh pricing.json
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print colored output
|
||||
print_status() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Default values
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
DEFAULT_INPUT_DIR="."
|
||||
DEFAULT_OUTPUT_DIR="."
|
||||
|
||||
# Check if at least one argument is provided
|
||||
if [ $# -eq 0 ]; then
|
||||
print_error "No input file specified"
|
||||
echo "Usage: $0 <input-file.json> [output-file.json]"
|
||||
echo "Examples:"
|
||||
echo " $0 file-hosts.json"
|
||||
echo " $0 ./json/adult-hosts.json"
|
||||
echo " $0 pricing.json pricing-optimized.json"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get input file
|
||||
INPUT_FILE="$1"
|
||||
|
||||
# Generate output filename if not provided
|
||||
if [ $# -eq 2 ]; then
|
||||
OUTPUT_FILE="$2"
|
||||
else
|
||||
# Extract filename without path and extension
|
||||
FILENAME=$(basename "$INPUT_FILE")
|
||||
NAME="${FILENAME%.*}"
|
||||
EXT="${FILENAME##*.}"
|
||||
OUTPUT_FILE="${NAME}-optimized.${EXT}"
|
||||
fi
|
||||
|
||||
# Check if input file exists
|
||||
if [ ! -f "$INPUT_FILE" ]; then
|
||||
print_error "Input file '$INPUT_FILE' not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create output directory if it doesn't exist
|
||||
OUTPUT_DIR=$(dirname "$OUTPUT_FILE")
|
||||
if [ ! -d "$OUTPUT_DIR" ] && [ "$OUTPUT_DIR" != "." ]; then
|
||||
print_status "Creating output directory: $OUTPUT_DIR"
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
fi
|
||||
|
||||
print_status "Processing: $INPUT_FILE"
|
||||
print_status "Output will be saved to: $OUTPUT_FILE"
|
||||
|
||||
# Python script to handle the conversion
|
||||
python3 -c "
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
from collections import defaultdict
|
||||
|
||||
def convert_to_indexed_format(input_file, output_file):
|
||||
try:
|
||||
# Read the input JSON
|
||||
print('Reading input file...')
|
||||
with open(input_file, 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
host_count = len(data)
|
||||
print(f'Loaded {host_count:,} hosts')
|
||||
|
||||
# Handle empty data
|
||||
if not data:
|
||||
print('Warning: Input file is empty')
|
||||
output_data = {'services': [], 'supported': {}}
|
||||
with open(output_file, 'w') as f:
|
||||
json.dump(output_data, f, separators=(',', ':'))
|
||||
return True
|
||||
|
||||
# Extract all services (keys from entries)
|
||||
all_services = set()
|
||||
for host_data in data.values():
|
||||
all_services.update(host_data.keys())
|
||||
|
||||
services = sorted(list(all_services))
|
||||
service_count = len(services)
|
||||
print(f'Found {service_count} services: {\", \".join(services[:5])}{\"...\" if service_count > 5 else \"\"}')
|
||||
|
||||
# Create service to index mapping
|
||||
service_to_index = {service: idx for idx, service in enumerate(services)}
|
||||
|
||||
# Convert data to indexed format
|
||||
print('Converting data to indexed format...')
|
||||
supported = {}
|
||||
total_support_instances = 0
|
||||
|
||||
for host, host_data in data.items():
|
||||
# Get indices of services with 'yes' values (case insensitive)
|
||||
supported_indices = [
|
||||
service_to_index[service]
|
||||
for service, value in host_data.items()
|
||||
if str(value).lower() == 'yes'
|
||||
]
|
||||
supported[host] = sorted(supported_indices)
|
||||
total_support_instances += len(supported_indices)
|
||||
|
||||
# Create output structure
|
||||
output_data = {
|
||||
'services': services,
|
||||
'supported': supported
|
||||
}
|
||||
|
||||
# Write optimized JSON (compact format)
|
||||
print('Writing optimized JSON...')
|
||||
with open(output_file, 'w') as f:
|
||||
json.dump(output_data, f, separators=(',', ':'))
|
||||
|
||||
# Get file sizes for comparison
|
||||
original_size = os.path.getsize(input_file)
|
||||
new_size = os.path.getsize(output_file)
|
||||
reduction = ((original_size - new_size) / original_size) * 100 if original_size > 0 else 0
|
||||
|
||||
print('✅ Conversion successful!')
|
||||
print(f'📁 Original size: {original_size:,} bytes')
|
||||
print(f'📁 New size: {new_size:,} bytes')
|
||||
print(f'📉 Size reduction: {reduction:.1f}%')
|
||||
print(f'💾 Output saved to: {output_file}')
|
||||
|
||||
# Show statistics
|
||||
avg_support_per_host = total_support_instances / host_count if host_count > 0 else 0
|
||||
|
||||
print('📈 Statistics:')
|
||||
print(f' - Hosts: {host_count:,}')
|
||||
print(f' - Services: {service_count:,}')
|
||||
print(f' - Total support instances: {total_support_instances:,}')
|
||||
print(f' - Average support per host: {avg_support_per_host:.1f}')
|
||||
|
||||
return True
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
print(f'❌ JSON parsing error: {str(e)}')
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f'❌ Error during conversion: {str(e)}')
|
||||
return False
|
||||
|
||||
# Run the conversion
|
||||
success = convert_to_indexed_format('$INPUT_FILE', '$OUTPUT_FILE')
|
||||
|
||||
if not success:
|
||||
sys.exit(1)
|
||||
" || {
|
||||
print_error "Python conversion failed. Please ensure Python 3 is installed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
print_success "Conversion completed successfully!"
|
||||
|
||||
# Optional: Show file size comparison in bash as well
|
||||
if command -v stat >/dev/null 2>&1; then
|
||||
ORIGINAL_SIZE=$(stat -f%z "$INPUT_FILE" 2>/dev/null || stat -c%s "$INPUT_FILE" 2>/dev/null)
|
||||
NEW_SIZE=$(stat -f%z "$OUTPUT_FILE" 2>/dev/null || stat -c%s "$OUTPUT_FILE" 2>/dev/null)
|
||||
|
||||
if [ $? -eq 0 ] && [ $ORIGINAL_SIZE -gt 0 ]; then
|
||||
REDUCTION_PERCENTAGE=$(( (ORIGINAL_SIZE - NEW_SIZE) * 100 / ORIGINAL_SIZE ))
|
||||
print_status "Final size reduction: ${REDUCTION_PERCENTAGE}%"
|
||||
fi
|
||||
fi
|
||||
158
scripts/replace-assets.js
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Improved script with better error handling and focused head tag processing
|
||||
function replaceAssets() {
|
||||
const file = path.resolve(__dirname, '..', 'dist', 'index.html');
|
||||
|
||||
// Check if dist/index.html exists
|
||||
if (!fs.existsSync(file)) {
|
||||
console.error('Error: dist/index.html not found');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
let html = fs.readFileSync(file, 'utf8');
|
||||
console.log('Original HTML loaded successfully');
|
||||
|
||||
// Extract the head section
|
||||
const headMatch = html.match(/(<head[^>]*>)([\s\S]*?)(<\/head>)/i);
|
||||
if (!headMatch) {
|
||||
console.error('Error: Could not find <head> tag in HTML');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const [fullHeadTag, headStart, headContent, headEnd] = headMatch;
|
||||
console.log('Head section found, processing assets...');
|
||||
|
||||
let updatedHeadContent = headContent;
|
||||
let cssReplaced = 0;
|
||||
let jsReplaced = 0;
|
||||
|
||||
// Compute simple query hash for cache-busting if files exist
|
||||
const cssMinPath = path.resolve(__dirname, '..', 'dist', 'css', 'styles-min.css');
|
||||
const jsMinPath = path.resolve(__dirname, '..', 'dist', 'js', 'app-min.js');
|
||||
const safeHash = (p) => {
|
||||
try {
|
||||
const buf = fs.readFileSync(p);
|
||||
let hash = 0;
|
||||
for (let i = 0; i < buf.length; i += Math.ceil(buf.length / 128) || 1) {
|
||||
hash = (hash * 31 + buf[i]) >>> 0;
|
||||
}
|
||||
return hash.toString(36);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
const cssHash = safeHash(cssMinPath);
|
||||
const jsHash = safeHash(jsMinPath);
|
||||
const cssTarget = cssHash ? `href="./css/styles-min.css?v=${cssHash}"` : 'href="./css/styles-min.css"';
|
||||
const jsTarget = jsHash ? `src="js/app-min.js?v=${jsHash}"` : 'src="js/app-min.js"';
|
||||
|
||||
// Replace CSS links in head - more flexible patterns
|
||||
const cssPatterns = [
|
||||
/href=["']\.\/css\/styles\.css["']/g,
|
||||
/href=["']css\/styles\.css["']/g,
|
||||
/href=["'][^"']*\/styles\.css["']/g
|
||||
];
|
||||
|
||||
cssPatterns.forEach(pattern => {
|
||||
const matches = updatedHeadContent.match(pattern);
|
||||
if (matches) {
|
||||
updatedHeadContent = updatedHeadContent.replace(pattern, cssTarget);
|
||||
cssReplaced += matches.length;
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure existing preload to styles-min.css carries the same version hash
|
||||
if (cssHash) {
|
||||
const preloadMinCssPattern = /href=["']\/?css\/styles-min\.css["']/g;
|
||||
if (preloadMinCssPattern.test(updatedHeadContent)) {
|
||||
updatedHeadContent = updatedHeadContent.replace(preloadMinCssPattern, `href="/css/styles-min.css?v=${cssHash}"`);
|
||||
}
|
||||
}
|
||||
|
||||
// Replace JS script src in head - more flexible patterns
|
||||
const jsPatterns = [
|
||||
/src=["']\.\/js\/app\.js["']/g,
|
||||
/src=["']js\/app\.js["']/g,
|
||||
/src=["'][^"']*\/app\.js["']/g
|
||||
];
|
||||
|
||||
jsPatterns.forEach(pattern => {
|
||||
const matches = updatedHeadContent.match(pattern);
|
||||
if (matches) {
|
||||
updatedHeadContent = updatedHeadContent.replace(pattern, jsTarget);
|
||||
jsReplaced += matches.length;
|
||||
}
|
||||
});
|
||||
|
||||
// Also check for script tags at the end of body (common pattern)
|
||||
const bodyMatch = html.match(/(<body[^>]*>)([\s\S]*?)(<\/body>)/i);
|
||||
if (bodyMatch) {
|
||||
const [fullBodyTag, bodyStart, bodyContent, bodyEnd] = bodyMatch;
|
||||
let updatedBodyContent = bodyContent;
|
||||
|
||||
jsPatterns.forEach(pattern => {
|
||||
const matches = updatedBodyContent.match(pattern);
|
||||
if (matches) {
|
||||
updatedBodyContent = updatedBodyContent.replace(pattern, jsTarget);
|
||||
jsReplaced += matches.length;
|
||||
}
|
||||
});
|
||||
|
||||
// Reconstruct the body if changes were made
|
||||
if (updatedBodyContent !== bodyContent) {
|
||||
html = html.replace(fullBodyTag, bodyStart + updatedBodyContent + bodyEnd);
|
||||
}
|
||||
}
|
||||
|
||||
// Reconstruct the HTML with updated head
|
||||
const updatedHeadTag = headStart + updatedHeadContent + headEnd;
|
||||
html = html.replace(fullHeadTag, updatedHeadTag);
|
||||
|
||||
// Log results
|
||||
console.log(`CSS replacements made: ${cssReplaced}`);
|
||||
console.log(`JS replacements made: ${jsReplaced}`);
|
||||
|
||||
if (cssReplaced === 0 && jsReplaced === 0) {
|
||||
console.warn('Warning: No asset links were found to replace');
|
||||
console.log('Checking for existing patterns in head section:');
|
||||
|
||||
// Debug: show what's actually in the head
|
||||
const linkTags = headContent.match(/<link[^>]*>/gi) || [];
|
||||
const scriptTags = headContent.match(/<script[^>]*>/gi) || [];
|
||||
|
||||
console.log('Found link tags:', linkTags);
|
||||
console.log('Found script tags:', scriptTags);
|
||||
} else {
|
||||
console.log('Asset links replaced successfully');
|
||||
}
|
||||
|
||||
// Write the updated HTML back
|
||||
fs.writeFileSync(file, html, 'utf8');
|
||||
console.log('Updated dist/index.html saved');
|
||||
|
||||
// Verify the minified files exist
|
||||
const cssFile = path.resolve(__dirname, '..', 'dist', 'css', 'styles-min.css');
|
||||
const jsFile = path.resolve(__dirname, '..', 'dist', 'js', 'app-min.js');
|
||||
|
||||
if (!fs.existsSync(cssFile)) {
|
||||
console.warn('Warning: styles-min.css not found - CSS minification may have failed');
|
||||
} else {
|
||||
console.log('✓ styles-min.css exists');
|
||||
}
|
||||
|
||||
if (!fs.existsSync(jsFile)) {
|
||||
console.warn('Warning: app-min.js not found - JS minification may have failed');
|
||||
} else {
|
||||
console.log('✓ app-min.js exists');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error processing HTML file:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
replaceAssets();
|
||||