pyrekordbox 0.3.1__py3-none-any.whl → 0.4.0__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.
Files changed (84) hide show
  1. pyrekordbox/__init__.py +8 -8
  2. pyrekordbox/__main__.py +3 -2
  3. pyrekordbox/_version.py +2 -2
  4. pyrekordbox/anlz/__init__.py +3 -2
  5. pyrekordbox/anlz/file.py +4 -2
  6. pyrekordbox/anlz/tags.py +3 -1
  7. pyrekordbox/config.py +79 -23
  8. pyrekordbox/db6/__init__.py +2 -2
  9. pyrekordbox/db6/aux_files.py +3 -2
  10. pyrekordbox/db6/database.py +227 -143
  11. pyrekordbox/db6/registry.py +1 -0
  12. pyrekordbox/db6/smartlist.py +375 -0
  13. pyrekordbox/db6/tables.py +81 -20
  14. pyrekordbox/logger.py +0 -1
  15. pyrekordbox/mysettings/__init__.py +5 -4
  16. pyrekordbox/mysettings/file.py +3 -1
  17. pyrekordbox/rbxml.py +5 -3
  18. pyrekordbox/utils.py +4 -3
  19. {pyrekordbox-0.3.1.dist-info → pyrekordbox-0.4.0.dist-info}/LICENSE +1 -1
  20. {pyrekordbox-0.3.1.dist-info → pyrekordbox-0.4.0.dist-info}/METADATA +26 -42
  21. pyrekordbox-0.4.0.dist-info/RECORD +25 -0
  22. {pyrekordbox-0.3.1.dist-info → pyrekordbox-0.4.0.dist-info}/WHEEL +1 -1
  23. {pyrekordbox-0.3.1.dist-info → pyrekordbox-0.4.0.dist-info}/top_level.txt +0 -2
  24. docs/Makefile +0 -20
  25. docs/make.bat +0 -35
  26. docs/source/_static/images/anlz_beat.svg +0 -53
  27. docs/source/_static/images/anlz_file.svg +0 -204
  28. docs/source/_static/images/anlz_pco2.svg +0 -138
  29. docs/source/_static/images/anlz_pcob.svg +0 -148
  30. docs/source/_static/images/anlz_pcp2.svg +0 -398
  31. docs/source/_static/images/anlz_pcpt.svg +0 -263
  32. docs/source/_static/images/anlz_ppth.svg +0 -123
  33. docs/source/_static/images/anlz_pqt2.svg +0 -324
  34. docs/source/_static/images/anlz_pqt2_2.svg +0 -253
  35. docs/source/_static/images/anlz_pqtz.svg +0 -140
  36. docs/source/_static/images/anlz_pssi.svg +0 -192
  37. docs/source/_static/images/anlz_pssi_entry.svg +0 -191
  38. docs/source/_static/images/anlz_pvbr.svg +0 -125
  39. docs/source/_static/images/anlz_pwav.svg +0 -130
  40. docs/source/_static/images/anlz_pwv3.svg +0 -139
  41. docs/source/_static/images/anlz_pwv4.svg +0 -139
  42. docs/source/_static/images/anlz_pwv5.svg +0 -139
  43. docs/source/_static/images/anlz_pwv5_entry.svg +0 -100
  44. docs/source/_static/images/anlz_pwv6.svg +0 -130
  45. docs/source/_static/images/anlz_pwv7.svg +0 -139
  46. docs/source/_static/images/anlz_pwvc.svg +0 -125
  47. docs/source/_static/images/anlz_tag.svg +0 -110
  48. docs/source/_static/images/x64dbg_rb_key.png +0 -0
  49. docs/source/_static/logos/dark/logo_primary.svg +0 -75
  50. docs/source/_static/logos/light/logo_primary.svg +0 -75
  51. docs/source/_static/logos/mid/logo_primary.svg +0 -75
  52. docs/source/_templates/apidoc/module.rst_t +0 -8
  53. docs/source/_templates/apidoc/package.rst_t +0 -57
  54. docs/source/_templates/apidoc/toc.rst_t +0 -7
  55. docs/source/_templates/autosummary/class.rst +0 -32
  56. docs/source/_templates/autosummary/module.rst +0 -55
  57. docs/source/api.md +0 -18
  58. docs/source/conf.py +0 -178
  59. docs/source/development/changes.md +0 -3
  60. docs/source/development/contributing.md +0 -3
  61. docs/source/formats/anlz.md +0 -634
  62. docs/source/formats/db6.md +0 -1233
  63. docs/source/formats/mysetting.md +0 -392
  64. docs/source/formats/xml.md +0 -376
  65. docs/source/index.md +0 -103
  66. docs/source/installation.md +0 -271
  67. docs/source/key.md +0 -103
  68. docs/source/quickstart.md +0 -185
  69. docs/source/requirements.txt +0 -7
  70. docs/source/tutorial/anlz.md +0 -7
  71. docs/source/tutorial/configuration.md +0 -66
  72. docs/source/tutorial/db6.md +0 -178
  73. docs/source/tutorial/index.md +0 -20
  74. docs/source/tutorial/mysetting.md +0 -124
  75. docs/source/tutorial/xml.md +0 -140
  76. pyrekordbox/db6/smart_playlist.py +0 -333
  77. pyrekordbox/xml.py +0 -8
  78. pyrekordbox-0.3.1.dist-info/RECORD +0 -84
  79. tests/__init__.py +0 -3
  80. tests/test_anlz.py +0 -206
  81. tests/test_config.py +0 -175
  82. tests/test_db6.py +0 -1115
  83. tests/test_mysetting.py +0 -203
  84. tests/test_xml.py +0 -629
