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
|
### Adult Hosts
|
||||||
|
|
||||||
38
README.md
|
|
@ -1,6 +1,6 @@
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<h1>
|
<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>
|
</h1>
|
||||||
|
|
||||||
<p><strong>Community‑maintained, up-to-date comparison</strong> of leading debrid / multi-hoster services for pricing, host coverage, policies & tools etc.</p>
|
<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>
|
<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>
|
</div>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
@ -58,8 +58,6 @@ Debrid ("multi-hoster") services act as paid aggregation layers between you and
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
<div class="support">
|
|
||||||
|
|
||||||
### Support This Project
|
### 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).
|
> ✨ 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)
|
[(↑ Back to Top)](#table-of-contents)
|
||||||
|
|
||||||
</div></div>
|
</div>
|
||||||
|
|
||||||
<div class="pricing">
|
|
||||||
|
|
||||||
## Pricing Comparison
|
## Pricing Comparison
|
||||||
|
|
||||||
|
|
@ -141,9 +137,7 @@ Debrid ("multi-hoster") services act as paid aggregation layers between you and
|
||||||
|
|
||||||
[(↑ Back to Top)](#table-of-contents)
|
[(↑ Back to Top)](#table-of-contents)
|
||||||
|
|
||||||
</div></div>
|
</div>
|
||||||
|
|
||||||
<div class="hosts">
|
|
||||||
|
|
||||||
## Available Hosts
|
## Available Hosts
|
||||||
|
|
||||||
|
|
@ -151,7 +145,7 @@ Debrid ("multi-hoster") services act as paid aggregation layers between you and
|
||||||
|
|
||||||
<br />
|
<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>. |
|
| ⚡ 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.
|
> 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
|
### 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)
|
[(↑ Back to Top)](#table-of-contents)
|
||||||
|
|
||||||
</div></div>
|
</div>
|
||||||
|
|
||||||
<div class="policies">
|
|
||||||
|
|
||||||
## Policies and Legal
|
## 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)
|
[(↑ Back to Top)](#table-of-contents)
|
||||||
|
|
||||||
</div></div>
|
</div>
|
||||||
|
|
||||||
<div class="speedtest">
|
|
||||||
|
|
||||||
## Speed Test
|
## Speed Test
|
||||||
|
|
||||||
|
|
@ -571,7 +561,7 @@ For a more accurate assessment, follow these steps:
|
||||||
|
|
||||||
[(↑ Back to Top)](#table-of-contents)
|
[(↑ 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
|
## Tools and Community
|
||||||
|
|
||||||
Enhance your debrid experience with these trusted tools, guides, and communities:
|
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)
|
[(↑ Back to Top)](#table-of-contents)
|
||||||
|
|
||||||
</div></div>
|
</div>
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Help keep this guide accurate! We welcome:
|
Help keep this guide accurate! We welcome:
|
||||||
|
|
@ -632,10 +620,10 @@ Help keep this guide accurate! We welcome:
|
||||||
- ✅ Policy clarifications
|
- ✅ Policy clarifications
|
||||||
- ✅ UX/UI suggestions
|
- ✅ UX/UI suggestions
|
||||||
|
|
||||||
**[See Contribution Guidelines →](./CONTRIBUTING.md)**
|
|
||||||
|
|
||||||
> 🛡️ All PRs are verified against official sources before merging.
|
> 🛡️ All PRs are verified against official sources before merging.
|
||||||
|
|
||||||
|
**[See Contribution Guidelines →](./CONTRIBUTING.md)**
|
||||||
|
|
||||||
<div align="right">
|
<div align="right">
|
||||||
|
|
||||||
[(↑ Back to Top)](#table-of-contents)
|
[(↑ 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",
|
"name": "@fynks/debrid-service-comparison",
|
||||||
"version": "1.1.0",
|
"version": "2.0.1",
|
||||||
"description": "Community‑maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools etc.",
|
"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.",
|
||||||
"private": true,
|
"main": "index.js",
|
||||||
"homepage": "https://awesome-android-root.org",
|
"homepage": "",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/fynks/debrid-services-comparison.git"
|
"url": ""
|
||||||
},
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/fynks/debrid-services-comparison/issues"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"docs:dev": "vitepress dev docs",
|
"minify:css": "cleancss -o dist/css/styles-min.css dist/css/styles.css",
|
||||||
"docs:build": "scripts/build-docs.sh && vitepress build docs",
|
"minify:js": "terser dist/js/app.js -o dist/js/app-min.js --compress --mangle",
|
||||||
"docs:preview": "vitepress preview docs"
|
"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": {
|
"author": "fynks",
|
||||||
"vitepress": "^1.6.4",
|
"dependencies": {
|
||||||
"terser": "^5.44.0"
|
"clean-css-cli": "^5.6.3",
|
||||||
},
|
"terser": "^5.44.0",
|
||||||
"keywords": [
|
"workbox-cli": "^7.3.0"
|
||||||
],
|
}
|
||||||
"author": {
|
|
||||||
"name": "debrid-services-comparison",
|
|
||||||
"url": "https://debridcompare.pages.dev"
|
|
||||||
},
|
|
||||||
"license": "MIT"
|
|
||||||
}
|
}
|
||||||
|
|
@ -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();
|
||||||