From d9aef94ed5df725d96bd1fb39338727e8e61b9b6 Mon Sep 17 00:00:00 2001 From: sepandhaghighi Date: Tue, 16 Dec 2025 17:23:56 +0330 Subject: [PATCH 1/6] feat : myip.wtf API IPv4 added --- ipspot/ipv4.py | 33 +++++++++++++++++++++++++++++++++ ipspot/params.py | 1 + 2 files changed, 34 insertions(+) diff --git a/ipspot/ipv4.py b/ipspot/ipv4.py index 2b8e82b..8ce962d 100644 --- a/ipspot/ipv4.py +++ b/ipspot/ipv4.py @@ -466,6 +466,34 @@ def _wtfismyip_com_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]] return {"status": False, "error": str(e)} +def _myip_wtf_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]] + ) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]: + """ + Get public IP and geolocation using myip.wtf. + + :param geo: geolocation flag + :param timeout: timeout value for API + """ + try: + data = _get_json_standard(url="https://json.ipv4.myip.wtf", timeout=timeout) + result = {"status": True, "data": {"ip": data["YourFuckingIPAddress"], "api": "myip.wtf"}} + if geo: + geo_data = { + "city": data.get("YourFuckingCity"), + "region": None, + "country": data.get("YourFuckingCountry"), + "country_code": data.get("YourFuckingCountryCode"), + "latitude": None, + "longitude": None, + "organization": data.get("YourFuckingISP"), + "timezone": None + } + result["data"].update(geo_data) + return result + except Exception as e: + return {"status": False, "error": str(e)} + + IPV4_API_MAP = { IPv4API.IFCONFIG_CO: { "thread_safe": False, @@ -542,6 +570,11 @@ def _wtfismyip_com_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]] "geo": True, "function": _wtfismyip_com_ipv4 }, + IPv4API.MYIP_WTF: { + "thread_safe": True, + "geo": True, + "function": _myip_wtf_ipv4 + }, } diff --git a/ipspot/params.py b/ipspot/params.py index 1c4ebf2..e39128d 100644 --- a/ipspot/params.py +++ b/ipspot/params.py @@ -38,6 +38,7 @@ class IPv4API(Enum): IPQUERY_IO = "ipquery.io" IPWHO_IS = "ipwho.is" WTFISMYIP_COM = "wtfismyip.com" + MYIP_WTF = "myip.wtf" class IPv6API(Enum): From 77a3c73d275ef4fa6f4465ed1fab49af00a152cb Mon Sep 17 00:00:00 2001 From: sepandhaghighi Date: Tue, 16 Dec 2025 17:25:31 +0330 Subject: [PATCH 2/6] feat : myip.wtf API IPv6 added --- ipspot/ipv6.py | 33 +++++++++++++++++++++++++++++++++ ipspot/params.py | 1 + 2 files changed, 34 insertions(+) diff --git a/ipspot/ipv6.py b/ipspot/ipv6.py index a2ca571..7f8ab4c 100644 --- a/ipspot/ipv6.py +++ b/ipspot/ipv6.py @@ -320,6 +320,34 @@ def _wtfismyip_com_ipv6(geo: bool, timeout: Union[float, Tuple[float, float]] return {"status": False, "error": str(e)} +def _myip_wtf_ipv6(geo: bool, timeout: Union[float, Tuple[float, float]] + ) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]: + """ + Get public IP and geolocation using myip.wtf. + + :param geo: geolocation flag + :param timeout: timeout value for API + """ + try: + data = _get_json_standard(url="https://json.ipv6.myip.wtf", timeout=timeout) + result = {"status": True, "data": {"ip": data["YourFuckingIPAddress"], "api": "myip.wtf"}} + if geo: + geo_data = { + "city": data.get("YourFuckingCity"), + "region": None, + "country": data.get("YourFuckingCountry"), + "country_code": data.get("YourFuckingCountryCode"), + "latitude": None, + "longitude": None, + "organization": data.get("YourFuckingISP"), + "timezone": None + } + result["data"].update(geo_data) + return result + except Exception as e: + return {"status": False, "error": str(e)} + + IPV6_API_MAP = { IPv6API.IP_SB: { "thread_safe": True, @@ -371,6 +399,11 @@ def _wtfismyip_com_ipv6(geo: bool, timeout: Union[float, Tuple[float, float]] "geo": True, "function": _wtfismyip_com_ipv6 }, + IPv6API.MYIP_WTF: { + "thread_safe": True, + "geo": True, + "function": _myip_wtf_ipv6 + }, } diff --git a/ipspot/params.py b/ipspot/params.py index e39128d..0d675e0 100644 --- a/ipspot/params.py +++ b/ipspot/params.py @@ -56,6 +56,7 @@ class IPv6API(Enum): MYIP_LA = "myip.la" FREEIPAPI_COM = "freeipapi.com" WTFISMYIP_COM = "wtfismyip.com" + MYIP_WTF = "myip.wtf" PARAMETERS_NAME_MAP = { From 22baf7ff00aeb41c844c463a8a3854d426ba48a8 Mon Sep 17 00:00:00 2001 From: sepandhaghighi Date: Tue, 16 Dec 2025 17:26:19 +0330 Subject: [PATCH 3/6] doc : README.md updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9f3bfc0..c9ba7b5 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,7 @@ Public IP and Location Info: #### IPv4 API -ℹ️ `ipv4-api` valid choices: [`auto-safe`, `auto`, `ip-api.com`, `ipinfo.io`, `ip.sb`, `ident.me`, `tnedi.me`, `ipapi.co`, `ipleak.net`, `my-ip.io`, `ifconfig.co`, `reallyfreegeoip.org`, `freeipapi.com`, `myip.la`, `ipquery.io`, `ipwho.is`, `wtfismyip.com`] +ℹ️ `ipv4-api` valid choices: [`auto-safe`, `auto`, `ip-api.com`, `ipinfo.io`, `ip.sb`, `ident.me`, `tnedi.me`, `ipapi.co`, `ipleak.net`, `my-ip.io`, `ifconfig.co`, `reallyfreegeoip.org`, `freeipapi.com`, `myip.la`, `ipquery.io`, `ipwho.is`, `wtfismyip.com`, `myip.wtf`] ℹ️ The default value: `auto-safe` @@ -230,7 +230,7 @@ Public IP and Location Info: #### IPv6 API -ℹ️ `ipv6-api` valid choices: [`auto-safe`, `auto`, `ip.sb`, `ident.me`, `tnedi.me`, `ipleak.net`, `my-ip.io`, `ifconfig.co`, `reallyfreegeoip.org`, `myip.la`, `freeipapi.com`, `wtfismyip.com`] +ℹ️ `ipv6-api` valid choices: [`auto-safe`, `auto`, `ip.sb`, `ident.me`, `tnedi.me`, `ipleak.net`, `my-ip.io`, `ifconfig.co`, `reallyfreegeoip.org`, `myip.la`, `freeipapi.com`, `wtfismyip.com`, `myip.wtf`] ℹ️ The default value: `auto-safe` From eb743729341bd10349e4f46bdcf029187497f6dd Mon Sep 17 00:00:00 2001 From: sepandhaghighi Date: Tue, 16 Dec 2025 17:27:59 +0330 Subject: [PATCH 4/6] fix : tests updated --- tests/test_ipv4_api.py | 8 ++++++++ tests/test_ipv6_api.py | 10 +++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/test_ipv4_api.py b/tests/test_ipv4_api.py index 942ef75..3a47a52 100644 --- a/tests/test_ipv4_api.py +++ b/tests/test_ipv4_api.py @@ -137,3 +137,11 @@ def test_public_ipv4_wtfismyip_com_success(): assert is_ipv4(result["data"]["ip"]) assert set(result["data"].keys()) == DATA_ITEMS assert result["data"]["api"] == "wtfismyip.com" + + +def test_public_ipv4_myip_wtf_success(): + result = get_public_ipv4(api=IPv4API.MYIP_WTF, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1) + assert result["status"] + assert is_ipv4(result["data"]["ip"]) + assert set(result["data"].keys()) == DATA_ITEMS + assert result["data"]["api"] == "myip.wtf" diff --git a/tests/test_ipv6_api.py b/tests/test_ipv6_api.py index 35d6cf0..1873b8b 100644 --- a/tests/test_ipv6_api.py +++ b/tests/test_ipv6_api.py @@ -95,4 +95,12 @@ def test_public_ipv6_auto_safe_success(): result = get_public_ipv6(api=IPv6API.AUTO_SAFE, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1) assert result["status"] assert is_ipv6(result["data"]["ip"]) - assert set(result["data"].keys()) == DATA_ITEMS \ No newline at end of file + assert set(result["data"].keys()) == DATA_ITEMS + + +def test_public_ipv6_myip_wtf_success(): + result = get_public_ipv6(api=IPv4API.MYIP_WTF, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1) + assert result["status"] + assert is_ipv6(result["data"]["ip"]) + assert set(result["data"].keys()) == DATA_ITEMS + assert result["data"]["api"] == "myip.wtf" \ No newline at end of file From b2c9dcb8ad1edad3a91ce6a3710c4b61aabc9a52 Mon Sep 17 00:00:00 2001 From: sepandhaghighi Date: Tue, 16 Dec 2025 17:28:48 +0330 Subject: [PATCH 5/6] doc : CHANGELOG.md updated --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c912b87..b03154d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] ### Added - Support [wtfismyip.com](https://wtfismyip.com/json) IPv6 API +- Support [myip.wtf](https://myip.wtf/) IPv6 API +- Support [myip.wtf](https://myip.wtf/) IPv4 API ### Changed - `README.md` updated ## [0.7] - 2025-12-09 From ed6294da19653466789a2231f19a1cc24f1007a1 Mon Sep 17 00:00:00 2001 From: sepandhaghighi Date: Wed, 17 Dec 2025 00:03:50 +0330 Subject: [PATCH 6/6] fix : minor edit in IPv6 test --- tests/test_ipv6_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_ipv6_api.py b/tests/test_ipv6_api.py index 1873b8b..0d82723 100644 --- a/tests/test_ipv6_api.py +++ b/tests/test_ipv6_api.py @@ -99,7 +99,7 @@ def test_public_ipv6_auto_safe_success(): def test_public_ipv6_myip_wtf_success(): - result = get_public_ipv6(api=IPv4API.MYIP_WTF, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1) + result = get_public_ipv6(api=IPv6API.MYIP_WTF, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1) assert result["status"] assert is_ipv6(result["data"]["ip"]) assert set(result["data"].keys()) == DATA_ITEMS