pyrekordbox 0.2.1__py3-none-any.whl → 0.2.2__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 (71) hide show
  1. docs/source/formats/anlz.md +178 -7
  2. docs/source/formats/db6.md +1 -1
  3. docs/source/index.md +2 -6
  4. docs/source/quickstart.md +68 -45
  5. docs/source/tutorial/index.md +1 -1
  6. pyrekordbox/__init__.py +1 -1
  7. pyrekordbox/_version.py +2 -2
  8. pyrekordbox/anlz/file.py +39 -0
  9. pyrekordbox/anlz/structs.py +3 -5
  10. pyrekordbox/config.py +71 -27
  11. pyrekordbox/db6/database.py +260 -33
  12. pyrekordbox/db6/registry.py +22 -0
  13. pyrekordbox/db6/tables.py +3 -4
  14. {pyrekordbox-0.2.1.dist-info → pyrekordbox-0.2.2.dist-info}/METADATA +12 -11
  15. pyrekordbox-0.2.2.dist-info/RECORD +80 -0
  16. {pyrekordbox-0.2.1.dist-info → pyrekordbox-0.2.2.dist-info}/top_level.txt +0 -2
  17. tests/test_config.py +175 -0
  18. tests/test_db6.py +78 -0
  19. build/lib/build/lib/docs/source/conf.py +0 -178
  20. build/lib/build/lib/pyrekordbox/__init__.py +0 -22
  21. build/lib/build/lib/pyrekordbox/__main__.py +0 -204
  22. build/lib/build/lib/pyrekordbox/_version.py +0 -16
  23. build/lib/build/lib/pyrekordbox/anlz/__init__.py +0 -127
  24. build/lib/build/lib/pyrekordbox/anlz/file.py +0 -186
  25. build/lib/build/lib/pyrekordbox/anlz/structs.py +0 -299
  26. build/lib/build/lib/pyrekordbox/anlz/tags.py +0 -508
  27. build/lib/build/lib/pyrekordbox/config.py +0 -596
  28. build/lib/build/lib/pyrekordbox/db6/__init__.py +0 -45
  29. build/lib/build/lib/pyrekordbox/db6/aux_files.py +0 -213
  30. build/lib/build/lib/pyrekordbox/db6/database.py +0 -1808
  31. build/lib/build/lib/pyrekordbox/db6/registry.py +0 -304
  32. build/lib/build/lib/pyrekordbox/db6/tables.py +0 -1618
  33. build/lib/build/lib/pyrekordbox/logger.py +0 -23
  34. build/lib/build/lib/pyrekordbox/mysettings/__init__.py +0 -32
  35. build/lib/build/lib/pyrekordbox/mysettings/file.py +0 -369
  36. build/lib/build/lib/pyrekordbox/mysettings/structs.py +0 -282
  37. build/lib/build/lib/pyrekordbox/utils.py +0 -162
  38. build/lib/build/lib/pyrekordbox/xml.py +0 -1294
  39. build/lib/build/lib/tests/__init__.py +0 -3
  40. build/lib/build/lib/tests/test_anlz.py +0 -206
  41. build/lib/build/lib/tests/test_db6.py +0 -1039
  42. build/lib/build/lib/tests/test_mysetting.py +0 -203
  43. build/lib/build/lib/tests/test_xml.py +0 -629
  44. build/lib/docs/source/conf.py +0 -178
  45. build/lib/pyrekordbox/__init__.py +0 -22
  46. build/lib/pyrekordbox/__main__.py +0 -204
  47. build/lib/pyrekordbox/_version.py +0 -16
  48. build/lib/pyrekordbox/anlz/__init__.py +0 -127
  49. build/lib/pyrekordbox/anlz/file.py +0 -186
  50. build/lib/pyrekordbox/anlz/structs.py +0 -299
  51. build/lib/pyrekordbox/anlz/tags.py +0 -508
  52. build/lib/pyrekordbox/config.py +0 -596
  53. build/lib/pyrekordbox/db6/__init__.py +0 -45
  54. build/lib/pyrekordbox/db6/aux_files.py +0 -213
  55. build/lib/pyrekordbox/db6/database.py +0 -1808
  56. build/lib/pyrekordbox/db6/registry.py +0 -304
  57. build/lib/pyrekordbox/db6/tables.py +0 -1618
  58. build/lib/pyrekordbox/logger.py +0 -23
  59. build/lib/pyrekordbox/mysettings/__init__.py +0 -32
  60. build/lib/pyrekordbox/mysettings/file.py +0 -369
  61. build/lib/pyrekordbox/mysettings/structs.py +0 -282
  62. build/lib/pyrekordbox/utils.py +0 -162
  63. build/lib/pyrekordbox/xml.py +0 -1294
  64. build/lib/tests/__init__.py +0 -3
  65. build/lib/tests/test_anlz.py +0 -206
  66. build/lib/tests/test_db6.py +0 -1039
  67. build/lib/tests/test_mysetting.py +0 -203
  68. build/lib/tests/test_xml.py +0 -629
  69. pyrekordbox-0.2.1.dist-info/RECORD +0 -129
  70. {pyrekordbox-0.2.1.dist-info → pyrekordbox-0.2.2.dist-info}/LICENSE +0 -0
  71. {pyrekordbox-0.2.1.dist-info → pyrekordbox-0.2.2.dist-info}/WHEEL +0 -0
