pihole6api 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pihole6api/client.py +5 -1
- pihole6api/config.py +47 -0
- pihole6api/conn.py +12 -1
- pihole6api/metrics.py +148 -38
- {pihole6api-0.1.0.dist-info → pihole6api-0.1.2.dist-info}/METADATA +3 -3
- {pihole6api-0.1.0.dist-info → pihole6api-0.1.2.dist-info}/RECORD +9 -9
- {pihole6api-0.1.0.dist-info → pihole6api-0.1.2.dist-info}/LICENSE +0 -0
- {pihole6api-0.1.0.dist-info → pihole6api-0.1.2.dist-info}/WHEEL +0 -0
- {pihole6api-0.1.0.dist-info → pihole6api-0.1.2.dist-info}/top_level.txt +0 -0
pihole6api/client.py
CHANGED
@@ -41,4 +41,8 @@ class PiHole6Client:
|
|
41
41
|
:param full: Boolean flag to get the full dataset.
|
42
42
|
:return: API response containing PADD summary.
|
43
43
|
"""
|
44
|
-
return self.connection.get("padd", params={"full": str(full).lower()})
|
44
|
+
return self.connection.get("padd", params={"full": str(full).lower()})
|
45
|
+
|
46
|
+
def close_session(self):
|
47
|
+
"""Close the Pi-hole session by calling the exit method in the connection."""
|
48
|
+
return self.connection.exit()
|
pihole6api/config.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import json
|
2
|
+
import urllib.parse
|
2
3
|
|
3
4
|
class PiHole6Configuration:
|
4
5
|
def __init__(self, connection):
|
@@ -77,3 +78,49 @@ class PiHole6Configuration:
|
|
77
78
|
:return: API response confirming the deletion.
|
78
79
|
"""
|
79
80
|
return self.connection.delete(f"config/{element}/{value}")
|
81
|
+
|
82
|
+
def add_local_a_record(self, host, ip):
|
83
|
+
"""
|
84
|
+
Add a local A record to Pi-hole.
|
85
|
+
|
86
|
+
:param host: The hostname (e.g., "foo.dev")
|
87
|
+
:param ip: The IP address (e.g., "192.168.1.1")
|
88
|
+
:return: API response
|
89
|
+
"""
|
90
|
+
encoded_value = urllib.parse.quote(f"{ip} {host}")
|
91
|
+
return self.connection.put(f"config/dns/hosts/{encoded_value}")
|
92
|
+
|
93
|
+
def remove_local_a_record(self, host, ip):
|
94
|
+
"""
|
95
|
+
Remove a local A record from Pi-hole.
|
96
|
+
|
97
|
+
:param host: The hostname (e.g., "foo.dev")
|
98
|
+
:param ip: The IP address (e.g., "192.168.1.1")
|
99
|
+
:return: API response
|
100
|
+
"""
|
101
|
+
encoded_value = urllib.parse.quote(f"{ip} {host}")
|
102
|
+
return self.connection.delete(f"config/dns/hosts/{encoded_value}")
|
103
|
+
|
104
|
+
def add_local_cname(self, host, target, ttl=300):
|
105
|
+
"""
|
106
|
+
Add a local CNAME record to Pi-hole.
|
107
|
+
|
108
|
+
:param host: The CNAME alias (e.g., "bar.xyz")
|
109
|
+
:param target: The target hostname (e.g., "foo.dev")
|
110
|
+
:param ttl: Time-to-live for the record (default: 300)
|
111
|
+
:return: API response
|
112
|
+
"""
|
113
|
+
encoded_value = urllib.parse.quote(f"{host},{target},{ttl}")
|
114
|
+
return self.connection.put(f"config/dns/cnameRecords/{encoded_value}")
|
115
|
+
|
116
|
+
def remove_local_cname(self, host, target, ttl=300):
|
117
|
+
"""
|
118
|
+
Remove a local CNAME record from Pi-hole.
|
119
|
+
|
120
|
+
:param host: The CNAME alias (e.g., "bar.xyz")
|
121
|
+
:param target: The target hostname (e.g., "foo.dev")
|
122
|
+
:param ttl: Time-to-live for the record (default: 300)
|
123
|
+
:return: API response
|
124
|
+
"""
|
125
|
+
encoded_value = urllib.parse.quote(f"{host},{target},{ttl}")
|
126
|
+
return self.connection.delete(f"config/dns/cnameRecords/{encoded_value}")
|
pihole6api/conn.py
CHANGED
@@ -124,4 +124,15 @@ class PiHole6Connection:
|
|
124
124
|
|
125
125
|
def patch(self, endpoint, data=None):
|
126
126
|
"""Send a PATCH request."""
|
127
|
-
return self._do_call("PATCH", endpoint, data=data)
|
127
|
+
return self._do_call("PATCH", endpoint, data=data)
|
128
|
+
|
129
|
+
def exit(self):
|
130
|
+
"""Delete the current session."""
|
131
|
+
response = self.delete("auth")
|
132
|
+
|
133
|
+
# Clear stored session info
|
134
|
+
self.session_id = None
|
135
|
+
self.csrf_token = None
|
136
|
+
self.validity = None
|
137
|
+
|
138
|
+
return response
|
pihole6api/metrics.py
CHANGED
@@ -11,68 +11,178 @@ class PiHole6Metrics:
|
|
11
11
|
"""Get activity graph data"""
|
12
12
|
return self.connection.get("history")
|
13
13
|
|
14
|
-
def get_history_clients(self):
|
15
|
-
"""
|
16
|
-
|
14
|
+
def get_history_clients(self, clients=20):
|
15
|
+
"""
|
16
|
+
Get per-client activity graph data
|
17
17
|
|
18
|
-
|
19
|
-
"""
|
20
|
-
|
18
|
+
:param num: Number of clients to return, 0 will return all clients
|
19
|
+
"""
|
20
|
+
params = {"n": clients}
|
21
|
+
return self.connection.get("history/clients", params=params)
|
21
22
|
|
22
|
-
def
|
23
|
-
"""
|
24
|
-
|
23
|
+
def get_history_database(self, start, end):
|
24
|
+
"""
|
25
|
+
Get long-term activity graph data
|
26
|
+
|
27
|
+
:param start: Start date in unix timestamp format
|
28
|
+
:param end: End date in unix timestamp format
|
29
|
+
"""
|
30
|
+
params = {"from": start, "until": end}
|
31
|
+
return self.connection.get("history/database", params=params)
|
32
|
+
|
33
|
+
def get_history_database_clients(self, start, end):
|
34
|
+
"""
|
35
|
+
Get per-client long-term activity graph data
|
36
|
+
|
37
|
+
:param start: Start date in unix timestamp format
|
38
|
+
:param end: End date in unix timestamp format
|
39
|
+
"""
|
40
|
+
params = {"from": start, "until": end}
|
41
|
+
return self.connection.get("history/database/clients", params=params)
|
25
42
|
|
26
43
|
# Query API Endpoints
|
27
|
-
def get_queries(self):
|
28
|
-
"""
|
29
|
-
|
44
|
+
def get_queries(self, n=100, from_ts=None, until_ts=None, upstream=None, domain=None, client=None, cursor=None):
|
45
|
+
"""
|
46
|
+
Get query log with optional filtering parameters.
|
47
|
+
|
48
|
+
:param int n: Number of queries to retrieve (default: 100).
|
49
|
+
:param int from_ts: Unix timestamp to filter queries from this time onward (optional).
|
50
|
+
:param int until_ts: Unix timestamp to filter queries up to this time (optional).
|
51
|
+
:param str upstream: Filter queries sent to a specific upstream destination (optional).
|
52
|
+
:param str domain: Filter queries for specific domains, supports wildcards `*` (optional).
|
53
|
+
:param str client: Filter queries originating from a specific client (optional).
|
54
|
+
:param str cursor: Cursor for pagination to fetch the next chunk of results (optional).
|
55
|
+
"""
|
56
|
+
params = {
|
57
|
+
"n": n,
|
58
|
+
"from": from_ts,
|
59
|
+
"until": until_ts,
|
60
|
+
"upstream": upstream,
|
61
|
+
"domain": domain,
|
62
|
+
"client": client,
|
63
|
+
"cursor": cursor
|
64
|
+
}
|
65
|
+
params = {k: v for k, v in params.items() if v is not None}
|
66
|
+
return self.connection.get("queries", params=params)
|
67
|
+
|
30
68
|
|
31
69
|
def get_query_suggestions(self):
|
32
70
|
"""Get query filter suggestions"""
|
33
71
|
return self.connection.get("queries/suggestions")
|
34
72
|
|
35
73
|
# Stats Database API Endpoints
|
36
|
-
def get_stats_database_query_types(self):
|
37
|
-
"""
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
74
|
+
def get_stats_database_query_types(self, start, end):
|
75
|
+
"""
|
76
|
+
Get query types (long-term database)
|
77
|
+
|
78
|
+
:param start: Start date in unix timestamp format
|
79
|
+
:param end: End date in unix timestamp format
|
80
|
+
"""
|
81
|
+
params = {"from": start, "until": end}
|
82
|
+
return self.connection.get("stats/database/query_types", params=params)
|
43
83
|
|
44
|
-
def
|
45
|
-
"""
|
46
|
-
|
84
|
+
def get_stats_database_summary(self, start, end):
|
85
|
+
"""
|
86
|
+
Get database content details
|
87
|
+
|
88
|
+
:param start: Start date in unix timestamp format
|
89
|
+
:param end: End date in unix timestamp format
|
90
|
+
"""
|
91
|
+
params = {"from": start, "until": end}
|
92
|
+
return self.connection.get("stats/database/summary", params=params)
|
47
93
|
|
48
|
-
def
|
49
|
-
"""
|
50
|
-
|
94
|
+
def get_stats_database_top_clients(self, start, end, blocked=None, count=None):
|
95
|
+
"""
|
96
|
+
Get top clients (long-term database).
|
51
97
|
|
52
|
-
|
53
|
-
|
54
|
-
|
98
|
+
:param int start: Start date in Unix timestamp format.
|
99
|
+
:param int end: End date in Unix timestamp format.
|
100
|
+
:param bool blocked: Return information about permitted or blocked queries (optional).
|
101
|
+
:param int count: Number of requested items (optional).
|
102
|
+
"""
|
103
|
+
params = {
|
104
|
+
"from": start,
|
105
|
+
"until": end,
|
106
|
+
"blocked": str(blocked).lower() if blocked is not None else None,
|
107
|
+
"count": count
|
108
|
+
}
|
109
|
+
params = {k: v for k, v in params.items() if v is not None}
|
110
|
+
return self.connection.get("stats/database/top_clients", params=params)
|
111
|
+
|
112
|
+
def get_stats_database_top_domains(self, start, end, blocked=None, count=None):
|
113
|
+
"""
|
114
|
+
Get top domains (long-term database)
|
115
|
+
|
116
|
+
:param int start: Start date in Unix timestamp format.
|
117
|
+
:param int end: End date in Unix timestamp format.
|
118
|
+
:param bool blocked: Return information about permitted or blocked queries (optional).
|
119
|
+
:param int count: Number of requested items (optional).
|
120
|
+
"""
|
121
|
+
params = {
|
122
|
+
"from": start,
|
123
|
+
"until": end,
|
124
|
+
"blocked": str(blocked).lower() if blocked is not None else None,
|
125
|
+
"count": count
|
126
|
+
}
|
127
|
+
params = {k: v for k, v in params.items() if v is not None}
|
128
|
+
return self.connection.get("stats/database/top_domains", params=params)
|
129
|
+
|
130
|
+
def get_stats_database_upstreams(self, start, end):
|
131
|
+
"""
|
132
|
+
Get upstream metrics (long-term database)
|
133
|
+
|
134
|
+
:param start: Start date in unix timestamp format
|
135
|
+
:param end: End date in unix timestamp format
|
136
|
+
"""
|
137
|
+
params = {"from": start, "until": end}
|
138
|
+
return self.connection.get("stats/database/upstreams", params=params)
|
55
139
|
|
56
140
|
# Stats API Endpoints
|
57
141
|
def get_stats_query_types(self):
|
58
142
|
"""Get current query types"""
|
59
143
|
return self.connection.get("stats/query_types")
|
60
144
|
|
61
|
-
def get_stats_recent_blocked(self):
|
62
|
-
"""
|
63
|
-
|
145
|
+
def get_stats_recent_blocked(self, count=None):
|
146
|
+
"""
|
147
|
+
Get most recently blocked domain
|
148
|
+
|
149
|
+
:param int count: Number of requested items (optional).
|
150
|
+
"""
|
151
|
+
params = {"count": count}
|
152
|
+
params = {k: v for k, v in params.items() if v is not None}
|
153
|
+
return self.connection.get("stats/recent_blocked", params=params)
|
64
154
|
|
65
155
|
def get_stats_summary(self):
|
66
156
|
"""Get an overview of Pi-hole activity"""
|
67
157
|
return self.connection.get("stats/summary")
|
68
158
|
|
69
|
-
def get_stats_top_clients(self):
|
70
|
-
"""
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
159
|
+
def get_stats_top_clients(self, blocked=None, count=None):
|
160
|
+
"""
|
161
|
+
Get top clients
|
162
|
+
|
163
|
+
:param bool blocked: Return information about permitted or blocked queries (optional).
|
164
|
+
:param int count: Number of requested items (optional).
|
165
|
+
"""
|
166
|
+
params = {
|
167
|
+
"blocked": str(blocked).lower() if blocked is not None else None,
|
168
|
+
"count": count
|
169
|
+
}
|
170
|
+
params = {k: v for k, v in params.items() if v is not None}
|
171
|
+
return self.connection.get("stats/top_clients", params=params)
|
172
|
+
|
173
|
+
def get_stats_top_domains(self, blocked=None, count=None):
|
174
|
+
"""
|
175
|
+
Get top domains
|
176
|
+
|
177
|
+
:param bool blocked: Return information about permitted or blocked queries (optional).
|
178
|
+
:param int count: Number of requested items (optional).
|
179
|
+
"""
|
180
|
+
params = {
|
181
|
+
"blocked": str(blocked).lower() if blocked is not None else None,
|
182
|
+
"count": count
|
183
|
+
}
|
184
|
+
params = {k: v for k, v in params.items() if v is not None}
|
185
|
+
return self.connection.get("stats/top_domains", params=params)
|
76
186
|
|
77
187
|
def get_stats_upstreams(self):
|
78
188
|
"""Get upstream destinations"""
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: pihole6api
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.2
|
4
4
|
Summary: Python API Client for Pi-hole 6
|
5
5
|
Author-email: Shane Barbetta <shane@barbetta.me>
|
6
6
|
License: MIT
|
@@ -23,7 +23,7 @@ Description-Content-Type: text/markdown
|
|
23
23
|
License-File: LICENSE
|
24
24
|
Requires-Dist: requests>=2.26.0
|
25
25
|
|
26
|
-
# pihole6api
|
26
|
+
# 🍓 pihole6api
|
27
27
|
|
28
28
|
This package provides a simple, modular SDK for the PiHole 6 REST API.
|
29
29
|
|
@@ -55,7 +55,7 @@ pip install -e .
|
|
55
55
|
### Initialize the Client
|
56
56
|
|
57
57
|
```python
|
58
|
-
from pihole6api
|
58
|
+
from pihole6api import PiHole6Client
|
59
59
|
client = PiHole6Client("https://your-pihole.local/", "your-password")
|
60
60
|
```
|
61
61
|
|
@@ -1,19 +1,19 @@
|
|
1
1
|
pihole6api/__init__.py,sha256=OKDAH2I6UjXcBmcj6rn5aNg5J60GCUBVFJ-_t83GiVQ,898
|
2
2
|
pihole6api/actions.py,sha256=8CBkr8nYfT8yfdCO6F9M9nompaYcFdsaYGiEa1eVDCw,693
|
3
|
-
pihole6api/client.py,sha256=
|
3
|
+
pihole6api/client.py,sha256=HYdRh3CSZJ0srbkpjIVnLo-iy1avqKDUne5ji2Aq394,2013
|
4
4
|
pihole6api/client_management.py,sha256=opPYGrjuW6SiwuxuvoOxnqjpmflU2znKHsqFbGSS3Gg,2439
|
5
|
-
pihole6api/config.py,sha256=
|
6
|
-
pihole6api/conn.py,sha256=
|
5
|
+
pihole6api/config.py,sha256=NdBHOudz147oIs5YVR3U4WLvqk3hU3HlZHnshy1NK4g,4680
|
6
|
+
pihole6api/conn.py,sha256=ArXgFtb3QG2HeBeDvhEuZ7jcBDR6fW8QorlCF46Y3MM,4840
|
7
7
|
pihole6api/dhcp.py,sha256=1A3z-3q9x51-6MOC3JMl7yR_5pHmRxZtMWtPqzWxYm0,629
|
8
8
|
pihole6api/dns_control.py,sha256=mxV3AIuGCsx0-1ibpMXor9QUGd_fDFfeaUENPhIK_TY,853
|
9
9
|
pihole6api/domain_management.py,sha256=vxhQSG5F8EFDGqtiNkF0H_KOWFMerXaAuJZT0nMa8ec,3492
|
10
10
|
pihole6api/ftl_info.py,sha256=e9W9vwkF8nHzjVlHpIMe-55qhhQngMj0swMlp2QNvPg,2540
|
11
11
|
pihole6api/group_management.py,sha256=MGHwegw-b9U9PIA-IBzqT-a1kYkpXyjfSXJJJjkyTxc,2225
|
12
12
|
pihole6api/list_management.py,sha256=B98FdgsIZhfRJHRxtRmwWsRPJ4rGlhvN-9gFEGdbb-c,3396
|
13
|
-
pihole6api/metrics.py,sha256=
|
13
|
+
pihole6api/metrics.py,sha256=czNyx9tUf2yZi_HnUpqykrtW51c042Rxq3zFl2_GjLY,7379
|
14
14
|
pihole6api/network_info.py,sha256=u5NIteFoI-yav05eE6v81-9gs3MeZVBlNCSBS5gzCT8,1006
|
15
|
-
pihole6api-0.1.
|
16
|
-
pihole6api-0.1.
|
17
|
-
pihole6api-0.1.
|
18
|
-
pihole6api-0.1.
|
19
|
-
pihole6api-0.1.
|
15
|
+
pihole6api-0.1.2.dist-info/LICENSE,sha256=hpO6J6J9O1VZxZeHQTxKMTmuobaHbApiZxp279I4xNU,1062
|
16
|
+
pihole6api-0.1.2.dist-info/METADATA,sha256=0kZSJq4RYKkx6fHMae0Tohtbwm7QVORbYnZ15GJdgPw,3837
|
17
|
+
pihole6api-0.1.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
18
|
+
pihole6api-0.1.2.dist-info/top_level.txt,sha256=Qrh46lxEC54rBR8T53em-tuZLWbmi1SDwL1rOhsgrME,11
|
19
|
+
pihole6api-0.1.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|