Skip to content

Instantly share code, notes, and snippets.

@st1vms
Last active March 22, 2025 11:38
Show Gist options
  • Save st1vms/52f3a974c7a60c06ea0b4a726974dd04 to your computer and use it in GitHub Desktop.
Save st1vms/52f3a974c7a60c06ea0b4a726974dd04 to your computer and use it in GitHub Desktop.

Revisions

  1. st1vms revised this gist Nov 6, 2023. 1 changed file with 3 additions and 4 deletions.
    7 changes: 3 additions & 4 deletions protonvpn_rater.py
    Original file line number Diff line number Diff line change
    @@ -48,19 +48,18 @@ def get_free_tier_ratings() -> list[tuple[str, float]] | None:
    print("Error retrieving stats...")
    return None

    tiers = __free_tiers()
    ret = []
    for entry in stats["LogicalServers"]:
    if not "Domain" in entry or not "Load" in entry:
    continue

    domain: str = entry["Domain"]
    load = entry["Load"]

    if domain.split(".")[0] in __free_tiers():
    if domain.split(".")[0] in tiers:
    ret.append((domain, load))

    ret = sorted(ret, key=lambda x: x[1])
    return ret
    return sorted(ret, key=lambda x: x[1])


    def __main() -> None:
  2. st1vms revised this gist Nov 6, 2023. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions protonvpn_rater.py
    Original file line number Diff line number Diff line change
    @@ -56,14 +56,14 @@ def get_free_tier_ratings() -> list[tuple[str, float]] | None:
    domain: str = entry["Domain"]
    load = entry["Load"]

    if domain.split(".")[0] in free_tiers():
    if domain.split(".")[0] in __free_tiers():
    ret.append((domain, load))

    ret = sorted(ret, key=lambda x: x[1])
    return ret


    def main() -> None:
    def __main() -> None:
    """Main"""
    i = 0
    while not i:
    @@ -82,7 +82,7 @@ def main() -> None:
    print(f"{rate[0]} -> {rate[1]}%")


    def free_tiers() -> set:
    def __free_tiers() -> set:
    """Embedded ProtonVPN free tiers domain names."""
    return {
    "node-jp-26",
    @@ -278,4 +278,4 @@ def free_tiers() -> set:


    if __name__ == "__main__":
    main()
    __main()
  3. st1vms created this gist Nov 6, 2023.
    281 changes: 281 additions & 0 deletions protonvpn_rater.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,281 @@
    """Auto retrieve ProtonVPN free-tiers load ratings"""
    from requests import get as http_get

    # Taken from https://account.protonvpn.com/downloads
    # Open dev-tools and look for GET requests to /api/vpn/logicals endpoint
    # Copy the entire cookie header value into this string
    __COOKIE_STRING = ""

    # Also copy the x-pm-uid header value from that same GET request into this string
    __X_PM_UID_STRING = ""

    # Also copy your browser User Agent into this string
    __USER_AGENT = ""


    def __get_json_stats() -> dict | None:
    url = "https://account.protonvpn.com/api/vpn/logicals"

    headers = {
    "Host": "account.protonvpn.com",
    "User-Agent": __USER_AGENT,
    "Accept": "application/vnd.protonmail.v1+json",
    "Accept-Language": "en-US,en;q=0.5",
    "Accept-Encoding": "gzip, deflate, br",
    "Referer": "https://account.protonvpn.com/downloads",
    "x-pm-appversion": "[email protected]",
    "DNT": "1",
    "Connection": "keep-alive",
    "x-pm-uid": __X_PM_UID_STRING,
    "Cookie": __COOKIE_STRING,
    "Sec-Fetch-Dest": "empty",
    "Sec-Fetch-Mode": "cors",
    "Sec-Fetch-Site": "same-origin",
    "TE": "trailers",
    }

    res = http_get(url, headers=headers, timeout=5)
    if res.status_code == 200:
    return res.json()
    return None


    def get_free_tier_ratings() -> list[tuple[str, float]] | None:
    """Retrieves list of tuples, containing ordered domain names with their load number"""

    stats = __get_json_stats()
    if not stats or not "LogicalServers" in stats:
    print("Error retrieving stats...")
    return None

    ret = []
    for entry in stats["LogicalServers"]:
    if not "Domain" in entry or not "Load" in entry:
    continue

    domain: str = entry["Domain"]
    load = entry["Load"]

    if domain.split(".")[0] in free_tiers():
    ret.append((domain, load))

    ret = sorted(ret, key=lambda x: x[1])
    return ret


    def main() -> None:
    """Main"""
    i = 0
    while not i:
    try:
    i = int(input("\nHow many results you want to get?\n>>").strip())
    if i <= 0:
    i = 0
    print("\nMust be a positive value!")
    continue
    except ValueError:
    i = 0
    continue

    ratings = get_free_tier_ratings()
    for rate in ratings[:i]:
    print(f"{rate[0]} -> {rate[1]}%")


    def free_tiers() -> set:
    """Embedded ProtonVPN free tiers domain names."""
    return {
    "node-jp-26",
    "node-nl-141",
    "node-nl-93",
    "node-nl-182",
    "node-us-198",
    "node-nl-161",
    "node-us-91",
    "node-us-61",
    "node-nl-139",
    "node-us-145",
    "node-nl-172",
    "node-us-175",
    "node-us-162",
    "node-nl-185",
    "node-nl-06",
    "node-nl-113",
    "node-nl-83",
    "node-ro-07",
    "node-nl-02",
    "node-nl-191",
    "node-nl-132",
    "node-nl-187",
    "node-nl-162",
    "node-nl-81",
    "node-jp-28",
    "node-nl-134",
    "node-us-128",
    "node-nl-199",
    "node-nl-124",
    "node-nl-123",
    "node-nl-163",
    "node-nl-189",
    "node-nl-98",
    "node-us-151",
    "node-nl-110",
    "node-nl-128",
    "node-jp-13",
    "node-nl-203",
    "node-nl-97",
    "node-us-159",
    "node-us-141",
    "node-us-72",
    "node-nl-180",
    "node-us-155",
    "node-nl-158",
    "node-nl-200",
    "node-nl-156",
    "node-us-191",
    "node-jp-19",
    "node-nl-72",
    "node-jp-24",
    "node-nl-196",
    "node-us-147",
    "node-nl-149",
    "node-nl-140",
    "node-pl-12",
    "node-nl-71",
    "node-nl-148",
    "node-nl-05",
    "node-us-137",
    "node-ro-04",
    "node-nl-94",
    "node-nl-95",
    "node-jp-15",
    "node-nl-130",
    "node-nl-178",
    "node-jp-18",
    "node-nl-68",
    "node-nl-105",
    "node-jp-16",
    "node-ro-03",
    "node-nl-74",
    "node-us-54",
    "node-nl-57",
    "node-us-146",
    "node-nl-76",
    "node-us-184",
    "node-ro-06",
    "node-nl-159",
    "node-nl-181",
    "node-nl-193",
    "node-nl-111",
    "node-jp-27",
    "node-nl-129",
    "node-us-154",
    "node-nl-117",
    "node-nl-150",
    "node-nl-109",
    "node-nl-108",
    "node-nl-142",
    "node-nl-133",
    "node-us-136",
    "node-us-193",
    "node-nl-170",
    "node-us-148",
    "node-nl-173",
    "node-nl-92",
    "node-jp-22",
    "node-us-70",
    "node-nl-79",
    "node-nl-186",
    "node-us-163",
    "node-nl-101",
    "node-us-73",
    "node-us-131",
    "node-us-55",
    "node-nl-197",
    "node-nl-96",
    "node-us-133",
    "node-nl-126",
    "node-jp-21",
    "node-us-47",
    "node-nl-184",
    "node-us-62",
    "node-nl-152",
    "node-nl-147",
    "node-nl-188",
    "node-us-45",
    "node-us-156",
    "node-nl-106",
    "node-us-196",
    "node-us-76",
    "node-us-60",
    "node-us-71",
    "node-nl-70",
    "node-nl-179",
    "node-us-152",
    "node-nl-201",
    "node-nl-102",
    "node-nl-127",
    "node-us-149",
    "node-jp-25",
    "node-nl-164",
    "node-nl-198",
    "node-nl-175",
    "node-us-142",
    "node-nl-137",
    "node-us-170",
    "node-nl-69",
    "node-us-132",
    "node-nl-114",
    "node-us-180",
    "node-us-150",
    "node-nl-90",
    "node-nl-125",
    "node-ro-05",
    "node-nl-154",
    "node-jp-20",
    "node-nl-75",
    "node-us-56",
    "node-pl-13",
    "node-nl-77",
    "node-nl-115",
    "node-nl-82",
    "node-nl-169",
    "node-nl-195",
    "node-nl-176",
    "node-pl-11",
    "node-nl-78",
    "node-nl-177",
    "node-nl-116",
    "node-nl-91",
    "node-nl-103",
    "node-us-78",
    "node-pl-10",
    "node-nl-153",
    "node-nl-138",
    "node-us-81",
    "node-nl-118",
    "node-nl-183",
    "node-us-138",
    "node-us-140",
    "node-jp-23",
    "node-us-139",
    "node-jp-11",
    "node-nl-190",
    "node-nl-160",
    "node-nl-04",
    "node-us-153",
    "node-nl-155",
    "node-nl-104",
    "node-nl-157",
    "node-nl-171",
    "node-pl-09",
    "node-us-157",
    "node-nl-73",
    "node-nl-192",
    "node-nl-03",
    "node-nl-131",
    }


    if __name__ == "__main__":
    main()