pyrekordbox 0.4.2__py3-none-any.whl → 0.4.4__py3-none-any.whl
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.
- pyrekordbox/__init__.py +1 -0
- pyrekordbox/__main__.py +1 -51
- pyrekordbox/_version.py +16 -3
- pyrekordbox/anlz/__init__.py +6 -6
- pyrekordbox/anlz/file.py +56 -43
- pyrekordbox/anlz/tags.py +108 -70
- pyrekordbox/config.py +18 -356
- pyrekordbox/db6/aux_files.py +40 -14
- pyrekordbox/db6/database.py +384 -236
- pyrekordbox/db6/registry.py +48 -34
- pyrekordbox/db6/smartlist.py +12 -12
- pyrekordbox/db6/tables.py +60 -58
- pyrekordbox/mysettings/__init__.py +3 -2
- pyrekordbox/mysettings/file.py +27 -24
- pyrekordbox/rbxml.py +321 -142
- pyrekordbox/utils.py +27 -6
- {pyrekordbox-0.4.2.dist-info → pyrekordbox-0.4.4.dist-info}/METADATA +13 -38
- pyrekordbox-0.4.4.dist-info/RECORD +25 -0
- {pyrekordbox-0.4.2.dist-info → pyrekordbox-0.4.4.dist-info}/WHEEL +1 -1
- {pyrekordbox-0.4.2.dist-info → pyrekordbox-0.4.4.dist-info}/licenses/LICENSE +1 -1
- pyrekordbox-0.4.2.dist-info/RECORD +0 -25
- {pyrekordbox-0.4.2.dist-info → pyrekordbox-0.4.4.dist-info}/top_level.txt +0 -0
pyrekordbox/utils.py
CHANGED
@@ -4,17 +4,21 @@
|
|
4
4
|
|
5
5
|
"""This module contains common constants and methods used in other modules."""
|
6
6
|
|
7
|
+
import base64
|
7
8
|
import os
|
8
9
|
import warnings
|
9
10
|
import xml.etree.cElementTree as xml
|
11
|
+
import zlib
|
10
12
|
from xml.dom import minidom
|
11
13
|
|
12
14
|
import psutil
|
13
15
|
|
14
16
|
warnings.simplefilter("always", DeprecationWarning)
|
15
17
|
|
18
|
+
BLOB_KEY = b"657f48f84c437cc1"
|
16
19
|
|
17
|
-
|
20
|
+
|
21
|
+
def warn_deprecated(name: str, new_name: str = "", hint: str = "", remove_in: str = "") -> None:
|
18
22
|
s = f"'{name}' is deprecated"
|
19
23
|
if remove_in:
|
20
24
|
s += f" and will be removed in version '{remove_in}'"
|
@@ -30,7 +34,7 @@ def warn_deprecated(name, new_name="", hint="", remove_in=""):
|
|
30
34
|
warnings.warn(s, DeprecationWarning, stacklevel=3)
|
31
35
|
|
32
36
|
|
33
|
-
def get_process_id(name: str, raise_exec=False) -> int:
|
37
|
+
def get_process_id(name: str, raise_exec: bool = False) -> int:
|
34
38
|
"""Returns the ID of a process if it exists.
|
35
39
|
|
36
40
|
Parameters
|
@@ -62,7 +66,8 @@ def get_process_id(name: str, raise_exec=False) -> int:
|
|
62
66
|
try:
|
63
67
|
proc_name = os.path.splitext(proc.name())[0] # needed on Windows (.exe)
|
64
68
|
if proc_name == name:
|
65
|
-
|
69
|
+
pid: int = proc.pid
|
70
|
+
return pid
|
66
71
|
except (psutil.AccessDenied, psutil.NoSuchProcess):
|
67
72
|
pass
|
68
73
|
if raise_exec:
|
@@ -70,7 +75,7 @@ def get_process_id(name: str, raise_exec=False) -> int:
|
|
70
75
|
return 0
|
71
76
|
|
72
77
|
|
73
|
-
def get_rekordbox_pid(raise_exec=False):
|
78
|
+
def get_rekordbox_pid(raise_exec: bool = False) -> int:
|
74
79
|
"""Returns the process ID of the Rekordbox application.
|
75
80
|
|
76
81
|
Parameters
|
@@ -96,7 +101,7 @@ def get_rekordbox_pid(raise_exec=False):
|
|
96
101
|
return get_process_id("rekordbox", raise_exec)
|
97
102
|
|
98
103
|
|
99
|
-
def get_rekordbox_agent_pid(raise_exec=False):
|
104
|
+
def get_rekordbox_agent_pid(raise_exec: bool = False) -> int:
|
100
105
|
"""Returns the process ID of the RekordboxAgent application.
|
101
106
|
|
102
107
|
Parameters
|
@@ -122,7 +127,7 @@ def get_rekordbox_agent_pid(raise_exec=False):
|
|
122
127
|
return get_process_id("rekordboxAgent", raise_exec)
|
123
128
|
|
124
129
|
|
125
|
-
def pretty_xml(element, indent=None, encoding="utf-8"):
|
130
|
+
def pretty_xml(element: xml.Element, indent: str = None, encoding: str = "utf-8") -> str:
|
126
131
|
r"""Generates a formatted string of an XML element.
|
127
132
|
|
128
133
|
Parameters
|
@@ -161,3 +166,19 @@ def pretty_xml(element, indent=None, encoding="utf-8"):
|
|
161
166
|
# Remove annoying empty lines
|
162
167
|
string = "\n".join([line for line in string.splitlines() if line.strip()])
|
163
168
|
return string
|
169
|
+
|
170
|
+
|
171
|
+
def obfuscate(plaintext: str) -> bytes:
|
172
|
+
"""Obfuscates a plaintext string using zlib compression and XOR encryption."""
|
173
|
+
key = BLOB_KEY
|
174
|
+
data = zlib.compress(plaintext.encode("utf-8"))
|
175
|
+
xored = bytes(b ^ key[i % len(key)] for i, b in enumerate(data))
|
176
|
+
return base64.b85encode(xored) # bytes
|
177
|
+
|
178
|
+
|
179
|
+
def deobfuscate(blob: bytes) -> str:
|
180
|
+
"""Deobfuscates a previously obfuscated string."""
|
181
|
+
key = BLOB_KEY
|
182
|
+
data = base64.b85decode(blob)
|
183
|
+
xored = bytes(b ^ key[i % len(key)] for i, b in enumerate(data))
|
184
|
+
return zlib.decompress(xored).decode("utf-8")
|
@@ -1,11 +1,11 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: pyrekordbox
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.4
|
4
4
|
Summary: Inofficial Python package for interacting with the library of Pioneers Rekordbox DJ software.
|
5
5
|
Author-email: Dylan Jones <dylanljones94@gmail.com>
|
6
6
|
License: MIT License
|
7
7
|
|
8
|
-
Copyright (c) 2022-
|
8
|
+
Copyright (c) 2022-2025, Dylan Jones
|
9
9
|
|
10
10
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
11
11
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -29,7 +29,7 @@ Project-URL: Source, https://github.com/dylanljones/pyrekordbox
|
|
29
29
|
Project-URL: Documentation, https://pyrekordbox.readthedocs.io/en/stable/
|
30
30
|
Project-URL: Tracker, https://github.com/dylanljones/pyrekordbox/issues
|
31
31
|
Platform: any
|
32
|
-
Classifier: Development Status ::
|
32
|
+
Classifier: Development Status :: 4 - Beta
|
33
33
|
Classifier: Intended Audience :: Developers
|
34
34
|
Classifier: Intended Audience :: Information Technology
|
35
35
|
Classifier: License :: OSI Approved :: MIT License
|
@@ -48,14 +48,12 @@ Requires-Python: >=3.8
|
|
48
48
|
Description-Content-Type: text/markdown
|
49
49
|
License-File: LICENSE
|
50
50
|
Requires-Dist: bidict>=0.21.0
|
51
|
-
Requires-Dist: blowfish>=0.6.0
|
52
51
|
Requires-Dist: construct>=2.10.0
|
53
52
|
Requires-Dist: numpy>=1.19.0
|
54
53
|
Requires-Dist: packaging
|
55
54
|
Requires-Dist: psutil>=5.9.0
|
56
55
|
Requires-Dist: sqlalchemy>=2.0.0
|
57
56
|
Requires-Dist: sqlcipher3-wheels
|
58
|
-
Requires-Dist: frida-tools
|
59
57
|
Requires-Dist: python-dateutil
|
60
58
|
Provides-Extra: test
|
61
59
|
Requires-Dist: hypothesis>=6.0.0; extra == "test"
|
@@ -87,11 +85,9 @@ Pioneers Rekordbox DJ Software. It currently supports
|
|
87
85
|
- Analysis files (ANLZ)
|
88
86
|
- My-Setting files
|
89
87
|
|
90
|
-
|
88
|
+
Check the [changelog][CHANGELOG] for recent changes!
|
91
89
|
|
92
|
-
|
93
|
-
> This project is still under development and might contain bugs or have breaking API changes in the future.
|
94
|
-
> Check the [changelog][CHANGELOG] for recent changes!
|
90
|
+
Tested Rekordbox versions: ``5.8.6 | 6.7.7 | 7.0.9``
|
95
91
|
|
96
92
|
|
97
93
|
## 🔧 Installation
|
@@ -143,10 +139,6 @@ from pyrekordbox.config import update_config
|
|
143
139
|
update_config("<pioneer_install_dir>", "<pioneer_app_dir>")
|
144
140
|
````
|
145
141
|
|
146
|
-
Alternatively the two paths can be specified in a configuration file under the section
|
147
|
-
`rekordbox`. Supported configuration files are pyproject.toml, setup.cfg, pyrekordbox.toml,
|
148
|
-
pyrekordbox.cfg and pyrekordbox.yaml.
|
149
|
-
|
150
142
|
|
151
143
|
### Rekordbox 6/7 database
|
152
144
|
|
@@ -193,19 +185,6 @@ So far only a few tables support adding or deleting entries:
|
|
193
185
|
- ``DjmdGenre``: Genres
|
194
186
|
- ``DjmdLabel``: Labels
|
195
187
|
|
196
|
-
If the automatic key extraction fails the command line interface of ``pyrekordbox``
|
197
|
-
provides a command for downloading the key from known sources and writing it to the
|
198
|
-
cache file:
|
199
|
-
````shell
|
200
|
-
python -m pyrekordbox download-key
|
201
|
-
````
|
202
|
-
Once the key is cached the database can be opened without providing the key.
|
203
|
-
The key can also be provided manually:
|
204
|
-
````python
|
205
|
-
db = Rekordbox6Database(key="<insert key here>")
|
206
|
-
````
|
207
|
-
|
208
|
-
|
209
188
|
### Rekordbox XML
|
210
189
|
|
211
190
|
The Rekordbox XML database is used for importing (and exporting) Rekordbox collections
|
@@ -263,9 +242,6 @@ Changing and creating the Rekordbox analysis files is planned as well, but for t
|
|
263
242
|
full structure of the analysis files has to be understood.
|
264
243
|
|
265
244
|
Unsupported ANLZ tags:
|
266
|
-
- PCOB
|
267
|
-
- PCO2
|
268
|
-
- PSSI
|
269
245
|
- PWV6
|
270
246
|
- PWV7
|
271
247
|
- PWVC
|
@@ -317,22 +293,20 @@ instead of opening an issue.
|
|
317
293
|
Pyrekordbox is tested on Windows and MacOS, however some features can't be tested in
|
318
294
|
the CI setup since it requires a working Rekordbox installation.
|
319
295
|
|
296
|
+
## ♡ Sponsor
|
297
|
+
|
298
|
+
If pyrekordbox has helped you or saved you time, consider supporting its development - every coffee makes a difference!
|
299
|
+
|
300
|
+
[](https://www.buymeacoffee.com/dylanljones)
|
301
|
+
|
320
302
|
|
321
303
|
## 🔗 Related Projects and References
|
322
304
|
|
323
305
|
- [crate-digger]: Java library for fetching and parsing rekordbox exports and track analysis files.
|
324
306
|
- [rekordcrate]: Library for parsing Pioneer Rekordbox device exports
|
325
307
|
- [supbox]: Get the currently playing track from Rekordbox v6 as Audio Hijack Shoutcast/Icecast metadata, display in your OBS video broadcast or export as JSON.
|
326
|
-
- Deep Symmetry has an extensive analysis of Rekordbox's ANLZ and .edb export file formats
|
308
|
+
- [Deep Symmetry] has an extensive analysis of Rekordbox's ANLZ and .edb export file formats
|
327
309
|
https://djl-analysis.deepsymmetry.org/djl-analysis
|
328
|
-
- rekordcrate reverse engineered the format of the Rekordbox MySetting files
|
329
|
-
https://holzhaus.github.io/rekordcrate/rekordcrate/setting/index.html
|
330
|
-
- rekordcloud went into detail about the internals of Rekordbox 6
|
331
|
-
https://rekord.cloud/blog/technical-inspection-of-rekordbox-6-and-its-new-internals.
|
332
|
-
- supbox has a nice implementation on finding the Rekordbox 6 database key
|
333
|
-
https://github.com/gabek/supbox
|
334
|
-
|
335
|
-
|
336
310
|
|
337
311
|
|
338
312
|
[tests-badge]: https://img.shields.io/github/actions/workflow/status/dylanljones/pyrekordbox/tests.yml?branch=master&label=tests&logo=github&style=flat
|
@@ -379,3 +353,4 @@ the CI setup since it requires a working Rekordbox installation.
|
|
379
353
|
[rekordcrate]: https://github.com/Holzhaus/rekordcrate
|
380
354
|
[crate-digger]: https://github.com/Deep-Symmetry/crate-digger
|
381
355
|
[supbox]: https://github.com/gabek/supbox
|
356
|
+
[Deep Symmetry]: https://deepsymmetry.org/
|
@@ -0,0 +1,25 @@
|
|
1
|
+
pyrekordbox/__init__.py,sha256=XtHMC6j7c11dxpf2mrXGz8Ux8TJnlIGcGZTwhs6NpVU,664
|
2
|
+
pyrekordbox/__main__.py,sha256=uo_UyoTBXQ-mE3oxe45YWuWH9N2t9HJ5RuzEXQYELVY,4431
|
3
|
+
pyrekordbox/_version.py,sha256=ReYqsThJkI0PbGcOHlpeQrPIWshdyOrU6h3QkRk8bHw,704
|
4
|
+
pyrekordbox/config.py,sha256=roJEkEoKJ8Nj4OlzyE8NXaxa8riXp1GR2tYZnhS1hxI,16485
|
5
|
+
pyrekordbox/logger.py,sha256=dq1BtXBGavuAjuc45mvjF6mOWaeZqZFzo2aBOJdJ0Ik,483
|
6
|
+
pyrekordbox/rbxml.py,sha256=rb7bRnr_Bmf3P3bMOh8VDtR2EsVe7E4VYuClLkA-_Lc,46764
|
7
|
+
pyrekordbox/utils.py,sha256=JGFvmXY7P_Kn1-yvSvWPILpaEVBe_gkNtDH_DWsbIK0,5133
|
8
|
+
pyrekordbox/anlz/__init__.py,sha256=1sArQ6P-bxBJFdcnzW4CAN20pNl3YbmDvm-8pQizTZY,3308
|
9
|
+
pyrekordbox/anlz/file.py,sha256=oUYuAjFj7hr1Y0EoAyNsLfk0W4ryqdkdzEEKs25nPF4,7898
|
10
|
+
pyrekordbox/anlz/structs.py,sha256=Lt4fkb3SAE8w146eWeWGnpgRoP6jhLMWrSMoMwPjG04,7925
|
11
|
+
pyrekordbox/anlz/tags.py,sha256=rlbUAyLc-J5_l4g4xiw59Rl3dW-SClDEb7ZLRXu1xLg,16791
|
12
|
+
pyrekordbox/db6/__init__.py,sha256=TZX_BPGZIkc4zSTULIc8yd_bf91MAezGtZevKNh3kZ0,856
|
13
|
+
pyrekordbox/db6/aux_files.py,sha256=kKRTj2UWJdHx043MX3-yK5HUWrnxjDNZYBDOHp5Oi14,8726
|
14
|
+
pyrekordbox/db6/database.py,sha256=CXqhCx4dmyG9yI_QhuPp1tV-Tefmw4UGQ0lek7jsTdk,86111
|
15
|
+
pyrekordbox/db6/registry.py,sha256=a7qpCdvoM9EzL8iQIq4WeYDcwgdhMZtM17xOo3uXftk,10617
|
16
|
+
pyrekordbox/db6/smartlist.py,sha256=ukQpKmA06iWAfdzS81Vb0g0qaTVnXQ7pgKa28KcMkiY,12300
|
17
|
+
pyrekordbox/db6/tables.py,sha256=vKjFsAE49JHnc7470z5T9DJMxBGaIGULgzDNcw2h1UE,69268
|
18
|
+
pyrekordbox/mysettings/__init__.py,sha256=czSTZpv8pHYJGbqsNrwxvmpt2zHV1LPEF6f2aVoqpB8,795
|
19
|
+
pyrekordbox/mysettings/file.py,sha256=yAPQmkT5eTRyhJJ-7hKLmyw1EzQxrkFueFBmu3jGJSY,13181
|
20
|
+
pyrekordbox/mysettings/structs.py,sha256=5Y1F3qTmsP1fRB39_BEHpQVxKx2DO9BytEuJUG_RNcY,8472
|
21
|
+
pyrekordbox-0.4.4.dist-info/licenses/LICENSE,sha256=JfWrNYI7JQpFyPTnZJmttDJqrJLIJKN9qVARn9m9Hyk,1074
|
22
|
+
pyrekordbox-0.4.4.dist-info/METADATA,sha256=HYouMIPHbHZEopQN9LgNNIhP12MuBDpH0nzznJ98vaE,14555
|
23
|
+
pyrekordbox-0.4.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
24
|
+
pyrekordbox-0.4.4.dist-info/top_level.txt,sha256=bUHkyxIHZDgSB6zhYnF1o4Yf1EQlTGGIkVRq9uEtsa4,12
|
25
|
+
pyrekordbox-0.4.4.dist-info/RECORD,,
|
@@ -1,25 +0,0 @@
|
|
1
|
-
pyrekordbox/__init__.py,sha256=hvg2dB7qhgGB6SmcRg8AION6mTGdlsThdHhsDZ9WYfs,622
|
2
|
-
pyrekordbox/__main__.py,sha256=ogn1wEOue1RUjGA0BxmgVIphcSCkoM1jZKRND0cAVLA,6016
|
3
|
-
pyrekordbox/_version.py,sha256=_F8vLxUxrAtC2alXNPGVa9l3P6_vLpQAzemS6QlnPGQ,511
|
4
|
-
pyrekordbox/config.py,sha256=yKRE0N_YU68kek-7bz0vouTgoQOVMXGKLZA21ydePd0,28333
|
5
|
-
pyrekordbox/logger.py,sha256=dq1BtXBGavuAjuc45mvjF6mOWaeZqZFzo2aBOJdJ0Ik,483
|
6
|
-
pyrekordbox/rbxml.py,sha256=4qx7YX2UegsYQ2ETfqR-Qyus-8jQ89mer1YjEvq1WtQ,38422
|
7
|
-
pyrekordbox/utils.py,sha256=hkYIgG5U4rzl2tjN9ESzLnf8OysEFybRQgmr6J7xq-k,4363
|
8
|
-
pyrekordbox/anlz/__init__.py,sha256=SEVY0oPX9ohCVViUbsoOLTrBrFewTh-61qJxwXgAJKg,3155
|
9
|
-
pyrekordbox/anlz/file.py,sha256=F6axHmprnp0j3pZkqmmp5iiJBUpqtWiAhSzlAJp2H6Y,6951
|
10
|
-
pyrekordbox/anlz/structs.py,sha256=Lt4fkb3SAE8w146eWeWGnpgRoP6jhLMWrSMoMwPjG04,7925
|
11
|
-
pyrekordbox/anlz/tags.py,sha256=nlPBKyRB8Z9J69bX2K8ZPQk_g1tMazKeVf2ViAqMX-c,13947
|
12
|
-
pyrekordbox/db6/__init__.py,sha256=TZX_BPGZIkc4zSTULIc8yd_bf91MAezGtZevKNh3kZ0,856
|
13
|
-
pyrekordbox/db6/aux_files.py,sha256=MehdQSc4iryiHvH8RfE9_9xMnD5qjRRDhTo0o0KRLw0,7592
|
14
|
-
pyrekordbox/db6/database.py,sha256=IHEEg8X3BiQF2MMfvYg36BvL6yqYY_jpCO-ysP8tU3Q,80738
|
15
|
-
pyrekordbox/db6/registry.py,sha256=zYq_B7INM97de7vUTxqmA4N_P53loDkBkYdzdoeSnvY,9725
|
16
|
-
pyrekordbox/db6/smartlist.py,sha256=GG6jE0BHMtx0RHgiVRpWYuL-Ex5edTNSLSDQNiCGzK0,12170
|
17
|
-
pyrekordbox/db6/tables.py,sha256=rQZ1qtJBtxiSrvmqGQEG61um5sf6UL5GeppFKO2p_zo,68539
|
18
|
-
pyrekordbox/mysettings/__init__.py,sha256=6iLTQ1KIjuoq8Zt3thmkjqJSxrRVIi7BrQpxNcsQK04,706
|
19
|
-
pyrekordbox/mysettings/file.py,sha256=JBfVe3jsmah_mGJjyC20_EqJZyJ7ftcOcCkRDKcWgv0,12671
|
20
|
-
pyrekordbox/mysettings/structs.py,sha256=5Y1F3qTmsP1fRB39_BEHpQVxKx2DO9BytEuJUG_RNcY,8472
|
21
|
-
pyrekordbox-0.4.2.dist-info/licenses/LICENSE,sha256=VwG9ZgC2UZnI0gTezGz1qkcAZ7sknBUQ1M62Z2nht54,1074
|
22
|
-
pyrekordbox-0.4.2.dist-info/METADATA,sha256=XhI0TjehrWsupNOK1AEQcomb29sE2ydlb2wuU9WEXQ0,15480
|
23
|
-
pyrekordbox-0.4.2.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
|
24
|
-
pyrekordbox-0.4.2.dist-info/top_level.txt,sha256=bUHkyxIHZDgSB6zhYnF1o4Yf1EQlTGGIkVRq9uEtsa4,12
|
25
|
-
pyrekordbox-0.4.2.dist-info/RECORD,,
|
File without changes
|