Compare commits
No commits in common. "main" and "2025-01-12" have entirely different histories.
main
...
2025-01-12
3
.github/FUNDING.yml
vendored
|
|
@ -1,3 +0,0 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
open_collective: carlos61
|
||||
4
.gitignore
vendored
|
|
@ -1,4 +0,0 @@
|
|||
docs/.vitepress/dist
|
||||
docs/.vitepress/cache
|
||||
node_modules
|
||||
tbd.md
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
|
||||
### Adult Hosts
|
||||
|
||||
| **Service Name** | **AllDebrid** | **RealDebrid** | **TorBox** | **Deepbrid** | **Premiumize** | **Mega-Debrid** | **High-Way** | **LinkSnappy** | **Debrid-Link** |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| Beeg | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Coomer | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Drtuber | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Eporner | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Hanime | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Hentai foundry | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Kemono | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Nhentai | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Pornhub | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Pornoxo | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Redgifs | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Redtube | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Rule34 | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Spankbang | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Stripchat | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Sunporno | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
|
||||
| Xhamster | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Xnxx | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Xvideos | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Xxxymovies | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Youjizz | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Youporn | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| **Total = 22** | **12/22** | **2/22** | **20/22** | **1/22** | **1/22** | **1/22** | **0/22** | **0/22** | **0/22** |
|
||||
|
||||
> **Last updated: March 9, 2026**
|
||||
|
||||
<div align="center">
|
||||
|
||||
### [Back to home](./README.md)
|
||||
|
||||
</div>
|
||||
9
CHANGELOG.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Sunday, January 12, 2025
|
||||
## Updated:
|
||||
- Hosts for torbox
|
||||
- Link for torbox hosts live updates
|
||||
- Timestamp
|
||||
|
||||
## Removed:
|
||||
- Deduplicated entries in hosts
|
||||
- Removed Some Adult hosts from file hosts
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
# Contributing to Debrid Services Comparison
|
||||
|
||||
Thank you for your interest in improving this project! Your contributions help keep the comparison accurate and up to date.
|
||||
|
||||
## How to Contribute
|
||||
|
||||
### Open an Issue
|
||||
1. Go to the [Issues tab](https://github.com/fynks/debrid-services-comparison/issues)
|
||||
2. Click **"New Issue"**
|
||||
3. Include:
|
||||
- Service name
|
||||
- Change observed (e.g., "AllDebrid now supports Terabox")
|
||||
- Proof: **Link to official page or screenshot**
|
||||
- Date of observation
|
||||
4. Submit — maintainers will review and update
|
||||
|
||||
### Submit a Pull Request
|
||||
1. Fork the repository
|
||||
2. Edit the relevant file (`README.md`, `Adult-hosts.md`, etc.)
|
||||
3. **Update the `Last updated date`** at the bottom
|
||||
4. Create a pull request with a clear description
|
||||
|
||||
## Guidelines
|
||||
|
||||
- Keep changes factual and neutral.
|
||||
- Use clear, concise language.
|
||||
- Reference official sources when possible.
|
||||
- Avoid promotional content.
|
||||
|
||||
---
|
||||
|
||||
**Thanks for helping make this resource better for everyone! 🚀**
|
||||
21
LICENSE
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2025 Fynks
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
98
convert.sh
Executable file
|
|
@ -0,0 +1,98 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Error handling
|
||||
handle_error() {
|
||||
echo "Error: $1"
|
||||
cleanup
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Cleanup function
|
||||
cleanup() {
|
||||
rm -f header.html template.html
|
||||
}
|
||||
|
||||
# Check requirements
|
||||
if ! command -v pandoc &> /dev/null; then
|
||||
handle_error "pandoc is not installed. Please install it first."
|
||||
fi
|
||||
|
||||
# Create template
|
||||
cat > template.html << 'EOL'
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
$header-includes$
|
||||
<title>Debrid Services Comparison</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header role="banner">
|
||||
<h1 class="title">$title$</h1>
|
||||
<nav role="navigation" aria-label="Table of contents">
|
||||
$toc$
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main id="main-content" role="main">
|
||||
$body$
|
||||
</main>
|
||||
|
||||
<footer role="contentinfo">
|
||||
<p><a href="https://github.com/fynks/debrid-services-comparison">Source ↗</a> | Made with ❤️ by Fynks</p>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded",(function(){const e=document.getElementById("available-hosts");if(e){const t=document.createElement("div");t.id="search-container",t.innerHTML='\n <input type="text" id="search-input" placeholder="Search the hosts..." />\n ',e.insertAdjacentElement("afterend",t);const n=document.getElementById("search-input");n.addEventListener("input",(function(){const e=n.value.toLowerCase(),t=document.querySelectorAll("table");if(t.length>1){const n=t[1].getElementsByTagName("tr");for(let t=1;t<n.length;t++){const o=n[t].getElementsByTagName("td");let a=!1;for(let t=0;t<o.length;t++)if(o[t].innerText.toLowerCase().includes(e)){a=!0;break}n[t].style.display=a?"":"none"}}}))}}));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
EOL
|
||||
|
||||
# Create header with improved meta tags
|
||||
cat > header.html << 'EOL'
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="A quick comparison of available hosts for AllDebrid, Real-Debrid, LinkSnappy, Premiumize, Debrid-Link, and TorBox.">
|
||||
<meta name="keywords" content="Debrid services, AllDebrid, Real-Debrid, LinkSnappy, Premiumize, Debrid-Link, TorBox, comparison, pricing, hosts, file hosts, downloading, free downloading, mediafire, mega.nz, mega free download, turbobit free download, rapidgator free download, nitroflare">
|
||||
<meta name="author" content="Fynks">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="theme-color" content="#0366d6">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://debrid-services-comparison.netlify.app/">
|
||||
<meta property="og:title" content="Debrid Services Comparison">
|
||||
<meta property="og:description" content="A quick comparison of available hosts for AllDebrid, Real-Debrid, LinkSnappy, Premiumize, Debrid-Link, and TorBox.">
|
||||
<meta property="og:image" content="https://debrid-services-comparison.netlify.app/image.png">
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image">
|
||||
<meta property="twitter:url" content="https://debrid-services-comparison.netlify.app/">
|
||||
<meta property="twitter:title" content="Debrid Services Comparison">
|
||||
<meta property="twitter:description" content="A quick comparison of available hosts for AllDebrid, Real-Debrid, LinkSnappy, Premiumize, Debrid-Link, and TorBox.">
|
||||
<meta property="twitter:image" content="https://debrid-services-comparison.netlify.app/image.png">
|
||||
EOL
|
||||
|
||||
# Convert markdown with progress
|
||||
echo "Starting conversion process..."
|
||||
echo "→ Generating HTML from markdown..."
|
||||
pandoc README.md \
|
||||
--from gfm \
|
||||
--to html5 \
|
||||
--standalone \
|
||||
--template=template.html \
|
||||
--include-in-header=header.html \
|
||||
--metadata title="Debrid Services Comparison" \
|
||||
--shift-heading-level-by=-1 \
|
||||
--toc-depth=2 \
|
||||
-o docs/index.html || handle_error "Conversion failed"
|
||||
|
||||
# Cleanup
|
||||
cleanup
|
||||
|
||||
echo "✓ Conversion complete! Output saved as docs/index.html"
|
||||
4
dist/.well-known/security.txt
vendored
|
|
@ -1,4 +0,0 @@
|
|||
Contact: https://github.com/fynks/debrid-services-comparison/issues
|
||||
Expires: 2026-12-31T23:59:59.000Z
|
||||
Preferred-Languages: en
|
||||
Canonical: https://debridcompare.pages.dev/.well-known/security.txt
|
||||
11
dist/browserconfig.xml
vendored
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square70x70logo src="/images/favicon-32x32.png"/>
|
||||
<square150x150logo src="/images/apple-touch-icon.png"/>
|
||||
<square310x310logo src="/images/apple-touch-icon.png"/>
|
||||
<TileColor>#2563eb</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
4232
dist/css/styles.css
vendored
BIN
dist/favicon.ico
vendored
|
Before Width: | Height: | Size: 15 KiB |
5
dist/favicon.svg
vendored
|
|
@ -1,5 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="256" height="256" viewBox="0 0 256 256" xml:space="preserve">
|
||||
<g style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform="translate(1.4065934065934016 1.4065934065934016) scale(2.81 2.81)">
|
||||
<path d="M 71.79 34.614 c -0.334 -0.497 -0.926 -0.745 -1.513 -0.63 l -18.311 3.528 l 3.718 -35.877 c 0.071 -0.682 -0.332 -1.32 -0.979 -1.55 c -0.648 -0.229 -1.362 0.011 -1.738 0.585 L 18.202 53.746 c -0.328 0.5 -0.325 1.144 0.008 1.639 c 0.33 0.493 0.922 0.742 1.513 0.632 l 18.312 -3.529 l -3.718 35.876 c -0.071 0.684 0.332 1.322 0.979 1.551 C 35.455 89.971 35.622 90 35.792 90 c 0.502 0 0.965 -0.251 1.241 -0.67 l 34.765 -53.076 C 72.126 35.754 72.122 35.11 71.79 34.614 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(216,159,0); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
BIN
dist/images/android-chrome-192x192.png
vendored
|
Before Width: | Height: | Size: 8.5 KiB |
BIN
dist/images/android-chrome-512x512.png
vendored
|
Before Width: | Height: | Size: 34 KiB |
BIN
dist/images/apple-touch-icon.png
vendored
|
Before Width: | Height: | Size: 7.7 KiB |
BIN
dist/images/favicon-16x16.png
vendored
|
Before Width: | Height: | Size: 410 B |
BIN
dist/images/favicon-32x32.png
vendored
|
Before Width: | Height: | Size: 924 B |
99
dist/images/flowchart.svg
vendored
|
|
@ -1,99 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 930" style="max-width: 800px;">
|
||||
<defs>
|
||||
<style>
|
||||
/* Light mode (default) */
|
||||
.box { fill: #fff; stroke: #333; stroke-width: 2; }
|
||||
.diamond { fill: #fff; stroke: #333; stroke-width: 2; }
|
||||
.text { font-family: Arial, sans-serif; font-size: 14px; text-anchor: middle; fill: #333; }
|
||||
.arrow { stroke: #333; stroke-width: 2; fill: none; marker-end: url(#arrowhead-light); }
|
||||
.label { font-family: Arial, sans-serif; font-size: 12px; text-anchor: middle; fill: #333; }
|
||||
#arrowhead-light { display: block; }
|
||||
#arrowhead-dark { display: none; }
|
||||
|
||||
/* Dark mode */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.box { fill: #1c1c1c; stroke: #8b949e; stroke-width: 2; }
|
||||
.diamond { fill: #1c1c1c; stroke: #8b949e; stroke-width: 2; }
|
||||
.text { fill: #c9d1d9; }
|
||||
.arrow { stroke: #8b949e; marker-end: url(#arrowhead-dark); }
|
||||
.label { fill: #8b949e; }
|
||||
#arrowhead-light { display: none; }
|
||||
#arrowhead-dark { display: block; }
|
||||
}
|
||||
</style>
|
||||
<marker id="arrowhead-light" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
||||
<polygon points="0 0, 10 3, 0 6" fill="#333" />
|
||||
</marker>
|
||||
<marker id="arrowhead-dark" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
||||
<polygon points="0 0, 10 3, 0 6" fill="#8b949e" />
|
||||
</marker>
|
||||
</defs>
|
||||
|
||||
<!-- Node A -->
|
||||
<rect x="250" y="20" width="300" height="60" rx="5" class="box"/>
|
||||
<text x="400" y="55" class="text">User provides file link or torrent</text>
|
||||
|
||||
<!-- Arrow A to B -->
|
||||
<path d="M 400 80 L 400 130" class="arrow"/>
|
||||
|
||||
<!-- Node B (Diamond) -->
|
||||
<path d="M 400 130 L 500 180 L 400 230 L 300 180 Z" class="diamond"/>
|
||||
<text x="400" y="180" class="text">File on supported</text>
|
||||
<text x="400" y="195" class="text">host?</text>
|
||||
|
||||
<!-- Arrow B to C -->
|
||||
<path d="M 400 230 L 400 270" class="arrow"/>
|
||||
<text x="430" y="255" class="label">Yes</text>
|
||||
|
||||
<!-- Node C -->
|
||||
<rect x="275" y="270" width="250" height="60" rx="5" class="box"/>
|
||||
<text x="400" y="305" class="text">Debrid service fetches file</text>
|
||||
|
||||
<!-- Arrow C to D -->
|
||||
<path d="M 400 330 L 400 370" class="arrow"/>
|
||||
|
||||
<!-- Node D -->
|
||||
<rect x="250" y="370" width="300" height="60" rx="5" class="box"/>
|
||||
<text x="400" y="405" class="text">File cached on high-speed servers</text>
|
||||
|
||||
<!-- Arrow D to E -->
|
||||
<path d="M 400 430 L 400 480" class="arrow"/>
|
||||
|
||||
<!-- Node E (Diamond) -->
|
||||
<path d="M 400 480 L 500 530 L 400 580 L 300 530 Z" class="diamond"/>
|
||||
<text x="400" y="530" class="text">Stream or</text>
|
||||
<text x="400" y="545" class="text">download?</text>
|
||||
|
||||
<!-- Arrow E to F (Stream) -->
|
||||
<path d="M 300 530 L 150 530 L 150 650" class="arrow"/>
|
||||
<text x="200" y="525" class="label">Stream</text>
|
||||
|
||||
<!-- Arrow E to G (Download) -->
|
||||
<path d="M 500 530 L 650 530 L 650 650" class="arrow"/>
|
||||
<text x="600" y="525" class="label">Download</text>
|
||||
|
||||
<!-- Node F -->
|
||||
<rect x="25" y="650" width="250" height="60" rx="5" class="box"/>
|
||||
<text x="150" y="685" class="text">Direct streaming link provided</text>
|
||||
|
||||
<!-- Node G -->
|
||||
<rect x="525" y="650" width="250" height="60" rx="5" class="box"/>
|
||||
<text x="650" y="685" class="text">High-speed download link provided</text>
|
||||
|
||||
<!-- Arrow F to H -->
|
||||
<path d="M 150 710 L 150 750 L 400 750" class="arrow"/>
|
||||
|
||||
<!-- Arrow G to H -->
|
||||
<path d="M 650 710 L 650 750 L 400 750" class="arrow"/>
|
||||
|
||||
<!-- Node H -->
|
||||
<rect x="275" y="750" width="250" height="60" rx="5" class="box"/>
|
||||
<text x="400" y="785" class="text">Access file instantly</text>
|
||||
|
||||
<!-- Arrow H to I -->
|
||||
<path d="M 400 810 L 400 850" class="arrow"/>
|
||||
|
||||
<!-- Node I -->
|
||||
<rect x="250" y="850" width="300" height="60" rx="5" class="box"/>
|
||||
<text x="400" y="885" class="text">File cached for 24-72 hours</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.8 KiB |
BIN
dist/images/og.png
vendored
|
Before Width: | Height: | Size: 438 KiB |
2342
dist/index.html
vendored
2390
dist/js/app.js
vendored
1
dist/json/adult-hosts.json
vendored
|
|
@ -1 +0,0 @@
|
|||
{"Beeg":{"AllDebrid":"✅","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Coomer":{"AllDebrid":"❌","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Drtuber":{"AllDebrid":"✅","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"✅","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Eporner":{"AllDebrid":"❌","RealDebrid":"❌","TorBox":"❌","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Hanime":{"AllDebrid":"❌","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Hentai foundry":{"AllDebrid":"❌","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Kemono":{"AllDebrid":"❌","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Nhentai":{"AllDebrid":"❌","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Pornhub":{"AllDebrid":"✅","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Pornoxo":{"AllDebrid":"✅","RealDebrid":"❌","TorBox":"❌","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Redgifs":{"AllDebrid":"❌","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Redtube":{"AllDebrid":"✅","RealDebrid":"✅","TorBox":"✅","Deepbrid":"✅","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Rule34":{"AllDebrid":"❌","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Spankbang":{"AllDebrid":"✅","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Stripchat":{"AllDebrid":"❌","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Sunporno":{"AllDebrid":"✅","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"✅","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Xhamster":{"AllDebrid":"✅","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Xnxx":{"AllDebrid":"✅","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Xvideos":{"AllDebrid":"✅","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Xxxymovies":{"AllDebrid":"✅","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Youjizz":{"AllDebrid":"✅","RealDebrid":"❌","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"},"Youporn":{"AllDebrid":"❌","RealDebrid":"✅","TorBox":"✅","Deepbrid":"❌","Premiumize":"❌","Mega-Debrid":"❌","High-Way":"❌","LinkSnappy":"❌","Debrid-Link":"❌"}}
|
||||
1
dist/json/file-hosts.json
vendored
25
dist/manifest.json
vendored
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"name": "Debrid Compare",
|
||||
"short_name": "DSC",
|
||||
"start_url": "https://debridcompare.pages.dev",
|
||||
"display": "standalone",
|
||||
"description": "Compare leading debrid / multi-hoster services for pricing, host coverage, policies & tools.",
|
||||
"lang": "en",
|
||||
"dir": "auto",
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"orientation": "any",
|
||||
"icons": [
|
||||
{
|
||||
"src": "images/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "images/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
4
dist/robots.txt
vendored
|
|
@ -1,4 +0,0 @@
|
|||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Sitemap: https://debridcompare.pages.dev/sitemap.xml
|
||||
1
dist/rzd7n8dtydkn3rusq48azrfacbx5zapr.txt
vendored
|
|
@ -1 +0,0 @@
|
|||
rzd7n8dtydkn3rusq48azrfacbx5zapr
|
||||
7
dist/sitemap.xml
vendored
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://debridcompare.pages.dev/</loc>
|
||||
<lastmod>2026-03-22</lastmod>
|
||||
</url>
|
||||
</urlset>
|
||||
BIN
docs/image.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
2453
docs/index.html
Normal file
1
docs/styles.css
Normal file
|
|
@ -0,0 +1 @@
|
|||
:root{--primary:#2563eb;--text:#1f2937;--text-light:#6b7280;--bg:#ffffff;--bg-alt:#f8fafc;--border:#e2e8f0;--radius:.5rem;--shadow:0 1px 3px rgba(0,0,0,.1);--transition:all .2s ease;}body{font-family:-apple-system,BlinkMacSystemFont,'Inter',system-ui,sans-serif;line-height:1.7;max-width:1100px;margin:0 auto;padding:2rem;color:var(--text);background:var(--bg);}h1,h2,h3,h4{margin-top:2.5rem;margin-bottom:1.5rem;font-weight:600;line-height:1.3;color:var(--text);}h1{font-size:2.25rem}h2{font-size:1.875rem}h3{font-size:1.5rem}a{color:var(--primary);text-decoration:none;transition:var(--transition);}a:hover{opacity:.8;text-decoration:underline;}table{width:100%;border-collapse:separate;border-spacing:0;margin:2rem 0;font-size:.95rem;border:1px solid var(--border);border-radius:var(--radius);}th,td{padding:1rem;text-align:left;border-bottom:1px solid var(--border);}th{background-color:var(--primary);color:white;rgba(107,114,128,.507);font-weight:600;top:0;}tr:nth-child(even){background:var(--bg-alt);}tr:hover{background:rgba(37,99,235,.05);transition:var(--transition);}th:first-child{border-top-left-radius:var(--radius);}th:last-child{border-top-right-radius:var(--radius);}tr:last-child td:first-child{border-bottom-left-radius:var(--radius);}tr:last-child td:last-child{border-bottom-right-radius:var(--radius);}#search-container{margin:2rem 0;top:1rem;z-index:100;background:var(--bg);padding:1rem 0;}#search-input{width:90%;padding:.75rem 1rem;border:1px solid var(--border);border-radius:var(--radius);font-size:1rem;transition:var(--transition);margin:auto;}#search-input:focus{outline:none;border-color:var(--primary);box-shadow:0 0 0 3px rgba(37,99,235,.1);}blockquote{margin:2rem 0;padding:1rem 1.5rem;border-left:4px solid var(--primary);background:var(--bg-alt);border-radius:0 var(--radius) var(--radius) 0;}code{background:var(--bg-alt);padding:.2em .4em;border-radius:var(--radius);font-size:.875em;font-family:ui-monospace,'Cascadia Code','Source Code Pro',Menlo,monospace;}@media (max-width:768px){body{padding:1rem}h1{font-size:1.875rem}h2{font-size:1.5rem}h3{font-size:1.25rem}table{border-radius:0;border-left:none;border-right:none}th,td{padding:.75rem;min-width:120px;font-size:.9rem}th{white-space:nowrap}}
|
||||
25
package.json
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"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": "https://debridcompare.pages.dev/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fynks/debrid-services-comparison"
|
||||
},
|
||||
"scripts": {
|
||||
"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",
|
||||
"prune-json": "rm -f dist/json/file-hosts.json dist/json/adult-hosts.json",
|
||||
"build": "npm run minify:css && npm run minify:js && npm run optimize-json && npm run prune-json && workbox generateSW workbox-config.js",
|
||||
"postbuild": "node scripts/replace-assets.js"
|
||||
},
|
||||
"author": "fynks",
|
||||
"dependencies": {
|
||||
"clean-css-cli": "^5.6.3",
|
||||
"terser": "^5.46.0",
|
||||
"workbox-cli": "^7.4.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,191 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# JSON Optimizer Script - Converts host data to indexed format
|
||||
# Converts ✅/❌ format to compact indexed format for better performance
|
||||
# Usage: ./scripts/json-optimizer.sh file-hosts.json
|
||||
# ./scripts/json-optimizer.sh adult-hosts.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 ./json/file-hosts.json file-hosts-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 '✅' values (new format)
|
||||
supported_indices = [
|
||||
service_to_index[service]
|
||||
for service, value in host_data.items()
|
||||
if str(value) == '✅'
|
||||
]
|
||||
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
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
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"';
|
||||
|
||||
// Normalize all stylesheet/script/preload references to minified assets with one hash.
|
||||
const cssHrefPattern = /href=["'](?:\.\/|\/)?css\/(?:styles|styles-min)\.css(?:\?[^"']*)?["']/g;
|
||||
const jsSrcPattern = /src=["'](?:\.\/|\/)?js\/(?:app|app-min)\.js(?:\?[^"']*)?["']/g;
|
||||
const jsHrefPattern = /href=["'](?:\.\/|\/)?js\/(?:app|app-min)\.js(?:\?[^"']*)?["']/g;
|
||||
|
||||
const cssMatches = updatedHeadContent.match(cssHrefPattern);
|
||||
if (cssMatches) {
|
||||
updatedHeadContent = updatedHeadContent.replace(cssHrefPattern, cssTarget);
|
||||
cssReplaced += cssMatches.length;
|
||||
}
|
||||
|
||||
const jsSrcHeadMatches = updatedHeadContent.match(jsSrcPattern);
|
||||
if (jsSrcHeadMatches) {
|
||||
updatedHeadContent = updatedHeadContent.replace(jsSrcPattern, jsTarget);
|
||||
jsReplaced += jsSrcHeadMatches.length;
|
||||
}
|
||||
|
||||
// Preload script links use href (not src), so normalize them too.
|
||||
const jsHrefHeadMatches = updatedHeadContent.match(jsHrefPattern);
|
||||
if (jsHrefHeadMatches) {
|
||||
const jsHrefTarget = jsHash ? `href="/js/app-min.js?v=${jsHash}"` : 'href="/js/app-min.js"';
|
||||
updatedHeadContent = updatedHeadContent.replace(jsHrefPattern, jsHrefTarget);
|
||||
jsReplaced += jsHrefHeadMatches.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;
|
||||
|
||||
const jsSrcBodyMatches = updatedBodyContent.match(jsSrcPattern);
|
||||
if (jsSrcBodyMatches) {
|
||||
updatedBodyContent = updatedBodyContent.replace(jsSrcPattern, jsTarget);
|
||||
jsReplaced += jsSrcBodyMatches.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();
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
module.exports = {
|
||||
// Base directory - still needed for SW generation
|
||||
globDirectory: "dist/",
|
||||
// Explicitly disable precaching for lean SW install
|
||||
globPatterns: [],
|
||||
|
||||
// Enhanced runtime caching strategies
|
||||
runtimeCaching: [
|
||||
// 1. Navigation routes (for SPAs) - Network first with offline fallback
|
||||
{
|
||||
urlPattern: ({ request }) => request.mode === 'navigate',
|
||||
handler: 'NetworkFirst',
|
||||
options: {
|
||||
cacheName: 'navigation-cache',
|
||||
networkTimeoutSeconds: 3, // Fallback to cache after 3s
|
||||
expiration: {
|
||||
maxEntries: 50,
|
||||
maxAgeSeconds: 24 * 60 * 60 // 24 hours
|
||||
},
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200] // Cache successful responses
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 2. HTML pages - Network first for fresh content
|
||||
{
|
||||
urlPattern: /\.html$/i,
|
||||
handler: 'NetworkFirst',
|
||||
options: {
|
||||
cacheName: 'html-cache',
|
||||
networkTimeoutSeconds: 2,
|
||||
expiration: {
|
||||
maxEntries: 50,
|
||||
maxAgeSeconds: 12 * 60 * 60 // 12 hours
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 3. JS/CSS - StaleWhileRevalidate with versioning awareness
|
||||
{
|
||||
urlPattern: /\.(?:js|css)$/i,
|
||||
handler: 'StaleWhileRevalidate',
|
||||
options: {
|
||||
cacheName: 'static-resources',
|
||||
expiration: {
|
||||
maxEntries: 60,
|
||||
maxAgeSeconds: 7 * 24 * 60 * 60, // 7 days
|
||||
purgeOnQuotaError: true // Auto-cleanup when storage is full
|
||||
},
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 4. Images - CacheFirst for performance
|
||||
{
|
||||
urlPattern: /\.(?:png|jpg|jpeg|gif|webp|svg|ico)$/i,
|
||||
handler: 'CacheFirst',
|
||||
options: {
|
||||
cacheName: 'image-cache',
|
||||
expiration: {
|
||||
maxEntries: 200, // More space for images
|
||||
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
|
||||
purgeOnQuotaError: true
|
||||
},
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200]
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
handlerDidError: async () => {
|
||||
// Return fallback image on error (use an existing icon)
|
||||
return caches.match('/favicon.svg');
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// 5. JSON responses (local and API) - NetworkFirst with timeout
|
||||
{
|
||||
urlPattern: ({url}) => /\.json$/i.test(url.pathname) || /\/api\//i.test(url.pathname) || /^https:\/\/api\./i.test(url.href),
|
||||
handler: 'NetworkFirst',
|
||||
options: {
|
||||
cacheName: 'api-cache',
|
||||
networkTimeoutSeconds: 5,
|
||||
expiration: {
|
||||
maxEntries: 100,
|
||||
maxAgeSeconds: 5 * 60 // 5 minutes for fresh API data
|
||||
},
|
||||
cacheableResponse: { statuses: [0, 200] },
|
||||
matchOptions: {
|
||||
ignoreSearch: false // Consider query params
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 8. Google Fonts - CacheFirst
|
||||
{
|
||||
urlPattern: /^https:\/\/fonts\.(?:googleapis|gstatic)\.com/,
|
||||
handler: 'CacheFirst',
|
||||
options: {
|
||||
cacheName: 'google-fonts',
|
||||
expiration: {
|
||||
maxEntries: 30,
|
||||
maxAgeSeconds: 365 * 24 * 60 * 60 // 1 year
|
||||
},
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
// Service worker output
|
||||
swDest: "dist/sw.js",
|
||||
|
||||
// Disable sourcemaps in production
|
||||
sourcemap: false,
|
||||
|
||||
// Immediate activation
|
||||
skipWaiting: true,
|
||||
clientsClaim: true,
|
||||
|
||||
// Additional improvements
|
||||
cleanupOutdatedCaches: true, // Remove old caches automatically
|
||||
navigateFallback: null, // No fallback since no precaching
|
||||
|
||||
// Ignore specific query parameters
|
||||
ignoreURLParametersMatching: [
|
||||
/^utm_/, // Marketing params
|
||||
/^fbclid$/ // Facebook click ID
|
||||
],
|
||||
|
||||
// Maximum file size to cache (15MB)
|
||||
maximumFileSizeToCacheInBytes: 15 * 1024 * 1024,
|
||||
|
||||
// Mode for generated SW
|
||||
mode: 'production'
|
||||
};
|
||||