pyrekordbox 0.4.2__py3-none-any.whl → 0.4.3__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/_version.py +2 -2
- pyrekordbox/anlz/__init__.py +6 -6
- pyrekordbox/anlz/file.py +40 -32
- pyrekordbox/anlz/tags.py +108 -70
- pyrekordbox/config.py +30 -24
- pyrekordbox/db6/aux_files.py +40 -14
- pyrekordbox/db6/database.py +379 -217
- pyrekordbox/db6/registry.py +48 -34
- pyrekordbox/db6/smartlist.py +12 -12
- pyrekordbox/db6/tables.py +51 -52
- pyrekordbox/mysettings/__init__.py +3 -2
- pyrekordbox/mysettings/file.py +27 -24
- pyrekordbox/rbxml.py +321 -142
- pyrekordbox/utils.py +7 -6
- {pyrekordbox-0.4.2.dist-info → pyrekordbox-0.4.3.dist-info}/METADATA +1 -1
- pyrekordbox-0.4.3.dist-info/RECORD +25 -0
- {pyrekordbox-0.4.2.dist-info → pyrekordbox-0.4.3.dist-info}/WHEEL +1 -1
- pyrekordbox-0.4.2.dist-info/RECORD +0 -25
- {pyrekordbox-0.4.2.dist-info → pyrekordbox-0.4.3.dist-info}/licenses/LICENSE +0 -0
- {pyrekordbox-0.4.2.dist-info → pyrekordbox-0.4.3.dist-info}/top_level.txt +0 -0
pyrekordbox/db6/registry.py
CHANGED
@@ -4,9 +4,19 @@
|
|
4
4
|
|
5
5
|
import logging
|
6
6
|
from contextlib import contextmanager
|
7
|
+
from datetime import datetime
|
8
|
+
from typing import TYPE_CHECKING, Any, Iterator, List, Tuple, Type
|
7
9
|
|
8
10
|
from sqlalchemy.orm.exc import ObjectDeletedError
|
9
11
|
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from .database import Rekordbox6Database
|
14
|
+
from .tables import AgentRegistry
|
15
|
+
|
16
|
+
|
17
|
+
Instances = Any
|
18
|
+
RegistryUpdateItem = Tuple[Instances, str, str, Any]
|
19
|
+
|
10
20
|
logger = logging.getLogger(__name__)
|
11
21
|
|
12
22
|
|
@@ -27,15 +37,15 @@ class RekordboxAgentRegistry:
|
|
27
37
|
The Rekordbox database instance.
|
28
38
|
"""
|
29
39
|
|
30
|
-
__update_sequence__ = list()
|
31
|
-
__update_history__ = list()
|
40
|
+
__update_sequence__: List[RegistryUpdateItem] = list()
|
41
|
+
__update_history__: List[RegistryUpdateItem] = list()
|
32
42
|
__enabled__ = True
|
33
43
|
|
34
|
-
def __init__(self, db):
|
44
|
+
def __init__(self, db: "Rekordbox6Database") -> None:
|
35
45
|
self.db = db
|
36
46
|
|
37
47
|
@classmethod
|
38
|
-
def on_update(cls, instance, key, value):
|
48
|
+
def on_update(cls, instance: Instances, key: str, value: Any) -> None:
|
39
49
|
"""Called when an instance of a database model is updated.
|
40
50
|
|
41
51
|
Parameters
|
@@ -52,7 +62,7 @@ class RekordboxAgentRegistry:
|
|
52
62
|
cls.__update_sequence__.append((instance, "update", key, value))
|
53
63
|
|
54
64
|
@classmethod
|
55
|
-
def on_create(cls, instance):
|
65
|
+
def on_create(cls, instance: Instances) -> None:
|
56
66
|
"""Called when an instance of a database model is created.
|
57
67
|
|
58
68
|
Parameters
|
@@ -65,7 +75,7 @@ class RekordboxAgentRegistry:
|
|
65
75
|
cls.__update_sequence__.append((instance, "create", "", ""))
|
66
76
|
|
67
77
|
@classmethod
|
68
|
-
def on_delete(cls, instance):
|
78
|
+
def on_delete(cls, instance: Instances) -> None:
|
69
79
|
"""Called when an instance of a database model is deleted.
|
70
80
|
|
71
81
|
Parameters
|
@@ -83,7 +93,7 @@ class RekordboxAgentRegistry:
|
|
83
93
|
cls.__update_sequence__.append((instance, "delete", "", ""))
|
84
94
|
|
85
95
|
@classmethod
|
86
|
-
def on_move(cls, instances):
|
96
|
+
def on_move(cls, instances: Instances) -> None:
|
87
97
|
"""Called when instanced of a database model are moved.
|
88
98
|
|
89
99
|
Parameters
|
@@ -96,24 +106,24 @@ class RekordboxAgentRegistry:
|
|
96
106
|
cls.__update_sequence__.append((instances, "move", "", ""))
|
97
107
|
|
98
108
|
@classmethod
|
99
|
-
def clear_buffer(cls):
|
109
|
+
def clear_buffer(cls) -> None:
|
100
110
|
"""Clears the update buffer and update history."""
|
101
111
|
cls.__update_history__.extend(cls.__update_sequence__)
|
102
112
|
cls.__update_sequence__.clear()
|
103
113
|
|
104
114
|
@classmethod
|
105
|
-
def enable_tracking(cls):
|
115
|
+
def enable_tracking(cls) -> None:
|
106
116
|
"""Enables the tracking of database changes."""
|
107
117
|
cls.__enabled__ = True
|
108
118
|
|
109
119
|
@classmethod
|
110
|
-
def disable_tracking(cls):
|
120
|
+
def disable_tracking(cls) -> None:
|
111
121
|
"""Disables the tracking of database changes."""
|
112
122
|
cls.__enabled__ = False
|
113
123
|
|
114
124
|
@classmethod
|
115
125
|
@contextmanager
|
116
|
-
def disabled(cls):
|
126
|
+
def disabled(cls) -> Iterator[Type["RekordboxAgentRegistry"]]:
|
117
127
|
"""Context manager to temporarily disable the tracking of database changes.
|
118
128
|
|
119
129
|
Examples
|
@@ -132,7 +142,7 @@ class RekordboxAgentRegistry:
|
|
132
142
|
if enabled:
|
133
143
|
cls.enable_tracking()
|
134
144
|
|
135
|
-
def get_registries(self):
|
145
|
+
def get_registries(self) -> Any:
|
136
146
|
"""Returns all agent registries.
|
137
147
|
|
138
148
|
Returns
|
@@ -141,7 +151,7 @@ class RekordboxAgentRegistry:
|
|
141
151
|
"""
|
142
152
|
return self.db.get_agent_registry()
|
143
153
|
|
144
|
-
def get_registry(self, key):
|
154
|
+
def get_registry(self, key: str) -> Any:
|
145
155
|
"""Returns the agent registry with the given key.
|
146
156
|
|
147
157
|
Parameters
|
@@ -155,7 +165,7 @@ class RekordboxAgentRegistry:
|
|
155
165
|
"""
|
156
166
|
return self.db.get_agent_registry(registry_id=key)
|
157
167
|
|
158
|
-
def get_string(self, key):
|
168
|
+
def get_string(self, key: str) -> str:
|
159
169
|
"""Returns the string value of the registry with the given key.
|
160
170
|
|
161
171
|
Parameters
|
@@ -167,9 +177,10 @@ class RekordboxAgentRegistry:
|
|
167
177
|
-------
|
168
178
|
value : str
|
169
179
|
"""
|
170
|
-
|
180
|
+
reg: "AgentRegistry" = self.db.get_agent_registry(registry_id=key)
|
181
|
+
return reg.str_1
|
171
182
|
|
172
|
-
def get_text(self, key):
|
183
|
+
def get_text(self, key: str) -> str:
|
173
184
|
"""Returns the text value of the registry with the given key.
|
174
185
|
|
175
186
|
Parameters
|
@@ -181,9 +192,10 @@ class RekordboxAgentRegistry:
|
|
181
192
|
-------
|
182
193
|
value : str
|
183
194
|
"""
|
184
|
-
|
195
|
+
reg: "AgentRegistry" = self.db.get_agent_registry(registry_id=key)
|
196
|
+
return reg.text_1
|
185
197
|
|
186
|
-
def get_int(self, key):
|
198
|
+
def get_int(self, key: str) -> int:
|
187
199
|
"""Returns the integer value of the registry with the given key.
|
188
200
|
|
189
201
|
Parameters
|
@@ -195,9 +207,10 @@ class RekordboxAgentRegistry:
|
|
195
207
|
-------
|
196
208
|
value : int
|
197
209
|
"""
|
198
|
-
|
210
|
+
reg: "AgentRegistry" = self.db.get_agent_registry(registry_id=key)
|
211
|
+
return reg.int_1
|
199
212
|
|
200
|
-
def get_date(self, key):
|
213
|
+
def get_date(self, key: str) -> datetime:
|
201
214
|
"""Returns the date value of the registry with the given key.
|
202
215
|
|
203
216
|
Parameters
|
@@ -209,9 +222,10 @@ class RekordboxAgentRegistry:
|
|
209
222
|
-------
|
210
223
|
value : datetime.datetime
|
211
224
|
"""
|
212
|
-
|
225
|
+
reg: "AgentRegistry" = self.db.get_agent_registry(registry_id=key)
|
226
|
+
return reg.date_1
|
213
227
|
|
214
|
-
def set_string(self, key, value):
|
228
|
+
def set_string(self, key: str, value: str) -> None:
|
215
229
|
"""Sets the string value of the registry with the given key.
|
216
230
|
|
217
231
|
Parameters
|
@@ -223,7 +237,7 @@ class RekordboxAgentRegistry:
|
|
223
237
|
"""
|
224
238
|
self.db.get_agent_registry(registry_id=key).str_1 = value
|
225
239
|
|
226
|
-
def set_text(self, key, value):
|
240
|
+
def set_text(self, key: str, value: str) -> None:
|
227
241
|
"""Sets the text value of the registry with the given key.
|
228
242
|
|
229
243
|
Parameters
|
@@ -235,7 +249,7 @@ class RekordboxAgentRegistry:
|
|
235
249
|
"""
|
236
250
|
self.db.get_agent_registry(registry_id=key).text_1 = value
|
237
251
|
|
238
|
-
def set_int(self, key, value):
|
252
|
+
def set_int(self, key: str, value: int) -> None:
|
239
253
|
"""Sets the integer value of the registry with the given key.
|
240
254
|
|
241
255
|
Parameters
|
@@ -247,7 +261,7 @@ class RekordboxAgentRegistry:
|
|
247
261
|
"""
|
248
262
|
self.db.get_agent_registry(registry_id=key).int_1 = value
|
249
263
|
|
250
|
-
def set_date(self, key, value):
|
264
|
+
def set_date(self, key: str, value: datetime) -> None:
|
251
265
|
"""Sets the date value of the registry with the given key.
|
252
266
|
|
253
267
|
Parameters
|
@@ -259,12 +273,12 @@ class RekordboxAgentRegistry:
|
|
259
273
|
"""
|
260
274
|
self.db.get_agent_registry(registry_id=key).date_1 = value
|
261
275
|
|
262
|
-
def get_local_update_count(self):
|
276
|
+
def get_local_update_count(self) -> int:
|
263
277
|
"""Returns the current global local USN (unique sequence number)."""
|
264
|
-
reg = self.db.get_agent_registry(registry_id="localUpdateCount")
|
278
|
+
reg: "AgentRegistry" = self.db.get_agent_registry(registry_id="localUpdateCount")
|
265
279
|
return reg.int_1
|
266
280
|
|
267
|
-
def set_local_update_count(self, value):
|
281
|
+
def set_local_update_count(self, value: int) -> None:
|
268
282
|
"""Sets the global local USN (unique sequence number).
|
269
283
|
|
270
284
|
Parameters
|
@@ -272,10 +286,10 @@ class RekordboxAgentRegistry:
|
|
272
286
|
value : int
|
273
287
|
The new USN value.
|
274
288
|
"""
|
275
|
-
reg = self.db.get_agent_registry(registry_id="localUpdateCount")
|
289
|
+
reg: "AgentRegistry" = self.db.get_agent_registry(registry_id="localUpdateCount")
|
276
290
|
reg.int_1 = value
|
277
291
|
|
278
|
-
def increment_local_update_count(self, num=1):
|
292
|
+
def increment_local_update_count(self, num: int = 1) -> int:
|
279
293
|
"""Increments the global local USN (unique sequence number) by the given number.
|
280
294
|
|
281
295
|
Parameters
|
@@ -290,11 +304,11 @@ class RekordboxAgentRegistry:
|
|
290
304
|
"""
|
291
305
|
if not isinstance(num, int) or num < 1:
|
292
306
|
raise ValueError("The USN can only be increment by a positive integer!")
|
293
|
-
reg = self.db.get_agent_registry(registry_id="localUpdateCount")
|
307
|
+
reg: "AgentRegistry" = self.db.get_agent_registry(registry_id="localUpdateCount")
|
294
308
|
reg.int_1 = reg.int_1 + num
|
295
309
|
return reg.int_1
|
296
310
|
|
297
|
-
def autoincrement_local_update_count(self, set_row_usn=True):
|
311
|
+
def autoincrement_local_update_count(self, set_row_usn: bool = True) -> int:
|
298
312
|
"""Auto-increments the global local USN (unique sequence number).
|
299
313
|
|
300
314
|
The number of changes in the update buffer is used to determine the
|
@@ -312,10 +326,10 @@ class RekordboxAgentRegistry:
|
|
312
326
|
The new global local USN.
|
313
327
|
"""
|
314
328
|
reg = self.db.get_agent_registry(registry_id="localUpdateCount")
|
315
|
-
usn = reg.int_1
|
329
|
+
usn: int = reg.int_1
|
316
330
|
self.disable_tracking()
|
317
331
|
self.db.flush()
|
318
|
-
with self.db.
|
332
|
+
with self.db.no_autoflush:
|
319
333
|
for instances, op, _, _ in self.__update_sequence__.copy():
|
320
334
|
usn += 1
|
321
335
|
if set_row_usn:
|
pyrekordbox/db6/smartlist.py
CHANGED
@@ -7,11 +7,11 @@ import xml.etree.cElementTree as xml
|
|
7
7
|
from dataclasses import dataclass
|
8
8
|
from datetime import datetime
|
9
9
|
from enum import Enum, IntEnum
|
10
|
-
from typing import List, Union
|
10
|
+
from typing import Any, Dict, List, Tuple, Union
|
11
11
|
|
12
12
|
from dateutil.relativedelta import relativedelta # noqa
|
13
13
|
from sqlalchemy import and_, not_, or_
|
14
|
-
from sqlalchemy.sql.elements import
|
14
|
+
from sqlalchemy.sql.elements import ColumnElement
|
15
15
|
|
16
16
|
from .tables import DjmdContent
|
17
17
|
|
@@ -99,7 +99,7 @@ _DATE_OPS = [
|
|
99
99
|
]
|
100
100
|
|
101
101
|
# Defines the valid operators for each property
|
102
|
-
VALID_OPS = {
|
102
|
+
VALID_OPS: Dict[str, Any] = {
|
103
103
|
Property.ARTIST: _STR_OPS,
|
104
104
|
Property.ALBUM: _STR_OPS,
|
105
105
|
Property.ALBUM_ARTIST: _STR_OPS,
|
@@ -126,7 +126,7 @@ VALID_OPS = {
|
|
126
126
|
}
|
127
127
|
|
128
128
|
# Defines the column names in the DB for properties that are directly mapped
|
129
|
-
PROPERTY_COLUMN_MAP = {
|
129
|
+
PROPERTY_COLUMN_MAP: Dict[str, str] = {
|
130
130
|
Property.ARTIST: "ArtistName",
|
131
131
|
Property.ALBUM: "AlbumName",
|
132
132
|
Property.ALBUM_ARTIST: "AlbumArtistName",
|
@@ -152,7 +152,7 @@ PROPERTY_COLUMN_MAP = {
|
|
152
152
|
Property.YEAR: "ReleaseYear",
|
153
153
|
}
|
154
154
|
|
155
|
-
TYPE_CONVERSION = {
|
155
|
+
TYPE_CONVERSION: Dict[str, Any] = {
|
156
156
|
Property.BPM: int,
|
157
157
|
Property.STOCK_DATE: lambda x: datetime.strptime(x, "%Y-%m-%d"),
|
158
158
|
Property.DATE_CREATED: lambda x: datetime.strptime(x, "%Y-%m-%d"),
|
@@ -176,7 +176,7 @@ class Condition:
|
|
176
176
|
value_left: Union[str, int]
|
177
177
|
value_right: Union[str, int]
|
178
178
|
|
179
|
-
def __post_init__(self):
|
179
|
+
def __post_init__(self) -> None:
|
180
180
|
if self.property not in PROPERTIES:
|
181
181
|
raise ValueError(
|
182
182
|
f"Invalid property: '{self.property}'! Supported properties: {PROPERTIES}"
|
@@ -196,15 +196,15 @@ class Condition:
|
|
196
196
|
|
197
197
|
def left_bitshift(x: int, nbit: int = 32) -> int:
|
198
198
|
"""Left shifts an N bit integer with sign change."""
|
199
|
-
return x - 2**nbit
|
199
|
+
return int(x - 2**nbit)
|
200
200
|
|
201
201
|
|
202
202
|
def right_bitshift(x: int, nbit: int = 32) -> int:
|
203
203
|
"""Right shifts an N bit integer with sign change."""
|
204
|
-
return x + 2**nbit
|
204
|
+
return int(x + 2**nbit)
|
205
205
|
|
206
206
|
|
207
|
-
def _get_condition_values(cond):
|
207
|
+
def _get_condition_values(cond: Condition) -> Tuple[Any, Any]:
|
208
208
|
val_left = cond.value_left
|
209
209
|
val_right = cond.value_right
|
210
210
|
func = None
|
@@ -223,7 +223,7 @@ def _get_condition_values(cond):
|
|
223
223
|
pass
|
224
224
|
|
225
225
|
if val_left == "":
|
226
|
-
val_left = None
|
226
|
+
val_left = None # type: ignore
|
227
227
|
|
228
228
|
return val_left, val_right
|
229
229
|
|
@@ -304,12 +304,12 @@ class SmartList:
|
|
304
304
|
cond = Condition(prop, int(operator), unit, value_left, value_right)
|
305
305
|
self.conditions.append(cond)
|
306
306
|
|
307
|
-
def filter_clause(self) ->
|
307
|
+
def filter_clause(self) -> ColumnElement[bool]:
|
308
308
|
"""Return a SQLAlchemy filter clause matching the content of the smart playlist.
|
309
309
|
|
310
310
|
Returns
|
311
311
|
-------
|
312
|
-
|
312
|
+
ColumnElement[bool]
|
313
313
|
A filter list macthing the contents of the smart playlist.
|
314
314
|
"""
|
315
315
|
logical_op = and_ if self.logical_operator == LogicalOperator.ALL else or_
|