Skip to content

Commit e5ca21c

Browse files
Universal Update 05/12/2026
Co-Authored-By: M Ramzan Ch <191318204+MegaMind-Solution@users.noreply.github.com>
1 parent fd64146 commit e5ca21c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1873
-13269
lines changed

.browserslistrc

Lines changed: 0 additions & 1 deletion
This file was deleted.

.gitignore

Lines changed: 0 additions & 5 deletions
This file was deleted.

.htmlnanorc

Lines changed: 0 additions & 3 deletions
This file was deleted.

.parcelrc

Lines changed: 0 additions & 5 deletions
This file was deleted.

.vscode/settings.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"cSpell.words": [
3+
"AMOLED",
4+
"cpolyline",
5+
"csvg",
6+
"homescreen"
7+
]
8+
}

README.md

Lines changed: 35 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,50 @@
1-
# DownGD <img src="logo.svg" width="50" height="50" align="left">
1+
# GitZip Pro 🚀
22

3-
> Download directory from a GitHub repo
3+
A powerful, pixel-perfect, single-page web application to download files or folders from GitHub repositories. It supports public URLs, private repositories (via Token), and requires **no server**.
44

5-
GitHub doesn’t let you download a single folder from a repo, which might be necessary when you just need a few files from a large repository.
5+
## ✨ Features
66

7-
This tool will handle the download of all the files in a directory, in a single click, after you entered your token.
7+
- **Download Sub-folders**: Download any specific folder from a repo as a ZIP.
8+
- **Client-Side Only**: Works 100% in the browser (GitHub Pages / Vercel compatible).
9+
- **Smart Routing**: Share links like `mysite.com/#/github.com/user/repo` to auto-start downloads.
10+
- **Private Repo Support**: Enter a Personal Access Token (stored locally) to access private files.
11+
- **Beautiful UI**: Smooth animations, file previews, and progress bars.
12+
- **Theming**: 8 Themes including Dracula, Cyberpunk, AMOLED, and more.
813