@@ -1,333 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # Author: Dylan Jones
3
- # Date: 2023-12-13
4
-
5
- import xml.etree.cElementTree as xml
6
- from enum import IntEnum
7
- from typing import List, Union
8
- from datetime import datetime
9
- from dataclasses import dataclass
10
-
11
- from sqlalchemy import or_, and_, not_
12
- from sqlalchemy.sql.elements import BooleanClauseList
13
- from dateutil.relativedelta import relativedelta # noqa
14
-
15
- from .tables import DjmdContent
16
-
17
- __all__ = [
18
- "LogicalOperator",
19
- "Operator",
20
- "Condition",
21
- "SmartList",
22
- ]
23
-
24
-
25
- class LogicalOperator(IntEnum):
26
- ALL = 1
27
- ANY = 2
28
-
29
-
30
- class Operator(IntEnum):
31
- EQUAL = 1
32
- NOT_EQUAL = 2
33
- GREATER = 3
34
- LESS = 4
35
- IN_RANGE = 5
36
- IN_LAST = 6
37
- NOT_IN_LAST = 7
38
- CONTAINS = 8
39
- NOT_CONTAINS = 9
40
- STARTS_WITH = 10
41
- ENDS_WITH = 11
42
-
43
-
44
- STR_OPS = [
45
- Operator.EQUAL,
46
- Operator.NOT_EQUAL,
47
- Operator.CONTAINS,
48
- Operator.NOT_CONTAINS,
49
- Operator.STARTS_WITH,
50
- Operator.ENDS_WITH,
51
- ]
52
-
53
- NUM_OPS = [
54
- Operator.EQUAL,
55
- Operator.NOT_EQUAL,
56
- Operator.GREATER,
57
- Operator.LESS,
58
- Operator.IN_RANGE,
59
- ]
60
-
61
- DATE_OPS = [
62
- Operator.EQUAL,
63
- Operator.NOT_EQUAL,
64
- Operator.GREATER,
65
- Operator.LESS,
66
- Operator.IN_RANGE,
67
- Operator.IN_LAST,
68
- Operator.NOT_IN_LAST,
69
- ]
70
-
71
-
72
- PROPERTY_MAP = {
73
- "artist": "ArtistName",
74
- "album": "AlbumName",
75
- "albumArtist": "AlbumArtist",
76
- "originalArtist": "OrgArtist",
77
- "bpm": "BPM",
78
- "grouping": "ColorID",
79
- "comments": "Commnt",
80
- "producer": "ComposerName",
81
- "stockDate": "StockDate",
82
- "dateCreated": "created_at",
83
- "counter": "DJPlayCount",
84
- "fileName": "FileNameL",
85
- "genre": "GenreName",
86
- "key": "Key",
87
- "label": "LabelName",
88
- "mixName": "",
89
- "myTag": "myTag",
90
- "rating": "Rating",
91
- "dateReleased": "ReleaseDate",
92
- "remixedBy": "RemixerName",
93
- "duration": "Length",
94
- "name": "Title",
95
- "year": "ReleaseYear",
96
- }
97
-
98
-
99
- VALID_OPS = {
100
- "artist": STR_OPS,
101
- "album": STR_OPS,
102
- "albumArtist": STR_OPS,
103
- "originalArtist": STR_OPS,
104
- "bpm": NUM_OPS,
105
- "grouping": [Operator.EQUAL, Operator.NOT_EQUAL],
106
- "comments": STR_OPS,
107
- "producer": STR_OPS,
108
- "stockDate": DATE_OPS,
109
- "dateCreated": DATE_OPS,
110
- "counter": NUM_OPS,
111
- "fileName": STR_OPS,
112
- "genre": STR_OPS,
113
- "key": STR_OPS,
114
- "label": STR_OPS,
115
- "mixName": STR_OPS,
116
- "myTag": [Operator.CONTAINS, Operator.NOT_CONTAINS],
117
- "rating": NUM_OPS,
118
- "dateReleased": DATE_OPS,
119
- "remixedBy": STR_OPS,
120
- "duration": NUM_OPS,
121
- "name": STR_OPS,
122
- "year": NUM_OPS,
123
- }
124
-
125
- TYPE_CONVERSION = {
126
- "bpm": int,
127
- "stockDate": lambda x: datetime.strptime(x, "%Y-%m-%d"),
128
- "dateCreated": lambda x: datetime.strptime(x, "%Y-%m-%d"),
129
- "counter": int,
130
- "rating": int,
131
- "dateReleased": lambda x: datetime.strptime(x, "%Y-%m-%d"),
132
- "duration": int,
133
- "year": int,
134
- }
135
-
136
-
137
- @dataclass
138
- class Condition:
139
- """Dataclass for a smart playlist condition."""
140
-
141
- property: str
142
- operator: int
143
- unit: str
144
- value_left: Union[str, int]
145
- value_right: Union[str, int]
146
-
147
- def __post_init__(self):
148
- if self.property not in VALID_OPS:
149
- raise ValueError(f"Invalid property: '{self.property}'")
150
-
151
- valid_ops = VALID_OPS[self.property]
152
- if self.operator not in valid_ops:
153
- raise ValueError(
154
- f"Invalid operator '{self.operator}' for '{self.property}', "
155
- f"must be one of {valid_ops}"
156
- )
157
-
158
- if self.operator == Operator.IN_RANGE:
159
- if not self.value_right:
160
- raise ValueError(f"Operator '{self.operator}' requires `value_right`")
161
-
162
-
163
- def _get_condition_values(cond):
164
- val_left = cond.value_left
165
- val_right = cond.value_right
166
- func = None
167
- if cond.operator in (Operator.IN_LAST, Operator.NOT_IN_LAST):
168
- func = int
169
- elif cond.property in TYPE_CONVERSION:
170
- func = TYPE_CONVERSION[cond.property]
171
-
172
- if func is not None:
173
- if val_left != "":
174
- val_left = func(val_left)
175
- if val_right != "":
176
- try:
177
- val_right = func(val_right)
178
- except ValueError:
179
- pass
180
- return val_left, val_right
181
-
182
-
183
- class SmartList:
184
- """Rekordbox smart playlist XML handler."""
185
-
186
- def __init__(
187
- self,
188
- playlist_id: Union[int, str] = None,
189
- logical_operator: int = None,
190
- auto_update: int = 1,
191
- ):
192
- self.playlist_id: Union[int, str] = playlist_id
193
- self.logical_operator: int = logical_operator
194
- self.auto_update: int = auto_update
195
- self.conditions: List[Condition] = list()
196
-
197
- def parse(self, source: str) -> None:
198
- """Parse the XML source of a smart playlist."""
199
- tree = xml.ElementTree(xml.fromstring(source))
200
- root = tree.getroot()
201
- conditions = list()
202
- for child in root.findall("CONDITION"):
203
- condition = Condition(
204
- property=child.attrib["PropertyName"],
205
- operator=int(child.attrib["Operator"]),
206
- unit=child.attrib["ValueUnit"],
207
- value_left=child.attrib["ValueLeft"],
208
- value_right=child.attrib["ValueRight"],
209
- )
210
- conditions.append(condition)
211
-
212
- self.playlist_id = int(root.attrib["Id"])
213
- self.logical_operator = int(root.attrib["LogicalOperator"])
214
- self.auto_update = int(root.attrib["AutomaticUpdate"])
215
- self.conditions = conditions
216
-
217
- def to_xml(self) -> str:
218
- """Convert the smart playlist conditions to XML."""
219
- attrib = {
220
- "Id": str(self.playlist_id),
221
- "LogicalOperator": str(self.logical_operator),
222
- "AutomaticUpdate": str(self.auto_update),
223
- }
224
- root = xml.Element("NODE", attrib=attrib)
225
- for cond in self.conditions:
226
- attrib = {
227
- "PropertyName": str(cond.property),
228
- "Operator": str(cond.operator),
229
- "ValueUnit": str(cond.unit),
230
- "ValueLeft": str(cond.value_left),
231
- "ValueRight": str(cond.value_right),
232
- }
233
- xml.SubElement(root, "CONDITION", attrib=attrib)
234
- return xml.tostring(root).decode("utf-8").replace(" /", "/")
235
-
236
- def add_condition(
237
- self,
238
- prop: str,
239
- operator: int,
240
- value_left: str,
241
- value_right: str = "",
242
- unit: str = "",
243
- ) -> None:
244
- """Add a condition to the smart playlist.
245
-
246
- Parameters
247
- ----------
248
- prop : str
249
- The property to filter on.
250
- operator : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} int
251
- The operator to use. Must be in the range of 1-11
252
- value_left : str
253
- The left value to use.
254
- value_right : str, optional
255
- The right value to use, by default "".
256
- unit : str, optional
257
- The unit to use, by default "".
258
- """
259
- cond = Condition(prop, operator, unit, value_left, value_right)
260
- self.conditions.append(cond)
261
-
262
- def filter_clause(self) -> BooleanClauseList:
263
- """Return a SQLAlchemy filter clause matching the content of the smart playlist.
264
-
265
- Returns
266
- -------
267
- BooleanClauseList
268
- A filter list macthing the contents of the smart playlist.
269
- """
270
- conditions = self.conditions
271
- logical_op = and_ if self.logical_operator == LogicalOperator.ALL else or_
272
- cond = conditions[0]
273
-
274
- colum_name = PROPERTY_MAP[cond.property]
275
-
276
- comps = list()
277
- for cond in conditions:
278
- val_left, val_right = _get_condition_values(cond)
279
-
280
- if cond.operator == Operator.EQUAL:
281
- comp = getattr(DjmdContent, colum_name) == val_left
282
-
283
- elif cond.operator == Operator.NOT_EQUAL:
284
- comp = getattr(DjmdContent, colum_name) != val_left
285
-
286
- elif cond.operator == Operator.GREATER:
287
- comp = getattr(DjmdContent, colum_name) > val_left
288
-
289
- elif cond.operator == Operator.LESS:
290
- comp = getattr(DjmdContent, colum_name) < val_left
291
-
292
- elif cond.operator == Operator.IN_RANGE:
293
- comp = getattr(DjmdContent, colum_name).between(val_left, val_right)
294
-
295
- elif cond.operator == Operator.CONTAINS:
296
- comp = getattr(DjmdContent, colum_name).contains(val_left)
297
-
298
- elif cond.operator == Operator.NOT_CONTAINS:
299
- comp = not_(getattr(DjmdContent, colum_name).contains(val_left))
300
-
301
- elif cond.operator == Operator.STARTS_WITH:
302
- comp = getattr(DjmdContent, colum_name).startswith(val_left)
303
-
304
- elif cond.operator == Operator.ENDS_WITH:
305
- comp = getattr(DjmdContent, colum_name).endswith(val_left)
306
-
307
- elif cond.operator == Operator.IN_LAST:
308
- now = datetime.now()
309
- if cond.unit == "day":
310
- t0 = now - relativedelta(days=val_left)
311
- comp = getattr(DjmdContent, colum_name) > t0
312
- elif cond.unit == "month":
313
- t0 = now - relativedelta(months=val_left)
314
- comp = getattr(DjmdContent, colum_name).month > t0
315
- else:
316
- raise ValueError(f"Unknown unit '{cond.unit}'")
317
-
318
- elif cond.operator == Operator.NOT_IN_LAST:
319
- now = datetime.now()
320
- if cond.unit == "day":
321
- t0 = now - relativedelta(days=val_left)
322
- comp = getattr(DjmdContent, colum_name) < t0
323
- elif cond.unit == "month":
324
- t0 = now - relativedelta(months=val_left)
325
- comp = getattr(DjmdContent, colum_name).month < t0
326
- else:
327
- raise ValueError(f"Unknown unit '{cond.unit}'")
328
-
329
- else:
330
- raise ValueError(f"Unknown operator '{cond.operator}'")
331
-
332
- comps.append(comp)
333
- return logical_op(*comps)
pyrekordbox/xml.py DELETED
@@ -1,8 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # Author: Dylan Jones
3
- # Date: 2022-04-10
4
-
5
- from .utils import warn_deprecated as _warn_deprecated
6
- from .rbxml import * # noqa: F401, F403
7
-
8
- _warn_deprecated("pyrekordbox.xml", "pyrekordbox.rbxml", remove_in="0.4.0")
@@ -1,84 +0,0 @@
1
- docs/Makefile,sha256=4zv3TVkTACm6JBaKgTES3ZI9cETXgM6ULbZkXZP1as8,638
2
- docs/make.bat,sha256=s8EuuVXNRnn4xmWLWTpk3Z01aqJSJT8ymrmK6ux0zbc,769
3
- docs/source/api.md,sha256=IKKMeQ2wFSS_ippOWJ63ELtMjfkNe27KjWcFFEdUXnE,276
4
- docs/source/conf.py,sha256=lPfAJtd0VY7uEDmHrEfHvQzNJg6WN_1seM9pCFc2e6E,6244
5
- docs/source/index.md,sha256=c67TMpDCaiqFe44n0pXWL__utlLAz7xqfDVjyWbxx3M,2660
6
- docs/source/installation.md,sha256=WmX6gjuPimA6uXhS7wZzKKG1AQCHpfB0nPm3g8_ur6A,9234
7
- docs/source/key.md,sha256=J9kx2Cgwm-ddLjbFkjBmAargPSg5WfVguJ1ffrDuCDs,3976
8
- docs/source/quickstart.md,sha256=kKau0nQHc0RByrVq0pgaDKWTUX_l4290ruqY08mXTCg,6301
9
- docs/source/requirements.txt,sha256=7YYc-tO0BQcBVUa4GvM1r1G5Ma9gkwGZpNbAKlJL97s,117
10
- docs/source/_static/images/anlz_beat.svg,sha256=cVooi17HFw3mOT39cFNB05tr-cZwbK_Hjmho6eBJNX8,2924
11
- docs/source/_static/images/anlz_file.svg,sha256=E74hjyTFJRy6tCxyTPfsYoM0GmOKoY1To_eHatpPEjs,12320
12
- docs/source/_static/images/anlz_pco2.svg,sha256=LAv_EZf72FbslKdHmuBy5ROWy8xKKkkXqp7mSk3WG20,8155
13
- docs/source/_static/images/anlz_pcob.svg,sha256=w4NRLCj0EMMnQ2i6tnlE-nFxETSiTs8PQF5nxMI3bgo,8682
14
- docs/source/_static/images/anlz_pcp2.svg,sha256=JDncv7fo6ylorWyaH7kZ6roYB7zryFbJE_HY4IfWG8E,24904
15
- docs/source/_static/images/anlz_pcpt.svg,sha256=8PcHBFAHXrDnTyC_7rO0TM-5cGy8BfjIXWxDi0zEK8Y,16473
16
- docs/source/_static/images/anlz_ppth.svg,sha256=-rPlwvBrrsYaL87GNI-WJJBFCYkcZwkWoGwH5NT8bLk,7124
17
- docs/source/_static/images/anlz_pqt2.svg,sha256=sRvbV-DjoTIWtxwChaw6kBqKFXNqBCF4V9hru9ZtdiE,18386
18
- docs/source/_static/images/anlz_pqt2_2.svg,sha256=8g3XCJDz8xbH_KK7CvMpmIZjaGrWBKQVlA4k4M3PF50,13774
19
- docs/source/_static/images/anlz_pqtz.svg,sha256=OPlW76hPkbhOByYgmVQfucTpb5irZXYcASZokfpK3A0,8141
20
- docs/source/_static/images/anlz_pssi.svg,sha256=zM8fsNshSMd0wDvO_qM7RzsAKVIEN8Y41jY76hBJjyQ,11684
21
- docs/source/_static/images/anlz_pssi_entry.svg,sha256=YkUg7fXtUst0OBI6vIlhHCK-nzhmR-22UGKFQ0pHxxA,12095
22
- docs/source/_static/images/anlz_pvbr.svg,sha256=7mA6S__F4AoX-GamftlevellDiTlcIWRWi77A7HZEDg,7284
23
- docs/source/_static/images/anlz_pwav.svg,sha256=psm3g7ILLVNgPNmPG2Hy7k9-q7qmnMnyQ3_-XYVAW2g,7566
24
- docs/source/_static/images/anlz_pwv3.svg,sha256=FwZJIiHj5hj-FB-cioNlxrGBeIEuZy2BOLEzSWC57IE,8389
25
- docs/source/_static/images/anlz_pwv4.svg,sha256=k5GQu2N965zPSG0FQWuml96UMfqBvs8Vy-Emklvn2dI,8173
26
- docs/source/_static/images/anlz_pwv5.svg,sha256=Ph1TSlji2BgWK3rVI7MvnpGM68wef1s-Hs6OlmC0oQQ,8173
27
- docs/source/_static/images/anlz_pwv5_entry.svg,sha256=TyNh_6gIsQKuDvS0RO5tmsptzmxiQ-LL1L3DQdIFi4I,5648
28
- docs/source/_static/images/anlz_pwv6.svg,sha256=J2KvE_bI-NTFSpFp7QsKSsgbWGCyuUAuW_dOgdnv2DY,7577
29
- docs/source/_static/images/anlz_pwv7.svg,sha256=n5NsTErvfsCw-otWdVXn12lM0tHyh-zQDZsZtQOJf0U,8173
30
- docs/source/_static/images/anlz_pwvc.svg,sha256=wO_tsxRDVnAbptbSZYK1z7YOH-0vNUqXDB9Udj4ungA,7128
31
- docs/source/_static/images/anlz_tag.svg,sha256=owPTtrTRDYCkaSg32_UJ-MTZp3K6WlkRQdJHTzdtxqs,6188
32
- docs/source/_static/images/x64dbg_rb_key.png,sha256=gtwUA6lbuFRbLQQACnBQ-aO8p5Ex-7E41dS0cW6XyAU,280011
33
- docs/source/_static/logos/dark/logo_primary.svg,sha256=pH4Q28u9JaCA4dVrKB-NDy00PNw2EhDwz7fIYUzezvk,3079
34
- docs/source/_static/logos/light/logo_primary.svg,sha256=MUbYjowOcWdtoHVnK7pyV9xcTRdm7gS4whw94pVMGSI,3080
35
- docs/source/_static/logos/mid/logo_primary.svg,sha256=utCWWbXXW5auRRposMMaMO9t_AflsN13rZGo3_Pg2WE,3078
36
- docs/source/_templates/apidoc/module.rst_t,sha256=keQqb9G8LA-JS5tuytgzfsxRXsADEvuOz3mJjY9qYHU,185
37
- docs/source/_templates/apidoc/package.rst_t,sha256=Ra-lunZcMyDtrb6vgrfAnBcBW4eFMTEIyg12fSe9h4o,1173
38
- docs/source/_templates/apidoc/toc.rst_t,sha256=6EfpNwcRXLa8Ae3NcovuSmV5PSBy5gP0t6XfphUYb7M,127
39
- docs/source/_templates/autosummary/class.rst,sha256=5yRMWkUNDXGvQE1gGm6yisL1bX4BDOsaBPciNUs_6vA,579
40
- docs/source/_templates/autosummary/module.rst,sha256=xSCcWeBqQdMgpese2OwFlvzSOMsPZKTBCLCwgD3OG4k,789
41
- docs/source/development/changes.md,sha256=ys1_zvYKQWEak_mBXBUMLpO3CWriHpjSAg1-17mTk04,40
42
- docs/source/development/contributing.md,sha256=7bERN03kHo2Wf0ZrgHYP4MfBSdFGmE_Kk0CxK0uay2I,43
43
- docs/source/formats/anlz.md,sha256=P7FrPqbu3i8SlRKVV9IU9cOQajKJHOjLlAWHheDGN7c,21455
44
- docs/source/formats/db6.md,sha256=fuB1_PaalHV4zRkhXh5_mn1ZgHfPnSu_OzUOYbVls6w,30121
45
- docs/source/formats/mysetting.md,sha256=OIYIn_B2HJcJtJM0wNjjzPy3xPkyz4raxg_-Y6E3D1k,9746
46
- docs/source/formats/xml.md,sha256=uL7eWWQfQXsyf55Vydt1iLq7Jzio3kIGbSfjpg5-CRY,8491
47
- docs/source/tutorial/anlz.md,sha256=JtcQIy44qaSP_GL0aL9VYQYOX8aVju7uFxgN3FPNy9o,145
48
- docs/source/tutorial/configuration.md,sha256=mqmeFM3I7pDA_ajPQWqVyvc9Y0PWGYXLr3yyojTGsL8,2127
49
- docs/source/tutorial/db6.md,sha256=nmaC6sF1noBxp0_LvihnzD9eMYeL-fCkAet4qiShOcc,6611
50
- docs/source/tutorial/index.md,sha256=zjx5uXESYzHIyeqtL4XjhZUDPOpNiutZ3gkUOeG8R9w,318
51
- docs/source/tutorial/mysetting.md,sha256=su-WMvEd3DrFF32RDfQBm3TlAUgK5PRPT1n_77BYnvY,3659
52
- docs/source/tutorial/xml.md,sha256=x_rFvsVzZtUV0upEkPWkgrmr3B-FYjZKWvBuJBLFAu0,6414
53
- pyrekordbox/__init__.py,sha256=ODYrBuSF14PNKNAxsbi5_VR-ja2P3ySK0WwM8l7MFCk,647
54
- pyrekordbox/__main__.py,sha256=R1lus_-hBG4Uf6SRuzXXFwaE-dT9Uma_lzMOGgsdDLs,5975
55
- pyrekordbox/_version.py,sha256=HzPz9rq3s1AiZXregKlqKaJJ2wGMtvH_a3V9la9CnpM,411
56
- pyrekordbox/config.py,sha256=ttihHzwfg3IGnp2IyCdnOWKhiH72HZ-dy7NQb4-SG-8,25190
57
- pyrekordbox/logger.py,sha256=qCY_3L_3WIMAvNmVKvh7oshGlWrd0T5aIW1bNCIu3Lo,521
58
- pyrekordbox/rbxml.py,sha256=0qsKc8SQa54URwWGt6oHTOHBiAQU2S8MbSxDbzKUB7A,38369
59
- pyrekordbox/utils.py,sha256=sT1xt-rM94Dir-S0OSSqKbquf9kdFbzZvBu3-7q0QDM,4361
60
- pyrekordbox/xml.py,sha256=7wFkMyWL4AQLINvxVxkQxlruG9c7R-gkxdP7xXFOkWU,241
61
- pyrekordbox/anlz/__init__.py,sha256=OSpyl3pmmnt3mG905J9qvNnYchsgrIfathw0QXoOhjo,3156
62
- pyrekordbox/anlz/file.py,sha256=r2FppO6efPzKfCfz6foX9G2aBu8gkKXMrjIm9fua3_M,6949
63
- pyrekordbox/anlz/structs.py,sha256=Lt4fkb3SAE8w146eWeWGnpgRoP6jhLMWrSMoMwPjG04,7925
64
- pyrekordbox/anlz/tags.py,sha256=uqneBP9CstYy7a4IpeEC9A5tfI59DQm0ik7yFXk_dNo,14094
65
- pyrekordbox/db6/__init__.py,sha256=d2ITtFzw41QfaI_v6QPYpr2KxgziGdsVyxOdXTvlPH0,886
66
- pyrekordbox/db6/aux_files.py,sha256=t0SfMCXBHjlCSfgRfpw1RTj0cmV0QY07xSLepjQqMnY,7591
67
- pyrekordbox/db6/database.py,sha256=dO2v7JNBMLDt7g22vLDmegzP3TYeeYiBnQqE5P5q8AE,78252
68
- pyrekordbox/db6/registry.py,sha256=L4X49HqKtvyD_c4Ad3HR7aM5bj468MgD3Yj6WUE0ri8,9724
69
- pyrekordbox/db6/smart_playlist.py,sha256=BOZrPHUU1r0_dM3fwLn8flBi5tigeScENoB3RFoyHiY,9911
70
- pyrekordbox/db6/tables.py,sha256=EnfZscPVVeVKmVTFmDoXT3sHMcfjgtq8j-GIMpElMuU,66326
71
- pyrekordbox/mysettings/__init__.py,sha256=rMS6Kknf1-X3PXF_TUxm8xui0H1Ap3R7G_9mqlnQUAM,705
72
- pyrekordbox/mysettings/file.py,sha256=dQEsdBivpverXCssyVNUeQyUXIooNrOGIIiPLwi_6T4,12669
73
- pyrekordbox/mysettings/structs.py,sha256=5Y1F3qTmsP1fRB39_BEHpQVxKx2DO9BytEuJUG_RNcY,8472
74
- tests/__init__.py,sha256=s321RtRiHJsLt0YFq0NRncW7u66uwYHQE-6IjPcg10o,67
75
- tests/test_anlz.py,sha256=hZAW5GFEJpU8UmmHYLuU5OZlApGrWZyPAR79KtaR0cw,5782
76
- tests/test_config.py,sha256=wYp4wHRhIk2grhGXhk4z9umrhOWhVvTOm2mHydzLEs8,6157
77
- tests/test_db6.py,sha256=O19L1nZiQX492ts3uY3yU6dprzcH7WTUobJKb4HErFA,37411
78
- tests/test_mysetting.py,sha256=te6B_BErGc6ThgBpAl45n0Nd0hWJcm-X9WTw14bR6MA,5781
79
- tests/test_xml.py,sha256=SMRML85D24AMpgqBASK1rd-5UdacTlyUVWZGpOoRp40,16854
80
- pyrekordbox-0.3.1.dist-info/LICENSE,sha256=Au8sngdQ79q5JsZXZJVU13j46VDxFbPwC4x6sSz8Jes,1074
81
- pyrekordbox-0.3.1.dist-info/METADATA,sha256=5OaFdFRXPPnvMKhbifLndCDzWvi74uwq3offFgT25z0,16720
82
- pyrekordbox-0.3.1.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
83
- pyrekordbox-0.3.1.dist-info/top_level.txt,sha256=Cv8QDfcJ7y8fYUm0Q8D5GoiGxaqb7qt8Z5ntVbj1cLk,23
84
- pyrekordbox-0.3.1.dist-info/RECORD,,
tests/__init__.py DELETED
@@ -1,3 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # Author: Dylan Jones
3
- # Date: 2022-05-07
tests/test_anlz.py DELETED
@@ -1,206 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # Author: Dylan Jones
3
- # Date: 2023-02-01
4
-
5
- import os
6
- import pytest
7
- import numpy as np
8
- from numpy.testing import assert_equal
9
- from pyrekordbox import anlz
10
-
11
- TEST_ROOT = os.path.join(os.path.dirname(os.path.dirname(__file__)), ".testdata")
12
- ANLZ_ROOT = os.path.join(TEST_ROOT, "export", "PIONEER", "USBANLZ")
13
- ANLZ_DIRS = list(anlz.walk_anlz_paths(ANLZ_ROOT))
14
- ANLZ_FILES = [paths for _, paths in ANLZ_DIRS]
15
-
16
-
17
- def test_parse():
18
- for root, files in ANLZ_DIRS:
19
- for path in files.values():
20
- anlz.AnlzFile.parse_file(path)
21
-
22
-
23
- def test_rebuild():
24
- for root, files in ANLZ_DIRS:
25
- for path in files.values():
26
- file = anlz.AnlzFile.parse_file(path)
27
- data = file.build()
28
- assert len(data) == file.file_header.len_file
29
- _ = anlz.AnlzFile.parse(data)
30
-
31
-
32
- def test_read_anlz_files():
33
- for root, files in ANLZ_DIRS:
34
- anlz_files = anlz.read_anlz_files(root)
35
- assert len(files) == len(anlz_files)
36
-
37
-
38
- # -- Tags ------------------------------------------------------------------------------
39
-
40
-
41
- @pytest.mark.parametrize("paths", ANLZ_FILES)
42
- def test_pqtz_tag_getters(paths):
43
- file = anlz.AnlzFile.parse_file(paths["DAT"])
44
- tag = file.get_tag("PQTZ")
45
- beats, bpms, times = tag.get()
46
- nbeats = len(beats)
47
- # Check that shape of arrays are equal
48
- assert nbeats == len(bpms)
49
- assert nbeats == len(times)
50
- # Check that the beats array only contains the values 1-4
51
- if nbeats:
52
- assert_equal(np.sort(np.unique(beats)), [1, 2, 3, 4])
53
-
54
- # Check other getters
55
- assert_equal(beats, tag.get_beats())
56
- assert_equal(bpms, tag.get_bpms())
57
- assert_equal(times, tag.get_times())
58
-
59
-
60
- def test_pqtz_tag_set_beats():
61
- paths = ANLZ_FILES[0]
62
- file = anlz.AnlzFile.parse_file(paths["DAT"])
63
- tag = file.get_tag("PQTZ")
64
-
65
- beats = np.ones(tag.count)
66
- tag.set_beats(beats)
67
- assert_equal(tag.get_beats(), beats)
68
-
69
-
70
- def test_pqtz_tag_set_bpms():
71
- paths = ANLZ_FILES[0]
72
- file = anlz.AnlzFile.parse_file(paths["DAT"])
73
- tag = file.get_tag("PQTZ")
74
-
75
- bpms = 100 * np.ones(tag.count, dtype=np.float64)
76
- tag.set_bpms(bpms)
77
- assert_equal(tag.get_bpms(), bpms)
78
-
79
-
80
- def test_pqtz_tag_set_times():
81
- paths = ANLZ_FILES[0]
82
- file = anlz.AnlzFile.parse_file(paths["DAT"])
83
- tag = file.get_tag("PQTZ")
84
-
85
- times = 0.5 * np.arange(tag.count)
86
- tag.set_times(times)
87
- assert_equal(tag.get_times(), times)
88
-
89
-
90
- def test_pqtz_tag_set():
91
- paths = ANLZ_FILES[0]
92
- file = anlz.AnlzFile.parse_file(paths["DAT"])
93
- tag = file.get_tag("PQTZ")
94
-
95
- beats = np.ones(tag.count)
96
- bpms = 100 * np.ones(tag.count, dtype=np.float64)
97
- times = 0.5 * np.arange(tag.count)
98
- tag.set(beats, bpms, times)
99
- assert_equal(tag.get_bpms(), bpms)
100
- assert_equal(tag.get_bpms(), bpms)
101
- assert_equal(tag.get_times(), times)
102
-
103
-
104
- @pytest.mark.parametrize("paths", ANLZ_FILES)
105
- def test_ppth_tag_getters(paths):
106
- tmp = ""
107
- for path in paths.values():
108
- file = anlz.AnlzFile.parse_file(path)
109
- tag = file.get_tag("PPTH")
110
- p = tag.get()
111
- if not tmp:
112
- tmp = p
113
- else:
114
- assert tmp == p
115
-
116
-
117
- def test_ppth_tag_setters():
118
- paths = ANLZ_FILES[0]
119
- extected = r"C:/new/path/to/file.mp3"
120
- for path in paths.values():
121
- file = anlz.AnlzFile.parse_file(path)
122
- tag = file.get_tag("PPTH")
123
- tag.set(r"C:\new\path\to\file.mp3")
124
- assert tag.get() == extected
125
-
126
-
127
- @pytest.mark.parametrize("paths", ANLZ_FILES)
128
- def test_pwav_tag_getters(paths):
129
- file = anlz.AnlzFile.parse_file(paths["DAT"])
130
- tag = file.get_tag("PWAV")
131
-
132
- heights, color = tag.get()
133
- assert len(heights) == len(color)
134
- assert np.all(np.logical_and(0 <= heights, heights <= 31))
135
- assert np.all(np.logical_and(0 <= color, color <= 7))
136
-
137
-
138
- @pytest.mark.parametrize("paths", ANLZ_FILES)
139
- def test_pwv2_tag_getters(paths):
140
- file = anlz.AnlzFile.parse_file(paths["DAT"])
141
- tag = file.get_tag("PWV2")
142
-
143
- heights, color = tag.get()
144
- assert len(heights) == len(color)
145
- assert np.all(np.logical_and(0 <= heights, heights <= 31))
146
- assert np.all(np.logical_and(0 <= color, color <= 7))
147
-
148
-
149
- @pytest.mark.parametrize("paths", ANLZ_FILES)
150
- def test_pwv3_tag_getters(paths):
151
- file = anlz.AnlzFile.parse_file(paths["EXT"])
152
- tag = file.get_tag("PWV3")
153
-
154
- heights, color = tag.get()
155
- assert len(heights) == len(color)
156
- assert np.all(np.logical_and(0 <= heights, heights <= 31))
157
- assert np.all(np.logical_and(0 <= color, color <= 7))
158
-
159
-
160
- @pytest.mark.parametrize("paths", ANLZ_FILES)
161
- def test_pwv4_tag_getters(paths):
162
- file = anlz.AnlzFile.parse_file(paths["EXT"])
163
- tag = file.get_tag("PWV4")
164
-
165
- heights, colors, blues = tag.get()
166
- assert len(heights) == len(colors)
167
- assert len(heights) == len(blues)
168
-
169
-
170
- @pytest.mark.parametrize("paths", ANLZ_FILES)
171
- def test_pwv5_tag_getters(paths):
172
- file = anlz.AnlzFile.parse_file(paths["EXT"])
173
- tag = file.get_tag("PWV5")
174
-
175
- heights, colors = tag.get()
176
- assert len(heights) == colors.shape[0]
177
-
178
-
179
- # -- File ------------------------------------------------------------------------------
180
-
181
-
182
- def test_anlzfile_getall_tags():
183
- paths = ANLZ_FILES[0]
184
- file = anlz.AnlzFile.parse_file(paths["DAT"])
185
- key = "PPTH"
186
- tags = file.getall_tags(key)
187
- assert len(tags) == 1
188
- assert tags[0].get() == file.get(key)
189
-
190
-
191
- def test_anlzfile_get():
192
- paths = ANLZ_FILES[0]
193
- file = anlz.AnlzFile.parse_file(paths["DAT"])
194
- key = "PPTH"
195
- tag = file.get_tag(key)
196
- assert file.get(key) == tag.get()
197
-
198
-
199
- def test_anlzfile_getall():
200
- paths = ANLZ_FILES[0]
201
- file = anlz.AnlzFile.parse_file(paths["DAT"])
202
- key = "PPTH"
203
- tag = file.get_tag(key)
204
- values = file.getall(key)
205
- assert len(values) == 1
206
- assert values[0] == tag.get()