@@ -1,213 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # Author: Dylan Jones
3
- # Date: 2023-09-10
4
-
5
- from pathlib import Path
6
- from datetime import datetime
7
- import xml.etree.cElementTree as xml
8
- from ..config import get_config
9
- from ..utils import pretty_xml
10
-
11
-
12
- class MasterPlaylistXml:
13
- """Rekordbox v6 masterPlaylists6.xml file handler.
14
-
15
- Rekordbox stores some playlist information in the masterPlaylists6.xml file.
16
- Each playlist is represented by a <PLAYLIST> element, containing the following
17
- attributes:
18
- - Id: The playlist ID in hexadecimal format.
19
- - ParentId: The parent playlist ID in hexadecimal format. The root playlist has
20
- - Attributes: The type of playlist. 0 = normal, 1 = folder, 4 = smart playlist.
21
- - Timestamp: The last time the playlist was updated.
22
- - Lib_Type: ? (0 for palylists/folders)
23
- - CheckType: ? (always 0)
24
- """
25
-
26
- KEYS = ["Id", "ParentId", "Attributes", "Timestamp", "Lib_Type", "CheckType"]
27
-
28
- def __init__(self, path=None, db_dir=None):
29
- if path is None:
30
- if db_dir is None:
31
- db_dir = get_config("rekordbox6", "db_dir")
32
- path = Path(db_dir) / "masterPlaylists6.xml"
33
-
34
- tree = xml.parse(str(path))
35
- self.path = path
36
- self.root = tree.getroot()
37
- self.product = self.root.find("PRODUCT")
38
- self.playlists = self.root.find("PLAYLISTS")
39
- self._changed = False
40
-
41
- @property
42
- def version(self):
43
- return self.root.attrib["Version"]
44
-
45
- @property
46
- def automatic_sync(self):
47
- return self.root.attrib["AutomaticSync"]
48
-
49
- @property
50
- def rekordbox_version(self):
51
- return self.product.attrib["Version"]
52
-
53
- @property
54
- def modified(self):
55
- return self._changed
56
-
57
- def get_playlists(self):
58
- """Returns a list of the attributes of all playlist elements."""
59
- items = list()
60
- for playlist in self.playlists:
61
- items.append(playlist.attrib)
62
- return items
63
-
64
- def get(self, playlist_id):
65
- """Returns element attribs with the PlaylistID used in the `master.db` database.
66
-
67
- Parameters
68
- ----------
69
- playlist_id : str or int
70
- The playlist ID used in the main `master.db` database. This id is converted
71
- to hexadecimal format before searching.
72
-
73
- Returns
74
- -------
75
- playlist : dict
76
- """
77
- hex_id = f"{int(playlist_id):X}"
78
- element = self.playlists.find(f'.//NODE[@Id="{hex_id}"]')
79
- if element is None:
80
- return None
81
- attribs = dict(element.attrib)
82
- attribs["Attribute"] = int(attribs["Attribute"])
83
- attribs["Timestamp"] = datetime.fromtimestamp(int(attribs["Timestamp"]) / 1000)
84
- attribs["Lib_Type"] = int(attribs["Lib_Type"])
85
- attribs["CheckType"] = int(attribs["CheckType"])
86
- return attribs
87
-
88
- def add(
89
- self,
90
- playlist_id: str,
91
- parent_id: str,
92
- attribute: int,
93
- updated_at: datetime,
94
- lib_type: int = 0,
95
- check_type: int = 0,
96
- ):
97
- """Adds a new element with the PlaylistID used in the `master.db` database.
98
-
99
- Parameters
100
- ----------
101
- playlist_id : str or int
102
- The playlist ID used in the main `master.db` database. This id is converted
103
- to hexadecimal format before searching.
104
- parent_id : str or int, optional
105
- The parent playlist ID used in the main `master.db` database. This id is
106
- converted to hexadecimal format.
107
- attribute : int, optional
108
- The type of playlist. 0 = normal, 1 = folder, 4 = smart playlist.
109
- updated_at : datetime, optional
110
- The last time the playlist was updated.
111
- lib_type : int, optional
112
- The libarray type. It seems to be always 0 for playlists.
113
- check_type : int, optional
114
- The check type. It seems to be always 0.
115
-
116
- Returns
117
- -------
118
- element : xml.Element
119
- The newly created element.
120
- """
121
- hex_id = f"{int(playlist_id):X}"
122
- parent_id = f"{int(parent_id):X}" if parent_id != "root" else "0"
123
- timestamp = int(updated_at.timestamp() * 1000)
124
- attrib = {
125
- "Id": hex_id,
126
- "ParentId": parent_id,
127
- "Attribute": str(attribute),
128
- "Timestamp": str(timestamp),
129
- "Lib_Type": str(lib_type),
130
- "CheckType": str(check_type),
131
- }
132
- if self.playlists.find(f'.//NODE[@Id="{hex_id}"]') is not None:
133
- raise ValueError(f"Playlist with ID {playlist_id} ({hex_id}) exists.")
134
- element = xml.SubElement(self.playlists, "NODE", attrib=attrib)
135
- self._changed = True
136
- return element
137
-
138
- def remove(self, playlist_id):
139
- """Removes the element with the PlaylistID used in the `master.db` database.
140
-
141
- Parameters
142
- ----------
143
- playlist_id : str or int
144
- The playlist ID used in the main `master.db` database. This id is converted
145
- to hexadecimal format before searching.
146
- """
147
- hex_id = f"{int(playlist_id):X}"
148
- element = self.playlists.find(f'.//NODE[@Id="{hex_id}"]')
149
- if element is None:
150
- raise ValueError(f"Playlist with ID {playlist_id} ({hex_id}) not found.")
151
- self.playlists.remove(element)
152
- self._changed = True
153
-
154
- def update(
155
- self,
156
- playlist_id: str,
157
- parent_id: str = None,
158
- attribute: int = None,
159
- updated_at: datetime = None,
160
- lib_type: int = None,
161
- check_type: int = None,
162
- ):
163
- """Updates the element with the PlaylistID used in the `master.db` database.
164
-
165
- Parameters
166
- ----------
167
- playlist_id : str or int
168
- The playlist ID used in the main `master.db` database. This id is converted
169
- to hexadecimal format before searching.
170
- parent_id : str or int, optional
171
- The parent playlist ID used in the main `master.db` database. This id is
172
- converted to hexadecimal format.
173
- attribute : int, optional
174
- The type of playlist. 0 = normal, 1 = folder, 4 = smart playlist.
175
- updated_at : datetime, optional
176
- The last time the playlist was updated.
177
- lib_type : int, optional
178
- The libarray type. It seems to be always 0 for playlists.
179
- check_type : int, optional
180
- The check type. It seems to be always 0.
181
- """
182
- hex_id = f"{int(playlist_id):X}"
183
- element = self.playlists.find(f'.//NODE[@Id="{hex_id}"]')
184
- if element is None:
185
- raise ValueError(f"Playlist with ID {playlist_id} ({hex_id}) not found.")
186
-
187
- attribs = dict()
188
- if parent_id is not None:
189
- attribs["ParentId"] = f"{int(parent_id):X}" if parent_id != "root" else "0"
190
- if attribute is not None:
191
- attribs["Attribute"] = str(attribute)
192
- if updated_at is not None:
193
- attribs["Timestamp"] = str(int(updated_at.timestamp() * 1000))
194
- if lib_type is not None:
195
- attribs["Lib_Type"] = str(lib_type)
196
- if check_type is not None:
197
- attribs["CheckType"] = str(check_type)
198
-
199
- element.attrib.update(attribs)
200
- self._changed = True
201
-
202
- def to_string(self, indent=None):
203
- return pretty_xml(self.root, indent, encoding="utf-8")
204
-
205
- def save(self, path=None, indent=None):
206
- if path is None:
207
- path = self.path
208
- path = str(path)
209
-
210
- string = self.to_string(indent)
211
- with open(path, "w") as fh:
212
- fh.write(string)
213
- self._changed = False