├── .github
└── workflows
│ ├── auto-update.yml
│ ├── index.js
│ ├── package-lock.json
│ └── package.json
├── .gitignore
├── README.md
├── all.txt
├── http.txt
├── socks4.txt
└── socks5.txt
/.github/workflows/auto-update.yml:
--------------------------------------------------------------------------------
1 | name: Proxy Updater
2 |
3 | on:
4 | schedule:
5 | - cron: "0 */3 * * *"
6 |
7 | workflow_dispatch:
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 |
12 | strategy:
13 | matrix:
14 | node-version: [16.x]
15 |
16 | steps:
17 | - name: Use Node.js ${{ matrix.node-version }}
18 | uses: actions/setup-node@v3
19 | with:
20 | node-version: ${{ matrix.node-version }}
21 | - uses: actions/checkout@v3
22 |
23 | - run: rm *.txt -rfv
24 | - name: start proxy scraper
25 | run: |
26 | cd .github/workflows
27 | npm ci
28 | node index.js
29 | - name: generating README.md
30 | run: |
31 | echo -e "
\n" > README.md
32 | echo -e "# proxy-list\n" >> README.md
33 | echo -e " [](https://github.com/zevtyardt/proxy-list \"Go to GitHub repo\")" >> README.md
34 | echo -e " [](https://github.com/zevtyardt/proxy-list)" >> README.md
35 | echo -e " [](https://github.com/zevtyardt/proxy-list)\n" >> README.md
36 |
37 | echo -e " [](https://github.com/zevtyardt/proxy-list/actions?query=workflow:\"Proxy+Updater\")" >> README.md
38 | echo -e " " >> README.md
39 | echo -e " [](https://github.com/zevtyardt/proxy-list/commits/main)" >> README.md
40 |
41 | echo -e "\n Ini adalah repository yang saya buat untuk mempermudah saya dan mungkin juga kalian dalam mencari sebuah proxy.\n" >> README.md
42 | echo -e " Repositori ini juga merupakan bagian dari project [proxy-rs](https://github.com/zevtyardt/proxy.rs)\n" >> README.md
43 | echo -e "\n
\n" >> README.md
44 |
45 | echo -e "---" >> README.md
46 | echo -e " - **jumlah proxy:** ±$(cat all.txt | wc -l)" >> README.md
47 | echo -e " - **terakhir diupdate:** $(TZ=Asia/Jakarta date +'%a, %d %b %y %T %Z')\n" >> README.md
48 |
49 | echo -e "#### Unduh" >> README.md
50 | echo -e " Salin dan tempel salah satu kode dibawah ke terminal" >> README.md
51 |
52 | for file in *.txt;
53 | do
54 | echo -e " - **$(echo $file | cut -d'.' -f1 | tr 'a-z' 'A-Z')** ($(cat $file | wc -l))" >> README.md
55 | echo -e " \`\`\`bash" >> README.md
56 | echo -e " curl https://raw.githubusercontent.com/zevtyardt/proxy-list/main/$file -o $file" >> README.md
57 | echo -e " \`\`\`" >> README.md
58 | done
59 |
60 | echo -e "\n#### Proxy Checker" >> README.md
61 | echo -e "Ref: [proxy-rs](https://github.com/zevtyardt/proxy.rs)" >> README.md
62 |
63 | echo -e "\n#### Catatan" >> README.md
64 | echo -e "Jangan lupa kasih ⭐ terus *fork* sama *follow* juga 🥰" >> README.md
65 |
66 | - name: start commit
67 | run: |
68 | git config --local user.name ${{ secrets.name }}
69 | git config --local user.email ${{ secrets.email }}
70 | git status
71 | git add *.txt README.md
72 | git commit -m "update: $(cat all.txt | wc -l) proxies"
73 | - name: push changes
74 | uses: ad-m/github-push-action@master
75 | with:
76 | github_token: ${{ secrets.TOKEN }}
77 | force: true
78 |
--------------------------------------------------------------------------------
/.github/workflows/index.js:
--------------------------------------------------------------------------------
1 | const axios = require("axios");
2 | const cheerio = require("cheerio");
3 | const https = require("https");
4 | const fs = require("fs");
5 |
6 | const PATH = "../..";
7 | const numPage = 200;
8 | const extract_table = (selector, data, custom_cb) => {
9 | const $ = cheerio.load(data);
10 | const table = $(selector);
11 | const head = table
12 | .find("thead")
13 | .find("th")
14 | .toArray()
15 | .map((e) => $(e).text().trim().replace(/\s+/gis, " "));
16 | const body = table
17 | .find("tbody")
18 | .find("tr")
19 | .toArray()
20 | .map((tr) => {
21 | if (custom_cb) return custom_cb($, tr);
22 |
23 | return $(tr)
24 | .find("td")
25 | .toArray()
26 | .map((td) => $(td).text().trim().replace(/\s+/gis, " "));
27 | })
28 | .filter((v) => v.length > 0);
29 | return {
30 | header: head,
31 | body: body,
32 | key: 4,
33 | };
34 | };
35 |
36 | const extract_proxy_list = (data, type) => {
37 | return {
38 | header: ["Ip", "Port", "Type"],
39 | body: data
40 | .split(/\r?\n/)
41 | .filter((v) => v.match(/(?:\d+\.?){4}\s*:\s*\d+/))
42 | .map((value) => [...value.trim().split(/\s*:\s*/), type.toUpperCase()]),
43 | key: 2,
44 | };
45 | };
46 |
47 | const axios_get = async (...args) => {
48 | try {
49 | return await axios.get(...args);
50 | } catch (err) {
51 | return err.response;
52 | }
53 | };
54 |
55 | const axios_post = async (...args) => {
56 | try {
57 | return await axios.post(...args);
58 | } catch (err) {
59 | return err.response;
60 | }
61 | };
62 | // providers
63 |
64 | const proxyscan = async function* () {
65 | const req = await axios_get("https://www.proxyscan.io/", {
66 | httpsAgent: new https.Agent({ rejectUnauthorized: false }),
67 | });
68 | yield extract_table(".table", req.data, ($, tr) => [
69 | $(tr).find("th").text().trim(),
70 | ...$(tr)
71 | .find("td")
72 | .toArray()
73 | .map((td) => $(td).text().trim().replace(/\s+/gis, " ")),
74 | ]);
75 |
76 | for (let type of ["http", "https", "socks4", "socks5"]) {
77 | let req = await axios_get(`https://www.proxyscan.io/download?type=${type}`);
78 | yield extract_proxy_list(req.data, type);
79 | }
80 | };
81 |
82 | const github_raw = async function* () {
83 | for (let type of ["http", "https", "socks4", "socks5"]) {
84 | let req = await axios.get(
85 | `https://raw.githubusercontent.com/ShiftyTR/Proxy-List/master/${type}.txt`
86 | );
87 | yield extract_proxy_list(req.data, type);
88 |
89 | req = await axios_get(
90 | `https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/${type}.txt`
91 | );
92 | yield extract_proxy_list(req.data, type);
93 |
94 | for (let folder of ["proxies", "proxies_anonymous"]) {
95 | for (let type of ["http", "socks4", "socks5"]) {
96 | req = await axios_get(
97 | `https://raw.githubusercontent.com/monosans/proxy-list/main/${folder}/${type}.txt`
98 | );
99 | yield extract_proxy_list(req.data, type);
100 | }
101 | }
102 |
103 | req = await axios_get(
104 | "https://raw.githubusercontent.com/hookzof/socks5_list/master/proxy.txt"
105 | );
106 | yield extract_proxy_list(req.data, "socks5");
107 | }
108 | };
109 |
110 | const api_openproxylist = async function* () {
111 | for (let type of ["http", "socks4", "socks5"]) {
112 | const req = await axios_get(`https://api.openproxylist.xyz/${type}.txt`);
113 | yield extract_proxy_list(req.data, type);
114 | }
115 | };
116 |
117 | const proxy_daily = async function* () {
118 | const types = ["HTTP", "SOCKS4", "SOCKS5"];
119 | const req = await axios_get("https://proxy-daily.com/");
120 | const $ = cheerio.load(req.data);
121 |
122 | const proxies = $(".freeProxyStyle");
123 | for (let i = 0; i < proxies.length; i++) {
124 | yield extract_proxy_list($(proxies[i]).text(), types[i]);
125 | }
126 | };
127 |
128 | const scrapingant = async () => {
129 | const req = await axios_get("https://scrapingant.com/proxies");
130 |
131 | const $ = cheerio.load(req.data);
132 | const dt = $("tr")
133 | .toArray()
134 | .map((v) => $(v).text().trim().split(/\n */));
135 |
136 | return {
137 | header: dt.shift(),
138 | body: dt,
139 | key: 2,
140 | };
141 | };
142 |
143 | const socks_proxy_net = async () => {
144 | const req = await axios_get("https://www.socks-proxy.net/");
145 | return extract_table(".table-striped", req.data);
146 | };
147 |
148 | const us_proxy = async () => {
149 | const req = await axios_get("https://us-proxy.org/");
150 | return extract_table(".table-striped", req.data);
151 | };
152 |
153 | const sslproxies = async () => {
154 | const req = await axios_get("https://www.sslproxies.org/");
155 | const data = extract_table(".table-striped", req.data);
156 | data.key = "HTTP";
157 | return data;
158 | };
159 |
160 | const free_proxy_list = async () => {
161 | const req = await axios_get("https://free-proxy-list.net/");
162 | const data = extract_table(".table-striped", req.data);
163 | return data;
164 | };
165 |
166 | const proxyscrape = async () => {
167 | const data = [];
168 | for (let proto of ["http", "socks4", "socks5"]) {
169 | const req = await axios_get(
170 | `https://api.proxyscrape.com/v2/?request=displayproxies&protocol=${proto}}&timeout=10000&country=all&ssl=all&anonymity=all`
171 | );
172 | const lines = req.data.split(/\r?\n/);
173 | for (let line of lines) {
174 | if (line.indexOf(":") < 0) continue;
175 | data.push([...line.trim().split(/\s*:\s*/), proto.toUpperCase()]);
176 | }
177 | }
178 | return {
179 | header: ["Ip", "Port", "Protocol"],
180 | body: data,
181 | key: 2,
182 | };
183 | };
184 |
185 | const proxynova = async () => {
186 | const req = await axios_get("https://api.proxynova.com/proxylist");
187 | const data = [];
188 | for (let dt of req.data.data || []) {
189 | dt.ip = eval(dt.ip);
190 | data.push([
191 | dt.ip,
192 | dt.port,
193 | `${dt.countryCode} ${dt.countryName} ${dt.cityName}`,
194 | dt.hostname,
195 | dt.asn,
196 | ]);
197 | }
198 |
199 | return {
200 | header: ["Ip", "Port", "Country", "Hostname", "ASN"],
201 | body: data,
202 | key: "HTTP",
203 | };
204 | };
205 |
206 | const hidemy = async function* () {
207 | const origin = "https://hidemy.name";
208 |
209 | let path = "/en/proxy-list";
210 | for (let i = 0; i < numPage; i++) {
211 | if (!path) break;
212 | const req = await axios_get(origin + path);
213 | yield extract_table("table", req.data);
214 |
215 | path = cheerio.load(req.data)("li.next_array").find("a")[0]?.attribs?.href;
216 | }
217 | };
218 |
219 | const freeproxy_world = async function* () {
220 | for (let i = 0; i < numPage; i++) {
221 | const req = await axios_get(
222 | `https://freeproxy.world/?type=&anonymity=&country=&speed=&port=&page=${i}`
223 | );
224 | const data = extract_table("table", req.data);
225 | if (data.body.length == 0) break;
226 | data.key = 5;
227 | yield data;
228 | }
229 | };
230 |
231 | const proxylist_org = async function* () {
232 | let page = 1;
233 | while (true) {
234 | const req = await axios_get(
235 | `https://proxy-list.org/english/index.php?p=${page}`
236 | );
237 | const $ = cheerio.load(req.data);
238 |
239 | const table = $(".proxy-table");
240 | const head = table
241 | .find(".header-row")
242 | .find("li")
243 | .toArray()
244 | .map((e) => $(e).text().trim().replace(/\s+/gis, " "));
245 |
246 | const body = table
247 | .find(".table")
248 | .find("ul")
249 | .toArray()
250 | .map((ul) => {
251 | const dt = $(ul)
252 | .find("li")
253 | .toArray()
254 | .map((td) => $(td).text().trim().replace(/\s+/gis, " "));
255 | const [ip, port] = Buffer.from(
256 | dt.shift().match(/["']([^"']+)/)[1],
257 | "base64"
258 | )
259 | .toString()
260 | .split(":");
261 | dt.splice(0, 0, ip, port);
262 | return dt;
263 | })
264 | .filter((v) => v.length > 0);
265 |
266 | head.shift();
267 | head.splice(0, 0, "Ip", "Port");
268 |
269 | if (body.length < 1) break;
270 |
271 | yield {
272 | header: head,
273 | body: body,
274 | key: 4,
275 | };
276 | page++;
277 | }
278 | };
279 |
280 | const iplocation = async function* () {
281 | let page = 0;
282 | while (true) {
283 | const req = await axios_get(
284 | `https://www.iplocation.net/proxy-list/index/${page}`
285 | );
286 | const $ = cheerio.load(req.data);
287 |
288 | const table = $("table");
289 | const head = table
290 | .find("thead")
291 | .find("th")
292 | .toArray()
293 | .map((e) => $(e).text().trim().replace(/\s+/gis, " "))
294 | .splice(0, 4);
295 |
296 | const body = table
297 | .find("tbody")
298 | .find("tr")
299 | .toArray()
300 | .map((tr) =>
301 | $(tr)
302 | .find("td")
303 | .toArray()
304 | .map((e) => $(e).text().trim().replace(/\s+/gis, " "))
305 | .splice(0, 4)
306 | )
307 | .filter((v) => v.length > 0);
308 | if (body.length < 1) break;
309 | yield {
310 | header: head,
311 | body: body,
312 | key: "HTTP",
313 | };
314 | page = page + 10;
315 | }
316 | };
317 |
318 | const my_proxy = async () => {
319 | const req = await axios_get("https://www.my-proxy.com/free-proxy-list.html");
320 | return {
321 | header: ["Ip", "Port", "Country Code"],
322 | body: [
323 | ...req.data.matchAll(
324 | /(?(?:\d+\.?){4}):(?\d+)#(?[A-Z]+)/gi
325 | ),
326 | ].map((v) => Object.values(v.groups)),
327 | key: "HTTP",
328 | };
329 | };
330 |
331 | const spysone = async function* () {
332 | for (let path of [
333 | "free-proxy-list",
334 | "anonymous-proxy-list",
335 | "http-proxy-list",
336 | "https-ssl-proxy",
337 | "non-anonymous-proxy-list",
338 | "socks-proxy-list",
339 | ]) {
340 | const url = `https://spys.one/en/${path}`;
341 |
342 | let req = await axios_get(url);
343 | let $ = cheerio.load(req.data);
344 | const postData = {};
345 | $("input").each((_, e) => (postData[e.attribs.name] = e.attribs.value));
346 | $("select").each((_, e) => {
347 | postData[e.attribs.name] =
348 | $(e.previousSibling).text().trim().toLowerCase() == "show"
349 | ? "5"
350 | : $(e)
351 | .find("option")
352 | .toArray()
353 | .filter((v) => v.attribs.selected !== undefined)[0].attribs.value;
354 | });
355 | req = await axios_post(url, postData);
356 | $ = cheerio.load(req.data);
357 | const vars = {};
358 | $(
359 | $("script")
360 | .toArray()
361 | .filter((e) => e.previousSibling?.name == "table")
362 | )
363 | .toArray()
364 | .forEach((script) => {
365 | script = $(script)
366 | .text()
367 | .split(";")
368 | .map((x) => x.split("="));
369 | for (let [k, v] of script) {
370 | if (!v) continue;
371 | try {
372 | if (/^\d+$/.test(v)) {
373 | vars[k] = parseInt(v);
374 | } else {
375 | for (let [c, n] of Object.entries(vars)) {
376 | if (v?.indexOf(c) >= 0) v = v.replace(c, n);
377 | }
378 | vars[k] = eval(v);
379 | }
380 | } catch (_) {
381 | return;
382 | }
383 | }
384 | });
385 | let tr = $("tr.spy1x").toArray();
386 | tr = tr.concat($("tr.spy1xx").toArray());
387 | tr = tr.map((e) =>
388 | $(e)
389 | .find("td")
390 | .toArray()
391 | .map((td) => $(td).text().trim())
392 | );
393 | const head = ["Ip", "Port", ...tr.shift().slice(1)];
394 | const body = tr.map((e) => {
395 | let [ip, port] = e.shift().split(/document.*?>"\+/);
396 | for (let o of new Set(port.match(/([a-z0-9]+)/gi))) {
397 | port = port.replace(new RegExp(o, "g"), vars[o]);
398 | }
399 | try {
400 | return [
401 | ip,
402 | port
403 | .slice(0, port.length - 1)
404 | .match(/\([^\)]+\)/g)
405 | .map((e) => eval(e))
406 | .join(""),
407 | e.shift().replace(/\s*\(.*?\)\s*/, ""),
408 | ...e,
409 | ];
410 | } catch (_) {}
411 | });
412 | yield { header: head, body: body, key: 2 };
413 | }
414 | };
415 |
416 | // MAIN PROGRAM
417 |
418 | //fs.mkdir(`${PATH}/csv/`, () => {});
419 |
420 | const main = async () => {
421 | const unique = {};
422 | let total = 0;
423 | const outs = { all: fs.createWriteStream(`${PATH}/all.txt`) };
424 | for (let raw_provider of [
425 | spysone,
426 | proxy_daily,
427 | my_proxy,
428 | iplocation,
429 | proxylist_org,
430 | proxynova,
431 | api_openproxylist,
432 | freeproxy_world,
433 | us_proxy,
434 | sslproxies,
435 | proxyscrape,
436 | scrapingant,
437 | github_raw,
438 | socks_proxy_net,
439 | free_proxy_list,
440 | proxyscan,
441 | hidemy,
442 | ]) {
443 | let provider;
444 | if (!raw_provider.constructor.name.startsWith("AsyncGen"))
445 | provider = async function* () {
446 | yield await raw_provider();
447 | };
448 | else provider = raw_provider;
449 | console.log(`> get_proxies from ${raw_provider.name}`);
450 |
451 | const generator = provider();
452 | let page = 1;
453 | while (true) {
454 | try {
455 | const { value: result, done } = await generator.next();
456 | if (!result && done) break;
457 |
458 | result.body.forEach((value) => {
459 | if (!value || value.length != result.header.length) return;
460 |
461 | const types = (
462 | typeof result.key == "string"
463 | ? result.key.toLowerCase()
464 | : value[result.key].toLowerCase()
465 | ).replace(/\s*proxy\s*/, "");
466 |
467 | for (let type of types.split(/\s*[, ]\s*/)) {
468 | //if (typeof result.key != "string") value[result.key] = type;
469 | type = type.indexOf("socks") >= 0 ? type : "http";
470 |
471 | if (!outs[type]) {
472 | unique[type] = new Set();
473 | outs[type] = fs.createWriteStream(`${PATH}/${type}.txt`);
474 | }
475 |
476 | const proxy = `${value[result.ip || 0]}:${value[result.port || 1]}`;
477 | if (unique[type].has(proxy)) return;
478 | outs[type].write(proxy + "\n");
479 | outs.all.write(proxy + "\n");
480 | unique[type].add(proxy);
481 | total++;
482 | }
483 | });
484 | console.log(`< done added ${result.body.length} proxies: ${page}`);
485 | } catch (_) {
486 | console.log("! failed scrape proxy: " + page);
487 | console.error(_);
488 | }
489 | page++;
490 | }
491 | }
492 | console.log(`< total proxy: ${total}`);
493 | };
494 |
495 | main();
496 |
--------------------------------------------------------------------------------
/.github/workflows/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "workflows",
3 | "lockfileVersion": 2,
4 | "requires": true,
5 | "packages": {
6 | "": {
7 | "dependencies": {
8 | "axios": "^1.1.3",
9 | "cheerio": "^1.0.0-rc.12"
10 | }
11 | },
12 | "node_modules/asynckit": {
13 | "version": "0.4.0",
14 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
15 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
16 | },
17 | "node_modules/axios": {
18 | "version": "1.1.3",
19 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.3.tgz",
20 | "integrity": "sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==",
21 | "dependencies": {
22 | "follow-redirects": "^1.15.0",
23 | "form-data": "^4.0.0",
24 | "proxy-from-env": "^1.1.0"
25 | }
26 | },
27 | "node_modules/boolbase": {
28 | "version": "1.0.0",
29 | "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
30 | "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
31 | },
32 | "node_modules/cheerio": {
33 | "version": "1.0.0-rc.12",
34 | "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
35 | "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
36 | "dependencies": {
37 | "cheerio-select": "^2.1.0",
38 | "dom-serializer": "^2.0.0",
39 | "domhandler": "^5.0.3",
40 | "domutils": "^3.0.1",
41 | "htmlparser2": "^8.0.1",
42 | "parse5": "^7.0.0",
43 | "parse5-htmlparser2-tree-adapter": "^7.0.0"
44 | },
45 | "engines": {
46 | "node": ">= 6"
47 | },
48 | "funding": {
49 | "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
50 | }
51 | },
52 | "node_modules/cheerio-select": {
53 | "version": "2.1.0",
54 | "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
55 | "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
56 | "dependencies": {
57 | "boolbase": "^1.0.0",
58 | "css-select": "^5.1.0",
59 | "css-what": "^6.1.0",
60 | "domelementtype": "^2.3.0",
61 | "domhandler": "^5.0.3",
62 | "domutils": "^3.0.1"
63 | },
64 | "funding": {
65 | "url": "https://github.com/sponsors/fb55"
66 | }
67 | },
68 | "node_modules/combined-stream": {
69 | "version": "1.0.8",
70 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
71 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
72 | "dependencies": {
73 | "delayed-stream": "~1.0.0"
74 | },
75 | "engines": {
76 | "node": ">= 0.8"
77 | }
78 | },
79 | "node_modules/css-select": {
80 | "version": "5.1.0",
81 | "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
82 | "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
83 | "dependencies": {
84 | "boolbase": "^1.0.0",
85 | "css-what": "^6.1.0",
86 | "domhandler": "^5.0.2",
87 | "domutils": "^3.0.1",
88 | "nth-check": "^2.0.1"
89 | },
90 | "funding": {
91 | "url": "https://github.com/sponsors/fb55"
92 | }
93 | },
94 | "node_modules/css-what": {
95 | "version": "6.1.0",
96 | "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
97 | "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
98 | "engines": {
99 | "node": ">= 6"
100 | },
101 | "funding": {
102 | "url": "https://github.com/sponsors/fb55"
103 | }
104 | },
105 | "node_modules/delayed-stream": {
106 | "version": "1.0.0",
107 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
108 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
109 | "engines": {
110 | "node": ">=0.4.0"
111 | }
112 | },
113 | "node_modules/dom-serializer": {
114 | "version": "2.0.0",
115 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
116 | "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
117 | "dependencies": {
118 | "domelementtype": "^2.3.0",
119 | "domhandler": "^5.0.2",
120 | "entities": "^4.2.0"
121 | },
122 | "funding": {
123 | "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
124 | }
125 | },
126 | "node_modules/domelementtype": {
127 | "version": "2.3.0",
128 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
129 | "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
130 | "funding": [
131 | {
132 | "type": "github",
133 | "url": "https://github.com/sponsors/fb55"
134 | }
135 | ]
136 | },
137 | "node_modules/domhandler": {
138 | "version": "5.0.3",
139 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
140 | "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
141 | "dependencies": {
142 | "domelementtype": "^2.3.0"
143 | },
144 | "engines": {
145 | "node": ">= 4"
146 | },
147 | "funding": {
148 | "url": "https://github.com/fb55/domhandler?sponsor=1"
149 | }
150 | },
151 | "node_modules/domutils": {
152 | "version": "3.0.1",
153 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
154 | "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
155 | "dependencies": {
156 | "dom-serializer": "^2.0.0",
157 | "domelementtype": "^2.3.0",
158 | "domhandler": "^5.0.1"
159 | },
160 | "funding": {
161 | "url": "https://github.com/fb55/domutils?sponsor=1"
162 | }
163 | },
164 | "node_modules/entities": {
165 | "version": "4.4.0",
166 | "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
167 | "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
168 | "engines": {
169 | "node": ">=0.12"
170 | },
171 | "funding": {
172 | "url": "https://github.com/fb55/entities?sponsor=1"
173 | }
174 | },
175 | "node_modules/follow-redirects": {
176 | "version": "1.15.2",
177 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
178 | "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
179 | "funding": [
180 | {
181 | "type": "individual",
182 | "url": "https://github.com/sponsors/RubenVerborgh"
183 | }
184 | ],
185 | "engines": {
186 | "node": ">=4.0"
187 | },
188 | "peerDependenciesMeta": {
189 | "debug": {
190 | "optional": true
191 | }
192 | }
193 | },
194 | "node_modules/form-data": {
195 | "version": "4.0.0",
196 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
197 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
198 | "dependencies": {
199 | "asynckit": "^0.4.0",
200 | "combined-stream": "^1.0.8",
201 | "mime-types": "^2.1.12"
202 | },
203 | "engines": {
204 | "node": ">= 6"
205 | }
206 | },
207 | "node_modules/htmlparser2": {
208 | "version": "8.0.1",
209 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
210 | "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==",
211 | "funding": [
212 | "https://github.com/fb55/htmlparser2?sponsor=1",
213 | {
214 | "type": "github",
215 | "url": "https://github.com/sponsors/fb55"
216 | }
217 | ],
218 | "dependencies": {
219 | "domelementtype": "^2.3.0",
220 | "domhandler": "^5.0.2",
221 | "domutils": "^3.0.1",
222 | "entities": "^4.3.0"
223 | }
224 | },
225 | "node_modules/mime-db": {
226 | "version": "1.52.0",
227 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
228 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
229 | "engines": {
230 | "node": ">= 0.6"
231 | }
232 | },
233 | "node_modules/mime-types": {
234 | "version": "2.1.35",
235 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
236 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
237 | "dependencies": {
238 | "mime-db": "1.52.0"
239 | },
240 | "engines": {
241 | "node": ">= 0.6"
242 | }
243 | },
244 | "node_modules/nth-check": {
245 | "version": "2.1.1",
246 | "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
247 | "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
248 | "dependencies": {
249 | "boolbase": "^1.0.0"
250 | },
251 | "funding": {
252 | "url": "https://github.com/fb55/nth-check?sponsor=1"
253 | }
254 | },
255 | "node_modules/parse5": {
256 | "version": "7.1.1",
257 | "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz",
258 | "integrity": "sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==",
259 | "dependencies": {
260 | "entities": "^4.4.0"
261 | },
262 | "funding": {
263 | "url": "https://github.com/inikulin/parse5?sponsor=1"
264 | }
265 | },
266 | "node_modules/parse5-htmlparser2-tree-adapter": {
267 | "version": "7.0.0",
268 | "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
269 | "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
270 | "dependencies": {
271 | "domhandler": "^5.0.2",
272 | "parse5": "^7.0.0"
273 | },
274 | "funding": {
275 | "url": "https://github.com/inikulin/parse5?sponsor=1"
276 | }
277 | },
278 | "node_modules/proxy-from-env": {
279 | "version": "1.1.0",
280 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
281 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
282 | }
283 | },
284 | "dependencies": {
285 | "asynckit": {
286 | "version": "0.4.0",
287 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
288 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
289 | },
290 | "axios": {
291 | "version": "1.1.3",
292 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.3.tgz",
293 | "integrity": "sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==",
294 | "requires": {
295 | "follow-redirects": "^1.15.0",
296 | "form-data": "^4.0.0",
297 | "proxy-from-env": "^1.1.0"
298 | }
299 | },
300 | "boolbase": {
301 | "version": "1.0.0",
302 | "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
303 | "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
304 | },
305 | "cheerio": {
306 | "version": "1.0.0-rc.12",
307 | "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
308 | "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
309 | "requires": {
310 | "cheerio-select": "^2.1.0",
311 | "dom-serializer": "^2.0.0",
312 | "domhandler": "^5.0.3",
313 | "domutils": "^3.0.1",
314 | "htmlparser2": "^8.0.1",
315 | "parse5": "^7.0.0",
316 | "parse5-htmlparser2-tree-adapter": "^7.0.0"
317 | }
318 | },
319 | "cheerio-select": {
320 | "version": "2.1.0",
321 | "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
322 | "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
323 | "requires": {
324 | "boolbase": "^1.0.0",
325 | "css-select": "^5.1.0",
326 | "css-what": "^6.1.0",
327 | "domelementtype": "^2.3.0",
328 | "domhandler": "^5.0.3",
329 | "domutils": "^3.0.1"
330 | }
331 | },
332 | "combined-stream": {
333 | "version": "1.0.8",
334 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
335 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
336 | "requires": {
337 | "delayed-stream": "~1.0.0"
338 | }
339 | },
340 | "css-select": {
341 | "version": "5.1.0",
342 | "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
343 | "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
344 | "requires": {
345 | "boolbase": "^1.0.0",
346 | "css-what": "^6.1.0",
347 | "domhandler": "^5.0.2",
348 | "domutils": "^3.0.1",
349 | "nth-check": "^2.0.1"
350 | }
351 | },
352 | "css-what": {
353 | "version": "6.1.0",
354 | "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
355 | "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw=="
356 | },
357 | "delayed-stream": {
358 | "version": "1.0.0",
359 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
360 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
361 | },
362 | "dom-serializer": {
363 | "version": "2.0.0",
364 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
365 | "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
366 | "requires": {
367 | "domelementtype": "^2.3.0",
368 | "domhandler": "^5.0.2",
369 | "entities": "^4.2.0"
370 | }
371 | },
372 | "domelementtype": {
373 | "version": "2.3.0",
374 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
375 | "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
376 | },
377 | "domhandler": {
378 | "version": "5.0.3",
379 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
380 | "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
381 | "requires": {
382 | "domelementtype": "^2.3.0"
383 | }
384 | },
385 | "domutils": {
386 | "version": "3.0.1",
387 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
388 | "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
389 | "requires": {
390 | "dom-serializer": "^2.0.0",
391 | "domelementtype": "^2.3.0",
392 | "domhandler": "^5.0.1"
393 | }
394 | },
395 | "entities": {
396 | "version": "4.4.0",
397 | "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
398 | "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA=="
399 | },
400 | "follow-redirects": {
401 | "version": "1.15.2",
402 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
403 | "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
404 | },
405 | "form-data": {
406 | "version": "4.0.0",
407 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
408 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
409 | "requires": {
410 | "asynckit": "^0.4.0",
411 | "combined-stream": "^1.0.8",
412 | "mime-types": "^2.1.12"
413 | }
414 | },
415 | "htmlparser2": {
416 | "version": "8.0.1",
417 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
418 | "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==",
419 | "requires": {
420 | "domelementtype": "^2.3.0",
421 | "domhandler": "^5.0.2",
422 | "domutils": "^3.0.1",
423 | "entities": "^4.3.0"
424 | }
425 | },
426 | "mime-db": {
427 | "version": "1.52.0",
428 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
429 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
430 | },
431 | "mime-types": {
432 | "version": "2.1.35",
433 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
434 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
435 | "requires": {
436 | "mime-db": "1.52.0"
437 | }
438 | },
439 | "nth-check": {
440 | "version": "2.1.1",
441 | "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
442 | "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
443 | "requires": {
444 | "boolbase": "^1.0.0"
445 | }
446 | },
447 | "parse5": {
448 | "version": "7.1.1",
449 | "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz",
450 | "integrity": "sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==",
451 | "requires": {
452 | "entities": "^4.4.0"
453 | }
454 | },
455 | "parse5-htmlparser2-tree-adapter": {
456 | "version": "7.0.0",
457 | "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
458 | "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
459 | "requires": {
460 | "domhandler": "^5.0.2",
461 | "parse5": "^7.0.0"
462 | }
463 | },
464 | "proxy-from-env": {
465 | "version": "1.1.0",
466 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
467 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
468 | }
469 | }
470 | }
471 |
--------------------------------------------------------------------------------
/.github/workflows/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "axios": "^1.1.3",
4 | "cheerio": "^1.0.0-rc.12"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # proxy-list
4 |
5 | [](https://github.com/zevtyardt/proxy-list "Go to GitHub repo")
6 | [](https://github.com/zevtyardt/proxy-list)
7 | [](https://github.com/zevtyardt/proxy-list)
8 |
9 | [](https://github.com/zevtyardt/proxy-list/actions?query=workflow:"Proxy+Updater")
10 | 
11 | [](https://github.com/zevtyardt/proxy-list/commits/main)
12 |
13 | Ini adalah repository yang saya buat untuk mempermudah saya dan mungkin juga kalian dalam mencari sebuah proxy.
14 |
15 | Repositori ini juga merupakan bagian dari project [proxy-rs](https://github.com/zevtyardt/proxy.rs)
16 |
17 |
18 |
19 |
20 | ---
21 | - **jumlah proxy:** ±195585
22 | - **terakhir diupdate:** Tue, 10 Jun 25 22:27:24 WIB
23 |
24 | #### Unduh
25 | Salin dan tempel salah satu kode dibawah ke terminal
26 | - **ALL** (195585)
27 | ```bash
28 | curl https://raw.githubusercontent.com/zevtyardt/proxy-list/main/all.txt -o all.txt
29 | ```
30 | - **HTTP** (85140)
31 | ```bash
32 | curl https://raw.githubusercontent.com/zevtyardt/proxy-list/main/http.txt -o http.txt
33 | ```
34 | - **SOCKS4** (93199)
35 | ```bash
36 | curl https://raw.githubusercontent.com/zevtyardt/proxy-list/main/socks4.txt -o socks4.txt
37 | ```
38 | - **SOCKS5** (17246)
39 | ```bash
40 | curl https://raw.githubusercontent.com/zevtyardt/proxy-list/main/socks5.txt -o socks5.txt
41 | ```
42 |
43 | #### Proxy Checker
44 | Ref: [proxy-rs](https://github.com/zevtyardt/proxy.rs)
45 |
46 | #### Catatan
47 | Jangan lupa kasih ⭐ terus *fork* sama *follow* juga 🥰
48 |
--------------------------------------------------------------------------------