├── .gitignore
├── LICENSE
├── README.md
├── api
├── __init__.py
├── macos.py
└── windows.py
├── assets
├── acrobat_large.png
├── acrobat_small.png
├── aftereffects_large.png
├── aftereffects_small.png
├── audition_large.png
├── audition_small.png
├── illustrator_large.png
├── illustrator_small.png
├── indesign_large.png
├── indesign_small.png
├── photoshop_large.png
├── photoshop_small.png
├── premierepro_large.png
└── premierepro_small.png
├── handler.py
├── meta.json
├── requirements.txt
└── rpc.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | .hypothesis/
51 | .pytest_cache/
52 |
53 | # Translations
54 | *.mo
55 | *.pot
56 |
57 | # Django stuff:
58 | *.log
59 | local_settings.py
60 | db.sqlite3
61 |
62 | # Flask stuff:
63 | instance/
64 | .webassets-cache
65 |
66 | # Scrapy stuff:
67 | .scrapy
68 |
69 | # Sphinx documentation
70 | docs/_build/
71 |
72 | # PyBuilder
73 | target/
74 |
75 | # Jupyter Notebook
76 | .ipynb_checkpoints
77 |
78 | # IPython
79 | profile_default/
80 | ipython_config.py
81 |
82 | # pyenv
83 | .python-version
84 |
85 | # pipenv
86 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
87 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
88 | # having no cross-platform support, pipenv may install dependencies that don’t work, or not
89 | # install all needed dependencies.
90 | #Pipfile.lock
91 |
92 | # celery beat schedule file
93 | celerybeat-schedule
94 |
95 | # SageMath parsed files
96 | *.sage.py
97 |
98 | # Environments
99 | .env
100 | .venv
101 | env/
102 | venv/
103 | ENV/
104 | env.bak/
105 | venv.bak/
106 |
107 | # Spyder project settings
108 | .spyderproject
109 | .spyproject
110 |
111 | # Rope project settings
112 | .ropeproject
113 |
114 | # mkdocs documentation
115 | /site
116 |
117 | # mypy
118 | .mypy_cache/
119 | .dmypy.json
120 | dmypy.json
121 |
122 | # Pyre type checker
123 | .pyre/
124 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Smokie
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ![alt text][header]
2 |
3 | # Adobe Discord Rich Presence
4 |
5 | [](https://www.codacy.com/app/imsmokie/adobe-rpc?utm_source=github.com&utm_medium=referral&utm_content=smokes/adobe-rpc&utm_campaign=Badge_Grade)
6 | [](https://www.python.org/)
7 | [](https://GitHub.com/smokes/adobe-rpc/issues/)
8 |
9 | Rich Presence for Discord to display what you're currently doing in most of adobe's applications
10 |
11 | ## Requirements
12 |
13 | - Python 3.4+ with Pip
14 | - If you're running a 64bit version of python, download the pywin32 binaries from [here!](https://github.com/mhammond/pywin32/releases)
15 | - Adobe apps (obviously)
16 |
17 | ## How to use
18 |
19 | - Clone the repo `$ git clone https://github.com/smokes/adobe-rpc.git`
20 | - Make sure you're running an Adobe application.
21 | - Install the required packages `$ pip install -r requirements.txt`
22 | - Run the script `$ python rpc.py`
23 | - Enjoy!
24 |
25 | ## Binaries
26 |
27 | The easiest way to use **adobe-rpc** is to download the **.exe** from the [releases!](https://github.com/smokes/adobe-rpc/releases) page.
28 |
29 | ## Preview
30 |
31 |
36 |
37 | ## TODOs
38 |
39 | - Macos support
40 | - Better error handling
41 | - Prevent app from exiting when Discord or any app isn't running.
42 |
43 | ## Contributing
44 |
45 | **adobe-rpc** currently doesn't support: Media Encoder, Xd and Audition. Please submit a PR where you add an app that we haven't included yet to the file **meta.json**, where you specify the app's process name.
46 |
47 | [header]: https://i.imgur.com/zGFYunZ.png "Repo header"
48 |
--------------------------------------------------------------------------------
/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/api/__init__.py
--------------------------------------------------------------------------------
/api/macos.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/api/macos.py
--------------------------------------------------------------------------------
/api/windows.py:
--------------------------------------------------------------------------------
1 | import win32gui
2 | import win32process
3 | import psutil
4 | import json
5 | import ntpath
6 |
7 |
8 | def get_title(pid):
9 | def callback(hwnd, hwnds):
10 | if win32gui.IsWindowVisible(hwnd) and win32gui.IsWindowEnabled(hwnd):
11 | _, found_pid = win32process.GetWindowThreadProcessId(hwnd)
12 | if found_pid == pid:
13 | hwnds.append(hwnd)
14 | hwnds = []
15 | win32gui.EnumWindows(callback, hwnds)
16 | window_title = win32gui.GetWindowText(hwnds[-1])
17 | return window_title
18 |
19 |
20 | with open('meta.json') as f:
21 | data = json.load(f)
22 |
23 |
24 | def get_process_info():
25 | for element in data:
26 | process_name = element['processName']
27 | for process in psutil.process_iter():
28 | process_info = process.as_dict(attrs=['pid', 'name'])
29 | if process_info['name'].lower() in process_name:
30 | element['pid'] = process_info['pid']
31 | return element
32 |
33 |
34 | def get_status(app_info, title):
35 | if app_info['largeText'].lower() in title.lower() and app_info['splitBy'] != " - ":
36 | return "{}: IDLE".format(app_info['smallText'])
37 | else:
38 | title_seperated = title.split(app_info['splitBy'])
39 | if app_info['splitBy'] == " - ":
40 | title_basename = ntpath.basename(
41 | title_seperated[app_info['splitIndex']])
42 | return "{}: {}".format(app_info['smallText'], title_basename)
43 | else:
44 | return "{}: {}".format(app_info['smallText'], title_seperated[app_info['splitIndex']])
45 |
--------------------------------------------------------------------------------
/assets/acrobat_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/assets/acrobat_large.png
--------------------------------------------------------------------------------
/assets/acrobat_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/assets/acrobat_small.png
--------------------------------------------------------------------------------
/assets/aftereffects_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/assets/aftereffects_large.png
--------------------------------------------------------------------------------
/assets/aftereffects_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/assets/aftereffects_small.png
--------------------------------------------------------------------------------
/assets/audition_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/assets/audition_large.png
--------------------------------------------------------------------------------
/assets/audition_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/assets/audition_small.png
--------------------------------------------------------------------------------
/assets/illustrator_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/assets/illustrator_large.png
--------------------------------------------------------------------------------
/assets/illustrator_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/assets/illustrator_small.png
--------------------------------------------------------------------------------
/assets/indesign_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/assets/indesign_large.png
--------------------------------------------------------------------------------
/assets/indesign_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/assets/indesign_small.png
--------------------------------------------------------------------------------
/assets/photoshop_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/assets/photoshop_large.png
--------------------------------------------------------------------------------
/assets/photoshop_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/assets/photoshop_small.png
--------------------------------------------------------------------------------
/assets/premierepro_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/assets/premierepro_large.png
--------------------------------------------------------------------------------
/assets/premierepro_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadir/adobe-rpc/b97cf95a222121b15f251a75ecdedfea3f9e868b/assets/premierepro_small.png
--------------------------------------------------------------------------------
/handler.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 |
4 | def get_rpc_update():
5 | if sys.platform in ['Windows', 'win32', 'cygwin']:
6 | try:
7 | from api.windows import get_title, get_process_info, get_status
8 |
9 | app_info = get_process_info()
10 | app_title = get_title(app_info['pid'])
11 | app_state = get_status(app_info, app_title)
12 |
13 | rpc_update = {'state': app_state,
14 | 'small_image': app_info['smallImageKey'],
15 | 'large_image': app_info['largeImageKey'],
16 | 'large_text': app_info['largeText'],
17 | 'small_text': app_info['smallText'],
18 | 'details': app_info['largeText']}
19 | return rpc_update
20 |
21 | except ImportError:
22 | print("Make sure you have pywin32 installed, for more info read README.md")
23 |
24 | elif sys.platform in ['Mac', 'darwin', 'os2', 'os2emx']:
25 | print("Macos support is currently not available.")
26 | sys.exit(0)
27 |
28 |
29 | def exception_handler(exception, future):
30 | print("")
31 |
--------------------------------------------------------------------------------
/meta.json:
--------------------------------------------------------------------------------
1 | [{
2 | "processName": "photoshop.exe",
3 | "splitBy": " @ ",
4 | "splitIndex": 0,
5 | "largeImageKey": "photoshop_large",
6 | "smallImageKey": "photoshop_small",
7 | "largeText": "Adobe Photoshop",
8 | "smallText": "Editing"
9 |
10 | },
11 | {
12 | "processName": "adobe premiere pro.exe",
13 | "splitBy": " - ",
14 | "splitIndex": 1,
15 | "largeImageKey": "premierepro_large",
16 | "smallImageKey": "premierepro_small",
17 | "largeText": "Adobe Premiere Pro",
18 | "smallText": "Editing"
19 | },
20 | {
21 | "processName": "illustrator.exe",
22 | "splitBy": " @ ",
23 | "splitIndex": 0,
24 | "largeImageKey": "illustrator_large",
25 | "smallImageKey": "illustrator_small",
26 | "largeText": "Adobe Illustrator",
27 | "smallText": "Editing"
28 | },
29 | {
30 | "processName": "afterfx.exe",
31 | "splitBy": " - ",
32 | "splitIndex": 1,
33 | "largeImageKey": "aftereffects_large",
34 | "smallImageKey": "aftereffects_small",
35 | "largeText": "Adobe After Effects",
36 | "smallText": "Editing"
37 | },
38 | {
39 | "processName": "acrobat.exe",
40 | "splitBy": " - ",
41 | "splitIndex": 0,
42 | "largeImageKey": "acrobat_large",
43 | "smallImageKey": "acrobat_small",
44 | "largeText": "Adobe Acrobat",
45 | "smallText": "Reading"
46 | },
47 | {
48 | "processName": "indesign.exe",
49 | "splitBy": " @ ",
50 | "splitIndex": 0,
51 | "largeImageKey": "indesign_large",
52 | "smallImageKey": "indesign_small",
53 | "largeText": "Adobe InDesign",
54 | "smallText": "Editing"
55 | }
56 | ]
57 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | pypresence
2 | pywin32
3 | psutil
--------------------------------------------------------------------------------
/rpc.py:
--------------------------------------------------------------------------------
1 | from pypresence import Presence
2 | import handler
3 | import time
4 |
5 | client_id = "482150417455775755"
6 | rich_presence = Presence(client_id)
7 |
8 | def connect():
9 | return rich_presence.connect()
10 |
11 | def connect_loop(retries=0):
12 | if retries > 10:
13 | return
14 | try:
15 | connect()
16 | except:
17 | print("Error connecting to Discord")
18 | time.sleep(10)
19 | retries += 1
20 | connect_loop(retries)
21 | else:
22 | update_loop()
23 |
24 | print("Started Adobe RPC")
25 |
26 | def update_loop():
27 | start_time = int(time.time())
28 | try:
29 | while True:
30 | rpc_data = handler.get_rpc_update()
31 | rich_presence.update(state=rpc_data['state'],
32 | small_image=rpc_data['small_image'],
33 | large_image=rpc_data['large_image'],
34 | large_text=rpc_data['large_text'],
35 | small_text=rpc_data['small_text'],
36 | details=rpc_data['details'],
37 | start=start_time)
38 | time.sleep(15)
39 | except:
40 | rich_presence.clear()
41 | print("Run Adobe/Discord app")
42 | time.sleep(5)
43 | update_loop()
44 |
45 | try:
46 | connect_loop()
47 | except KeyboardInterrupt:
48 | print("Stopped Adobe RPC")
49 |
--------------------------------------------------------------------------------