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.
- docs/source/formats/anlz.md +178 -7
- docs/source/formats/db6.md +1 -1
- docs/source/index.md +2 -6
- docs/source/quickstart.md +68 -45
- docs/source/tutorial/index.md +1 -1
- pyrekordbox/__init__.py +1 -1
- pyrekordbox/_version.py +2 -2
- pyrekordbox/anlz/file.py +39 -0
- pyrekordbox/anlz/structs.py +3 -5
- pyrekordbox/config.py +71 -27
- pyrekordbox/db6/database.py +260 -33
- pyrekordbox/db6/registry.py +22 -0
- pyrekordbox/db6/tables.py +3 -4
- {pyrekordbox-0.2.1.dist-info → pyrekordbox-0.2.2.dist-info}/METADATA +12 -11
- pyrekordbox-0.2.2.dist-info/RECORD +80 -0
- {pyrekordbox-0.2.1.dist-info → pyrekordbox-0.2.2.dist-info}/top_level.txt +0 -2
- tests/test_config.py +175 -0
- tests/test_db6.py +78 -0
- build/lib/build/lib/docs/source/conf.py +0 -178
- build/lib/build/lib/pyrekordbox/__init__.py +0 -22
- build/lib/build/lib/pyrekordbox/__main__.py +0 -204
- build/lib/build/lib/pyrekordbox/_version.py +0 -16
- build/lib/build/lib/pyrekordbox/anlz/__init__.py +0 -127
- build/lib/build/lib/pyrekordbox/anlz/file.py +0 -186
- build/lib/build/lib/pyrekordbox/anlz/structs.py +0 -299
- build/lib/build/lib/pyrekordbox/anlz/tags.py +0 -508
- build/lib/build/lib/pyrekordbox/config.py +0 -596
- build/lib/build/lib/pyrekordbox/db6/__init__.py +0 -45
- build/lib/build/lib/pyrekordbox/db6/aux_files.py +0 -213
- build/lib/build/lib/pyrekordbox/db6/database.py +0 -1808
- build/lib/build/lib/pyrekordbox/db6/registry.py +0 -304
- build/lib/build/lib/pyrekordbox/db6/tables.py +0 -1618
- build/lib/build/lib/pyrekordbox/logger.py +0 -23
- build/lib/build/lib/pyrekordbox/mysettings/__init__.py +0 -32
- build/lib/build/lib/pyrekordbox/mysettings/file.py +0 -369
- build/lib/build/lib/pyrekordbox/mysettings/structs.py +0 -282
- build/lib/build/lib/pyrekordbox/utils.py +0 -162
- build/lib/build/lib/pyrekordbox/xml.py +0 -1294
- build/lib/build/lib/tests/__init__.py +0 -3
- build/lib/build/lib/tests/test_anlz.py +0 -206
- build/lib/build/lib/tests/test_db6.py +0 -1039
- build/lib/build/lib/tests/test_mysetting.py +0 -203
- build/lib/build/lib/tests/test_xml.py +0 -629
- build/lib/docs/source/conf.py +0 -178
- build/lib/pyrekordbox/__init__.py +0 -22
- build/lib/pyrekordbox/__main__.py +0 -204
- build/lib/pyrekordbox/_version.py +0 -16
- build/lib/pyrekordbox/anlz/__init__.py +0 -127
- build/lib/pyrekordbox/anlz/file.py +0 -186
- build/lib/pyrekordbox/anlz/structs.py +0 -299
- build/lib/pyrekordbox/anlz/tags.py +0 -508
- build/lib/pyrekordbox/config.py +0 -596
- build/lib/pyrekordbox/db6/__init__.py +0 -45
- build/lib/pyrekordbox/db6/aux_files.py +0 -213
- build/lib/pyrekordbox/db6/database.py +0 -1808
- build/lib/pyrekordbox/db6/registry.py +0 -304
- build/lib/pyrekordbox/db6/tables.py +0 -1618
- build/lib/pyrekordbox/logger.py +0 -23
- build/lib/pyrekordbox/mysettings/__init__.py +0 -32
- build/lib/pyrekordbox/mysettings/file.py +0 -369
- build/lib/pyrekordbox/mysettings/structs.py +0 -282
- build/lib/pyrekordbox/utils.py +0 -162
- build/lib/pyrekordbox/xml.py +0 -1294
- build/lib/tests/__init__.py +0 -3
- build/lib/tests/test_anlz.py +0 -206
- build/lib/tests/test_db6.py +0 -1039
- build/lib/tests/test_mysetting.py +0 -203
- build/lib/tests/test_xml.py +0 -629
- pyrekordbox-0.2.1.dist-info/RECORD +0 -129
- {pyrekordbox-0.2.1.dist-info → pyrekordbox-0.2.2.dist-info}/LICENSE +0 -0
- {pyrekordbox-0.2.1.dist-info → pyrekordbox-0.2.2.dist-info}/WHEEL +0 -0
tests/test_config.py
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Author: Dylan Jones
|
3
|
+
# Date: 2023-10-02
|
4
|
+
|
5
|
+
import pytest
|
6
|
+
import json
|
7
|
+
from pathlib import Path
|
8
|
+
from pyrekordbox.config import update_config, get_config
|
9
|
+
|
10
|
+
RB_SETTING = """<?xml version="1.0" encoding="UTF-8"?>
|
11
|
+
<PROPERTIES><VALUE name="masterDbDirectory" val="{db_dir}"/></PROPERTIES>
|
12
|
+
"""
|
13
|
+
|
14
|
+
RB_OPTIONS = {"options": [["db-path", ""]]}
|
15
|
+
|
16
|
+
|
17
|
+
def mock_rekordbox_settings_file(pioneer_app_dir, rb_app_dir):
|
18
|
+
db_dir = pioneer_app_dir / "rekordbox"
|
19
|
+
text = RB_SETTING.format(db_dir=db_dir)
|
20
|
+
file = rb_app_dir / "rekordbox3.settings"
|
21
|
+
file.write_text(text)
|
22
|
+
|
23
|
+
|
24
|
+
def mock_rekordbox_options_file(agent_storage_dir, db_path):
|
25
|
+
file = agent_storage_dir / "options.json"
|
26
|
+
options = RB_OPTIONS.copy()
|
27
|
+
options["options"][0][1] = str(db_path)
|
28
|
+
with open(file, "w") as fp:
|
29
|
+
json.dump(options, fp)
|
30
|
+
|
31
|
+
|
32
|
+
@pytest.fixture(scope="session")
|
33
|
+
def pioneer_app_dir(tmp_path_factory):
|
34
|
+
root = tmp_path_factory.mktemp("Pioneer")
|
35
|
+
rb_dir = root / "rekordbox"
|
36
|
+
rb6_dir = root / "rekordbox6"
|
37
|
+
agent_storage_dir = root / "rekordboxAgent" / "storage"
|
38
|
+
rb_dir.mkdir(parents=True)
|
39
|
+
rb6_dir.mkdir(parents=True)
|
40
|
+
agent_storage_dir.mkdir(parents=True)
|
41
|
+
|
42
|
+
# Mock `rekordbox3.settings` files
|
43
|
+
mock_rekordbox_settings_file(root, rb_dir)
|
44
|
+
mock_rekordbox_settings_file(root, rb6_dir)
|
45
|
+
|
46
|
+
# Mock database files
|
47
|
+
rb5_db = rb_dir / "datafile.edb"
|
48
|
+
rb6_db = rb_dir / "master.db"
|
49
|
+
rb5_db.touch()
|
50
|
+
rb6_db.touch()
|
51
|
+
|
52
|
+
# Mock `options.json` file (RBv6)
|
53
|
+
mock_rekordbox_options_file(agent_storage_dir, rb6_db)
|
54
|
+
|
55
|
+
return root
|
56
|
+
|
57
|
+
|
58
|
+
@pytest.fixture(scope="session")
|
59
|
+
def pioneer_install_dir(tmp_path_factory):
|
60
|
+
root = tmp_path_factory.mktemp("Pioneer")
|
61
|
+
rb5_dir = root / "rekordbox 5.1.1"
|
62
|
+
rb6_dir = root / "rekordbox 6.1.1"
|
63
|
+
rb5_dir_alt = root / "rekordbox 5.1.2"
|
64
|
+
rb6_dir_alt = root / "rekordbox 6.1.2"
|
65
|
+
|
66
|
+
rb5_dir.mkdir(parents=True)
|
67
|
+
rb6_dir.mkdir(parents=True)
|
68
|
+
rb5_dir_alt.mkdir(parents=True)
|
69
|
+
rb6_dir_alt.mkdir(parents=True)
|
70
|
+
return root
|
71
|
+
|
72
|
+
|
73
|
+
def test_pioneer_config(pioneer_install_dir, pioneer_app_dir):
|
74
|
+
update_config(pioneer_install_dir, pioneer_app_dir)
|
75
|
+
install_dir = get_config("pioneer", "install_dir")
|
76
|
+
app_dir = get_config("pioneer", "app_dir")
|
77
|
+
|
78
|
+
assert isinstance(install_dir, Path)
|
79
|
+
assert isinstance(app_dir, Path)
|
80
|
+
assert install_dir == pioneer_install_dir
|
81
|
+
assert app_dir == pioneer_app_dir
|
82
|
+
|
83
|
+
|
84
|
+
def test_rb5_config(pioneer_install_dir, pioneer_app_dir):
|
85
|
+
update_config(pioneer_install_dir, pioneer_app_dir)
|
86
|
+
expected_version = "5.1.2"
|
87
|
+
|
88
|
+
app_dir = get_config("rekordbox5", "app_dir")
|
89
|
+
install_dir = get_config("rekordbox5", "install_dir")
|
90
|
+
db_dir = get_config("rekordbox5", "db_dir")
|
91
|
+
db_path = get_config("rekordbox5", "db_path")
|
92
|
+
version = get_config("rekordbox5", "version")
|
93
|
+
|
94
|
+
assert isinstance(install_dir, Path)
|
95
|
+
assert isinstance(app_dir, Path)
|
96
|
+
assert isinstance(db_dir, Path)
|
97
|
+
assert isinstance(db_path, Path)
|
98
|
+
assert install_dir == (pioneer_install_dir / f"rekordbox {expected_version}")
|
99
|
+
assert app_dir == (pioneer_app_dir / "rekordbox")
|
100
|
+
assert db_dir == (pioneer_app_dir / "rekordbox")
|
101
|
+
assert db_path == (pioneer_app_dir / "rekordbox" / "datafile.edb")
|
102
|
+
assert version == expected_version
|
103
|
+
|
104
|
+
|
105
|
+
def test_rb6_config(pioneer_install_dir, pioneer_app_dir):
|
106
|
+
update_config(pioneer_install_dir, pioneer_app_dir)
|
107
|
+
expected_version = "6.1.2"
|
108
|
+
|
109
|
+
app_dir = get_config("rekordbox6", "app_dir")
|
110
|
+
install_dir = get_config("rekordbox6", "install_dir")
|
111
|
+
db_dir = get_config("rekordbox6", "db_dir")
|
112
|
+
db_path = get_config("rekordbox6", "db_path")
|
113
|
+
version = get_config("rekordbox6", "version")
|
114
|
+
|
115
|
+
assert isinstance(install_dir, Path)
|
116
|
+
assert isinstance(app_dir, Path)
|
117
|
+
assert isinstance(db_dir, Path)
|
118
|
+
assert isinstance(db_path, Path)
|
119
|
+
assert install_dir == (pioneer_install_dir / f"rekordbox {expected_version}")
|
120
|
+
assert app_dir == (pioneer_app_dir / "rekordbox6")
|
121
|
+
assert db_dir == (pioneer_app_dir / "rekordbox")
|
122
|
+
assert db_path == (pioneer_app_dir / "rekordbox" / "master.db")
|
123
|
+
assert version == expected_version
|
124
|
+
|
125
|
+
|
126
|
+
def test_rb5_config_alt(pioneer_install_dir, pioneer_app_dir):
|
127
|
+
# test default: latest version
|
128
|
+
update_config(pioneer_install_dir, pioneer_app_dir)
|
129
|
+
expected_version = "5.1.2"
|
130
|
+
|
131
|
+
app_dir = get_config("rekordbox5", "app_dir")
|
132
|
+
install_dir = get_config("rekordbox5", "install_dir")
|
133
|
+
version = get_config("rekordbox5", "version")
|
134
|
+
assert install_dir == (pioneer_install_dir / f"rekordbox {expected_version}")
|
135
|
+
assert app_dir == (pioneer_app_dir / "rekordbox")
|
136
|
+
assert version == expected_version
|
137
|
+
|
138
|
+
# test alternative version
|
139
|
+
update_config(
|
140
|
+
pioneer_install_dir, pioneer_app_dir, rb5_install_dirname="rekordbox 5.1.1"
|
141
|
+
)
|
142
|
+
expected_version = "5.1.1"
|
143
|
+
|
144
|
+
app_dir = get_config("rekordbox5", "app_dir")
|
145
|
+
install_dir = get_config("rekordbox5", "install_dir")
|
146
|
+
version = get_config("rekordbox5", "version")
|
147
|
+
assert install_dir == (pioneer_install_dir / f"rekordbox {expected_version}")
|
148
|
+
assert app_dir == (pioneer_app_dir / "rekordbox")
|
149
|
+
assert version == expected_version
|
150
|
+
|
151
|
+
|
152
|
+
def test_rb6_config_alt(pioneer_install_dir, pioneer_app_dir):
|
153
|
+
# test default: latest version
|
154
|
+
update_config(pioneer_install_dir, pioneer_app_dir)
|
155
|
+
expected_version = "6.1.2"
|
156
|
+
|
157
|
+
app_dir = get_config("rekordbox6", "app_dir")
|
158
|
+
install_dir = get_config("rekordbox6", "install_dir")
|
159
|
+
version = get_config("rekordbox6", "version")
|
160
|
+
assert install_dir == (pioneer_install_dir / f"rekordbox {expected_version}")
|
161
|
+
assert app_dir == (pioneer_app_dir / "rekordbox6")
|
162
|
+
assert version == expected_version
|
163
|
+
|
164
|
+
# test alternative version
|
165
|
+
update_config(
|
166
|
+
pioneer_install_dir, pioneer_app_dir, rb6_install_dirname="rekordbox 6.1.1"
|
167
|
+
)
|
168
|
+
expected_version = "6.1.1"
|
169
|
+
|
170
|
+
app_dir = get_config("rekordbox6", "app_dir")
|
171
|
+
install_dir = get_config("rekordbox6", "install_dir")
|
172
|
+
version = get_config("rekordbox6", "version")
|
173
|
+
assert install_dir == (pioneer_install_dir / f"rekordbox {expected_version}")
|
174
|
+
assert app_dir == (pioneer_app_dir / "rekordbox6")
|
175
|
+
assert version == expected_version
|
tests/test_db6.py
CHANGED
@@ -998,6 +998,84 @@ def test_rename_playlist(db):
|
|
998
998
|
assert _check_playlist_xml(db)
|
999
999
|
|
1000
1000
|
|
1001
|
+
def test_add_album(db):
|
1002
|
+
old_usn = db.get_local_usn()
|
1003
|
+
name = "test"
|
1004
|
+
db.add_album(name)
|
1005
|
+
db.commit()
|
1006
|
+
|
1007
|
+
# Check that album was created and USN is incremented
|
1008
|
+
instance = db.get_album(Name=name).one()
|
1009
|
+
assert instance.Name == name
|
1010
|
+
assert instance.rb_local_usn == old_usn + 1
|
1011
|
+
assert db.get_local_usn() == old_usn + 1
|
1012
|
+
|
1013
|
+
# Fail if album with same name is added
|
1014
|
+
with pytest.raises(ValueError):
|
1015
|
+
db.add_album(name)
|
1016
|
+
|
1017
|
+
# Add album with album artist by artist
|
1018
|
+
artist = db.get_artist().first()
|
1019
|
+
album = db.add_album("album 2", artist=artist)
|
1020
|
+
assert album.AlbumArtistID == artist.ID
|
1021
|
+
|
1022
|
+
# Add album with album artist by ID
|
1023
|
+
artist = db.get_artist().first()
|
1024
|
+
album = db.add_album("album 3", artist=artist.ID)
|
1025
|
+
assert album.AlbumArtistID == artist.ID
|
1026
|
+
|
1027
|
+
|
1028
|
+
def test_add_artist(db):
|
1029
|
+
old_usn = db.get_local_usn()
|
1030
|
+
name = "test"
|
1031
|
+
db.add_artist(name)
|
1032
|
+
db.commit()
|
1033
|
+
|
1034
|
+
# Check that album was created and USN is incremented
|
1035
|
+
instance = db.get_artist(Name=name).one()
|
1036
|
+
assert instance.Name == name
|
1037
|
+
assert instance.rb_local_usn == old_usn + 1
|
1038
|
+
assert db.get_local_usn() == old_usn + 1
|
1039
|
+
|
1040
|
+
# Fail if album with same name is added
|
1041
|
+
with pytest.raises(ValueError):
|
1042
|
+
db.add_artist(name)
|
1043
|
+
|
1044
|
+
|
1045
|
+
def test_add_genre(db):
|
1046
|
+
old_usn = db.get_local_usn()
|
1047
|
+
name = "test"
|
1048
|
+
db.add_genre(name)
|
1049
|
+
db.commit()
|
1050
|
+
|
1051
|
+
# Check that album was created and USN is incremented
|
1052
|
+
instance = db.get_genre(Name=name).one()
|
1053
|
+
assert instance.Name == name
|
1054
|
+
assert instance.rb_local_usn == old_usn + 1
|
1055
|
+
assert db.get_local_usn() == old_usn + 1
|
1056
|
+
|
1057
|
+
# Fail if album with same name is added
|
1058
|
+
with pytest.raises(ValueError):
|
1059
|
+
db.add_genre(name)
|
1060
|
+
|
1061
|
+
|
1062
|
+
def test_add_label(db):
|
1063
|
+
old_usn = db.get_local_usn()
|
1064
|
+
name = "test"
|
1065
|
+
db.add_label(name)
|
1066
|
+
db.commit()
|
1067
|
+
|
1068
|
+
# Check that album was created and USN is incremented
|
1069
|
+
instance = db.get_label(Name=name).one()
|
1070
|
+
assert instance.Name == name
|
1071
|
+
assert instance.rb_local_usn == old_usn + 1
|
1072
|
+
assert db.get_local_usn() == old_usn + 1
|
1073
|
+
|
1074
|
+
# Fail if album with same name is added
|
1075
|
+
with pytest.raises(ValueError):
|
1076
|
+
db.add_label(name)
|
1077
|
+
|
1078
|
+
|
1001
1079
|
def test_get_anlz_paths():
|
1002
1080
|
content = DB.get_content().first()
|
1003
1081
|
|
@@ -1,178 +0,0 @@
|
|
1
|
-
# Configuration file for the Sphinx documentation builder.
|
2
|
-
#
|
3
|
-
# This file only contains a selection of the most common options. For a full
|
4
|
-
# list see the documentation:
|
5
|
-
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
6
|
-
|
7
|
-
# -- Path setup --------------------------------------------------------------
|
8
|
-
|
9
|
-
# If extensions (or modules to document with autodoc) are in another directory,
|
10
|
-
# add these directories to sys.path here. If the directory is relative to the
|
11
|
-
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
12
|
-
#
|
13
|
-
import os
|
14
|
-
import sys
|
15
|
-
|
16
|
-
sys.path.insert(0, os.path.abspath("../.."))
|
17
|
-
|
18
|
-
import pyrekordbox
|
19
|
-
|
20
|
-
|
21
|
-
# -- Project information -----------------------------------------------------
|
22
|
-
|
23
|
-
project = "pyrekordbox"
|
24
|
-
copyright = "2022-2023, Dylan Jones"
|
25
|
-
author = "Dylan L. Jones"
|
26
|
-
release = pyrekordbox.__version__
|
27
|
-
version = release
|
28
|
-
for sp in "abcfr":
|
29
|
-
version = version.split(sp)[0]
|
30
|
-
|
31
|
-
# -- General configuration ---------------------------------------------------
|
32
|
-
|
33
|
-
# If your documentation needs a minimal Sphinx version, state it here.
|
34
|
-
needs_sphinx = "4.4"
|
35
|
-
|
36
|
-
# Add any Sphinx extension module names here, as strings. They can be
|
37
|
-
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
38
|
-
# ones.
|
39
|
-
extensions = [
|
40
|
-
"sphinx.ext.autodoc",
|
41
|
-
"numpydoc",
|
42
|
-
"myst_parser",
|
43
|
-
"numpydoc",
|
44
|
-
"sphinx_copybutton",
|
45
|
-
"sphinx.ext.napoleon",
|
46
|
-
"sphinx.ext.autosummary",
|
47
|
-
"sphinx.ext.autosectionlabel",
|
48
|
-
"matplotlib.sphinxext.plot_directive",
|
49
|
-
"sphinx.ext.intersphinx", # links to numpy, scipy ... docs
|
50
|
-
"sphinx.ext.coverage",
|
51
|
-
"sphinx.ext.extlinks", # define roles for links
|
52
|
-
"sphinx.ext.viewcode",
|
53
|
-
]
|
54
|
-
|
55
|
-
# If you need extensions of a certain version or higher, list them here.
|
56
|
-
needs_extensions = {"myst_parser": "0.13.7"}
|
57
|
-
|
58
|
-
# Add any paths that contain templates here, relative to this directory.
|
59
|
-
templates_path = ["_templates"]
|
60
|
-
|
61
|
-
# List of patterns, relative to source directory, that match files and
|
62
|
-
# directories to ignore when looking for source files.
|
63
|
-
# This pattern also affects html_static_path and html_extra_path.
|
64
|
-
|
65
|
-
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "tests"]
|
66
|
-
|
67
|
-
# The suffix(es) of source filenames.
|
68
|
-
# You can specify multiple suffix as a list of string:
|
69
|
-
source_suffix = [".rst", ".md"]
|
70
|
-
|
71
|
-
# Add any paths that contain custom static files (such as style sheets) here,
|
72
|
-
# relative to this directory. They are copied after the builtin static files,
|
73
|
-
# so a file named "default.css" will overwrite the builtin "default.css".
|
74
|
-
html_static_path = ["_static"]
|
75
|
-
|
76
|
-
html_theme_options = {
|
77
|
-
"light_logo": "logos/dark/logo_primary.svg",
|
78
|
-
"dark_logo": "logos/light/logo_primary.svg",
|
79
|
-
"sidebar_hide_name": True,
|
80
|
-
"footer_icons": [
|
81
|
-
{
|
82
|
-
"name": "GitHub",
|
83
|
-
"url": "https://github.com/dylanljones/pyrekordbox",
|
84
|
-
"html": """
|
85
|
-
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16">
|
86
|
-
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
|
87
|
-
</svg>
|
88
|
-
""",
|
89
|
-
"class": "",
|
90
|
-
},
|
91
|
-
],
|
92
|
-
}
|
93
|
-
|
94
|
-
# html_title = f"{release} documentation"
|
95
|
-
|
96
|
-
# -- Options for HTML output -------------------------------------------------
|
97
|
-
|
98
|
-
# The theme to use for HTML and HTML Help pages. See the documentation for
|
99
|
-
# a list of builtin themes.
|
100
|
-
html_theme = "furo"
|
101
|
-
|
102
|
-
# The name of the Pygments (syntax highlighting) style to use.
|
103
|
-
# pygments_style = "sphinx"
|
104
|
-
# pygments_dark_style = "monokai"
|
105
|
-
|
106
|
-
# We need headers to be linkable to so ask MyST-Parser to autogenerate anchor IDs for
|
107
|
-
# headers up to and including level 3.
|
108
|
-
myst_heading_anchors = 3
|
109
|
-
|
110
|
-
# Prettier support formatting some MyST syntax but not all, so let's disable the
|
111
|
-
# unsupported yet still enabled by default ones.
|
112
|
-
myst_disable_syntax = [
|
113
|
-
"colon_fence",
|
114
|
-
"myst_block_break",
|
115
|
-
"myst_line_comment",
|
116
|
-
"math_block",
|
117
|
-
]
|
118
|
-
|
119
|
-
|
120
|
-
# Don't show type hints
|
121
|
-
autodoc_typehints = "none"
|
122
|
-
|
123
|
-
# Preserve order
|
124
|
-
autodoc_member_order = "bysource"
|
125
|
-
|
126
|
-
|
127
|
-
# -- Apidoc ------------------------------------------------------------------
|
128
|
-
|
129
|
-
add_module_names = True
|
130
|
-
|
131
|
-
|
132
|
-
# -- Autosummary -------------------------------------------------------------
|
133
|
-
|
134
|
-
autosummary_generate = True
|
135
|
-
# autosummary_imported_members = True
|
136
|
-
|
137
|
-
|
138
|
-
# -- Numpy extension ---------------------------------------------------------
|
139
|
-
|
140
|
-
numpydoc_use_plots = True
|
141
|
-
# numpydoc_xref_param_type = True
|
142
|
-
# numpydoc_xref_ignore = "all" # not working...
|
143
|
-
numpydoc_show_class_members = False
|
144
|
-
|
145
|
-
|
146
|
-
# -- Intersphinx -------------------------------------------------------------
|
147
|
-
|
148
|
-
# taken from https://gist.github.com/bskinn/0e164963428d4b51017cebdb6cda5209
|
149
|
-
intersphinx_mapping = {
|
150
|
-
"python": (r"https://docs.python.org", None),
|
151
|
-
"numpy": (r"https://docs.scipy.org/doc/numpy/", None),
|
152
|
-
"np": (r"https://docs.scipy.org/doc/numpy/", None),
|
153
|
-
"matplotlib": (r"https://matplotlib.org/", None),
|
154
|
-
"<name>": ("https://docs.python.org/3/", None),
|
155
|
-
}
|
156
|
-
|
157
|
-
|
158
|
-
# -- Auto-run sphinx-apidoc --------------------------------------------------
|
159
|
-
|
160
|
-
|
161
|
-
def run_apidoc(_):
|
162
|
-
from sphinx.ext.apidoc import main
|
163
|
-
import os
|
164
|
-
import sys
|
165
|
-
|
166
|
-
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
|
167
|
-
cur_dir = os.path.abspath(os.path.dirname(__file__))
|
168
|
-
proj_dir = os.path.dirname(os.path.dirname(cur_dir))
|
169
|
-
doc_dir = os.path.join(proj_dir, "docs")
|
170
|
-
output_path = os.path.join(doc_dir, "source", "generated")
|
171
|
-
module = os.path.join(proj_dir, "pyrekordbox")
|
172
|
-
exclude = os.path.join(module, "tests")
|
173
|
-
template_dir = os.path.join(doc_dir, "source", "_templates", "apidoc")
|
174
|
-
main(["-fMeT", "-o", output_path, module, exclude, "--templatedir", template_dir])
|
175
|
-
|
176
|
-
|
177
|
-
def setup(app):
|
178
|
-
app.connect("builder-inited", run_apidoc)
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
# Author: Dylan Jones
|
3
|
-
# Date: 2022-04-10
|
4
|
-
|
5
|
-
from .logger import logger
|
6
|
-
from .config import show_config, get_config
|
7
|
-
from .xml import RekordboxXml, XmlDuplicateError, XmlAttributeKeyError
|
8
|
-
from .anlz import get_anlz_paths, walk_anlz_paths, read_anlz_files, AnlzFile
|
9
|
-
from .mysettings import (
|
10
|
-
get_mysetting_paths,
|
11
|
-
read_mysetting_file,
|
12
|
-
MySettingFile,
|
13
|
-
MySetting2File,
|
14
|
-
DjmMySettingFile,
|
15
|
-
DevSettingFile,
|
16
|
-
)
|
17
|
-
from .db6 import Rekordbox6Database, open_rekordbox_database
|
18
|
-
|
19
|
-
try:
|
20
|
-
from ._version import version as __version__
|
21
|
-
except ImportError: # pragma: no cover
|
22
|
-
__version__ = "unknown"
|
@@ -1,204 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
# Author: Dylan Jones
|
3
|
-
# Date: 2023-08-15
|
4
|
-
|
5
|
-
import os
|
6
|
-
import re
|
7
|
-
import sys
|
8
|
-
import shutil
|
9
|
-
import urllib.request
|
10
|
-
from pathlib import Path
|
11
|
-
from pyrekordbox.config import write_db6_key_cache, _cache_file
|
12
|
-
|
13
|
-
KEY_SOURCES = [
|
14
|
-
{
|
15
|
-
"url": r"https://raw.githubusercontent.com/mganss/CueGen/19878e6eb3f586dee0eb3eb4f2ce3ef18309de9d/CueGen/Generator.cs", # noqa: E501
|
16
|
-
"regex": re.compile(
|
17
|
-
r'((.|\n)*)Config\.UseSqlCipher.*\?.*"(?P<dp>.*)".*:.*null',
|
18
|
-
flags=re.IGNORECASE | re.MULTILINE,
|
19
|
-
),
|
20
|
-
},
|
21
|
-
{
|
22
|
-
"url": r"https://raw.githubusercontent.com/dvcrn/go-rekordbox/8be6191ba198ed7abd4ad6406d177ed7b4f749b5/cmd/getencryptionkey/main.go", # noqa: E501
|
23
|
-
"regex": re.compile(
|
24
|
-
r'((.|\n)*)fmt\.Print\("(?P<dp>.*)"\)', flags=re.IGNORECASE | re.MULTILINE
|
25
|
-
),
|
26
|
-
},
|
27
|
-
]
|
28
|
-
|
29
|
-
|
30
|
-
class WorkingDir:
|
31
|
-
def __init__(self, path):
|
32
|
-
self._prev = Path.cwd()
|
33
|
-
self.path = Path(path)
|
34
|
-
|
35
|
-
def __enter__(self):
|
36
|
-
if self.path != self._prev:
|
37
|
-
self.path.mkdir(parents=True, exist_ok=True)
|
38
|
-
os.chdir(self.path)
|
39
|
-
|
40
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
41
|
-
if self.path != self._prev:
|
42
|
-
os.chdir(self._prev)
|
43
|
-
|
44
|
-
|
45
|
-
def clone_repo(https_url: str) -> Path:
|
46
|
-
path = Path.cwd() / https_url.split("/")[-1]
|
47
|
-
if not path.exists():
|
48
|
-
os.system(f"git clone {https_url}")
|
49
|
-
assert path.exists()
|
50
|
-
else:
|
51
|
-
print(f"Repository {https_url} already cloned")
|
52
|
-
return path
|
53
|
-
|
54
|
-
|
55
|
-
def clone_pysqlcipher3() -> Path:
|
56
|
-
return clone_repo(r"https://github.com/coleifer/sqlcipher3")
|
57
|
-
|
58
|
-
|
59
|
-
def clone_sqlcipher_amalgamation() -> Path:
|
60
|
-
return clone_repo(r"https://github.com/geekbrother/sqlcipher-amalgamation")
|
61
|
-
|
62
|
-
|
63
|
-
def patch_pysqlcipher_setup(pysqlcipher_dir, cryptolib="libcrypto.lib"):
|
64
|
-
path = Path(pysqlcipher_dir, "setup.py")
|
65
|
-
|
66
|
-
with open(path, "r") as fh:
|
67
|
-
text = fh.read()
|
68
|
-
|
69
|
-
if cryptolib:
|
70
|
-
lib_old = "os.environ.get('OPENSSL_LIBNAME') or 'libeay32.lib'"
|
71
|
-
lib_new = f"os.environ.get('OPENSSL_LIBNAME') or '{cryptolib}'"
|
72
|
-
text = text.replace(lib_old, lib_new)
|
73
|
-
|
74
|
-
with open(path, "w") as fh:
|
75
|
-
fh.write(text)
|
76
|
-
|
77
|
-
|
78
|
-
def prepare_pysqlcipher(pysqlcipher_dir: Path, amalgamation_src: Path):
|
79
|
-
# Copy amalgamation files to pysqlcipher directory
|
80
|
-
root = pysqlcipher_dir
|
81
|
-
root.mkdir(parents=True, exist_ok=True)
|
82
|
-
shutil.copy2(amalgamation_src / "sqlite3.c", root / "sqlite3.c")
|
83
|
-
shutil.copy2(amalgamation_src / "sqlite3.h", root / "sqlite3.h")
|
84
|
-
|
85
|
-
|
86
|
-
def install_pysqlcipher(
|
87
|
-
tmpdir="pysqlcipher3",
|
88
|
-
crypto_lib="libcrypto.lib",
|
89
|
-
pyexecutable="",
|
90
|
-
build=True,
|
91
|
-
install=True,
|
92
|
-
cleanup=True,
|
93
|
-
):
|
94
|
-
if sys.platform != "win32":
|
95
|
-
print("Not on Windows, aborting...")
|
96
|
-
return
|
97
|
-
|
98
|
-
tmpdir = Path(tmpdir)
|
99
|
-
# Download pysqlcipher3 and prepare amalgamation build
|
100
|
-
with WorkingDir(tmpdir):
|
101
|
-
pysqlcipher_dir = clone_pysqlcipher3()
|
102
|
-
amalgamation_dir = clone_sqlcipher_amalgamation()
|
103
|
-
amalgamation_src = amalgamation_dir / "src"
|
104
|
-
|
105
|
-
prepare_pysqlcipher(pysqlcipher_dir, amalgamation_src)
|
106
|
-
if os.getenv("OPENSSL_LIBNAME") is None:
|
107
|
-
print("No OPENSSL_LIBNAME environment variable found, updating `setup.py`!")
|
108
|
-
patch_pysqlcipher_setup(pysqlcipher_dir, crypto_lib)
|
109
|
-
|
110
|
-
# Build amalgamation and install pysqlcipher
|
111
|
-
if not pyexecutable:
|
112
|
-
pyexecutable = sys.executable
|
113
|
-
|
114
|
-
with WorkingDir(pysqlcipher_dir):
|
115
|
-
if build:
|
116
|
-
# Build amalgamation
|
117
|
-
print()
|
118
|
-
os.system(f"{pyexecutable} setup.py build_static build")
|
119
|
-
if install:
|
120
|
-
# Install pysqlcipher package
|
121
|
-
print()
|
122
|
-
os.system(f"{pyexecutable} setup.py install")
|
123
|
-
|
124
|
-
# Remove temporary files
|
125
|
-
if cleanup:
|
126
|
-
try:
|
127
|
-
print()
|
128
|
-
print("Cleaning up")
|
129
|
-
tmpdir.unlink(missing_ok=True)
|
130
|
-
except PermissionError as e:
|
131
|
-
print()
|
132
|
-
print(e)
|
133
|
-
print(f"Could not remove temporary directory '{tmpdir}'!")
|
134
|
-
|
135
|
-
|
136
|
-
def download_db6_key():
|
137
|
-
dp = ""
|
138
|
-
for source in KEY_SOURCES:
|
139
|
-
url = source["url"]
|
140
|
-
regex = source["regex"]
|
141
|
-
print(f"Looking for key: {url}")
|
142
|
-
|
143
|
-
res = urllib.request.urlopen(url)
|
144
|
-
data = res.read().decode("utf-8")
|
145
|
-
match = regex.match(data)
|
146
|
-
if match:
|
147
|
-
dp = match.group("dp")
|
148
|
-
break
|
149
|
-
if dp:
|
150
|
-
print(f"Found key, updating cache file {_cache_file}")
|
151
|
-
write_db6_key_cache(dp)
|
152
|
-
else:
|
153
|
-
print("No key found in the online sources.")
|
154
|
-
|
155
|
-
|
156
|
-
def main():
|
157
|
-
from argparse import ArgumentParser
|
158
|
-
|
159
|
-
parser = ArgumentParser("pyrekordbox")
|
160
|
-
subparsers = parser.add_subparsers(dest="command")
|
161
|
-
|
162
|
-
# Download Rekordbx 6 database key command
|
163
|
-
subparsers.add_parser(
|
164
|
-
"download-key",
|
165
|
-
help="Download the Rekordbox 6 database key from the internet "
|
166
|
-
"and write it to the cache file.",
|
167
|
-
)
|
168
|
-
|
169
|
-
# Install pysqlcipher3 command (Windows only)
|
170
|
-
install_parser = subparsers.add_parser(
|
171
|
-
"install-sqlcipher",
|
172
|
-
help="Build sqlcipher against amalgamation and install pysqlcipher3",
|
173
|
-
)
|
174
|
-
install_parser.add_argument(
|
175
|
-
"-t",
|
176
|
-
"--tmpdir",
|
177
|
-
type=str,
|
178
|
-
default=".tmp",
|
179
|
-
help="Path for storing temporary data (default: '.tmp')",
|
180
|
-
)
|
181
|
-
install_parser.add_argument(
|
182
|
-
"-l",
|
183
|
-
"--cryptolib",
|
184
|
-
type=str,
|
185
|
-
default="libcrypto.lib",
|
186
|
-
help="The name of the OpenSSl crypto libary (default: 'libcrypto.lib')",
|
187
|
-
)
|
188
|
-
install_parser.add_argument(
|
189
|
-
"-b",
|
190
|
-
"--buildonly",
|
191
|
-
action="store_true",
|
192
|
-
help="Don't install sqlcipher3, only build the amalgamation",
|
193
|
-
)
|
194
|
-
|
195
|
-
# Parse args and handle command
|
196
|
-
args = parser.parse_args(sys.argv[1:])
|
197
|
-
if args.command == "download-key":
|
198
|
-
download_db6_key()
|
199
|
-
elif args.command == "install-sqlcipher":
|
200
|
-
install_pysqlcipher(args.tmpdir, args.cryptolib, install=not args.buildonly)
|
201
|
-
|
202
|
-
|
203
|
-
if __name__ == "__main__":
|
204
|
-
main()
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# file generated by setuptools_scm
|
2
|
-
# don't change, don't track in version control
|
3
|
-
TYPE_CHECKING = False
|
4
|
-
if TYPE_CHECKING:
|
5
|
-
from typing import Tuple, Union
|
6
|
-
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
7
|
-
else:
|
8
|
-
VERSION_TUPLE = object
|
9
|
-
|
10
|
-
version: str
|
11
|
-
__version__: str
|
12
|
-
__version_tuple__: VERSION_TUPLE
|
13
|
-
version_tuple: VERSION_TUPLE
|
14
|
-
|
15
|
-
__version__ = version = '0.2.1'
|
16
|
-
__version_tuple__ = version_tuple = (0, 2, 1)
|