python-ntfy 0.1.0__tar.gz → 0.2.0__tar.gz

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.
@@ -1,12 +1,14 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-ntfy
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: An ntfy library aiming for feature completeness
5
5
  Author: Matthew Cane
6
6
  Author-email: matthew.cane0@gmail.com
7
7
  Requires-Python: >=3.11,<4.0
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
10
12
  Requires-Dist: requests (>=2.31.0,<3.0.0)
11
13
  Description-Content-Type: text/markdown
12
14
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python-ntfy"
3
- version = "0.1.0"
3
+ version = "0.2.0"
4
4
  description = "An ntfy library aiming for feature completeness"
5
5
  authors = ["Matthew Cane <matthew.cane0@gmail.com>"]
6
6
  readme = "README.md"
@@ -1,8 +1,7 @@
1
1
  import os
2
2
 
3
-
4
3
  class NtfyClient:
5
- from ._send_functions import send, send_file
4
+ from ._send_functions import send, send_file, MessagePriority, ViewAction, BroadcastAction, HttpAction
6
5
  from ._get_functions import get_cached_messages
7
6
 
8
7
  def __init__(
@@ -15,9 +14,9 @@ class NtfyClient:
15
14
  :param server: The server to connect to. Must include the protocol (http/https)
16
15
  :return:
17
16
  """
18
- self._server = server
17
+ self._server = os.environ.get("NTFY_SERVER") or server
19
18
  self._topic = topic
20
- self.__set_url(server, topic)
19
+ self.__set_url(self._server, topic)
21
20
 
22
21
  if (user := os.environ.get("NTFY_USER")) and (
23
22
  password := os.environ.get("NTFY_PASSWORD")
@@ -0,0 +1,188 @@
1
+ import json, requests
2
+ from enum import Enum
3
+ from typing import Optional, Union
4
+
5
+ class MessagePriority(Enum):
6
+ """
7
+ Ntfy message priority levels.
8
+ """
9
+ MIN = "1"
10
+ LOW = "2"
11
+ DEFAULT = "3"
12
+ HIGH = "4"
13
+ MAX = "5"
14
+ URGENT = MAX
15
+
16
+ class ActionType(Enum):
17
+ """
18
+ Action button types
19
+ """
20
+ VIEW = "view"
21
+ BROADCAST = "broadcast"
22
+ HTTP = "http"
23
+
24
+ class Action():
25
+ def __init__(self, label: str, url: str, clear: bool = False):
26
+ self.label = label
27
+ self.url = url
28
+ self.actions: list = []
29
+ self.clear = clear
30
+
31
+
32
+ class ViewAction(Action):
33
+ def __init__(self, label: str, url: str, clear: bool = False):
34
+ self.action = ActionType.VIEW
35
+ super().__init__(label=label, url=url, clear=clear)
36
+
37
+ def to_dict(self):
38
+ return {
39
+ "action": self.action.value,
40
+ "label": self.label,
41
+ "url": self.url,
42
+ "clear": self.clear
43
+ }
44
+
45
+ def to_header(self):
46
+ return f"action={self.action.value}, label={self.label}, url={self.url}, clear={self.clear}"
47
+
48
+ class BroadcastAction(Action):
49
+ def __init__(self, label: str, intent: str = "io.heckel.ntfy.USER_ACTION", extras: Optional[dict] = None, clear: bool = False):
50
+ self.action = ActionType.BROADCAST
51
+ self.intent = intent
52
+ self.extras = extras
53
+ super().__init__(label, ActionType.BROADCAST, clear)
54
+
55
+ def to_dict(self):
56
+ return {
57
+ "action": self.action.value,
58
+ "label": self.label,
59
+ "extras": self.extras,
60
+ "clear": self.clear
61
+ }
62
+
63
+ def to_header(self):
64
+ extras = ""
65
+ if self.extras is not None:
66
+ for key, value in self.extras.items():
67
+ extras += f"{key}={value},"
68
+ return f"action={self.action.value}, label={self.label}, url={self.url}, clear={self.clear}"
69
+
70
+ class HttpAction(Action):
71
+ def __init__(
72
+ self,
73
+ label: str,
74
+ url: str,
75
+ method: str = "POST",
76
+ headers: Optional[dict] = None,
77
+ body: Optional[str] = None,
78
+ clear: bool = False
79
+ ):
80
+ self.action = ActionType.HTTP
81
+ self.method = method
82
+ self.headers = headers
83
+ self.body = body
84
+ super().__init__(label, url, clear)
85
+
86
+ def to_dict(self):
87
+ action_dict = {
88
+ "action": self.action.value,
89
+ "label": self.label,
90
+ "url": self.url,
91
+ "method": self.method,
92
+ "clear": self.clear
93
+ }
94
+ if self.headers:
95
+ action_dict["headers"] = self.headers
96
+ if self.body:
97
+ action_dict["body"] = self.body
98
+ return action_dict
99
+
100
+ def to_header(self):
101
+ header_str = f"action={self.action.value}, label={self.label}, url={self.url}, method={self.method}, clear={self.clear}"
102
+ if self.headers is not None:
103
+ headers = ""
104
+ for key, value in self.headers.items():
105
+ headers += f"headers.{key}={value}"
106
+ header_str += f", {headers}"
107
+ if self.body:
108
+ header_str += f", body={self.body}"
109
+ print(header_str)
110
+ return header_str
111
+
112
+
113
+ def send(
114
+ self,
115
+ message: str,
116
+ title: str = None,
117
+ priority: Optional[MessagePriority] = MessagePriority.DEFAULT,
118
+ tags: list = [],
119
+ actions: list[Union[ViewAction, BroadcastAction, HttpAction, None]] = [],
120
+ format_as_markdown: bool = False
121
+ ):
122
+ """
123
+ Send a text based message to the server
124
+
125
+ :param message: The message to send
126
+ :param title: The title of the message. Optional
127
+ :param priority: The priority of the message. Optional, defaults to MessagePriority.DEFAULT
128
+ :param tags: A list of tags to attach to the message. Can be an emoji short code. Optional
129
+ :param format_as_markdown: If true, the message will be formatted as markdown. Optional
130
+ :param actions: A list of Actions objects to attach to the message. Optional
131
+ :return: The response from the server
132
+
133
+ :examples:
134
+ response = client.send(message="Example message")
135
+ response = client.send(message="Example message", title="Example title", priority=MessagePriority.HIGH, tags=["fire", "warning"])
136
+ response = client.send(message="*Example markdown*", format_as_markdown=True)
137
+ """
138
+ headers = {
139
+ "Title": title,
140
+ "Priority": priority.value,
141
+ "Tags": ",".join(tags),
142
+ "Markdown": "true" if format_as_markdown else "false",
143
+ }
144
+ if len(actions) > 0:
145
+ headers['Actions'] = " ; ".join([action.to_header() for action in actions])
146
+
147
+ response = json.loads(
148
+ requests.post(url=self.url, data=message, headers=headers, auth=self._auth).text
149
+ )
150
+ return response
151
+
152
+
153
+ def send_file(
154
+ self,
155
+ file: str,
156
+ title: str = None,
157
+ priority: Optional[MessagePriority] = MessagePriority.DEFAULT,
158
+ tags: list = [],
159
+ actions: list[Union[ViewAction, BroadcastAction, HttpAction, None]] = []
160
+ ):
161
+ """
162
+ Send a file to the server
163
+
164
+ :param file_path: The path to the file to send.
165
+ :param title: The title of the file. Optional
166
+ :param priority: The priority of the message. Optional, defaults to MessagePriority.DEFAULT
167
+ :param tags: A list of tags to attach to the message. Can be an emoji short code. Optional
168
+ :param actions: A list of ActionButton objects to attach to the message. Optional
169
+ :return: The response from the server
170
+
171
+ :examples:
172
+ response = client.send_file(file_path="example.txt")
173
+ """
174
+ headers = {
175
+ "Title": title,
176
+ "Filename": file.split("/")[-1],
177
+ "Priority": priority.value,
178
+ "Tags": ",".join(tags),
179
+ "Actions": " ; ".join([action.to_header() for action in actions])
180
+ }
181
+
182
+ with open(file, "rb") as file:
183
+ response = json.loads(
184
+ requests.post(
185
+ url=self.url, data=file, headers=headers, auth=self._auth
186
+ ).text
187
+ )
188
+ return response
@@ -1,48 +0,0 @@
1
- import json, requests
2
-
3
-
4
- def send(self, message: str, title: str = None, format_as_markdown: bool = False):
5
- """
6
- Send a text based message to the server
7
-
8
- :param message: The message to send
9
- :param title: The title of the message. Optional
10
- :param format_as_markdown: If true, the message will be formatted as markdown. Optional
11
- :return: The response from the server
12
-
13
- :examples:
14
- response = client.send(message="Example message")
15
- response = client.send(message="Example message", title="Example title")
16
- response = client.send(message="*Example markdown*", format_as_markdown=True)
17
- """
18
- headers = {
19
- "Title": title,
20
- "Markdown": "true" if format_as_markdown else "false",
21
- }
22
-
23
- response = json.loads(
24
- requests.post(url=self.url, data=message, headers=headers, auth=self._auth).text
25
- )
26
- return response
27
-
28
-
29
- def send_file(self, file: str, title: str = None):
30
- """
31
- Send a file to the server
32
-
33
- :param file_path: The path to the file to send
34
- :param title: The title of the file. Optional
35
- :return: The response from the server
36
-
37
- :examples:
38
- response = client.send_file(file_path="example.txt")
39
- """
40
- headers = {"Title": title, "Filename": file.split("/")[-1]}
41
-
42
- with open(file, "rb") as file:
43
- response = json.loads(
44
- requests.post(
45
- url=self.url, data=file, headers=headers, auth=self._auth
46
- ).text
47
- )
48
- return response
File without changes