├── LICENSE
├── README.md
├── install.py
└── netmirror.py
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Kourva
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | netmirror
4 |
ArtixLinux Mirror Optimizer. Selects fastest mirror in mirrors based on ping ms
5 |
6 |
7 |
8 |
9 | # ▍Preview
10 | Mirror list is inside the main script. so if you want to **add** or **remove** mirrors, edit netmirror file.
11 | Netmirror will ping all mirrors and print the fastest mirror.
12 | Mirrors are for Artix Linux
13 | ```bash
14 | $ netmirror
15 | Ping process started on mirrors...
16 | * mirrors.dotsrc.org [130.225.254.116] 159.792 ms █▓▒░
17 | * mirror.clarkson.edu [128.153.145.19 ] 226.728 ms █▓▒░
18 | * mirror.freedif.org [132.147.122.105] 290.100 ms █▓▒░
19 | * mirror.albony.xyz [188.114.99.0 ] 121.820 ms █▓▒░
20 | * mirrors.cloud.tencent.com [43.152.29.12 ] 126.056 ms █▓▒░
21 | * mirrors.42tm.tech [103.224.182.249] 286.557 ms █▓▒░
22 | * mirror.aarnet.edu.au [202.158.214.106] 477.169 ms █▓▒░
23 |
24 | Fastest mirror: https://mirror.albony.xyz/artix
25 | * speed: 121.82 ms
26 | ```
27 |
28 |
29 | # ▍Setup
30 | Installing **netmirror** is so simple. just follow following steps...
31 | ▢ **⒈Clone repository**
32 | ```bash
33 | git clone https://github.com/Kourva/netmirror
34 | ```
35 | ▢ **⒉Navigate to netmirror directory**
36 | ```bash
37 | cd netmirror/
38 | ```
39 | ▢ **⒊Make files executable**
40 | ```bash
41 | chmod +x install.py netmirror.py
42 | ```
43 | ▢ **⒋Install the netmirror**
44 | ```bash
45 | python install.py
46 | ```
47 |
48 |
49 | # ▍Uninstall
50 | use installer with --uninstall argument to uninstall the netmirror as follows...
51 | ```bash
52 | python install.py --uninstall
53 | ```
54 |
--------------------------------------------------------------------------------
/install.py:
--------------------------------------------------------------------------------
1 | # Libraries
2 | import os, sys, shutil
3 |
4 |
5 | # Function to check root access
6 | def check_root():
7 | return not os.geteuid()
8 |
9 |
10 | # Check if netmirror is already installed
11 | def check_installed():
12 | return os.path.exists("/usr/bin/netmirror")
13 |
14 |
15 | # Installing process
16 | def installer():
17 | if check_installed():
18 | # If package is already installed, print message and exit
19 | print("\ninfo: netmirror is already installed.")
20 | sys.exit(0)
21 |
22 | # Print install message
23 | print("\ninfo: installing netmirror for you.")
24 |
25 | # Copy file to /usr/bin
26 | try:
27 | shutil.copyfile("netmirror.py", "/usr/bin/netmirror")
28 | except:
29 | print("error: failed to copy file to /usr/bin")
30 | sys.exit(1)
31 |
32 | # Change permissions
33 | try:
34 | os.chmod("/usr/bin/netmirror", 0o755)
35 | except:
36 | print("error: failed to set executable permission for /usr/bin/netmirror")
37 | sys.exit(1)
38 |
39 | # Print success message
40 | print("success: netmirror has been installed.")
41 |
42 |
43 | # Uninstalling process
44 | def uninstaller():
45 | # Print uninstall message
46 | print("\ninfo: uninstalling package from your system.")
47 |
48 | # Remove file from /usr/bin
49 | if check_installed():
50 | try:
51 | os.remove("/usr/bin/netmirror")
52 | except:
53 | print("error: failed to remove /usr/bin/netmirror")
54 | sys.exit(1)
55 |
56 | # Print success message
57 | print("success: netmirror has been uninstalled.")
58 | else:
59 | # If package is not installed, print message and exit
60 | print("info: netmirror is not installed.")
61 | sys.exit(0)
62 |
63 |
64 | if __name__ == "__main__":
65 | if check_root():
66 | if len(sys.argv) > 1 and sys.argv[1] == "--uninstall":
67 | uninstaller()
68 | else:
69 | installer()
70 | else:
71 | raise sys.exit("error: you cannot perform this operation unless you are root.")
72 |
--------------------------------------------------------------------------------
/netmirror.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | # ArtixLinux Mirror Optimizer || netmirror
5 | # Author : Kourva
6 | # Source : https://github.com/Kourva/netmirror
7 |
8 |
9 | #*# Imports
10 | import os
11 | import re
12 | import socket
13 | import subprocess
14 | import requests
15 | from urllib.parse import urlparse
16 |
17 |
18 |
19 | #*# Mirrors
20 | url = "https://gitea.artixlinux.org/packages/artix-mirrorlist/raw/branch/master/mirrorlist"
21 | response = requests.get(url)
22 | response.raise_for_status()
23 |
24 | lines = response.text.splitlines()
25 |
26 | #*# Remove Comments and irrelevant things
27 | regexs = [
28 | (r"#.*", ""), # COMMENTS
29 | (r"Server\ =\ ", ""), # Irrelevant placeholder before server link
30 | ]
31 |
32 | #*# Get each mirror from lines extracted from mirrorlist raw file, using re to filter out the links
33 | mirrors = []
34 | for i,line in enumerate(lines, start=1):
35 | for pat, repl in regexs:
36 | line = re.sub(pat, repl, line)
37 | if line.strip() == '':
38 | pass
39 | else:
40 | mirrors.append(line.strip())
41 |
42 | #*# Ping all mirrors
43 | def ping_mirrors():
44 | #*# Get Ip address
45 | ipaddr = lambda url: socket.gethostbyname(urlparse(url).hostname) if urlparse(url).hostname else None
46 |
47 | # Check mirrors
48 | speeds = {}
49 | print("Ping process started on mirrors...")
50 |
51 | # Get terminal size
52 | cols = os.get_terminal_size().columns
53 | info_bar = cols // 2
54 |
55 | for mirror in mirrors:
56 | # Get mirror Ip address
57 | # If server not accessible, then jump it and go to next one.
58 | try:
59 | ipadrs = ipaddr(mirror)
60 | except Exception as e:
61 | print(f"NOT ACCESSIBLE! : {e}")
62 | continue
63 |
64 | _, _, name, *_ = mirror.rsplit("/")
65 | info = name.ljust(info_bar)
66 | print(f" \33[2;36m*\33[m {info} [\33[2;36m{ipadrs.ljust(15)}\33[m]", end=" ")
67 | try:
68 | # Ping mirror
69 | ping_output = subprocess.check_output(
70 | ['ping', '-c', '3', '-q', '-i', '0.2', '-w', '1', ipadrs],
71 | stderr=subprocess.STDOUT,
72 | universal_newlines=True
73 | )
74 | # Find ping ms
75 | match = re.search(r"= (\d+\.\d+)/", ping_output)
76 | if match:
77 | speed_ms = float(match.groups()[0])
78 | speeds[mirror] = speed_ms
79 | if speed_ms <= 150:
80 | print(f"\33[2;32m{match.groups()[0]} ms █▓▒░\33[m", end="\n")
81 | if speed_ms > 150:
82 | print(f"\33[2;33m{match.groups()[0]} ms █▓▒░\33[m", end="\n")
83 |
84 | # Cancel progress when user pressed Ctrl+C
85 | except KeyboardInterrupt:raise SystemExit("\n\33[2;31mGot keyboard Interrupt. Leaving progress!\33[m")
86 | # Except ping error and set mirror unavailable
87 | except:print(f"\33[2;31mFailed █▓▒░\33[m", end="\n")
88 |
89 | # Return mirrors with ping ms
90 | return speeds
91 |
92 | #*# Update Mirrors
93 | def update_mirrors():
94 | # Get mirrors speed
95 | speeds = ping_mirrors()
96 |
97 | # Print no mirrors available if all mirrors down
98 | if not speeds:print("No mirrors available.")
99 |
100 | # Find the fastest mirror and show save prompt
101 | else:
102 | # Sort the mirrors and find best mirror
103 | best_mirror = min(speeds, key=speeds.get)
104 |
105 | # Print fastest mirror
106 | print(f"\nFastest mirror:\33[2;36m {best_mirror}\33[m\n \33[2;36m*\33[m speed: {speeds[best_mirror]} ms")
107 |
108 | #*# Main section
109 | if __name__ == '__main__':update_mirrors()
110 | else:print("error: you cannot perform this operation unless you are root.")
111 |
--------------------------------------------------------------------------------