diff --git a/DOCS.md b/DOCS.md
index d66c334..eddc429 100644
--- a/DOCS.md
+++ b/DOCS.md
@@ -79,7 +79,7 @@ Examples can be seen in the repository (`Discord-RPC/examples`) or [here](https:
Parameters :
- state (`str`)
- details (`str`)
- - act_type (`int`) : [Activity Types](https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-types) (Activity Type `1` and `4` is currently disabled, see [#28](https://github.com/Senophyx/Discord-RPC/issues/28#issuecomment-2301287350)).
+ - act_type (`discordrpc.Activity`) : [Activity Types](https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-types) (Activity Type `1` and `4` is currently disabled, see [#28](https://github.com/Senophyx/Discord-RPC/issues/28#issuecomment-2301287350)).
- ts_start (`int`) : Timestamp start.
- ts_end (`int`) : Timestamp end.
- large_image (`str`) : The name of the image that has been uploaded to the Discord Developer Portal.
@@ -91,9 +91,9 @@ Examples can be seen in the repository (`Discord-RPC/examples`) or [here](https:
- join_secret (`str`) : Secret for chat invitations and ask to join button.
- spectate_secret (`str`) : Secret for spectate button.
- match_secret (`str`) : Secret for for spectate and join button
- - buttons (`list`) : list of dicts for buttons on user's profile. You can use `discordrpc.button.Button` for more easier.
+ - buttons (`list`) : list of dicts for buttons on user's profile. You can use `discordrpc.Button` for more easier.
- Return : nothing.
+ Return : `True` if rpc successfully connected.
- method `RPC.disconnect()`
Disconnecting and closing RPC socket.
@@ -122,17 +122,36 @@ Examples can be seen in the repository (`Discord-RPC/examples`) or [here](https:
Return : `True` or `False`
+## class `discordrpc.Activity`
+- Enum `Activity`
+ Simplified Activity type payload in `RPC.set_activity`
+
+ Available values :
+ - Playing
+ - Streaming
+ - Listening
+ - Watching
+ - Custom
+ - Competing
+
+> [!NOTE]
+> Activity Type `Streaming` and `Custom` currently disabled.
+> [Details](https://github.com/Senophyx/Discord-RPC/issues/28#issuecomment-2301287350)
+
+
## class `discordrpc.Button()`
- function `Button()`
Simplified button payload in `RPC.set_activity`
Parameters :
- - button_one_label (`str`) : Label for button one.
- - button_one_url (`str`) : Url for button one.
- - button_two_label (`str`) : Label for button two.
- - button_two_url (`str`) : Url for button two.
+ - text (`test`)
+ - text (`url`)
+
+ Return : Payload dict.
- Return : List of button dict.
+> [!NOTE]
+> Discord does not display buttons in your own Activity.
+> You won’t see them yourself — but other users will see them correctly.
## class `discordrpc.utils`
- variable `discordrpc.utils.timestamp()`
@@ -193,4 +212,4 @@ Examples can be seen in the repository (`Discord-RPC/examples`) or [here](https:
```
Discord-RPC project is under MIT License
Copyright (c) 2021-2024 Senophyx and EterNomm.
-```
\ No newline at end of file
+```
diff --git a/README.md b/README.md
index d642e0b..f644582 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,8 @@
# Discord RPC
An Python wrapper for Discord RPC API. Allow you to make own custom RPC.
-[](https://senophyx.id/projects/discord-rpc/#change-logs)
+[](https://senophyx.id/projects/discord-rpc/#change-logs)
+[](https://github.com/Senophyx/Discord-RPC/blob/main/DOCS.md)
## Install
- PyPI
@@ -32,7 +33,6 @@ rpc.run()
```
`rpc.run()` is only used if you are only running Discord RPC on the current file/instance. If there are other programs/tasks on the current instance, `rpc.run()` does not need to be used.
-See documentation [here](https://github.com/Senophyx/Discord-RPC/blob/main/DOCS.md).
More examples [here](https://github.com/Senophyx/discord-rpc/tree/main/examples).
diff --git a/discordrpc/__init__.py b/discordrpc/__init__.py
index 9cb6ee3..e8598b3 100644
--- a/discordrpc/__init__.py
+++ b/discordrpc/__init__.py
@@ -1,6 +1,7 @@
from .presence import RPC
from .button import Button
from .exceptions import *
+from .types import *
from .utils import timestamp, date_to_timestamp
__title__ = "Discord RPC"
diff --git a/discordrpc/button.py b/discordrpc/button.py
index b053e00..154220b 100644
--- a/discordrpc/button.py
+++ b/discordrpc/button.py
@@ -1,32 +1,7 @@
from .exceptions import *
-valid_url = ["https://", "http://"]
-def _payload(label:str, url:str):
- if any(v in url for v in valid_url):
- payloads = {"label": label, "url": url}
- return payloads
- else:
+def Button(text:str, url:str):
+ if not url.startswith(("http://", "https://")):
raise InvalidURL
-
-
-def Button(
- button_one_label:str,
- button_one_url:str,
- button_two_label:str,
- button_two_url:str):
-
- if button_one_label == None:
- raise ButtonError('"button_one_label" cannot None')
- if button_one_url == None:
- raise ButtonError('"button_one_url" cannot None')
- if button_two_label == None:
- raise ButtonError('"button_two_label" cannot None')
- if button_two_url == None:
- raise ButtonError('"button_two_url" cannot None')
-
- btn_one = _payload(label=button_one_label, url=button_one_url)
- btn_two = _payload(label=button_two_label, url=button_two_url)
- payloads = [btn_one, btn_two]
-
- return payloads
\ No newline at end of file
+ return {"label": text, "url": url}
diff --git a/discordrpc/exceptions.py b/discordrpc/exceptions.py
index 1d8f3da..740152e 100644
--- a/discordrpc/exceptions.py
+++ b/discordrpc/exceptions.py
@@ -28,7 +28,11 @@ class ButtonError(RPCException):
def __init__(self, message: str = None):
super().__init__(message=message)
-# https://github.com/Senophyx/Discord-RPC/issues/28#issuecomment-2301287350
class InvalidActivityType(RPCException):
+ def __init__(self, message):
+ super().__init__(f"Activity type must be , not {message}")
+
+# https://github.com/Senophyx/Discord-RPC/issues/28#issuecomment-2301287350
+class ActivityTypeDisabled(RPCException):
def __init__(self):
super().__init__(f"Activity Type 1 and 4 currently disabled. See https://github.com/Senophyx/Discord-RPC/issues/28#issuecomment-2301287350")
\ No newline at end of file
diff --git a/discordrpc/presence.py b/discordrpc/presence.py
index fba93b3..c8ebfee 100644
--- a/discordrpc/presence.py
+++ b/discordrpc/presence.py
@@ -6,6 +6,7 @@
import uuid
import re
from .exceptions import *
+from .types import *
from .utils import remove_none
import logging
import time
@@ -55,27 +56,32 @@ def _setup(self):
def set_activity(
self,
- state: str=None, details:str=None, act_type:int=0,
+ state: str=None, details:str=None, act_type:Activity=Activity.Playing,
ts_start:int=None, ts_end:int=None,
large_image:str=None, large_text:str=None,
small_image:str=None, small_text:str=None,
party_id:str=None, party_size:list=None,
join_secret:str=None, spectate_secret:str=None,
match_secret:str=None, buttons:list=None
- ):
+ ) -> bool:
if type(party_id) == int:
party_id = str(party_id)
+ if type(act_type) != Activity:
+ raise InvalidActivityType(type(act_type))
+
# https://github.com/Senophyx/Discord-RPC/issues/28#issuecomment-2301287350
- invalidType = ["1", "4"]
- if any(invtype in str(act_type) for invtype in invalidType):
- raise InvalidActivityType()
+ if act_type in [Activity.Streaming, Activity.Custom]:
+ raise ActivityTypeDisabled()
+
+ if buttons and len(buttons) > 2:
+ raise ButtonError("Max 2 buttons allowed")
act = {
"state": state,
"details": details,
- "type": act_type,
+ "type": act_type.value,
"timestamps": {
"start": ts_start,
"end": ts_end
@@ -113,9 +119,14 @@ def set_activity(
if not self.ipc.connected:
return
- self.ipc._send(payload, OP_FRAME)
- self.is_running = True
- log.info('RPC set')
+ try:
+ self.ipc._send(payload, OP_FRAME)
+ self.is_running = True
+ log.info('RPC set')
+ return True
+ except Exception as e:
+ log.error('Failed to set RPC')
+ self.disconnect()
def disconnect(self):
if not self.ipc.connected:
@@ -146,16 +157,19 @@ def __init__(self, app_id, exit_if_discord_close, exit_on_disconnect):
try:
self.socket = open(path, "w+b")
except OSError as e:
- if not self.exit_if_discord_close:
- raise Error("Failed to open {!r}: {}".format(path, e))
+ if self.exit_if_discord_close:
+ log.debug("Failed to open {!r}: {}".format(path, e))
+ raise DiscordNotOpened()
+ else:
+ log.debug("Discord seems to be close.")
else:
break
else:
- if not self.exit_if_discord_close:
+ if self.exit_if_discord_close:
raise DiscordNotOpened()
else:
- log.debug("Discord seems to be close.")
+ log.warning("Discord is closed")
self.connected = False
if self.connected:
@@ -208,10 +222,14 @@ def handshake(self):
raise InvalidID
def disconnect(self):
- self._send({}, OP_CLOSE)
-
- self.socket.close()
+ try:
+ self._send({}, OP_CLOSE)
+ self.socket.close()
+ except Exception as e:
+ log.debug("Socket closed before command was received")
+
self.socket = None
+ self.connected = False
log.warning("Closing RPC")
if self.exit_on_disconnect:
@@ -239,10 +257,10 @@ def __init__(self, app_id, exit_if_discord_close, exit_on_disconnect):
pass
else:
- if not self.exit_if_discord_close:
+ if self.exit_if_discord_close:
raise DiscordNotOpened()
else:
- log.debug("Discord seems to be close.")
+ log.warning("Discord is closed")
self.connected = False
if self.connected:
@@ -285,12 +303,16 @@ def handshake(self):
raise InvalidID
def disconnect(self):
- self._send({}, OP_CLOSE)
+ try:
+ self._send({}, OP_CLOSE)
+ self.socket.shutdown(socket.SHUT_RDWR)
+ self.socket.close()
+ except Exception as e:
+ log.debug("Socket closed before command was received")
- self.socket.shutdown(socket.SHUT_RDWR)
- self.socket.close()
self.socket = None
+ self.connected = False
log.warning("Closing RPC")
if self.exit_on_disconnect:
- sys.exit()
+ sys.exit()
diff --git a/discordrpc/types.py b/discordrpc/types.py
new file mode 100644
index 0000000..31251c0
--- /dev/null
+++ b/discordrpc/types.py
@@ -0,0 +1,12 @@
+from enum import Enum
+
+
+# https://discord.com/developers/docs/events/gateway-events#activity-object-activity-types
+
+class Activity(Enum):
+ Playing = 0
+ Streaming = 1
+ Listening = 2
+ Watching = 3
+ Custom = 4
+ Competing = 5
diff --git a/examples/rpc-with-activitytype.py b/examples/rpc-with-activitytype.py
new file mode 100644
index 0000000..da30c87
--- /dev/null
+++ b/examples/rpc-with-activitytype.py
@@ -0,0 +1,21 @@
+import discordrpc
+from discordrpc import Activity
+import time
+
+
+rpc = discordrpc.RPC(app_id=123456789)
+
+
+current_time = int(time.time())
+finish_time = current_time + 200
+
+rpc.set_activity(
+ state="With activity type",
+ details="Music",
+ act_type=Activity.Listening,
+ ts_start=current_time,
+ ts_end=finish_time
+)
+
+
+rpc.run()
diff --git a/examples/rpc-with-button.py b/examples/rpc-with-button.py
index 388b307..436ae4c 100644
--- a/examples/rpc-with-button.py
+++ b/examples/rpc-with-button.py
@@ -1,21 +1,17 @@
import discordrpc
-from discordrpc.button import Button
+from discordrpc import Button
rpc = discordrpc.RPC(app_id=1234567891011)
-button = Button(
- button_one_label="Repository",
- button_one_url="https://github.com/Senophyx/discord-rpc",
- button_two_label="Discord Server",
- button_two_url="https://discord.gg/qpT2AeYZRN"
- )
rpc.set_activity(
state="Made by Senophyx",
details="Discord-RPC",
- buttons=button
+ buttons=[
+ Button("Repository", "https://github.com/Senophyx/discord-rpc"),
+ Button("Discord", "https://discord.gg/qpT2AeYZRN"),
+ ]
)
-
rpc.run()
\ No newline at end of file
diff --git a/setup.py b/setup.py
index db4e658..4b1e249 100644
--- a/setup.py
+++ b/setup.py
@@ -1,11 +1,11 @@
from setuptools import setup, find_packages
import re
-with open('README.md') as f:
+with open('README.md', encoding='utf-8') as f:
long_description = f.read()
version = ''
-with open('discordrpc/__init__.py') as f:
+with open('discordrpc/__init__.py', encoding='utf-8') as f:
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', f.read(), re.MULTILINE).group(1)
if not version: