pihole6api 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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
- """Get per-client activity graph data"""
16
- return self.connection.get("history/clients")
14
+ def get_history_clients(self, clients=20):
15
+ """
16
+ Get per-client activity graph data
17
17
 
18
- def get_history_database(self):
19
- """Get long-term activity graph data"""
20
- return self.connection.get("history/database")
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 get_history_database_clients(self):
23
- """Get per-client long-term activity graph data"""
24
- return self.connection.get("history/database/clients")
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
- """Get query log"""
29
- return self.connection.get("queries")
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
- """Get query types (long-term database)"""
38
- return self.connection.get("stats/database/query_types")
39
-
40
- def get_stats_database_summary(self):
41
- """Get database content details"""
42
- return self.connection.get("stats/database/summary")
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 get_stats_database_top_clients(self):
45
- """Get top clients (long-term database)"""
46
- return self.connection.get("stats/database/top_clients")
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 get_stats_database_top_domains(self):
49
- """Get top domains (long-term database)"""
50
- return self.connection.get("stats/database/top_domains")
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
- def get_stats_database_upstreams(self):
53
- """Get upstream metrics (long-term database)"""
54
- return self.connection.get("stats/database/upstreams")
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
- """Get most recently blocked domain"""
63
- return self.connection.get("stats/recent_blocked")
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
- """Get top clients"""
71
- return self.connection.get("stats/top_clients")
72
-
73
- def get_stats_top_domains(self):
74
- """Get top domains"""
75
- return self.connection.get("stats/top_domains")
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.0
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.client import PiHole6Client
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=IgUjiBUx_EFzQujgQZcX2h9dfDfI83aVeipUeStHWY0,1855
3
+ pihole6api/client.py,sha256=HYdRh3CSZJ0srbkpjIVnLo-iy1avqKDUne5ji2Aq394,2013
4
4
  pihole6api/client_management.py,sha256=opPYGrjuW6SiwuxuvoOxnqjpmflU2znKHsqFbGSS3Gg,2439
5
- pihole6api/config.py,sha256=RlTyIZ0G9K2qZxB6nZgT3HsCn03y7q1qRjVwJ4ZY5Kc,2914
6
- pihole6api/conn.py,sha256=sYjS8Gvk2GuA482eyvFknTKgeeesLnS5ylI9I4yUNRo,4581
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=KgklFtXrO_f2ZnFd6C7tATVPuUJwMl_dGr4Ul5Wgc1k,2758
13
+ pihole6api/metrics.py,sha256=czNyx9tUf2yZi_HnUpqykrtW51c042Rxq3zFl2_GjLY,7379
14
14
  pihole6api/network_info.py,sha256=u5NIteFoI-yav05eE6v81-9gs3MeZVBlNCSBS5gzCT8,1006
15
- pihole6api-0.1.0.dist-info/LICENSE,sha256=hpO6J6J9O1VZxZeHQTxKMTmuobaHbApiZxp279I4xNU,1062
16
- pihole6api-0.1.0.dist-info/METADATA,sha256=Fefv0L6mqT5fYsBbNLr8uHNS2XBk6bIR0KyFvdCY5Ng,3839
17
- pihole6api-0.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
18
- pihole6api-0.1.0.dist-info/top_level.txt,sha256=Qrh46lxEC54rBR8T53em-tuZLWbmi1SDwL1rOhsgrME,11
19
- pihole6api-0.1.0.dist-info/RECORD,,
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,,