9-
> You can create a [new token here](https://github.com/settings/personal-access-tokens/new), [example](https://imgbb.com/VWBGvhHm).
14+
## 🛠️ Installation / Deployment
1015

16+
Since this requires no build step, deployment is instant.
1117

12-
The download starts automatically when you visit pass the link to the GitHub directory as `url` parameter, like:
18+
### Option 1: GitHub Pages (Recommended)
19+
1. Fork this repository (or create a new one).
20+
2. Upload `index.html`, `style.css`, `script.js`, and `wiki.html`.
21+
3. Go to **Settings > Pages**.
22+
4. Select `main` branch and click **Save**.
23+
5. Your site is live!
1324

14-
[**downgd.github.io/downgd.github.io/**`?url=https://github.com/mrdoob/three.js/tree/dev/build`](https://downgd.github.io/downgd.github.io/?url=https://github.com/mrdoob/three.js/tree/dev/build)
25+
### Option 2: Local Use
26+
1. Download the files.
27+
2. Open `index.html` in Chrome/Edge/Firefox.
28+
3. *Note: LocalStorage features work, but some browsers restrict clipboard access on local files.*
1529

16-
You can also specify download filename by adding `filename` parameter, like:
30+
## 🔗 How to Use Smart Links
1731

18-
[**downgd.github.io/downgd.github.io/**`?url=https://github.com/mrdoob/three.js/tree/dev/build&filename=three-js-build`](https://downgd.github.io/downgd.github.io/?url=https://github.com/mrdoob/three.js/tree/dev/build&filename=three-js-build) to save the file as **three-js-build.zip**.
32+
To share a direct download link with a friend, simply add the GitHub URL after the hash (`#`):
1933

20-
This is an alternative to the existing [GitZip](https://kinolien.github.io/gitzip/) and [DownGit](https://minhaskamal.github.io/DownGit/) but without the cruft.
34+
`https://your-site.github.io/#/github.com/facebook/react/tree/main/packages`
2135

22-
## Development Guide
36+
When the user visits this link, the app will:
37+
1. Parse the URL.
38+
2. Auto-fill the input.
39+
3. Immediately start fetching and zipping the folder.
2340

24-
To run the project locally or contribute, follow these steps:
41+
## 🔑 Private Repositories
2542

26-
### Prerequisites
43+
1. Generate a GitHub Token (Settings > Developer Settings > Personal Access Tokens).
44+
2. Scopes needed: `repo` (for private) or just public access.
45+
3. Open GitZip Pro > Click Gear Icon (⚙️).
46+
4. Paste token. It is saved in your browser's LocalStorage and never sent to any 3rd party server.
2747

28-
Make sure you have the following installed:
48+
## 🤝 Contributing
2949

30-
- [Node.js](https://nodejs.org/)
31-
- [Git](https://git-scm.com/)
32-
33-
### Setup
34-
35-
1. **Clone the repository:**
36-
37-
```bash
38-
git clone https://github.com/downgd/downgd.github.io
39-
cd downgd.github.io
40-
```
41-
42-
2. **Install dependencies:**
43-
44-
```bash
45-
npm install
46-
```
47-
48-
3. **Start development server:**
49-
50-
```bash
51-
npm start
52-
53-
# or
54-
55-
npm run watch:build
56-
```
57-
58-
This runs:
59-
60-
* TypeScript in watch mode
61-
* Parcel dev server at [http://localhost:1234](http://localhost:1234)
62-
* Vitest in watch mode for unit testing
63-
64-
## Related
65-
66-
- [list-github-dir-content](https://github.com/fregante/list-github-dir-content) - List all the files in a GitHub repo’s directory
67-
- [Refined GitHub](https://github.com/refined-github/refined-github) - Browser extension that adds a link to this app to GitHub (and much more)
68-
69-
## License
70-
71-
MIT © [M Ramzan Ch](http://twitter.com/rm4814691)
50+
Feel free to open issues or submit PRs. The code is written in vanilla JS/CSS for maximum simplicity and performance.

authenticated-fetch.ts

Lines changed: 0 additions & 39 deletions
This file was deleted.

cha/index.html

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>GitHub Directory Downloader</title>
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<link rel="stylesheet" href="style.css" />
8+
</head>
9+
<body>
10+
11+
<div class="app">
12+
<header>
13+
<h1>GitHub Downloader</h1>
14+
<p>Download files or folders from GitHub instantly</p>
15+
</header>
16+
17+
<section class="input-card">
18+
<input id="githubUrl" placeholder="Paste GitHub file or folder URL here…" />
19+
<input id="tokenInput" type="password" placeholder="GitHub Token (optional)" />
20+
21+
<div class="options">
22+
<label>
23+
<input type="checkbox" id="zipToggle" checked />
24+
Download as ZIP
25+
</label>
26+
27+
<select id="themeSelect"></select>
28+
<input type="color" id="accentPicker" />
29+
</div>
30+
31+
<button id="downloadBtn">Download</button>
32+
</section>
33+
34+
<section id="preview"></section>
35+
36+
<section class="progress">
37+
<div id="progressText"></div>
38+
<div class="progress-bar">
39+
<div id="progressFill"></div>
40+
</div>
41+
</section>
42+
43+
<footer>
44+
<span>Client-side • No server • Open-source ready</span>
45+
</footer>
46+
</div>
47+
48+
<script src="https://cdn.jsdelivr.net/npm/jszip@3.10.1/dist/jszip.min.js"></script>
49+
<script src="https://cdn.jsdelivr.net/npm/file-saver@2.0.5/dist/FileSaver.min.js"></script>
50+
<script src="script.js"></script>
51+
</body>
52+
</html>

cha/script.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
const urlInput = document.getElementById("githubUrl");
2+
const tokenInput = document.getElementById("tokenInput");
3+
const zipToggle = document.getElementById("zipToggle");
4+
const preview = document.getElementById("preview");
5+
const progressText = document.getElementById("progressText");
6+
const progressFill = document.getElementById("progressFill");
7+
const themeSelect = document.getElementById("themeSelect");
8+
const accentPicker = document.getElementById("accentPicker");
9+
10+
const THEMES = ["dark", "light", "dracula", "github", "vscode", "ocean"];
11+
THEMES.forEach(t => {
12+
const o = document.createElement("option");
13+
o.value = t;
14+
o.textContent = t;
15+
themeSelect.appendChild(o);
16+
});
17+
18+
function applyTheme() {
19+
document.documentElement.dataset.theme = themeSelect.value;
20+
document.documentElement.style.setProperty("--accent", accentPicker.value);
21+
localStorage.setItem("theme", themeSelect.value);
22+
localStorage.setItem("accent", accentPicker.value);
23+
}
24+
25+
themeSelect.onchange = applyTheme;
26+
accentPicker.oninput = applyTheme;
27+
28+
themeSelect.value = localStorage.getItem("theme") || "dark";
29+
accentPicker.value = localStorage.getItem("accent") || "#58a6ff";
30+
applyTheme();
31+
32+
tokenInput.value = localStorage.getItem("token") || "";
33+
tokenInput.oninput = () => localStorage.setItem("token", tokenInput.value);
34+
35+
function parseGitHubUrl(url) {
36+
const m = url.match(/github\.com\/([^\/]+)\/([^\/]+)(\/(tree|blob)\/([^\/]+)(\/.*)?)?/);
37+
if (!m) throw "Invalid GitHub URL";
38+
return {
39+
owner: m[1],
40+
repo: m[2],
41+
branch: m[5] || "main",
42+
path: m[6]?.replace(/^\/+/, "") || ""
43+
};
44+
}
45+
46+
async function api(url) {
47+
const headers = {};
48+
if (tokenInput.value) headers.Authorization = `token ${tokenInput.value}`;
49+
const r = await fetch(url, { headers });
50+
if (!r.ok) throw r.status === 404 ? "Repo not found" :
51+
r.status === 403 ? "Rate limit or private repo" :
52+
"Network error";
53+
return r.json();
54+
}
55+
56+
async function fetchRepoTree(info) {
57+
progressText.textContent = "Fetching repository tree…";
58+
const tree = await api(`https://api.github.com/repos/${info.owner}/${info.repo}/git/trees/${info.branch}?recursive=1`);
59+
return tree.tree.filter(f => f.path.startsWith(info.path));
60+
}
61+
62+
async function downloadFolderAsZip(files, info) {
63+
progressText.textContent = "Zipping files…";
64+
const zip = new JSZip();
65+
let i = 0;
66+
for (const f of files) {
67+
if (f.type !== "blob") continue;
68+
const raw = await fetch(`https://raw.githubusercontent.com/${info.owner}/${info.repo}/${info.branch}/${f.path}`);
69+
zip.file(f.path.replace(info.path, ""), await raw.blob());
70+
progressFill.style.width = (++i / files.length * 100) + "%";
71+
}
72+
saveAs(await zip.generateAsync({ type: "blob" }),
73+
`${info.repo}-${info.path.replace(/\//g, "_")}.zip`);
74+
}
75+
76+
async function downloadFile(info) {
77+
const url = `https://raw.githubusercontent.com/${info.owner}/${info.repo}/${info.branch}/${info.path}`;
78+
saveAs(await fetch(url).then(r => r.blob()), info.path.split("/").pop());
79+
}
80+
81+
document.getElementById("downloadBtn").onclick = async () => {
82+
try {
83+
progressFill.style.width = "0%";
84+
const info = parseGitHubUrl(urlInput.value);
85+
localStorage.setItem("lastUrl", urlInput.value);
86+
87+
const files = await fetchRepoTree(info);
88+
preview.innerHTML = files.map(f => `📄 ${f.path}`).join("<br>");
89+
90+
if (files.length === 1 && files[0].type === "blob" && !zipToggle.checked) {
91+
await downloadFile(info);
92+
} else {
93+
await downloadFolderAsZip(files, info);
94+
}
95+
96+
progressText.textContent = "Done";
97+
} catch (e) {
98+
alert(e);
99+
}
100+
};
101+
102+
urlInput.value = new URLSearchParams(location.search).get("url")
103+
|| localStorage.getItem("lastUrl") || "";
104+
105+
document.addEventListener("keydown", e => {
106+
if (e.key === "Enter") document.getElementById("downloadBtn").click();
107+
});

0 commit comments

Comments
 (0)