Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 48 additions & 8 deletions DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ Examples can be seen in the repository (`Discord-RPC/examples`) or [here](https:
Parameters :
- state (`str`)
- details (`str`)
- 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)).
- act_type (`discordrpc.Activity`) : [Activity Types](#class-discordrpcactivity) (Activity Type `1` and `4` is currently disabled, see [#28](https://github.com/Senophyx/Discord-RPC/issues/28#issuecomment-2301287350)).
- state_url (`str`) : URL that is linked when clicking on the state text.
- details_url (`str`) : URL that is linked when clicking on the details text.
- 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.
Expand All @@ -94,10 +96,15 @@ 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` for more easier.
- buttons (`list`) : list of dicts for buttons on user's profile. You can use [`discordrpc.Button`](#function-discordrpcbutton) for more easier.

Return : `True` if rpc successfully connected.

- method `RPC.clear()`<br>
Clear activity status.

Return : nothing.

- method `RPC.disconnect()`<br>
Disconnecting and closing RPC socket.

Expand All @@ -124,10 +131,15 @@ Examples can be seen in the repository (`Discord-RPC/examples`) or [here](https:

Return : `True` or `False`

- variable `self.User`<br>
Returns information about the user to whom the connection occurred.<br>
[Available attributes](#class-discordrpcuser)


## class `discordrpc.Activity`
- Enum `Activity`<br>
Simplified Activity type payload in `RPC.set_activity`
Simplified Activity type payload in `RPC.set_activity`<br>
[Discord docs](https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-types)

Available values :
- Playing
Expand All @@ -142,20 +154,40 @@ Examples can be seen in the repository (`Discord-RPC/examples`) or [here](https:
> [Details](https://github.com/Senophyx/Discord-RPC/issues/28#issuecomment-2301287350)


## class `discordrpc.Button()`
- function `Button()`<br>
Simplified button payload in `RPC.set_activity`
## function `discordrpc.Button()`
- Simplified button payload in `RPC.set_activity`

Parameters :
- text (`test`)
- text (`url`)
- text (`str`)
- url (`str`)

Return : Payload dict.

> [!NOTE]
> Discord does not display buttons in your own Activity.<br>
> You won’t see them yourself — but other users will see them correctly.


## function `discordrpc.Progressbar()`
- Simplified `ts_start` and `ts_end` payload in `RPC.set_activity`

Parameters :
- current (`int`)
- duration (`int`)

Return : Payload dict.


## class `discordrpc.User()`
Attributes :
- id (`int`)
- username (`str`)
- name (`str`)
- avatar (URL `str`)
- bot (`bool`)
- premium_type (`int`) ([details](https://discord.com/developers/docs/resources/user#user-object-premium-types))


## class `discordrpc.utils`
- variable `discordrpc.utils.timestamp()`<br>
Return current time in epoch timestamp (`int`).
Expand All @@ -169,6 +201,9 @@ Examples can be seen in the repository (`Discord-RPC/examples`) or [here](https:
date_to_timestamp('14/06/2025-00:00:00')
```

- function `discordrpc.utils.use_local_time()`<br>
Simplified `ts_start` payload in `RPC.set_activity`


## Exceptions & Errors
- `RPCException`<br>
Expand Down Expand Up @@ -204,6 +239,11 @@ Examples can be seen in the repository (`Discord-RPC/examples`) or [here](https:
How-to-Fix : Check if `Button` function are set correctly


- `ProgressbarError`<br>
There is an error in the `Progressbar` function, usually because the first parameter (current) is more then second parameter (duration).

How-to-Fix : Make sure that duration > current


## Links
- [Github Repository](https://github.com/Senophyx/Discord-RPC)
Expand Down
3 changes: 2 additions & 1 deletion discordrpc/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from .presence import RPC
from .button import Button
from .progressbar import Progressbar
from .exceptions import *
from .types import *
from .utils import timestamp, date_to_timestamp
from .utils import timestamp, date_to_timestamp, use_local_time

__title__ = "Discord RPC"
__version__ = "5.1"
Expand Down
2 changes: 1 addition & 1 deletion discordrpc/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

def Button(text:str, url:str):
if not url.startswith(("http://", "https://")):
raise InvalidURL
raise InvalidURL()
return {"label": text, "url": url}
6 changes: 5 additions & 1 deletion discordrpc/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,15 @@ class ButtonError(RPCException):
def __init__(self, message: str = None):
super().__init__(message=message)

class ProgressbarError(RPCException):
def __init__(self, message):
super().__init__(message=message)

class InvalidActivityType(RPCException):
def __init__(self, message):
super().__init__(f"Activity type must be <Activity>, not {message}")

# https://github.com/Senophyx/Discord-RPC/issues/28#issuecomment-2301287350
class ActivityTypeDisabled(RPCException):
def __init__(self):
super().__init__(f"Activity type `Streaming` and `Custom` currently disabled. See https://github.com/Senophyx/Discord-RPC/issues/28#issuecomment-2301287350")
super().__init__(f"Activity type `Streaming` and `Custom` currently disabled. See https://github.com/Senophyx/Discord-RPC/issues/28#issuecomment-2301287350")
36 changes: 21 additions & 15 deletions discordrpc/presence.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import re
from .exceptions import *
from .types import *
from .utils import remove_none
from .utils import *
import logging
import time

Expand All @@ -28,7 +28,9 @@ def __init__(self, app_id:int, debug:bool=False, output:bool=True, exit_if_disco
self.app_id = str(app_id)
self.exit_if_discord_close = exit_if_discord_close
self.exit_on_disconnect = exit_on_disconnect
self.User={}

self.user_data = {}
self.User = User()

if debug == True:
log.setLevel(logging.DEBUG)
Expand All @@ -42,27 +44,26 @@ def __init__(self, app_id:int, debug:bool=False, output:bool=True, exit_if_disco
def _setup(self):
if sys.platform == "win32":
self.ipc = WindowsPipe(self.app_id, self.exit_if_discord_close, self.exit_on_disconnect)
if not self.ipc.connected:
return

self.User=self.ipc.handshake()

else:
self.ipc = UnixPipe(self.app_id, self.exit_if_discord_close, self.exit_on_disconnect)
if not self.ipc.connected:
return

self.User=self.ipc.handshake()

if not self.ipc.connected: return
self.user_data = self.ipc.handshake()
self.User = User(self.user_data)

def set_activity(
self,
state: str=None, details:str=None, act_type:Activity=Activity.Playing,
state_url:str=None, details_url:str=None,
ts_start:int=None, ts_end:int=None,
# progressbar:dict=None,
# use_local_time:bool=False,
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
match_secret:str=None, buttons:list=None,
clear=False
) -> bool:

if type(party_id) == int:
Expand All @@ -82,6 +83,8 @@ def set_activity(
"state": state,
"details": details,
"type": act_type.value,
"state_url": state_url,
"details_url": details_url,
"timestamps": {
"start": ts_start,
"end": ts_end
Expand All @@ -108,7 +111,7 @@ def set_activity(
'cmd': 'SET_ACTIVITY',
'args': {
'pid': os.getpid(),
'activity': remove_none(act)
'activity': None if clear else remove_none(act)
},
'nonce': str(uuid.uuid4())
}
Expand All @@ -128,6 +131,9 @@ def set_activity(
log.error('Failed to set RPC')
self.disconnect()

def clear(self):
self.set_activity(clear=True)

def disconnect(self):
if not self.ipc.connected:
return
Expand Down Expand Up @@ -219,7 +225,7 @@ def handshake(self):

except KeyError:
if data['code'] == 4000:
raise InvalidID
raise InvalidID()

def disconnect(self):
try:
Expand Down Expand Up @@ -300,7 +306,7 @@ def handshake(self):

except KeyError:
if data['code'] == 4000:
raise InvalidID
raise InvalidID()

def disconnect(self):
try:
Expand Down
14 changes: 14 additions & 0 deletions discordrpc/progressbar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import time
from .exceptions import *


def Progressbar(current:int, duration:int) -> dict:
if int(current) > int(duration):
raise ProgressbarError("Current cannot exceed Duration")

current_time = int(time.time()) - int(current)
finish_time = current_time + int(duration)

return {
"ts_start": current_time, "ts_end": finish_time
}
22 changes: 21 additions & 1 deletion discordrpc/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,31 @@


# 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


class User():
def __init__(self, data:dict=None):
data = data or {}
self.id: int = int(data.get('id', 0))
self.username: str = data.get('username')
self.name: str = data.get('global_name')
self.avatar: str = self._parse_avatar(data)
self.bot: bool = data.get('bot', False)
self.premium_type: int = int(data.get('premium_type', 0)) # https://discord.com/developers/docs/resources/user#user-object-premium-types

def _parse_avatar(self, data:dict, size:int=1024) -> str:
if data.get('avatar'):
ext = "gif" if data.get('avatar').startswith("a_") else "png"
return f"https://cdn.discordapp.com/avatars/{self.id}/{data.get('avatar')}.{ext}?size={size}"
else:
return f"https://cdn.discordapp.com/embed/avatars/0.png"

def __str__(self):
return f"User({self.name})"
13 changes: 10 additions & 3 deletions discordrpc/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import time
import datetime
from datetime import datetime

# Credits to qwertyquerty
# https://github.com/qwertyquerty/pypresence/blob/master/pypresence/utils.py#L12C1-L21C13
Expand All @@ -21,5 +21,12 @@ def remove_none(d: dict):

def date_to_timestamp(date:str):
return int(time.mktime(
datetime.datetime.strptime(date, "%d/%m/%Y-%H:%M:%S").timetuple()
))
datetime.strptime(date, "%d/%m/%Y-%H:%M:%S").timetuple()
))

def use_local_time():
now = datetime.now()
seconds_since_midnight = now.hour * 3600 + now.minute * 60 + now.second
return {
"ts_start": int(time.time()) - seconds_since_midnight
}
10 changes: 10 additions & 0 deletions examples/get-user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import discordrpc

rpc = discordrpc.RPC(app_id=1397914682659963050)

print(rpc.User.id)
print(rpc.User.name)
print(f"@{rpc.User.username}")
print(rpc.User.avatar)

rpc.run()
13 changes: 13 additions & 0 deletions examples/rpc-local-time.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import discordrpc
from discordrpc import use_local_time


rpc = discordrpc.RPC(app_id=1397914682659963050)

rpc.set_activity(
state="Wow! It's shows my clock",
details="Local time example",
**use_local_time()
)

rpc.run()
14 changes: 14 additions & 0 deletions examples/rpc-with-progressbar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import discordrpc
from discordrpc import Activity, Progressbar


rpc = discordrpc.RPC(app_id=1397914682659963050)

rpc.set_activity(
state="With Progressbar",
details="Music",
act_type=Activity.Listening,
**Progressbar(50, 200)
)

rpc.run()