Compare commits
308 Commits
1.2.8
...
visualisat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c435464972 | ||
|
|
da2f28811a | ||
|
|
0bfa736081 | ||
|
|
1392bcbbe1 | ||
|
|
11705889f1 | ||
|
|
604dd2dbde | ||
|
|
25065ba98f | ||
|
|
7b16ec62bb | ||
|
|
d8f31592b9 | ||
|
|
80bb0f476d | ||
|
|
b7222ac85c | ||
|
|
241bca0828 | ||
|
|
90d86b10a3 | ||
|
|
4130c6670f | ||
|
|
8d262959c1 | ||
|
|
b9b70399d8 | ||
|
|
527ccd212a | ||
|
|
4a5afbeb1e | ||
|
|
63c14e014b | ||
|
|
801658c6b9 | ||
|
|
16fe665295 | ||
|
|
2bb0dbada2 | ||
|
|
2cd9498469 | ||
|
|
d1ee27fff9 | ||
|
|
91adf5ba32 | ||
|
|
d68f464269 | ||
|
|
c684a95f89 | ||
|
|
1d03bb2178 | ||
|
|
39f9128ecf | ||
|
|
ca2e802239 | ||
|
|
9a513a9a56 | ||
|
|
1c2e87b741 | ||
|
|
fe4d9979ce | ||
|
|
d8ae790ebf | ||
|
|
ac31d79294 | ||
|
|
4ffebd77b1 | ||
|
|
6682efae2f | ||
|
|
480161c6b7 | ||
|
|
a8ba420d72 | ||
|
|
fc0ec91652 | ||
|
|
0701b97324 | ||
|
|
3867932e1e | ||
|
|
e2907f6051 | ||
|
|
0827ec7f16 | ||
|
|
24d2adf363 | ||
|
|
592729d00b | ||
|
|
c4a564bb56 | ||
|
|
812a02a3a1 | ||
|
|
944936914b | ||
|
|
e7c901d4f3 | ||
|
|
8e996119af | ||
|
|
4348a654ca | ||
|
|
f0be1c782a | ||
|
|
e9898d08bc | ||
|
|
1ad13cd3b0 | ||
|
|
5c640e0e36 | ||
|
|
059def8d0c | ||
|
|
cf15a1f423 | ||
|
|
5d35b0eedd | ||
|
|
5fcb71d08f | ||
|
|
15c2237d4a | ||
|
|
93af866185 | ||
|
|
109ff90401 | ||
|
|
d4b06289c3 | ||
|
|
4351c555a0 | ||
|
|
ce4db40983 | ||
|
|
d37fb7410c | ||
|
|
f1cdd71494 | ||
|
|
000ba997fb | ||
|
|
579efffd14 | ||
|
|
3a098c8a0c | ||
|
|
5bce0ae87f | ||
|
|
afe6967c46 | ||
|
|
e91bab6d42 | ||
|
|
5a64247761 | ||
|
|
9ed89afdb2 | ||
|
|
0ac338026c | ||
|
|
4e5f84a7b7 | ||
|
|
320a3c6815 | ||
|
|
72dd1d783a | ||
|
|
d2205cfe81 | ||
|
|
5830f247f6 | ||
|
|
8b4c57d933 | ||
|
|
67cec09176 | ||
|
|
2df658e1f3 | ||
|
|
f3bc9b151c | ||
|
|
b06b59d0c5 | ||
|
|
99d75ade06 | ||
|
|
3f63246068 | ||
|
|
b205a5f964 | ||
|
|
aeaef12dd4 | ||
|
|
02d76f17f7 | ||
|
|
e4e12c6fa6 | ||
|
|
270ae6085b | ||
|
|
7065a405a5 | ||
|
|
d8c72c3dd9 | ||
|
|
b65502e167 | ||
|
|
132f8df853 | ||
|
|
12e3cffe63 | ||
|
|
56a637682d | ||
|
|
d9b105f89e | ||
|
|
bd6b45e43f | ||
|
|
539172fb70 | ||
|
|
ebd92b3a7f | ||
|
|
b00ae5b210 | ||
|
|
c8e3cf981b | ||
|
|
038f69779f | ||
|
|
a4de7559ac | ||
|
|
0537b072fe | ||
|
|
2657c9f96a | ||
|
|
7e178b1f1a | ||
|
|
dd8513d02c | ||
|
|
5f0175094b | ||
|
|
b4c5b9e1e1 | ||
|
|
2ce0ed2ef8 | ||
|
|
176768f7f8 | ||
|
|
50b954034c | ||
|
|
cab7b6c335 | ||
|
|
fce1dacafc | ||
|
|
94aa6fb940 | ||
|
|
0cfd4aaad1 | ||
|
|
9e72b4fe80 | ||
|
|
1151443372 | ||
|
|
8f6993e7c8 | ||
|
|
a6ab1a7689 | ||
|
|
098b21d818 | ||
|
|
d61adeb595 | ||
|
|
8bfc3bc41c | ||
|
|
0dda2feec3 | ||
|
|
1d0d03ed83 | ||
|
|
330284f03e | ||
|
|
fc3ed3a2ce | ||
|
|
6a656036fe | ||
|
|
5c76c633a5 | ||
|
|
d487c3ea07 | ||
|
|
83dca405af | ||
|
|
acd0b6d3ea | ||
|
|
159242aff4 | ||
|
|
4b014253cf | ||
|
|
1ec6b5582e | ||
|
|
08b8d04500 | ||
|
|
54679b1d57 | ||
|
|
8d648e668e | ||
|
|
5897e786dc | ||
|
|
7f549aa991 | ||
|
|
792e7b6274 | ||
|
|
92c58b0b60 | ||
|
|
5fac9a1c8d | ||
|
|
7f4f715003 | ||
|
|
75d1d4098e | ||
|
|
30e80068a3 | ||
|
|
5fe9a1528f | ||
|
|
7777eda115 | ||
|
|
ce4f2ece93 | ||
|
|
52399d73fe | ||
|
|
6e98166148 | ||
|
|
c658a77b05 | ||
|
|
1880dc8153 | ||
|
|
b5fd3d5717 | ||
|
|
3c3480fb84 | ||
|
|
f628914173 | ||
|
|
c100fb1bb8 | ||
|
|
8c804c4fba | ||
|
|
912a7c7da9 | ||
|
|
0a5815c82e | ||
|
|
6513b3032b | ||
|
|
8c51401bdc | ||
|
|
45fc9c83d4 | ||
|
|
be57d8147a | ||
|
|
a97908fb6b | ||
|
|
c0417d4bb3 | ||
|
|
062e2cfb84 | ||
|
|
700f7dbe36 | ||
|
|
0487118dad | ||
|
|
f3d088e48b | ||
|
|
f8afd49fcf | ||
|
|
363fcb5aba | ||
|
|
183aba4181 | ||
|
|
742be01aa6 | ||
|
|
38c8054873 | ||
|
|
da9e9840b8 | ||
|
|
c4646531b0 | ||
|
|
65d9b6a9e9 | ||
|
|
046f40fbca | ||
|
|
a0ca50ac30 | ||
|
|
d939733675 | ||
|
|
61a8a3a84a | ||
|
|
d4858a338c | ||
|
|
31380a5bd4 | ||
|
|
e45b9aabeb | ||
|
|
27e782d8cf | ||
|
|
0bfc2ee198 | ||
|
|
e7fc4b1706 | ||
|
|
6dea1a2149 | ||
|
|
7844a2b932 | ||
|
|
96a53bfbe5 | ||
|
|
fe5fbae4b4 | ||
|
|
a9140232e5 | ||
|
|
835090dd96 | ||
|
|
af5590dcb1 | ||
|
|
26b5588d7d | ||
|
|
390bf049f2 | ||
|
|
321272b695 | ||
|
|
342805e0f3 | ||
|
|
e614626913 | ||
|
|
2ddacf2f98 | ||
|
|
a47531d4ce | ||
|
|
84b758e395 | ||
|
|
51b69a85c4 | ||
|
|
52774a3222 | ||
|
|
9030b2567b | ||
|
|
ee7bb449a5 | ||
|
|
d901258f11 | ||
|
|
6372c5ee7d | ||
|
|
75f0402793 | ||
|
|
20e5c014ef | ||
|
|
1ebc32c3aa | ||
|
|
a5f94b608b | ||
|
|
e0d61223a4 | ||
|
|
459eea5bc4 | ||
|
|
09d02c53a3 | ||
|
|
61a701554e | ||
|
|
d280e6426f | ||
|
|
5b9bb3efa7 | ||
|
|
b8cbe49f8c | ||
|
|
633e5707ef | ||
|
|
d54290c3a7 | ||
|
|
3ef2b53e46 | ||
|
|
d3a4dd6da6 | ||
|
|
0158f7f08a | ||
|
|
8cea020fac | ||
|
|
f6b38fecb0 | ||
|
|
5e2729fafe | ||
|
|
19dce1c25d | ||
|
|
00bb722e25 | ||
|
|
cbaf4d3121 | ||
|
|
4b5370044b | ||
|
|
ffbe1ec9fd | ||
|
|
53e43db91b | ||
|
|
2858cdabc2 | ||
|
|
cf74eeb120 | ||
|
|
790a1b4dbf | ||
|
|
ee6332af1e | ||
|
|
bf0704f6b2 | ||
|
|
ae13fe7f52 | ||
|
|
90678e72ac | ||
|
|
a0ec244008 | ||
|
|
fba4f84fb6 | ||
|
|
950774f1c8 | ||
|
|
340bc21537 | ||
|
|
a86ba4dffc | ||
|
|
d6bc6e33c0 | ||
|
|
7e128a9af5 | ||
|
|
0f0746be9d | ||
|
|
bec3fe9fd5 | ||
|
|
83c666baf9 | ||
|
|
b9b54e6e96 | ||
|
|
b2ff6240eb | ||
|
|
26a7c74a24 | ||
|
|
a34954ec4a | ||
|
|
349ab62e75 | ||
|
|
65e960f2c5 | ||
|
|
e22fef8ca4 | ||
|
|
3e99045e2c | ||
|
|
4fcade273e | ||
|
|
5eaff0d26e | ||
|
|
5b22f12b4a | ||
|
|
5f85c2e7a5 | ||
|
|
4fb5a7b6bc | ||
|
|
04c6c862c4 | ||
|
|
baec45f742 | ||
|
|
9efdbd2c10 | ||
|
|
d8800b80d5 | ||
|
|
ec715abb0d | ||
|
|
1485801efb | ||
|
|
4f9ac3d33a | ||
|
|
1577ce4d67 | ||
|
|
7eee74a2e9 | ||
|
|
d9e38fb3be | ||
|
|
81cc90e54a | ||
|
|
bd9771a88f | ||
|
|
f5cd81fe09 | ||
|
|
277e2cff59 | ||
|
|
6fa9514059 | ||
|
|
c5e38b71f7 | ||
|
|
3746915ae7 | ||
|
|
21bdf88d09 | ||
|
|
ff032c3cd7 | ||
|
|
c083110051 | ||
|
|
a7dbeb5d76 | ||
|
|
634f6ea9f5 | ||
|
|
f9e4f9a09a | ||
|
|
aab9889174 | ||
|
|
3b560e4e4f | ||
|
|
9e327c9556 | ||
|
|
1ec640e088 | ||
|
|
463aaf6942 | ||
|
|
71287dd77e | ||
|
|
b66c0f5573 | ||
|
|
a9f2c384fa | ||
|
|
ae9584c213 | ||
|
|
4db1c5ceb8 | ||
|
|
1738259467 | ||
|
|
fcee02edc1 | ||
|
|
4fff5820c5 | ||
|
|
9aa6da2faf | ||
|
|
279934411c | ||
|
|
fd829551e8 |
@@ -130,7 +130,10 @@ InsertBraces: false
|
|||||||
InsertTrailingCommas: None
|
InsertTrailingCommas: None
|
||||||
JavaScriptQuotes: Leave
|
JavaScriptQuotes: Leave
|
||||||
JavaScriptWrapImports: true
|
JavaScriptWrapImports: true
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
KeepEmptyLines:
|
||||||
|
AtEndOfFile: true
|
||||||
|
AtStartOfBlock: true
|
||||||
|
AtStartOfFile: true
|
||||||
LambdaBodyIndentation: Signature
|
LambdaBodyIndentation: Signature
|
||||||
MacroBlockBegin: ''
|
MacroBlockBegin: ''
|
||||||
MacroBlockEnd: ''
|
MacroBlockEnd: ''
|
||||||
|
|||||||
194
.github/workflows/build.yml
vendored
194
.github/workflows/build.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
opensuse_version: [ 'tumbleweed', 'leap:15.6' ]
|
opensuse_version: [ 'tumbleweed', 'leap:15.6', 'leap:16.0' ]
|
||||||
container:
|
container:
|
||||||
image: opensuse/${{matrix.opensuse_version}}
|
image: opensuse/${{matrix.opensuse_version}}
|
||||||
steps:
|
steps:
|
||||||
@@ -27,11 +27,11 @@ jobs:
|
|||||||
- name: Upgrade packages (Leap)
|
- name: Upgrade packages (Leap)
|
||||||
if: matrix.opensuse_version != 'tumbleweed'
|
if: matrix.opensuse_version != 'tumbleweed'
|
||||||
run: zypper -n --gpg-auto-import-keys up
|
run: zypper -n --gpg-auto-import-keys up
|
||||||
- name: Install gcc (Tumbleweed)
|
- name: Install gcc
|
||||||
if: matrix.opensuse_version == 'tumbleweed'
|
if: matrix.opensuse_version != 'leap:15.6'
|
||||||
run: zypper -n --gpg-auto-import-keys in gcc gcc-c++
|
run: zypper -n --gpg-auto-import-keys in gcc gcc-c++
|
||||||
- name: Install gcc (Leap)
|
- name: Install gcc (leap:15.6)
|
||||||
if: matrix.opensuse_version != 'tumbleweed'
|
if: matrix.opensuse_version == 'leap:15.6'
|
||||||
run: zypper -n --gpg-auto-import-keys in gcc14 gcc14-c++
|
run: zypper -n --gpg-auto-import-keys in gcc14 gcc14-c++
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: >
|
run: >
|
||||||
@@ -62,6 +62,7 @@ jobs:
|
|||||||
libchromaprint-devel
|
libchromaprint-devel
|
||||||
fftw3-devel
|
fftw3-devel
|
||||||
libebur128-devel
|
libebur128-devel
|
||||||
|
projectM-devel
|
||||||
desktop-file-utils
|
desktop-file-utils
|
||||||
update-desktop-files
|
update-desktop-files
|
||||||
appstream-glib
|
appstream-glib
|
||||||
@@ -78,12 +79,13 @@ jobs:
|
|||||||
qt6-base-common-devel
|
qt6-base-common-devel
|
||||||
qt6-sql-sqlite
|
qt6-sql-sqlite
|
||||||
qt6-linguist-devel
|
qt6-linguist-devel
|
||||||
|
qt6-openglwidgets-devel
|
||||||
gtest
|
gtest
|
||||||
gmock
|
gmock
|
||||||
sparsehash-devel
|
sparsehash-devel
|
||||||
rapidjson-devel
|
rapidjson-devel
|
||||||
- name: Install kdsingleapplication-qt6-devel
|
- name: Install kdsingleapplication-qt6-devel
|
||||||
if: matrix.opensuse_version == 'tumbleweed'
|
if: matrix.opensuse_version != 'leap:15.6'
|
||||||
run: zypper -n --gpg-auto-import-keys in kdsingleapplication-qt6-devel
|
run: zypper -n --gpg-auto-import-keys in kdsingleapplication-qt6-devel
|
||||||
- name: Build and install KDSingleApplication
|
- name: Build and install KDSingleApplication
|
||||||
if: matrix.opensuse_version == 'leap:15.6'
|
if: matrix.opensuse_version == 'leap:15.6'
|
||||||
@@ -97,7 +99,7 @@ jobs:
|
|||||||
cmake --build build --config Release --parallel 4
|
cmake --build build --config Release --parallel 4
|
||||||
cmake --install build
|
cmake --install build
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
@@ -115,14 +117,14 @@ jobs:
|
|||||||
- name: Copy source tarball
|
- name: Copy source tarball
|
||||||
working-directory: build
|
working-directory: build
|
||||||
run: cp strawberry-*.tar.xz /usr/src/packages/SOURCES/
|
run: cp strawberry-*.tar.xz /usr/src/packages/SOURCES/
|
||||||
- name: Build RPM (Tumbleweed)
|
- name: Build RPM
|
||||||
if: matrix.opensuse_version == 'tumbleweed'
|
if: matrix.opensuse_version != 'leap:15.6'
|
||||||
env:
|
env:
|
||||||
RPM_BUILD_NCPUS: 4
|
RPM_BUILD_NCPUS: 4
|
||||||
working-directory: build
|
working-directory: build
|
||||||
run: rpmbuild -ba strawberry.spec
|
run: rpmbuild -ba strawberry.spec
|
||||||
- name: Build RPM (Leap)
|
- name: Build RPM (leap:15.6)
|
||||||
if: matrix.opensuse_version != 'tumbleweed'
|
if: matrix.opensuse_version == 'leap:15.6'
|
||||||
env:
|
env:
|
||||||
RPM_BUILD_NCPUS: 4
|
RPM_BUILD_NCPUS: 4
|
||||||
CC: gcc-14
|
CC: gcc-14
|
||||||
@@ -134,14 +136,14 @@ jobs:
|
|||||||
run: echo "subdir=$(echo ${{matrix.opensuse_version}} | sed 's/leap:/lp/g' | sed 's/\.//g')" > $GITHUB_OUTPUT
|
run: echo "subdir=$(echo ${{matrix.opensuse_version}} | sed 's/leap:/lp/g' | sed 's/\.//g')" > $GITHUB_OUTPUT
|
||||||
- name: Upload source
|
- name: Upload source
|
||||||
if: matrix.opensuse_version == 'tumbleweed'
|
if: matrix.opensuse_version == 'tumbleweed'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: source
|
name: source
|
||||||
path: |
|
path: |
|
||||||
/usr/src/packages/SOURCES/*.xz
|
/usr/src/packages/SOURCES/*.xz
|
||||||
- name: Upload rpm
|
- name: Upload rpm
|
||||||
if: matrix.opensuse_version != 'tumbleweed'
|
if: matrix.opensuse_version != 'tumbleweed'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: opensuse-${{steps.set-subdir.outputs.subdir}}
|
name: opensuse-${{steps.set-subdir.outputs.subdir}}
|
||||||
path: |
|
path: |
|
||||||
@@ -156,7 +158,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
fedora_version: [ '39', '40', '41', '42' ]
|
fedora_version: [ '41', '42', '43' ]
|
||||||
container:
|
container:
|
||||||
image: fedora:${{matrix.fedora_version}}
|
image: fedora:${{matrix.fedora_version}}
|
||||||
steps:
|
steps:
|
||||||
@@ -200,6 +202,7 @@ jobs:
|
|||||||
libchromaprint-devel
|
libchromaprint-devel
|
||||||
libebur128-devel
|
libebur128-devel
|
||||||
fftw-devel
|
fftw-devel
|
||||||
|
libprojectM-devel
|
||||||
desktop-file-utils
|
desktop-file-utils
|
||||||
libappstream-glib
|
libappstream-glib
|
||||||
hicolor-icon-theme
|
hicolor-icon-theme
|
||||||
@@ -209,7 +212,7 @@ jobs:
|
|||||||
sparsehash-devel
|
sparsehash-devel
|
||||||
rapidjson-devel
|
rapidjson-devel
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
@@ -234,7 +237,7 @@ jobs:
|
|||||||
working-directory: build
|
working-directory: build
|
||||||
run: rpmbuild -ba strawberry.spec
|
run: rpmbuild -ba strawberry.spec
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: fedora-${{matrix.fedora_version}}
|
name: fedora-${{matrix.fedora_version}}
|
||||||
path: |
|
path: |
|
||||||
@@ -290,6 +293,7 @@ jobs:
|
|||||||
lib64Qt6DBus-devel
|
lib64Qt6DBus-devel
|
||||||
lib64Qt6Gui-devel
|
lib64Qt6Gui-devel
|
||||||
lib64Qt6Widgets-devel
|
lib64Qt6Widgets-devel
|
||||||
|
lib64Qt6OpenGLWidgets-devel
|
||||||
lib64Qt6Test-devel
|
lib64Qt6Test-devel
|
||||||
lib64kdsingleapplication-devel
|
lib64kdsingleapplication-devel
|
||||||
lib64xkbcommon-devel
|
lib64xkbcommon-devel
|
||||||
@@ -307,7 +311,7 @@ jobs:
|
|||||||
- name: Remove files
|
- name: Remove files
|
||||||
run: rm -rf /usr/lib64/qt6/lib/cmake/Qt6Sql/{Qt6QMYSQL*,Qt6QODBCD*,Qt6QPSQL*,Qt6QIBase*}
|
run: rm -rf /usr/lib64/qt6/lib/cmake/Qt6Sql/{Qt6QMYSQL*,Qt6QODBCD*,Qt6QPSQL*,Qt6QIBase*}
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
@@ -333,7 +337,7 @@ jobs:
|
|||||||
run: rpmbuild -ba strawberry.spec
|
run: rpmbuild -ba strawberry.spec
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
if: matrix.openmandriva_version != 'cooker'
|
if: matrix.openmandriva_version != 'cooker'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: openmandriva-${{matrix.openmandriva_version}}
|
name: openmandriva-${{matrix.openmandriva_version}}
|
||||||
path: |
|
path: |
|
||||||
@@ -384,6 +388,7 @@ jobs:
|
|||||||
lib64fftw-devel
|
lib64fftw-devel
|
||||||
lib64dbus-devel
|
lib64dbus-devel
|
||||||
lib64appstream-devel
|
lib64appstream-devel
|
||||||
|
lib64projectm-devel
|
||||||
lib64qt6core-devel
|
lib64qt6core-devel
|
||||||
lib64qt6gui-devel
|
lib64qt6gui-devel
|
||||||
lib64qt6widgets-devel
|
lib64qt6widgets-devel
|
||||||
@@ -393,6 +398,7 @@ jobs:
|
|||||||
lib64qt6dbus-devel
|
lib64qt6dbus-devel
|
||||||
lib64qt6help-devel
|
lib64qt6help-devel
|
||||||
lib64qt6test-devel
|
lib64qt6test-devel
|
||||||
|
lib64qt6openglwidgets-devel
|
||||||
lib64sparsehash-devel
|
lib64sparsehash-devel
|
||||||
lib64kdsingleapplication-devel
|
lib64kdsingleapplication-devel
|
||||||
desktop-file-utils
|
desktop-file-utils
|
||||||
@@ -409,7 +415,7 @@ jobs:
|
|||||||
cmake --build build --config Release --parallel 4
|
cmake --build build --config Release --parallel 4
|
||||||
cmake --install build
|
cmake --install build
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
@@ -434,7 +440,7 @@ jobs:
|
|||||||
working-directory: build
|
working-directory: build
|
||||||
run: rpmbuild -ba strawberry.spec
|
run: rpmbuild -ba strawberry.spec
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: mageia-${{matrix.mageia_version}}
|
name: mageia-${{matrix.mageia_version}}
|
||||||
path: |
|
path: |
|
||||||
@@ -449,7 +455,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
debian_version: [ 'bookworm', 'trixie' ]
|
debian_version: [ 'bookworm', 'trixie', 'forky' ]
|
||||||
container:
|
container:
|
||||||
image: debian:${{matrix.debian_version}}
|
image: debian:${{matrix.debian_version}}
|
||||||
steps:
|
steps:
|
||||||
@@ -499,7 +505,12 @@ jobs:
|
|||||||
qt6-tools-dev-tools
|
qt6-tools-dev-tools
|
||||||
qt6-l10n-tools
|
qt6-l10n-tools
|
||||||
rapidjson-dev
|
rapidjson-dev
|
||||||
|
libprojectm-dev
|
||||||
|
- name: Install KDSingleApplication
|
||||||
|
if: matrix.debian_version != 'bookworm'
|
||||||
|
run: apt install -y libkdsingleapplication-qt6-dev
|
||||||
- name: Build and install KDSingleApplication
|
- name: Build and install KDSingleApplication
|
||||||
|
if: matrix.debian_version == 'bookworm'
|
||||||
run: |
|
run: |
|
||||||
git clone --depth 1 --recurse-submodules https://github.com/KDAB/KDSingleApplication
|
git clone --depth 1 --recurse-submodules https://github.com/KDAB/KDSingleApplication
|
||||||
cd KDSingleApplication
|
cd KDSingleApplication
|
||||||
@@ -507,7 +518,7 @@ jobs:
|
|||||||
cmake --build build --config Release --parallel 4
|
cmake --build build --config Release --parallel 4
|
||||||
cmake --install build
|
cmake --install build
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
@@ -524,7 +535,7 @@ jobs:
|
|||||||
- name: Copy deb
|
- name: Copy deb
|
||||||
run: cp ../*.deb .
|
run: cp ../*.deb .
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: debian-${{matrix.debian_version}}
|
name: debian-${{matrix.debian_version}}
|
||||||
path: |
|
path: |
|
||||||
@@ -538,7 +549,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
ubuntu_version: [ 'noble', 'oracular' ]
|
ubuntu_version: [ 'noble', 'plucky', 'questing' ]
|
||||||
container:
|
container:
|
||||||
image: ubuntu:${{matrix.ubuntu_version}}
|
image: ubuntu:${{matrix.ubuntu_version}}
|
||||||
steps:
|
steps:
|
||||||
@@ -591,7 +602,12 @@ jobs:
|
|||||||
qt6-tools-dev-tools
|
qt6-tools-dev-tools
|
||||||
qt6-l10n-tools
|
qt6-l10n-tools
|
||||||
rapidjson-dev
|
rapidjson-dev
|
||||||
|
libprojectm-dev
|
||||||
|
- name: Install KDSingleApplication
|
||||||
|
if: matrix.ubuntu_version != 'noble' && matrix.ubuntu_version != 'plucky'
|
||||||
|
run: apt install -y libkdsingleapplication-qt6-dev
|
||||||
- name: Build and install KDSingleApplication
|
- name: Build and install KDSingleApplication
|
||||||
|
if: matrix.ubuntu_version == 'noble' || matrix.ubuntu_version == 'plucky'
|
||||||
run: |
|
run: |
|
||||||
git clone --depth 1 --recurse-submodules https://github.com/KDAB/KDSingleApplication
|
git clone --depth 1 --recurse-submodules https://github.com/KDAB/KDSingleApplication
|
||||||
cd KDSingleApplication
|
cd KDSingleApplication
|
||||||
@@ -599,7 +615,7 @@ jobs:
|
|||||||
cmake --build build --config Release --parallel 4
|
cmake --build build --config Release --parallel 4
|
||||||
cmake --install build
|
cmake --install build
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
@@ -616,7 +632,7 @@ jobs:
|
|||||||
- name: Copy deb
|
- name: Copy deb
|
||||||
run: cp ../*.deb ../*.ddeb .
|
run: cp ../*.deb ../*.ddeb .
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ubuntu-${{matrix.ubuntu_version}}
|
name: ubuntu-${{matrix.ubuntu_version}}
|
||||||
path: |
|
path: |
|
||||||
@@ -631,7 +647,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
ubuntu_version: [ 'noble', 'oracular' ]
|
ubuntu_version: [ 'noble', 'plucky', 'questing' ]
|
||||||
container:
|
container:
|
||||||
image: ubuntu:${{matrix.ubuntu_version}}
|
image: ubuntu:${{matrix.ubuntu_version}}
|
||||||
steps:
|
steps:
|
||||||
@@ -685,13 +701,14 @@ jobs:
|
|||||||
gstreamer1.0-pulseaudio
|
gstreamer1.0-pulseaudio
|
||||||
libkdsingleapplication-qt6-dev
|
libkdsingleapplication-qt6-dev
|
||||||
rapidjson-dev
|
rapidjson-dev
|
||||||
|
libprojectm-dev
|
||||||
- name: Install keyboxd
|
- name: Install keyboxd
|
||||||
if: matrix.ubuntu_version == 'noble'
|
if: matrix.ubuntu_version == 'noble'
|
||||||
env:
|
env:
|
||||||
DEBIAN_FRONTEND: noninteractive
|
DEBIAN_FRONTEND: noninteractive
|
||||||
run: apt install -y keyboxd
|
run: apt install -y keyboxd
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
@@ -727,16 +744,22 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
- name: Free disk space
|
||||||
|
run: |
|
||||||
|
df -h
|
||||||
|
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
|
||||||
|
sudo apt-get clean
|
||||||
|
df -h
|
||||||
- name: Build FreeBSD
|
- name: Build FreeBSD
|
||||||
id: build-freebsd
|
id: build-freebsd
|
||||||
uses: vmactions/freebsd-vm@v1.1.9
|
uses: vmactions/freebsd-vm@v1.3.2
|
||||||
with:
|
with:
|
||||||
usesh: true
|
usesh: true
|
||||||
mem: 4096
|
mem: 8192
|
||||||
prepare: pkg install -y git cmake pkgconf boost-libs alsa-lib glib qt6-base qt6-tools sqlite gstreamer1 gstreamer1-plugins chromaprint libebur128 taglib libcdio libmtp gdk-pixbuf2 libgpod fftw3 icu kdsingleapplication googletest pulseaudio sparsehash rapidjson
|
prepare: pkg install -y git cmake pkgconf boost-libs alsa-lib glib qt6-base qt6-tools sqlite gstreamer1 gstreamer1-plugins chromaprint libebur128 taglib libcdio libmtp gdk-pixbuf2 libgpod fftw3 icu kdsingleapplication googletest pulseaudio sparsehash rapidjson
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
@@ -752,13 +775,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Build OpenBSD
|
- name: Build OpenBSD
|
||||||
id: build-openbsd
|
id: build-openbsd
|
||||||
uses: vmactions/openbsd-vm@v1.1.6
|
uses: vmactions/openbsd-vm@v1.2.9
|
||||||
with:
|
with:
|
||||||
usesh: true
|
usesh: true
|
||||||
mem: 4096
|
mem: 4096
|
||||||
@@ -779,7 +802,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
runner: [ 'macos-13', 'macos-15' ]
|
runner: [ 'macos-15-intel', 'macos-15' ]
|
||||||
buildtype: [ 'release' ]
|
buildtype: [ 'release' ]
|
||||||
|
|
||||||
runs-on: ${{ matrix.runner }}
|
runs-on: ${{ matrix.runner }}
|
||||||
@@ -788,7 +811,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Set MACOSX_DEPLOYMENT_TARGET
|
- name: Set MACOSX_DEPLOYMENT_TARGET
|
||||||
run: |
|
run: |
|
||||||
for i in 13 14 15; do
|
for i in 12 13 14 15; do
|
||||||
if [ -d "/Library/Developer/CommandLineTools/SDKs/MacOSX${i}.sdk" ]; then
|
if [ -d "/Library/Developer/CommandLineTools/SDKs/MacOSX${i}.sdk" ]; then
|
||||||
echo "Using macOS SDK ${i}"
|
echo "Using macOS SDK ${i}"
|
||||||
echo "MACOSX_DEPLOYMENT_TARGET=${i}.0" >> $GITHUB_ENV
|
echo "MACOSX_DEPLOYMENT_TARGET=${i}.0" >> $GITHUB_ENV
|
||||||
@@ -818,20 +841,20 @@ jobs:
|
|||||||
rm -f uninstall.sh
|
rm -f uninstall.sh
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: Import certificate file
|
- name: Import certificate file
|
||||||
if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false
|
if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false
|
||||||
uses: apple-actions/import-codesign-certs@v5
|
uses: apple-actions/import-codesign-certs@v6
|
||||||
with:
|
with:
|
||||||
p12-file-base64: ${{ secrets.APPLE_DEVELOPER_ID_CERTIFICATE }}
|
p12-file-base64: ${{ secrets.APPLE_DEVELOPER_ID_CERTIFICATE }}
|
||||||
p12-password: ${{ secrets.APPLE_DEVELOPER_ID_CERTIFICATE_PASSWORD }}
|
p12-password: ${{ secrets.APPLE_DEVELOPER_ID_CERTIFICATE_PASSWORD }}
|
||||||
|
|
||||||
- name: Download macOS dependencies
|
- name: Download macOS dependencies
|
||||||
run: curl -f -O -L https://github.com/strawberrymusicplayer/strawberry-macos-dependencies/releases/latest/download/strawberry-macos-${{env.arch}}-${{env.buildtype}}.tar.xz
|
run: curl -f -O -L https://github.com/strawberrymusicplayer/strawberry-macos-dependencies$(test "${{env.arch}}" = "x86_64" && echo "-intel" || echo "")/releases/latest/download/strawberry-macos-${{env.arch}}-${{env.buildtype}}.tar.xz
|
||||||
|
|
||||||
- name: Extract macOS dependencies
|
- name: Extract macOS dependencies
|
||||||
run: sudo tar -C / -xf strawberry-macos-${{env.arch}}-${{env.buildtype}}.tar.xz
|
run: sudo tar -C / -xf strawberry-macos-${{env.arch}}-${{env.buildtype}}.tar.xz
|
||||||
@@ -882,9 +905,9 @@ jobs:
|
|||||||
run: make deploy
|
run: make deploy
|
||||||
|
|
||||||
- name: Manually Codesign
|
- name: Manually Codesign
|
||||||
if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false && matrix.runner == 'macos-13'
|
if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false && matrix.runner == 'macos-15-intel'
|
||||||
working-directory: build
|
working-directory: build
|
||||||
run: codesign -s 383J84DVB6 -f strawberry.app/Contents/Frameworks/{libpcre2-8.0.dylib,libpcre2-16.0.dylib,libpng16.16.dylib,libfreetype.6.dylib,libzstd.1.dylib} strawberry.app/Contents/Frameworks/png.framework/png strawberry.app
|
run: codesign -s 383J84DVB6 -f strawberry.app/Contents/Frameworks/{libpcre2-8.0.dylib,libpcre2-16.0.dylib,libpng16.16.dylib,libfreetype.6.dylib,libzstd.1.dylib,libbrotlicommon.1.dylib,libbrotlienc.1.dylib} strawberry.app/Contents/Frameworks/png.framework/png strawberry.app
|
||||||
|
|
||||||
- name: Manually Codesign
|
- name: Manually Codesign
|
||||||
if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false && matrix.runner == 'macos-15'
|
if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false && matrix.runner == 'macos-15'
|
||||||
@@ -946,7 +969,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Set MACOSX_DEPLOYMENT_TARGET
|
- name: Set MACOSX_DEPLOYMENT_TARGET
|
||||||
run: |
|
run: |
|
||||||
for i in 13 14 15; do
|
for i in 12 13 14 15; do
|
||||||
if [ -d "/Library/Developer/CommandLineTools/SDKs/MacOSX${i}.sdk" ]; then
|
if [ -d "/Library/Developer/CommandLineTools/SDKs/MacOSX${i}.sdk" ]; then
|
||||||
echo "Using macOS SDK ${i}"
|
echo "Using macOS SDK ${i}"
|
||||||
echo "MACOSX_DEPLOYMENT_TARGET=${i}.0" >> $GITHUB_ENV
|
echo "MACOSX_DEPLOYMENT_TARGET=${i}.0" >> $GITHUB_ENV
|
||||||
@@ -969,7 +992,7 @@ jobs:
|
|||||||
run: echo "cmake_buildtype=$(echo ${{env.buildtype}} | awk '{print toupper(substr($0,0,1))tolower(substr($0,2))}')" >> $GITHUB_ENV
|
run: echo "cmake_buildtype=$(echo ${{env.buildtype}} | awk '{print toupper(substr($0,0,1))tolower(substr($0,2))}')" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
@@ -1072,7 +1095,7 @@ jobs:
|
|||||||
run: echo "cmake_buildtype=$(echo ${{matrix.buildtype}} | sed 's/.*/\u&/')" >> $GITHUB_ENV
|
run: echo "cmake_buildtype=$(echo ${{matrix.buildtype}} | sed 's/.*/\u&/')" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
@@ -1246,12 +1269,42 @@ jobs:
|
|||||||
build-windows-msvc:
|
build-windows-msvc:
|
||||||
name: Build Windows MSVC
|
name: Build Windows MSVC
|
||||||
if: github.repository != 'strawberrymusicplayer/strawberry-private' && github.ref != 'refs/heads/l10n_master'
|
if: github.repository != 'strawberrymusicplayer/strawberry-private' && github.ref != 'refs/heads/l10n_master'
|
||||||
runs-on: windows-2022
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
arch: [ 'x86', 'x86_64' ]
|
include:
|
||||||
buildtype: [ 'release' ]
|
- name: "x86_64 debug"
|
||||||
|
runner: windows-2022
|
||||||
|
arch: x86_64
|
||||||
|
buildtype: debug
|
||||||
|
|
||||||
|
- name: "x86_64 release"
|
||||||
|
runner: windows-2022
|
||||||
|
arch: x86_64
|
||||||
|
buildtype: release
|
||||||
|
|
||||||
|
- name: "x86 debug"
|
||||||
|
runner: windows-2022
|
||||||
|
arch: x86
|
||||||
|
buildtype: debug
|
||||||
|
|
||||||
|
- name: "x86 release"
|
||||||
|
runner: windows-2022
|
||||||
|
arch: x86
|
||||||
|
buildtype: release
|
||||||
|
|
||||||
|
- name: "arm64 debug"
|
||||||
|
runner: windows-11-arm
|
||||||
|
arch: arm64
|
||||||
|
buildtype: debug
|
||||||
|
|
||||||
|
- name: "arm64 release"
|
||||||
|
runner: windows-11-arm
|
||||||
|
arch: arm64
|
||||||
|
buildtype: release
|
||||||
|
|
||||||
|
runs-on: ${{matrix.runner}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Set prefix path
|
- name: Set prefix path
|
||||||
@@ -1265,6 +1318,20 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: echo "cmake_buildtype=$(echo ${{matrix.buildtype}} | sed 's/.*/\u&/')" >> $GITHUB_ENV
|
run: echo "cmake_buildtype=$(echo ${{matrix.buildtype}} | sed 's/.*/\u&/')" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Show SDK versions
|
||||||
|
shell: bash
|
||||||
|
run: ls -la "c:/Program Files (x86)/Windows Kits/10/include"
|
||||||
|
|
||||||
|
- name: Set SDK version
|
||||||
|
if: matrix.arch != 'arm64'
|
||||||
|
shell: bash
|
||||||
|
run: echo "sdk_version=10.0.22621.0" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Set SDK version
|
||||||
|
if: matrix.arch == 'arm64'
|
||||||
|
shell: bash
|
||||||
|
run: echo "sdk_version=10.0.26100.0" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Install rsync
|
- name: Install rsync
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: choco install --no-progress rsync
|
run: choco install --no-progress rsync
|
||||||
@@ -1293,7 +1360,9 @@ jobs:
|
|||||||
|
|
||||||
- name: Copy bin files
|
- name: Copy bin files
|
||||||
shell: bash
|
shell: bash
|
||||||
run: cp /c/strawberry/c/bin/{patch.exe,strip.exe,strings.exe,objdump.exe} ${{env.prefix_path_unix}}/bin
|
run: |
|
||||||
|
cp /c/mingw64/bin/{strip.exe,strings.exe,objdump.exe} ${{env.prefix_path_unix}}/bin
|
||||||
|
cp /c/strawberry/c/bin/patch.exe ${{env.prefix_path_unix}}/bin
|
||||||
|
|
||||||
- name: Delete conflicting files
|
- name: Delete conflicting files
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -1347,11 +1416,11 @@ jobs:
|
|||||||
uses: ilammy/msvc-dev-cmd@v1
|
uses: ilammy/msvc-dev-cmd@v1
|
||||||
with:
|
with:
|
||||||
arch: ${{matrix.arch}}
|
arch: ${{matrix.arch}}
|
||||||
sdk: 10.0.20348.0
|
sdk: ${{env.sdk_version}}
|
||||||
vsversion: 2022
|
vsversion: 2022
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
@@ -1364,15 +1433,18 @@ jobs:
|
|||||||
shell: cmd
|
shell: cmd
|
||||||
run: cmake -E make_directory build
|
run: cmake -E make_directory build
|
||||||
|
|
||||||
- name: Set ENABLE_WIN32_CONSOLE (debug)
|
- name: Set ENABLE_WIN32_CONSOLE
|
||||||
if: matrix.buildtype == 'debug'
|
|
||||||
shell: bash
|
shell: bash
|
||||||
run: echo "win32_console=ON" >> $GITHUB_ENV
|
run: echo "enable_win32_console=$(test "${{matrix.buildtype}}" = "debug" && echo "ON" || echo "OFF")" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set ENABLE_WIN32_CONSOLE (release)
|
- name: Set ENABLE_SPOTIFY
|
||||||
if: matrix.buildtype == 'release'
|
|
||||||
shell: bash
|
shell: bash
|
||||||
run: echo "win32_console=OFF" >> $GITHUB_ENV
|
run: echo "enable_spotify=$(test -f "${{env.prefix_path_unix}}/lib/gstreamer-1.0/gstspotify.dll" && echo "ON" || echo "OFF")" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Remove -lm from .pc files
|
||||||
|
if: matrix.arch == 'arm64'
|
||||||
|
shell: bash
|
||||||
|
run: sed -i 's/\-lm$//g' ${{env.prefix_path_unix}}/lib/pkgconfig/*.pc
|
||||||
|
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
shell: cmd
|
shell: cmd
|
||||||
@@ -1384,14 +1456,14 @@ jobs:
|
|||||||
-DCMAKE_BUILD_TYPE="${{env.cmake_buildtype}}"
|
-DCMAKE_BUILD_TYPE="${{env.cmake_buildtype}}"
|
||||||
-DCMAKE_PREFIX_PATH="${{env.prefix_path_forwardslash}}/lib/cmake"
|
-DCMAKE_PREFIX_PATH="${{env.prefix_path_forwardslash}}/lib/cmake"
|
||||||
-DARCH="${{matrix.arch}}"
|
-DARCH="${{matrix.arch}}"
|
||||||
-DENABLE_WIN32_CONSOLE=${{env.win32_console}}
|
-DENABLE_WIN32_CONSOLE=${{env.enable_win32_console}}
|
||||||
-DPKG_CONFIG_EXECUTABLE="${{env.prefix_path_forwardslash}}/bin/pkg-config.exe"
|
-DPKG_CONFIG_EXECUTABLE="${{env.prefix_path_forwardslash}}/bin/pkg-config.exe"
|
||||||
-DICU_ROOT="${{env.prefix_path_forwardslash}}"
|
-DICU_ROOT="${{env.prefix_path_forwardslash}}"
|
||||||
-DENABLE_GIO=OFF
|
-DENABLE_GIO=OFF
|
||||||
-DENABLE_AUDIOCD=OFF
|
-DENABLE_AUDIOCD=OFF
|
||||||
-DENABLE_MTP=OFF
|
-DENABLE_MTP=OFF
|
||||||
-DENABLE_GPOD=OFF
|
-DENABLE_GPOD=OFF
|
||||||
-DENABLE_SPOTIFY=ON
|
-DENABLE_SPOTIFY=${{env.enable_spotify}}
|
||||||
|
|
||||||
- name: Run Make
|
- name: Run Make
|
||||||
shell: cmd
|
shell: cmd
|
||||||
@@ -1581,11 +1653,11 @@ jobs:
|
|||||||
DEBIAN_FRONTEND: noninteractive
|
DEBIAN_FRONTEND: noninteractive
|
||||||
run: sudo apt install -y git rsync
|
run: sudo apt install -y git rsync
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v7
|
||||||
with:
|
with:
|
||||||
path: artifacts
|
path: artifacts
|
||||||
- name: SSH Setup
|
- name: SSH Setup
|
||||||
@@ -1629,7 +1701,7 @@ jobs:
|
|||||||
DEBIAN_FRONTEND: noninteractive
|
DEBIAN_FRONTEND: noninteractive
|
||||||
run: sudo apt install -y git jq gh
|
run: sudo apt install -y git jq gh
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Show release assets
|
- name: Show release assets
|
||||||
@@ -1637,7 +1709,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||||
run: gh release view "${{github.event.release.tag_name}}" --json assets | jq -r '.assets[].name'
|
run: gh release view "${{github.event.release.tag_name}}" --json assets | jq -r '.assets[].name'
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v7
|
||||||
with:
|
with:
|
||||||
path: artifacts
|
path: artifacts
|
||||||
- name: Add artifacts to release
|
- name: Add artifacts to release
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,7 @@
|
|||||||
/build
|
/build
|
||||||
/bin
|
/bin
|
||||||
/CMakeLists.txt.user
|
/CMakeLists.txt.user
|
||||||
|
/.qtcreator
|
||||||
/.kdev4
|
/.kdev4
|
||||||
/strawberry.kdev4
|
/strawberry.kdev4
|
||||||
/.vscode
|
/.vscode
|
||||||
@@ -12,3 +13,4 @@
|
|||||||
/CMakeSettings.json
|
/CMakeSettings.json
|
||||||
/dist/scripts/maketarball.sh
|
/dist/scripts/maketarball.sh
|
||||||
/debian/changelog
|
/debian/changelog
|
||||||
|
_codeql_detected_source_root
|
||||||
|
|||||||
42
3rdparty/discord-rpc/CMakeLists.txt
vendored
42
3rdparty/discord-rpc/CMakeLists.txt
vendored
@@ -1 +1,41 @@
|
|||||||
add_subdirectory(src)
|
set(DISCORD_RPC_SOURCES
|
||||||
|
discord_rpc.h
|
||||||
|
discord_register.h
|
||||||
|
discord_rpc.cpp
|
||||||
|
discord_rpc_connection.h
|
||||||
|
discord_rpc_connection.cpp
|
||||||
|
discord_serialization.h
|
||||||
|
discord_serialization.cpp
|
||||||
|
discord_connection.h
|
||||||
|
discord_backoff.h
|
||||||
|
discord_msg_queue.h
|
||||||
|
)
|
||||||
|
|
||||||
|
if(UNIX)
|
||||||
|
list(APPEND DISCORD_RPC_SOURCES discord_connection_unix.cpp)
|
||||||
|
if(APPLE)
|
||||||
|
list(APPEND DISCORD_RPC_SOURCES discord_register_osx.m)
|
||||||
|
add_definitions(-DDISCORD_OSX)
|
||||||
|
else()
|
||||||
|
list(APPEND DISCORD_RPC_SOURCES discord_register_linux.cpp)
|
||||||
|
add_definitions(-DDISCORD_LINUX)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
list(APPEND DISCORD_RPC_SOURCES discord_connection_win.cpp discord_register_win.cpp)
|
||||||
|
add_definitions(-DDISCORD_WINDOWS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(discord-rpc STATIC ${DISCORD_RPC_SOURCES})
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
target_link_libraries(discord-rpc PRIVATE "-framework AppKit")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
target_link_libraries(discord-rpc PRIVATE psapi advapi32)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_include_directories(discord-rpc SYSTEM PRIVATE ${RapidJSON_INCLUDE_DIRS})
|
||||||
|
target_include_directories(discord-rpc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|||||||
63
3rdparty/discord-rpc/discord_backoff.h
vendored
Normal file
63
3rdparty/discord-rpc/discord_backoff.h
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Discord, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DISCORD_BACKOFF_H
|
||||||
|
#define DISCORD_BACKOFF_H
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
namespace discord_rpc {
|
||||||
|
|
||||||
|
struct Backoff {
|
||||||
|
int64_t minAmount;
|
||||||
|
int64_t maxAmount;
|
||||||
|
int64_t current;
|
||||||
|
int fails;
|
||||||
|
std::mt19937_64 randGenerator;
|
||||||
|
std::uniform_real_distribution<> randDistribution;
|
||||||
|
|
||||||
|
double rand01() { return randDistribution(randGenerator); }
|
||||||
|
|
||||||
|
Backoff(int64_t min, int64_t max)
|
||||||
|
: minAmount(min), maxAmount(max), current(min), fails(0), randGenerator(static_cast<uint64_t>(time(0))) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
fails = 0;
|
||||||
|
current = minAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t nextDelay() {
|
||||||
|
++fails;
|
||||||
|
int64_t delay = static_cast<int64_t>(static_cast<double>(current) * 2.0 * rand01());
|
||||||
|
current = std::min(current + delay, maxAmount);
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace discord_rpc
|
||||||
|
|
||||||
|
#endif // DISCORD_BACKOFF_H
|
||||||
48
3rdparty/discord-rpc/discord_connection.h
vendored
Normal file
48
3rdparty/discord-rpc/discord_connection.h
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Discord, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DISCORD_CONNECTION_H
|
||||||
|
#define DISCORD_CONNECTION_H
|
||||||
|
|
||||||
|
// This is to wrap the platform specific kinds of connect/read/write.
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
namespace discord_rpc {
|
||||||
|
|
||||||
|
// not really connectiony, but need per-platform
|
||||||
|
int GetProcessId();
|
||||||
|
|
||||||
|
struct BaseConnection {
|
||||||
|
static BaseConnection *Create();
|
||||||
|
static void Destroy(BaseConnection*&);
|
||||||
|
bool isOpen = false;
|
||||||
|
bool Open();
|
||||||
|
bool Close();
|
||||||
|
bool Write(const void *data, size_t length);
|
||||||
|
bool Read(void *data, size_t length);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace discord_rpc
|
||||||
|
|
||||||
|
#endif // DISCORD_CONNECTION_H
|
||||||
@@ -1,4 +1,27 @@
|
|||||||
#include "connection.h"
|
/*
|
||||||
|
* Copyright 2017 Discord, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "discord_connection.h"
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -16,11 +39,11 @@ int GetProcessId() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct BaseConnectionUnix : public BaseConnection {
|
struct BaseConnectionUnix : public BaseConnection {
|
||||||
int sock { -1 };
|
int sock{ -1 };
|
||||||
};
|
};
|
||||||
|
|
||||||
static BaseConnectionUnix Connection;
|
static BaseConnectionUnix Connection;
|
||||||
static sockaddr_un PipeAddr {};
|
static sockaddr_un PipeAddr{};
|
||||||
#ifdef MSG_NOSIGNAL
|
#ifdef MSG_NOSIGNAL
|
||||||
static int MsgFlags = MSG_NOSIGNAL;
|
static int MsgFlags = MSG_NOSIGNAL;
|
||||||
#else
|
#else
|
||||||
@@ -28,28 +51,34 @@ static int MsgFlags = 0;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char *GetTempPath() {
|
static const char *GetTempPath() {
|
||||||
|
|
||||||
const char *temp = getenv("XDG_RUNTIME_DIR");
|
const char *temp = getenv("XDG_RUNTIME_DIR");
|
||||||
temp = temp ? temp : getenv("TMPDIR");
|
temp = temp ? temp : getenv("TMPDIR");
|
||||||
temp = temp ? temp : getenv("TMP");
|
temp = temp ? temp : getenv("TMP");
|
||||||
temp = temp ? temp : getenv("TEMP");
|
temp = temp ? temp : getenv("TEMP");
|
||||||
temp = temp ? temp : "/tmp";
|
temp = temp ? temp : "/tmp";
|
||||||
|
|
||||||
return temp;
|
return temp;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ BaseConnection *BaseConnection::Create() {
|
BaseConnection *BaseConnection::Create() {
|
||||||
PipeAddr.sun_family = AF_UNIX;
|
PipeAddr.sun_family = AF_UNIX;
|
||||||
return &Connection;
|
return &Connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ void BaseConnection::Destroy(BaseConnection *&c) {
|
void BaseConnection::Destroy(BaseConnection *&c) {
|
||||||
auto self = reinterpret_cast<BaseConnectionUnix *>(c);
|
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(c);
|
||||||
self->Close();
|
self->Close();
|
||||||
c = nullptr;
|
c = nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Open() {
|
bool BaseConnection::Open() {
|
||||||
|
|
||||||
const char *tempPath = GetTempPath();
|
const char *tempPath = GetTempPath();
|
||||||
auto self = reinterpret_cast<BaseConnectionUnix *>(this);
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
self->sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
self->sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (self->sock == -1) {
|
if (self->sock == -1) {
|
||||||
return false;
|
return false;
|
||||||
@@ -61,8 +90,7 @@ bool BaseConnection::Open() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int pipeNum = 0; pipeNum < 10; ++pipeNum) {
|
for (int pipeNum = 0; pipeNum < 10; ++pipeNum) {
|
||||||
snprintf(
|
snprintf(PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum);
|
||||||
PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum);
|
|
||||||
int err = connect(self->sock, reinterpret_cast<const sockaddr*>(&PipeAddr), sizeof(PipeAddr));
|
int err = connect(self->sock, reinterpret_cast<const sockaddr*>(&PipeAddr), sizeof(PipeAddr));
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
self->isOpen = true;
|
self->isOpen = true;
|
||||||
@@ -70,22 +98,28 @@ bool BaseConnection::Open() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self->Close();
|
self->Close();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Close() {
|
bool BaseConnection::Close() {
|
||||||
auto self = reinterpret_cast<BaseConnectionUnix *>(this);
|
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
if (self->sock == -1) {
|
if (self->sock == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
close(self->sock);
|
close(self->sock);
|
||||||
self->sock = -1;
|
self->sock = -1;
|
||||||
self->isOpen = false;
|
self->isOpen = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Write(const void *data, size_t length) {
|
bool BaseConnection::Write(const void *data, size_t length) {
|
||||||
auto self = reinterpret_cast<BaseConnectionUnix *>(this);
|
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
|
|
||||||
if (self->sock == -1) {
|
if (self->sock == -1) {
|
||||||
return false;
|
return false;
|
||||||
@@ -95,11 +129,14 @@ bool BaseConnection::Write(const void *data, size_t length) {
|
|||||||
if (sentBytes < 0) {
|
if (sentBytes < 0) {
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return sentBytes == static_cast<ssize_t>(length);
|
return sentBytes == static_cast<ssize_t>(length);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Read(void *data, size_t length) {
|
bool BaseConnection::Read(void *data, size_t length) {
|
||||||
auto self = reinterpret_cast<BaseConnectionUnix *>(this);
|
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
|
|
||||||
if (self->sock == -1) {
|
if (self->sock == -1) {
|
||||||
return false;
|
return false;
|
||||||
@@ -115,8 +152,9 @@ bool BaseConnection::Read(void *data, size_t length) {
|
|||||||
else if (res == 0) {
|
else if (res == 0) {
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<size_t>(res) == length;
|
return static_cast<size_t>(res) == length;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace discord_rpc
|
} // namespace discord_rpc
|
||||||
|
|
||||||
@@ -1,9 +1,33 @@
|
|||||||
#include "connection.h"
|
/*
|
||||||
|
* Copyright 2017 Discord, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "discord_connection.h"
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#define NOMCX
|
#define NOMCX
|
||||||
#define NOSERVICE
|
#define NOSERVICE
|
||||||
#define NOIME
|
#define NOIME
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
@@ -14,29 +38,31 @@ int GetProcessId() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct BaseConnectionWin : public BaseConnection {
|
struct BaseConnectionWin : public BaseConnection {
|
||||||
HANDLE pipe { INVALID_HANDLE_VALUE };
|
HANDLE pipe{ INVALID_HANDLE_VALUE };
|
||||||
};
|
};
|
||||||
|
|
||||||
static BaseConnectionWin Connection;
|
static BaseConnectionWin Connection;
|
||||||
|
|
||||||
/*static*/ BaseConnection *BaseConnection::Create() {
|
BaseConnection *BaseConnection::Create() {
|
||||||
return &Connection;
|
return &Connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ void BaseConnection::Destroy(BaseConnection *&c) {
|
void BaseConnection::Destroy(BaseConnection *&c) {
|
||||||
|
|
||||||
auto self = reinterpret_cast<BaseConnectionWin*>(c);
|
auto self = reinterpret_cast<BaseConnectionWin*>(c);
|
||||||
self->Close();
|
self->Close();
|
||||||
c = nullptr;
|
c = nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Open() {
|
bool BaseConnection::Open() {
|
||||||
wchar_t pipeName[] { L"\\\\?\\pipe\\discord-ipc-0" };
|
|
||||||
|
wchar_t pipeName[]{ L"\\\\?\\pipe\\discord-ipc-0" };
|
||||||
const size_t pipeDigit = sizeof(pipeName) / sizeof(wchar_t) - 2;
|
const size_t pipeDigit = sizeof(pipeName) / sizeof(wchar_t) - 2;
|
||||||
pipeName[pipeDigit] = L'0';
|
pipeName[pipeDigit] = L'0';
|
||||||
auto self = reinterpret_cast<BaseConnectionWin *>(this);
|
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
self->pipe = ::CreateFileW(
|
self->pipe = ::CreateFileW(pipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||||
pipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
|
||||||
if (self->pipe != INVALID_HANDLE_VALUE) {
|
if (self->pipe != INVALID_HANDLE_VALUE) {
|
||||||
self->isOpen = true;
|
self->isOpen = true;
|
||||||
return true;
|
return true;
|
||||||
@@ -57,21 +83,26 @@ bool BaseConnection::Open() {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Close() {
|
bool BaseConnection::Close() {
|
||||||
auto self = reinterpret_cast<BaseConnectionWin *>(this);
|
|
||||||
|
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
||||||
::CloseHandle(self->pipe);
|
::CloseHandle(self->pipe);
|
||||||
self->pipe = INVALID_HANDLE_VALUE;
|
self->pipe = INVALID_HANDLE_VALUE;
|
||||||
self->isOpen = false;
|
self->isOpen = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Write(const void *data, size_t length) {
|
bool BaseConnection::Write(const void *data, size_t length) {
|
||||||
|
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
auto self = reinterpret_cast<BaseConnectionWin *>(this);
|
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
||||||
assert(self);
|
assert(self);
|
||||||
if (!self) {
|
if (!self) {
|
||||||
return false;
|
return false;
|
||||||
@@ -85,16 +116,18 @@ bool BaseConnection::Write(const void *data, size_t length) {
|
|||||||
}
|
}
|
||||||
const DWORD bytesLength = static_cast<DWORD>(length);
|
const DWORD bytesLength = static_cast<DWORD>(length);
|
||||||
DWORD bytesWritten = 0;
|
DWORD bytesWritten = 0;
|
||||||
return ::WriteFile(self->pipe, data, bytesLength, &bytesWritten, nullptr) == TRUE &&
|
|
||||||
bytesWritten == bytesLength;
|
return ::WriteFile(self->pipe, data, bytesLength, &bytesWritten, nullptr) == TRUE && bytesWritten == bytesLength;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Read(void *data, size_t length) {
|
bool BaseConnection::Read(void *data, size_t length) {
|
||||||
|
|
||||||
assert(data);
|
assert(data);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto self = reinterpret_cast<BaseConnectionWin *>(this);
|
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
||||||
assert(self);
|
assert(self);
|
||||||
if (!self) {
|
if (!self) {
|
||||||
return false;
|
return false;
|
||||||
@@ -119,8 +152,9 @@ bool BaseConnection::Read(void *data, size_t length) {
|
|||||||
else {
|
else {
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace discord_rpc
|
} // namespace discord_rpc
|
||||||
|
|
||||||
64
3rdparty/discord-rpc/discord_msg_queue.h
vendored
Normal file
64
3rdparty/discord-rpc/discord_msg_queue.h
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Discord, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DISCORD_MSG_QUEUE_H
|
||||||
|
#define DISCORD_MSG_QUEUE_H
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
// A simple queue. No locks, but only works with a single thread as producer and a single thread as
|
||||||
|
// a consumer. Mutex up as needed.
|
||||||
|
|
||||||
|
namespace discord_rpc {
|
||||||
|
|
||||||
|
template<typename ElementType, std::size_t QueueSize>
|
||||||
|
class MsgQueue {
|
||||||
|
ElementType queue_[QueueSize];
|
||||||
|
std::atomic_uint nextAdd_{ 0 };
|
||||||
|
std::atomic_uint nextSend_{ 0 };
|
||||||
|
std::atomic_uint pendingSends_{ 0 };
|
||||||
|
|
||||||
|
public:
|
||||||
|
MsgQueue() {}
|
||||||
|
|
||||||
|
ElementType *GetNextAddMessage() {
|
||||||
|
// if we are falling behind, bail
|
||||||
|
if (pendingSends_.load() >= QueueSize) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto index = (nextAdd_++) % QueueSize;
|
||||||
|
return &queue_[index];
|
||||||
|
}
|
||||||
|
void CommitAdd() { ++pendingSends_; }
|
||||||
|
|
||||||
|
bool HavePendingSends() const { return pendingSends_.load() != 0; }
|
||||||
|
ElementType *GetNextSendMessage() {
|
||||||
|
auto index = (nextSend_++) % QueueSize;
|
||||||
|
return &queue_[index];
|
||||||
|
}
|
||||||
|
void CommitSend() { --pendingSends_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace discord_rpc
|
||||||
|
|
||||||
|
#endif // DISCORD_MSG_QUEUE_H
|
||||||
37
3rdparty/discord-rpc/discord_register.h
vendored
Normal file
37
3rdparty/discord-rpc/discord_register.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Discord, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DISCORD_REGISTER_H
|
||||||
|
#define DISCORD_REGISTER_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Discord_Register(const char *applicationId, const char *command);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // DISCORD_REGISTER_H
|
||||||
120
3rdparty/discord-rpc/discord_register_linux.cpp
vendored
Normal file
120
3rdparty/discord-rpc/discord_register_linux.cpp
vendored
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Discord, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "discord_rpc.h"
|
||||||
|
#include "discord_register.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static bool Mkdir(const char *path) {
|
||||||
|
int result = mkdir(path, 0755);
|
||||||
|
if (result == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (errno == EEXIST) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// We want to register games so we can run them from Discord client as discord-<appid>://
|
||||||
|
extern "C" void Discord_Register(const char *applicationId, const char *command) {
|
||||||
|
|
||||||
|
// Add a desktop file and update some mime handlers so that xdg-open does the right thing.
|
||||||
|
|
||||||
|
const char *home = getenv("HOME");
|
||||||
|
if (!home) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char exePath[1024]{};
|
||||||
|
if (!command || !command[0]) {
|
||||||
|
const ssize_t size = readlink("/proc/self/exe", exePath, sizeof(exePath));
|
||||||
|
if (size <= 0 || size >= static_cast<ssize_t>(sizeof(exePath))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
exePath[size] = '\0';
|
||||||
|
command = exePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr char desktopFileFormat[] = "[Desktop Entry]\n"
|
||||||
|
"Name=Game %s\n"
|
||||||
|
"Exec=%s %%u\n" // note: it really wants that %u in there
|
||||||
|
"Type=Application\n"
|
||||||
|
"NoDisplay=true\n"
|
||||||
|
"Categories=Discord;Games;\n"
|
||||||
|
"MimeType=x-scheme-handler/discord-%s;\n";
|
||||||
|
char desktopFile[2048]{};
|
||||||
|
int fileLen = snprintf(desktopFile, sizeof(desktopFile), desktopFileFormat, applicationId, command, applicationId);
|
||||||
|
if (fileLen <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char desktopFilename[256]{};
|
||||||
|
(void)snprintf(desktopFilename, sizeof(desktopFilename), "/discord-%s.desktop", applicationId);
|
||||||
|
|
||||||
|
char desktopFilePath[1024]{};
|
||||||
|
(void)snprintf(desktopFilePath, sizeof(desktopFilePath), "%s/.local", home);
|
||||||
|
if (!Mkdir(desktopFilePath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strcat(desktopFilePath, "/share");
|
||||||
|
if (!Mkdir(desktopFilePath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strcat(desktopFilePath, "/applications");
|
||||||
|
if (!Mkdir(desktopFilePath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strcat(desktopFilePath, desktopFilename);
|
||||||
|
|
||||||
|
FILE *fp = fopen(desktopFilePath, "w");
|
||||||
|
if (fp) {
|
||||||
|
fwrite(desktopFile, 1, fileLen, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char xdgMimeCommand[1024]{};
|
||||||
|
snprintf(xdgMimeCommand,
|
||||||
|
sizeof(xdgMimeCommand),
|
||||||
|
"xdg-mime default discord-%s.desktop x-scheme-handler/discord-%s",
|
||||||
|
applicationId,
|
||||||
|
applicationId);
|
||||||
|
if (system(xdgMimeCommand) < 0) {
|
||||||
|
fprintf(stderr, "Failed to register mime handler\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
99
3rdparty/discord-rpc/discord_register_osx.m
vendored
Normal file
99
3rdparty/discord-rpc/discord_register_osx.m
vendored
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Discord, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
|
||||||
|
#include "discord_register.h"
|
||||||
|
|
||||||
|
static void RegisterCommand(const char *applicationId, const char *command) {
|
||||||
|
|
||||||
|
// There does not appear to be a way to register arbitrary commands on OSX, so instead we'll save the command
|
||||||
|
// to a file in the Discord config path, and when it is needed, Discord can try to load the file there, open
|
||||||
|
// the command therein (will pass to js's window.open, so requires a url-like thing)
|
||||||
|
|
||||||
|
// Note: will not work for sandboxed apps
|
||||||
|
NSString *home = NSHomeDirectory();
|
||||||
|
if (!home) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *path = [[[[[[home stringByAppendingPathComponent:@"Library"]
|
||||||
|
stringByAppendingPathComponent:@"Application Support"]
|
||||||
|
stringByAppendingPathComponent:@"discord"]
|
||||||
|
stringByAppendingPathComponent:@"games"]
|
||||||
|
stringByAppendingPathComponent:[NSString stringWithUTF8String:applicationId]]
|
||||||
|
stringByAppendingPathExtension:@"json"];
|
||||||
|
[[NSFileManager defaultManager] createDirectoryAtPath:[path stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
|
||||||
|
|
||||||
|
NSString *jsonBuffer = [NSString stringWithFormat:@"{\"command\": \"%s\"}", command];
|
||||||
|
[jsonBuffer writeToFile:path atomically:NO encoding:NSUTF8StringEncoding error:nil];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RegisterURL(const char *applicationId) {
|
||||||
|
|
||||||
|
char url[256];
|
||||||
|
snprintf(url, sizeof(url), "discord-%s", applicationId);
|
||||||
|
CFStringRef cfURL = CFStringCreateWithCString(NULL, url, kCFStringEncodingUTF8);
|
||||||
|
|
||||||
|
NSString* myBundleId = [[NSBundle mainBundle] bundleIdentifier];
|
||||||
|
if (!myBundleId) {
|
||||||
|
fprintf(stderr, "No bundle id found\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSURL* myURL = [[NSBundle mainBundle] bundleURL];
|
||||||
|
if (!myURL) {
|
||||||
|
fprintf(stderr, "No bundle url found\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus status = LSSetDefaultHandlerForURLScheme(cfURL, (__bridge CFStringRef)myBundleId);
|
||||||
|
if (status != noErr) {
|
||||||
|
fprintf(stderr, "Error in LSSetDefaultHandlerForURLScheme: %d\n", (int)status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = LSRegisterURL((__bridge CFURLRef)myURL, true);
|
||||||
|
if (status != noErr) {
|
||||||
|
fprintf(stderr, "Error in LSRegisterURL: %d\n", (int)status);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Discord_Register(const char *applicationId, const char *command) {
|
||||||
|
|
||||||
|
if (command) {
|
||||||
|
RegisterCommand(applicationId, command);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// raii lite
|
||||||
|
@autoreleasepool {
|
||||||
|
RegisterURL(applicationId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,3 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Discord, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#include "discord_rpc.h"
|
#include "discord_rpc.h"
|
||||||
#include "discord_register.h"
|
#include "discord_register.h"
|
||||||
|
|
||||||
@@ -5,6 +28,7 @@
|
|||||||
#define NOMCX
|
#define NOMCX
|
||||||
#define NOSERVICE
|
#define NOSERVICE
|
||||||
#define NOIME
|
#define NOIME
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <psapi.h>
|
#include <psapi.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@@ -46,12 +70,8 @@ static HRESULT StringCbPrintfW(LPWSTR pszDest, size_t cbDest, LPCWSTR pszFormat,
|
|||||||
#endif
|
#endif
|
||||||
#define RegSetKeyValueW regset
|
#define RegSetKeyValueW regset
|
||||||
|
|
||||||
static LSTATUS regset(HKEY hkey,
|
static LSTATUS regset(HKEY hkey, LPCWSTR subkey, LPCWSTR name, DWORD type, const void *data, DWORD len) {
|
||||||
LPCWSTR subkey,
|
|
||||||
LPCWSTR name,
|
|
||||||
DWORD type,
|
|
||||||
const void *data,
|
|
||||||
DWORD len) {
|
|
||||||
HKEY htkey = hkey, hsubkey = nullptr;
|
HKEY htkey = hkey, hsubkey = nullptr;
|
||||||
LSTATUS ret;
|
LSTATUS ret;
|
||||||
if (subkey && subkey[0]) {
|
if (subkey && subkey[0]) {
|
||||||
@@ -64,16 +84,18 @@ static LSTATUS regset(HKEY hkey,
|
|||||||
if (hsubkey && hsubkey != hkey)
|
if (hsubkey && hsubkey != hkey)
|
||||||
RegCloseKey(hsubkey);
|
RegCloseKey(hsubkey);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Discord_RegisterW(const wchar_t *applicationId, const wchar_t *command) {
|
static void Discord_RegisterW(const wchar_t *applicationId, const wchar_t *command) {
|
||||||
|
|
||||||
// https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx
|
// https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx
|
||||||
// we want to register games so we can run them as discord-<appid>://
|
// we want to register games so we can run them as discord-<appid>://
|
||||||
// Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions.
|
// Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions.
|
||||||
|
|
||||||
wchar_t exeFilePath[MAX_PATH];
|
wchar_t exeFilePath[MAX_PATH]{};
|
||||||
DWORD exeLen = GetModuleFileNameW(nullptr, exeFilePath, MAX_PATH);
|
DWORD exeLen = GetModuleFileNameW(nullptr, exeFilePath, MAX_PATH);
|
||||||
wchar_t openCommand[1024];
|
wchar_t openCommand[1024]{};
|
||||||
|
|
||||||
if (command && command[0]) {
|
if (command && command[0]) {
|
||||||
StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", command);
|
StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", command);
|
||||||
@@ -83,18 +105,16 @@ static void Discord_RegisterW(const wchar_t *applicationId, const wchar_t *comma
|
|||||||
StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", exeFilePath);
|
StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", exeFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
wchar_t protocolName[64];
|
wchar_t protocolName[64]{};
|
||||||
StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%s", applicationId);
|
StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%s", applicationId);
|
||||||
wchar_t protocolDescription[128];
|
wchar_t protocolDescription[128]{};
|
||||||
StringCbPrintfW(
|
StringCbPrintfW(protocolDescription, sizeof(protocolDescription), L"URL:Run game %s protocol", applicationId);
|
||||||
protocolDescription, sizeof(protocolDescription), L"URL:Run game %s protocol", applicationId);
|
|
||||||
wchar_t urlProtocol = 0;
|
wchar_t urlProtocol = 0;
|
||||||
|
|
||||||
wchar_t keyName[256];
|
wchar_t keyName[256]{};
|
||||||
StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%s", protocolName);
|
StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%s", protocolName);
|
||||||
HKEY key;
|
HKEY key;
|
||||||
auto status =
|
auto status = RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, nullptr, 0, KEY_WRITE, nullptr, &key, nullptr);
|
||||||
RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, nullptr, 0, KEY_WRITE, nullptr, &key, nullptr);
|
|
||||||
if (status != ERROR_SUCCESS) {
|
if (status != ERROR_SUCCESS) {
|
||||||
fprintf(stderr, "Error creating key\n");
|
fprintf(stderr, "Error creating key\n");
|
||||||
return;
|
return;
|
||||||
@@ -102,8 +122,7 @@ static void Discord_RegisterW(const wchar_t *applicationId, const wchar_t *comma
|
|||||||
DWORD len;
|
DWORD len;
|
||||||
LSTATUS result;
|
LSTATUS result;
|
||||||
len = static_cast<DWORD>(lstrlenW(protocolDescription) + 1);
|
len = static_cast<DWORD>(lstrlenW(protocolDescription) + 1);
|
||||||
result =
|
result = RegSetKeyValueW(key, nullptr, nullptr, REG_SZ, protocolDescription, len * sizeof(wchar_t));
|
||||||
RegSetKeyValueW(key, nullptr, nullptr, REG_SZ, protocolDescription, len * sizeof(wchar_t));
|
|
||||||
if (FAILED(result)) {
|
if (FAILED(result)) {
|
||||||
fprintf(stderr, "Error writing description\n");
|
fprintf(stderr, "Error writing description\n");
|
||||||
}
|
}
|
||||||
@@ -114,26 +133,26 @@ static void Discord_RegisterW(const wchar_t *applicationId, const wchar_t *comma
|
|||||||
fprintf(stderr, "Error writing description\n");
|
fprintf(stderr, "Error writing description\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
result = RegSetKeyValueW(
|
result = RegSetKeyValueW(key, L"DefaultIcon", nullptr, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t));
|
||||||
key, L"DefaultIcon", nullptr, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t));
|
|
||||||
if (FAILED(result)) {
|
if (FAILED(result)) {
|
||||||
fprintf(stderr, "Error writing icon\n");
|
fprintf(stderr, "Error writing icon\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
len = static_cast<DWORD>(lstrlenW(openCommand) + 1);
|
len = static_cast<DWORD>(lstrlenW(openCommand) + 1);
|
||||||
result = RegSetKeyValueW(
|
result = RegSetKeyValueW(key, L"shell\\open\\command", nullptr, REG_SZ, openCommand, len * sizeof(wchar_t));
|
||||||
key, L"shell\\open\\command", nullptr, REG_SZ, openCommand, len * sizeof(wchar_t));
|
|
||||||
if (FAILED(result)) {
|
if (FAILED(result)) {
|
||||||
fprintf(stderr, "Error writing command\n");
|
fprintf(stderr, "Error writing command\n");
|
||||||
}
|
}
|
||||||
RegCloseKey(key);
|
RegCloseKey(key);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_Register(const char *applicationId, const char *command) {
|
extern "C" void Discord_Register(const char *applicationId, const char *command) {
|
||||||
wchar_t appId[32];
|
|
||||||
|
wchar_t appId[32]{};
|
||||||
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
|
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
|
||||||
|
|
||||||
wchar_t openCommand[1024];
|
wchar_t openCommand[1024]{};
|
||||||
const wchar_t *wcommand = nullptr;
|
const wchar_t *wcommand = nullptr;
|
||||||
if (command && command[0]) {
|
if (command && command[0]) {
|
||||||
const auto commandBufferLen = sizeof(openCommand) / sizeof(*openCommand);
|
const auto commandBufferLen = sizeof(openCommand) / sizeof(*openCommand);
|
||||||
@@ -142,42 +161,5 @@ extern "C" void Discord_Register(const char *applicationId, const char *command)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Discord_RegisterW(appId, wcommand);
|
Discord_RegisterW(appId, wcommand);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_RegisterSteamGame(const char *applicationId,
|
|
||||||
const char *steamId) {
|
|
||||||
wchar_t appId[32];
|
|
||||||
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
|
|
||||||
|
|
||||||
wchar_t wSteamId[32];
|
|
||||||
MultiByteToWideChar(CP_UTF8, 0, steamId, -1, wSteamId, 32);
|
|
||||||
|
|
||||||
HKEY key;
|
|
||||||
auto status = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", 0, KEY_READ, &key);
|
|
||||||
if (status != ERROR_SUCCESS) {
|
|
||||||
fprintf(stderr, "Error opening Steam key\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wchar_t steamPath[MAX_PATH];
|
|
||||||
DWORD pathBytes = sizeof(steamPath);
|
|
||||||
status = RegQueryValueExW(key, L"SteamExe", nullptr, nullptr, (BYTE *)steamPath, &pathBytes);
|
|
||||||
RegCloseKey(key);
|
|
||||||
if (status != ERROR_SUCCESS || pathBytes < 1) {
|
|
||||||
fprintf(stderr, "Error reading SteamExe key\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD pathChars = pathBytes / sizeof(wchar_t);
|
|
||||||
for (DWORD i = 0; i < pathChars; ++i) {
|
|
||||||
if (steamPath[i] == L'/') {
|
|
||||||
steamPath[i] = L'\\';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wchar_t command[1024];
|
|
||||||
StringCbPrintfW(command, sizeof(command), L"\"%s\" steam://rungameid/%s", steamPath, wSteamId);
|
|
||||||
|
|
||||||
Discord_RegisterW(appId, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,23 +1,48 @@
|
|||||||
#include "discord_rpc.h"
|
/*
|
||||||
|
* Copyright 2017 Discord, Inc.
|
||||||
#include "backoff.h"
|
*
|
||||||
#include "discord_register.h"
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
#include "msg_queue.h"
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
#include "rpc_connection.h"
|
* the Software without restriction, including without limitation the rights to
|
||||||
#include "serialization.h"
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
namespace discord_rpc {
|
#include "discord_rpc.h"
|
||||||
|
#include "discord_backoff.h"
|
||||||
|
#include "discord_register.h"
|
||||||
|
#include "discord_msg_queue.h"
|
||||||
|
#include "discord_rpc_connection.h"
|
||||||
|
#include "discord_serialization.h"
|
||||||
|
|
||||||
constexpr size_t MaxMessageSize { 16 * 1024 };
|
using namespace discord_rpc;
|
||||||
constexpr size_t MessageQueueSize { 8 };
|
|
||||||
constexpr size_t JoinQueueSize { 8 };
|
static void Discord_UpdateConnection();
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr size_t MaxMessageSize{ 16 * 1024 };
|
||||||
|
constexpr size_t MessageQueueSize{ 8 };
|
||||||
|
constexpr size_t JoinQueueSize{ 8 };
|
||||||
|
|
||||||
struct QueuedMessage {
|
struct QueuedMessage {
|
||||||
size_t length;
|
size_t length;
|
||||||
@@ -45,39 +70,37 @@ struct User {
|
|||||||
// Rounded way up because I'm paranoid about games breaking from future changes in these sizes
|
// Rounded way up because I'm paranoid about games breaking from future changes in these sizes
|
||||||
};
|
};
|
||||||
|
|
||||||
static RpcConnection *Connection { nullptr };
|
static RpcConnection *Connection{ nullptr };
|
||||||
static DiscordEventHandlers QueuedHandlers {};
|
static DiscordEventHandlers QueuedHandlers{};
|
||||||
static DiscordEventHandlers Handlers {};
|
static DiscordEventHandlers Handlers{};
|
||||||
static std::atomic_bool WasJustConnected { false };
|
static std::atomic_bool WasJustConnected{ false };
|
||||||
static std::atomic_bool WasJustDisconnected { false };
|
static std::atomic_bool WasJustDisconnected{ false };
|
||||||
static std::atomic_bool GotErrorMessage { false };
|
static std::atomic_bool GotErrorMessage{ false };
|
||||||
static std::atomic_bool WasJoinGame { false };
|
static std::atomic_bool WasJoinGame{ false };
|
||||||
static std::atomic_bool WasSpectateGame { false };
|
static std::atomic_bool WasSpectateGame{ false };
|
||||||
static std::atomic_bool UpdatePresence { false };
|
static std::atomic_bool UpdatePresence{ false };
|
||||||
static char JoinGameSecret[256];
|
static char JoinGameSecret[256];
|
||||||
static char SpectateGameSecret[256];
|
static char SpectateGameSecret[256];
|
||||||
static int LastErrorCode { 0 };
|
static int LastErrorCode{ 0 };
|
||||||
static char LastErrorMessage[256];
|
static char LastErrorMessage[256];
|
||||||
static int LastDisconnectErrorCode { 0 };
|
static int LastDisconnectErrorCode{ 0 };
|
||||||
static char LastDisconnectErrorMessage[256];
|
static char LastDisconnectErrorMessage[256];
|
||||||
static std::mutex PresenceMutex;
|
static std::mutex PresenceMutex;
|
||||||
static std::mutex HandlerMutex;
|
static std::mutex HandlerMutex;
|
||||||
static QueuedMessage QueuedPresence {};
|
static QueuedMessage QueuedPresence{};
|
||||||
static MsgQueue<QueuedMessage, MessageQueueSize> SendQueue;
|
static MsgQueue<QueuedMessage, MessageQueueSize> SendQueue;
|
||||||
static MsgQueue<User, JoinQueueSize> JoinAskQueue;
|
static MsgQueue<User, JoinQueueSize> JoinAskQueue;
|
||||||
static User connectedUser;
|
static User connectedUser;
|
||||||
|
|
||||||
// We want to auto connect, and retry on failure, but not as fast as possible. This does expoential
|
// We want to auto connect, and retry on failure, but not as fast as possible. This does expoential backoff from 0.5 seconds to 1 minute
|
||||||
// backoff from 0.5 seconds to 1 minute
|
|
||||||
static Backoff ReconnectTimeMs(500, 60 * 1000);
|
static Backoff ReconnectTimeMs(500, 60 * 1000);
|
||||||
static auto NextConnect = std::chrono::system_clock::now();
|
static auto NextConnect = std::chrono::system_clock::now();
|
||||||
static int Pid { 0 };
|
static int Pid{ 0 };
|
||||||
static int Nonce { 1 };
|
static int Nonce{ 1 };
|
||||||
|
|
||||||
static void Discord_UpdateConnection(void);
|
|
||||||
class IoThreadHolder {
|
class IoThreadHolder {
|
||||||
private:
|
private:
|
||||||
std::atomic_bool keepRunning { true };
|
std::atomic_bool keepRunning{ true };
|
||||||
std::mutex waitForIOMutex;
|
std::mutex waitForIOMutex;
|
||||||
std::condition_variable waitForIOActivity;
|
std::condition_variable waitForIOActivity;
|
||||||
std::thread ioThread;
|
std::thread ioThread;
|
||||||
@@ -86,14 +109,14 @@ class IoThreadHolder {
|
|||||||
void Start() {
|
void Start() {
|
||||||
keepRunning.store(true);
|
keepRunning.store(true);
|
||||||
ioThread = std::thread([&]() {
|
ioThread = std::thread([&]() {
|
||||||
const std::chrono::duration<int64_t, std::milli> maxWait { 500LL };
|
const std::chrono::duration<int64_t, std::milli> maxWait { 500LL };
|
||||||
Discord_UpdateConnection();
|
|
||||||
while (keepRunning.load()) {
|
|
||||||
std::unique_lock<std::mutex> lock(waitForIOMutex);
|
|
||||||
waitForIOActivity.wait_for(lock, maxWait);
|
|
||||||
Discord_UpdateConnection();
|
Discord_UpdateConnection();
|
||||||
}
|
while (keepRunning.load()) {
|
||||||
});
|
std::unique_lock<std::mutex> lock(waitForIOMutex);
|
||||||
|
waitForIOActivity.wait_for(lock, maxWait);
|
||||||
|
Discord_UpdateConnection();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Notify() { waitForIOActivity.notify_all(); }
|
void Notify() { waitForIOActivity.notify_all(); }
|
||||||
@@ -108,14 +131,55 @@ class IoThreadHolder {
|
|||||||
|
|
||||||
~IoThreadHolder() { Stop(); }
|
~IoThreadHolder() { Stop(); }
|
||||||
};
|
};
|
||||||
static IoThreadHolder *IoThread { nullptr };
|
|
||||||
|
static IoThreadHolder *IoThread{ nullptr };
|
||||||
|
|
||||||
static void UpdateReconnectTime() {
|
static void UpdateReconnectTime() {
|
||||||
NextConnect = std::chrono::system_clock::now() +
|
|
||||||
std::chrono::duration<int64_t, std::milli> { ReconnectTimeMs.nextDelay() };
|
NextConnect = std::chrono::system_clock::now() + std::chrono::duration<int64_t, std::milli> { ReconnectTimeMs.nextDelay() };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Discord_UpdateConnection(void) {
|
static void SignalIOActivity() {
|
||||||
|
|
||||||
|
if (IoThread != nullptr) {
|
||||||
|
IoThread->Notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool RegisterForEvent(const char *evtName) {
|
||||||
|
|
||||||
|
auto qmessage = SendQueue.GetNextAddMessage();
|
||||||
|
if (qmessage) {
|
||||||
|
qmessage->length = JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
|
||||||
|
SendQueue.CommitAdd();
|
||||||
|
SignalIOActivity();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool DeregisterForEvent(const char *evtName) {
|
||||||
|
|
||||||
|
auto qmessage = SendQueue.GetNextAddMessage();
|
||||||
|
if (qmessage) {
|
||||||
|
qmessage->length = JsonWriteUnsubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
|
||||||
|
SendQueue.CommitAdd();
|
||||||
|
SignalIOActivity();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
static void Discord_UpdateConnection() {
|
||||||
|
|
||||||
if (!Connection) {
|
if (!Connection) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -217,54 +281,18 @@ static void Discord_UpdateConnection(void) {
|
|||||||
SendQueue.CommitSend();
|
SendQueue.CommitSend();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SignalIOActivity() {
|
extern "C" void Discord_Initialize(const char *applicationId, DiscordEventHandlers *handlers, const int autoRegister) {
|
||||||
if (IoThread != nullptr) {
|
|
||||||
IoThread->Notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool RegisterForEvent(const char *evtName) {
|
|
||||||
auto qmessage = SendQueue.GetNextAddMessage();
|
|
||||||
if (qmessage) {
|
|
||||||
qmessage->length =
|
|
||||||
JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
|
|
||||||
SendQueue.CommitAdd();
|
|
||||||
SignalIOActivity();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool DeregisterForEvent(const char *evtName) {
|
|
||||||
auto qmessage = SendQueue.GetNextAddMessage();
|
|
||||||
if (qmessage) {
|
|
||||||
qmessage->length =
|
|
||||||
JsonWriteUnsubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
|
|
||||||
SendQueue.CommitAdd();
|
|
||||||
SignalIOActivity();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void Discord_Initialize(const char *applicationId,
|
|
||||||
DiscordEventHandlers *handlers,
|
|
||||||
int autoRegister,
|
|
||||||
const char *optionalSteamId) {
|
|
||||||
IoThread = new (std::nothrow) IoThreadHolder();
|
IoThread = new (std::nothrow) IoThreadHolder();
|
||||||
if (IoThread == nullptr) {
|
if (IoThread == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (autoRegister) {
|
if (autoRegister) {
|
||||||
if (optionalSteamId && optionalSteamId[0]) {
|
Discord_Register(applicationId, nullptr);
|
||||||
Discord_RegisterSteamGame(applicationId, optionalSteamId);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Discord_Register(applicationId, nullptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Pid = GetProcessId();
|
Pid = GetProcessId();
|
||||||
@@ -323,9 +351,11 @@ extern "C" void Discord_Initialize(const char *applicationId,
|
|||||||
};
|
};
|
||||||
|
|
||||||
IoThread->Start();
|
IoThread->Start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_Shutdown(void) {
|
extern "C" void Discord_Shutdown() {
|
||||||
|
|
||||||
if (!Connection) {
|
if (!Connection) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -341,16 +371,19 @@ extern "C" void Discord_Shutdown(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RpcConnection::Destroy(Connection);
|
RpcConnection::Destroy(Connection);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_UpdatePresence(const DiscordRichPresence *presence) {
|
extern "C" void Discord_UpdatePresence(const DiscordRichPresence *presence) {
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(PresenceMutex);
|
std::lock_guard<std::mutex> guard(PresenceMutex);
|
||||||
QueuedPresence.length = JsonWriteRichPresenceObj(
|
QueuedPresence.length = JsonWriteRichPresenceObj(QueuedPresence.buffer, sizeof(QueuedPresence.buffer), Nonce++, Pid, presence);
|
||||||
QueuedPresence.buffer, sizeof(QueuedPresence.buffer), Nonce++, Pid, presence);
|
|
||||||
UpdatePresence.exchange(true);
|
UpdatePresence.exchange(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
SignalIOActivity();
|
SignalIOActivity();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_ClearPresence(void) {
|
extern "C" void Discord_ClearPresence(void) {
|
||||||
@@ -358,20 +391,22 @@ extern "C" void Discord_ClearPresence(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_Respond(const char *userId, /* DISCORD_REPLY_ */ int reply) {
|
extern "C" void Discord_Respond(const char *userId, /* DISCORD_REPLY_ */ int reply) {
|
||||||
|
|
||||||
// if we are not connected, let's not batch up stale messages for later
|
// if we are not connected, let's not batch up stale messages for later
|
||||||
if (!Connection || !Connection->IsOpen()) {
|
if (!Connection || !Connection->IsOpen()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto qmessage = SendQueue.GetNextAddMessage();
|
auto qmessage = SendQueue.GetNextAddMessage();
|
||||||
if (qmessage) {
|
if (qmessage) {
|
||||||
qmessage->length =
|
qmessage->length = JsonWriteJoinReply(qmessage->buffer, sizeof(qmessage->buffer), userId, reply, Nonce++);
|
||||||
JsonWriteJoinReply(qmessage->buffer, sizeof(qmessage->buffer), userId, reply, Nonce++);
|
|
||||||
SendQueue.CommitAdd();
|
SendQueue.CommitAdd();
|
||||||
SignalIOActivity();
|
SignalIOActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_RunCallbacks(void) {
|
extern "C" void Discord_RunCallbacks() {
|
||||||
|
|
||||||
// Note on some weirdness: internally we might connect, get other signals, disconnect any number
|
// Note on some weirdness: internally we might connect, get other signals, disconnect any number
|
||||||
// of times inbetween calls here. Externally, we want the sequence to seem sane, so any other
|
// of times inbetween calls here. Externally, we want the sequence to seem sane, so any other
|
||||||
// signals are book-ended by calls to ready and disconnect.
|
// signals are book-ended by calls to ready and disconnect.
|
||||||
@@ -380,8 +415,8 @@ extern "C" void Discord_RunCallbacks(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wasDisconnected = WasJustDisconnected.exchange(false);
|
const bool wasDisconnected = WasJustDisconnected.exchange(false);
|
||||||
bool isConnected = Connection->IsOpen();
|
const bool isConnected = Connection->IsOpen();
|
||||||
|
|
||||||
if (isConnected) {
|
if (isConnected) {
|
||||||
// if we are connected, disconnect cb first
|
// if we are connected, disconnect cb first
|
||||||
@@ -394,10 +429,7 @@ extern "C" void Discord_RunCallbacks(void) {
|
|||||||
if (WasJustConnected.exchange(false)) {
|
if (WasJustConnected.exchange(false)) {
|
||||||
std::lock_guard<std::mutex> guard(HandlerMutex);
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
if (Handlers.ready) {
|
if (Handlers.ready) {
|
||||||
DiscordUser du { connectedUser.userId,
|
DiscordUser du{ connectedUser.userId, connectedUser.username, connectedUser.discriminator, connectedUser.avatar };
|
||||||
connectedUser.username,
|
|
||||||
connectedUser.discriminator,
|
|
||||||
connectedUser.avatar };
|
|
||||||
Handlers.ready(&du);
|
Handlers.ready(&du);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -429,11 +461,11 @@ extern "C" void Discord_RunCallbacks(void) {
|
|||||||
// maybe show them in one common dialog and/or start fetching the avatars in parallel, and if
|
// maybe show them in one common dialog and/or start fetching the avatars in parallel, and if
|
||||||
// not it should be trivial for the implementer to make a queue themselves.
|
// not it should be trivial for the implementer to make a queue themselves.
|
||||||
while (JoinAskQueue.HavePendingSends()) {
|
while (JoinAskQueue.HavePendingSends()) {
|
||||||
auto req = JoinAskQueue.GetNextSendMessage();
|
const auto req = JoinAskQueue.GetNextSendMessage();
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(HandlerMutex);
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
if (Handlers.joinRequest) {
|
if (Handlers.joinRequest) {
|
||||||
DiscordUser du { req->userId, req->username, req->discriminator, req->avatar };
|
DiscordUser du{ req->userId, req->username, req->discriminator, req->avatar };
|
||||||
Handlers.joinRequest(&du);
|
Handlers.joinRequest(&du);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -447,17 +479,19 @@ extern "C" void Discord_RunCallbacks(void) {
|
|||||||
Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage);
|
Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_UpdateHandlers(DiscordEventHandlers *newHandlers) {
|
extern "C" void Discord_UpdateHandlers(DiscordEventHandlers *newHandlers) {
|
||||||
|
|
||||||
if (newHandlers) {
|
if (newHandlers) {
|
||||||
#define HANDLE_EVENT_REGISTRATION(handler_name, event) \
|
#define HANDLE_EVENT_REGISTRATION(handler_name, event) \
|
||||||
if (!Handlers.handler_name && newHandlers->handler_name) { \
|
if (!Handlers.handler_name && newHandlers->handler_name) { \
|
||||||
RegisterForEvent(event); \
|
RegisterForEvent(event); \
|
||||||
} \
|
} \
|
||||||
else if (Handlers.handler_name && !newHandlers->handler_name) { \
|
else if (Handlers.handler_name && !newHandlers->handler_name) { \
|
||||||
DeregisterForEvent(event); \
|
DeregisterForEvent(event); \
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> guard(HandlerMutex);
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
HANDLE_EVENT_REGISTRATION(joinGame, "ACTIVITY_JOIN")
|
HANDLE_EVENT_REGISTRATION(joinGame, "ACTIVITY_JOIN")
|
||||||
@@ -472,8 +506,5 @@ extern "C" void Discord_UpdateHandlers(DiscordEventHandlers *newHandlers) {
|
|||||||
std::lock_guard<std::mutex> guard(HandlerMutex);
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
Handlers = {};
|
Handlers = {};
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace discord_rpc
|
|
||||||
|
|
||||||
94
3rdparty/discord-rpc/discord_rpc.h
vendored
Normal file
94
3rdparty/discord-rpc/discord_rpc.h
vendored
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Discord, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DISCORD_RPC_H
|
||||||
|
#define DISCORD_RPC_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct DiscordRichPresence {
|
||||||
|
int type;
|
||||||
|
int status_display_type;
|
||||||
|
const char *name; /* max 128 bytes */
|
||||||
|
const char *state; /* max 128 bytes */
|
||||||
|
const char *details; /* max 128 bytes */
|
||||||
|
int64_t startTimestamp;
|
||||||
|
int64_t endTimestamp;
|
||||||
|
const char *largeImageKey; /* max 32 bytes */
|
||||||
|
const char *largeImageText; /* max 128 bytes */
|
||||||
|
const char *smallImageKey; /* max 32 bytes */
|
||||||
|
const char *smallImageText; /* max 128 bytes */
|
||||||
|
const char *partyId; /* max 128 bytes */
|
||||||
|
int partySize;
|
||||||
|
int partyMax;
|
||||||
|
int partyPrivacy;
|
||||||
|
const char *matchSecret; /* max 128 bytes */
|
||||||
|
const char *joinSecret; /* max 128 bytes */
|
||||||
|
const char *spectateSecret; /* max 128 bytes */
|
||||||
|
int8_t instance;
|
||||||
|
} DiscordRichPresence;
|
||||||
|
|
||||||
|
typedef struct DiscordUser {
|
||||||
|
const char *userId;
|
||||||
|
const char *username;
|
||||||
|
const char *discriminator;
|
||||||
|
const char *avatar;
|
||||||
|
} DiscordUser;
|
||||||
|
|
||||||
|
typedef struct DiscordEventHandlers {
|
||||||
|
void (*ready)(const DiscordUser *request);
|
||||||
|
void (*disconnected)(int errorCode, const char *message);
|
||||||
|
void (*errored)(int errorCode, const char *message);
|
||||||
|
void (*joinGame)(const char *joinSecret);
|
||||||
|
void (*spectateGame)(const char *spectateSecret);
|
||||||
|
void (*joinRequest)(const DiscordUser *request);
|
||||||
|
} DiscordEventHandlers;
|
||||||
|
|
||||||
|
#define DISCORD_REPLY_NO 0
|
||||||
|
#define DISCORD_REPLY_YES 1
|
||||||
|
#define DISCORD_REPLY_IGNORE 2
|
||||||
|
#define DISCORD_PARTY_PRIVATE 0
|
||||||
|
#define DISCORD_PARTY_PUBLIC 1
|
||||||
|
|
||||||
|
void Discord_Initialize(const char *applicationId, DiscordEventHandlers *handlers, const int autoRegister);
|
||||||
|
void Discord_Shutdown(void);
|
||||||
|
|
||||||
|
// checks for incoming messages, dispatches callbacks
|
||||||
|
void Discord_RunCallbacks(void);
|
||||||
|
|
||||||
|
void Discord_UpdatePresence(const DiscordRichPresence *presence);
|
||||||
|
void Discord_ClearPresence(void);
|
||||||
|
|
||||||
|
void Discord_Respond(const char *userid, /* DISCORD_REPLY_ */ int reply);
|
||||||
|
|
||||||
|
void Discord_UpdateHandlers(DiscordEventHandlers *handlers);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // DISCORD_RPC_H
|
||||||
@@ -1,24 +1,52 @@
|
|||||||
#include "rpc_connection.h"
|
/*
|
||||||
#include "serialization.h"
|
* Copyright 2017 Discord, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "discord_rpc_connection.h"
|
||||||
|
#include "discord_serialization.h"
|
||||||
|
|
||||||
namespace discord_rpc {
|
namespace discord_rpc {
|
||||||
|
|
||||||
static const int RpcVersion = 1;
|
static const int RpcVersion = 1;
|
||||||
static RpcConnection Instance;
|
static RpcConnection Instance;
|
||||||
|
|
||||||
/*static*/ RpcConnection *RpcConnection::Create(const char *applicationId) {
|
RpcConnection *RpcConnection::Create(const char *applicationId) {
|
||||||
|
|
||||||
Instance.connection = BaseConnection::Create();
|
Instance.connection = BaseConnection::Create();
|
||||||
StringCopy(Instance.appId, applicationId);
|
StringCopy(Instance.appId, applicationId);
|
||||||
return &Instance;
|
return &Instance;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ void RpcConnection::Destroy(RpcConnection *&c) {
|
void RpcConnection::Destroy(RpcConnection *&c) {
|
||||||
|
|
||||||
c->Close();
|
c->Close();
|
||||||
BaseConnection::Destroy(c->connection);
|
BaseConnection::Destroy(c->connection);
|
||||||
c = nullptr;
|
c = nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RpcConnection::Open() {
|
void RpcConnection::Open() {
|
||||||
|
|
||||||
if (state == State::Connected) {
|
if (state == State::Connected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -51,17 +79,21 @@ void RpcConnection::Open() {
|
|||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RpcConnection::Close() {
|
void RpcConnection::Close() {
|
||||||
|
|
||||||
if (onDisconnect && (state == State::Connected || state == State::SentHandshake)) {
|
if (onDisconnect && (state == State::Connected || state == State::SentHandshake)) {
|
||||||
onDisconnect(lastErrorCode, lastErrorMessage);
|
onDisconnect(lastErrorCode, lastErrorMessage);
|
||||||
}
|
}
|
||||||
connection->Close();
|
connection->Close();
|
||||||
state = State::Disconnected;
|
state = State::Disconnected;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RpcConnection::Write(const void *data, size_t length) {
|
bool RpcConnection::Write(const void *data, size_t length) {
|
||||||
|
|
||||||
sendFrame.opcode = Opcode::Frame;
|
sendFrame.opcode = Opcode::Frame;
|
||||||
memcpy(sendFrame.message, data, length);
|
memcpy(sendFrame.message, data, length);
|
||||||
sendFrame.length = static_cast<uint32_t>(length);
|
sendFrame.length = static_cast<uint32_t>(length);
|
||||||
@@ -69,14 +101,17 @@ bool RpcConnection::Write(const void *data, size_t length) {
|
|||||||
Close();
|
Close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RpcConnection::Read(JsonDocument &message) {
|
bool RpcConnection::Read(JsonDocument &message) {
|
||||||
|
|
||||||
if (state != State::Connected && state != State::SentHandshake) {
|
if (state != State::Connected && state != State::SentHandshake) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MessageFrame readFrame;
|
MessageFrame readFrame{};
|
||||||
for (;;) {
|
for (;;) {
|
||||||
bool didRead = connection->Read(&readFrame, sizeof(MessageFrameHeader));
|
bool didRead = connection->Read(&readFrame, sizeof(MessageFrameHeader));
|
||||||
if (!didRead) {
|
if (!didRead) {
|
||||||
@@ -127,7 +162,7 @@ bool RpcConnection::Read(JsonDocument &message) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace discord_rpc
|
} // namespace discord_rpc
|
||||||
|
|
||||||
88
3rdparty/discord-rpc/discord_rpc_connection.h
vendored
Normal file
88
3rdparty/discord-rpc/discord_rpc_connection.h
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Discord, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DISCORD_RPC_CONNECTION_H
|
||||||
|
#define DISCORD_RPC_CONNECTION_H
|
||||||
|
|
||||||
|
#include "discord_connection.h"
|
||||||
|
#include "discord_serialization.h"
|
||||||
|
|
||||||
|
namespace discord_rpc {
|
||||||
|
|
||||||
|
// I took this from the buffer size libuv uses for named pipes; I suspect ours would usually be much smaller.
|
||||||
|
constexpr size_t MaxRpcFrameSize = 64 * 1024;
|
||||||
|
|
||||||
|
struct RpcConnection {
|
||||||
|
enum class ErrorCode : int {
|
||||||
|
Success = 0,
|
||||||
|
PipeClosed = 1,
|
||||||
|
ReadCorrupt = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Opcode : uint32_t {
|
||||||
|
Handshake = 0,
|
||||||
|
Frame = 1,
|
||||||
|
Close = 2,
|
||||||
|
Ping = 3,
|
||||||
|
Pong = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MessageFrameHeader {
|
||||||
|
Opcode opcode;
|
||||||
|
uint32_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MessageFrame : public MessageFrameHeader {
|
||||||
|
char message[MaxRpcFrameSize - sizeof(MessageFrameHeader)];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class State : uint32_t {
|
||||||
|
Disconnected,
|
||||||
|
SentHandshake,
|
||||||
|
AwaitingResponse,
|
||||||
|
Connected,
|
||||||
|
};
|
||||||
|
|
||||||
|
BaseConnection *connection{ nullptr };
|
||||||
|
State state{ State::Disconnected };
|
||||||
|
void (*onConnect)(JsonDocument &message) { nullptr };
|
||||||
|
void (*onDisconnect)(int errorCode, const char *message) { nullptr };
|
||||||
|
char appId[64]{};
|
||||||
|
int lastErrorCode{ 0 };
|
||||||
|
char lastErrorMessage[256]{};
|
||||||
|
RpcConnection::MessageFrame sendFrame;
|
||||||
|
|
||||||
|
static RpcConnection *Create(const char *applicationId);
|
||||||
|
static void Destroy(RpcConnection*&);
|
||||||
|
|
||||||
|
inline bool IsOpen() const { return state == State::Connected; }
|
||||||
|
|
||||||
|
void Open();
|
||||||
|
void Close();
|
||||||
|
bool Write(const void *data, size_t length);
|
||||||
|
bool Read(JsonDocument &message);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace discord_rpc
|
||||||
|
|
||||||
|
#endif // DISCORD_RPC_CONNECTION_H
|
||||||
@@ -1,11 +1,35 @@
|
|||||||
#include "serialization.h"
|
/*
|
||||||
#include "connection.h"
|
* Copyright 2017 Discord, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "discord_serialization.h"
|
||||||
|
#include "discord_connection.h"
|
||||||
#include "discord_rpc.h"
|
#include "discord_rpc.h"
|
||||||
|
|
||||||
namespace discord_rpc {
|
namespace discord_rpc {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void NumberToString(char *dest, T number) {
|
void NumberToString(char *dest, T number) {
|
||||||
|
|
||||||
if (!number) {
|
if (!number) {
|
||||||
*dest++ = '0';
|
*dest++ = '0';
|
||||||
*dest++ = 0;
|
*dest++ = 0;
|
||||||
@@ -26,6 +50,7 @@ void NumberToString(char *dest, T number) {
|
|||||||
*dest++ = temp[place];
|
*dest++ = temp[place];
|
||||||
}
|
}
|
||||||
*dest = 0;
|
*dest = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// it's ever so slightly faster to not have to strlen the key
|
// it's ever so slightly faster to not have to strlen the key
|
||||||
@@ -62,24 +87,25 @@ struct WriteArray {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void WriteOptionalString(JsonWriter &w, T &k, const char *value) {
|
void WriteOptionalString(JsonWriter &w, T &k, const char *value) {
|
||||||
|
|
||||||
if (value && value[0]) {
|
if (value && value[0]) {
|
||||||
w.Key(k, sizeof(T) - 1);
|
w.Key(k, sizeof(T) - 1);
|
||||||
w.String(value);
|
w.String(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void JsonWriteNonce(JsonWriter &writer, int nonce) {
|
static void JsonWriteNonce(JsonWriter &writer, const int nonce) {
|
||||||
|
|
||||||
WriteKey(writer, "nonce");
|
WriteKey(writer, "nonce");
|
||||||
char nonceBuffer[32];
|
char nonceBuffer[32];
|
||||||
NumberToString(nonceBuffer, nonce);
|
NumberToString(nonceBuffer, nonce);
|
||||||
writer.String(nonceBuffer);
|
writer.String(nonceBuffer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t JsonWriteRichPresenceObj(char *dest,
|
size_t JsonWriteRichPresenceObj(char *dest, const size_t maxLen, const int nonce, const int pid, const DiscordRichPresence *presence) {
|
||||||
size_t maxLen,
|
|
||||||
int nonce,
|
|
||||||
int pid,
|
|
||||||
const DiscordRichPresence *presence) {
|
|
||||||
JsonWriter writer(dest, maxLen);
|
JsonWriter writer(dest, maxLen);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -102,6 +128,9 @@ size_t JsonWriteRichPresenceObj(char *dest,
|
|||||||
if (presence->type >= 0 && presence->type <= 5) {
|
if (presence->type >= 0 && presence->type <= 5) {
|
||||||
WriteKey(writer, "type");
|
WriteKey(writer, "type");
|
||||||
writer.Int(presence->type);
|
writer.Int(presence->type);
|
||||||
|
|
||||||
|
WriteKey(writer, "status_display_type");
|
||||||
|
writer.Int(presence->status_display_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteOptionalString(writer, "name", presence->name);
|
WriteOptionalString(writer, "name", presence->name);
|
||||||
@@ -168,6 +197,7 @@ size_t JsonWriteRichPresenceObj(char *dest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t JsonWriteHandshakeObj(char *dest, size_t maxLen, int version, const char *applicationId) {
|
size_t JsonWriteHandshakeObj(char *dest, size_t maxLen, int version, const char *applicationId) {
|
||||||
|
|
||||||
JsonWriter writer(dest, maxLen);
|
JsonWriter writer(dest, maxLen);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -179,9 +209,11 @@ size_t JsonWriteHandshakeObj(char *dest, size_t maxLen, int version, const char
|
|||||||
}
|
}
|
||||||
|
|
||||||
return writer.Size();
|
return writer.Size();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t JsonWriteSubscribeCommand(char *dest, size_t maxLen, int nonce, const char *evtName) {
|
size_t JsonWriteSubscribeCommand(char *dest, size_t maxLen, int nonce, const char *evtName) {
|
||||||
|
|
||||||
JsonWriter writer(dest, maxLen);
|
JsonWriter writer(dest, maxLen);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -197,9 +229,11 @@ size_t JsonWriteSubscribeCommand(char *dest, size_t maxLen, int nonce, const cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
return writer.Size();
|
return writer.Size();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t JsonWriteUnsubscribeCommand(char *dest, size_t maxLen, int nonce, const char *evtName) {
|
size_t JsonWriteUnsubscribeCommand(char *dest, size_t maxLen, int nonce, const char *evtName) {
|
||||||
|
|
||||||
JsonWriter writer(dest, maxLen);
|
JsonWriter writer(dest, maxLen);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -215,9 +249,11 @@ size_t JsonWriteUnsubscribeCommand(char *dest, size_t maxLen, int nonce, const c
|
|||||||
}
|
}
|
||||||
|
|
||||||
return writer.Size();
|
return writer.Size();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t JsonWriteJoinReply(char *dest, size_t maxLen, const char *userId, int reply, int nonce) {
|
size_t JsonWriteJoinReply(char *dest, size_t maxLen, const char *userId, const int reply, const int nonce) {
|
||||||
|
|
||||||
JsonWriter writer(dest, maxLen);
|
JsonWriter writer(dest, maxLen);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -243,7 +279,7 @@ size_t JsonWriteJoinReply(char *dest, size_t maxLen, const char *userId, int rep
|
|||||||
}
|
}
|
||||||
|
|
||||||
return writer.Size();
|
return writer.Size();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace discord_rpc
|
} // namespace discord_rpc
|
||||||
|
|
||||||
@@ -1,9 +1,35 @@
|
|||||||
#pragma once
|
/*
|
||||||
|
* Copyright 2017 Discord, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DISCORD_SERIALIZATION_H
|
||||||
|
#define DISCORD_SERIALIZATION_H
|
||||||
|
|
||||||
#include <rapidjson/document.h>
|
#include <rapidjson/document.h>
|
||||||
#include <rapidjson/stringbuffer.h>
|
#include <rapidjson/stringbuffer.h>
|
||||||
#include <rapidjson/writer.h>
|
#include <rapidjson/writer.h>
|
||||||
|
|
||||||
|
struct DiscordRichPresence;
|
||||||
|
|
||||||
namespace discord_rpc {
|
namespace discord_rpc {
|
||||||
|
|
||||||
// if only there was a standard library function for this
|
// if only there was a standard library function for this
|
||||||
@@ -24,12 +50,7 @@ inline size_t StringCopy(char (&dest)[Len], const char *src) {
|
|||||||
size_t JsonWriteHandshakeObj(char *dest, size_t maxLen, int version, const char *applicationId);
|
size_t JsonWriteHandshakeObj(char *dest, size_t maxLen, int version, const char *applicationId);
|
||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
struct DiscordRichPresence;
|
size_t JsonWriteRichPresenceObj(char *dest, const size_t maxLen, const int nonce, const int pid, const DiscordRichPresence *presence);
|
||||||
size_t JsonWriteRichPresenceObj(char *dest,
|
|
||||||
size_t maxLen,
|
|
||||||
int nonce,
|
|
||||||
int pid,
|
|
||||||
const DiscordRichPresence *presence);
|
|
||||||
size_t JsonWriteSubscribeCommand(char *dest, size_t maxLen, int nonce, const char *evtName);
|
size_t JsonWriteSubscribeCommand(char *dest, size_t maxLen, int nonce, const char *evtName);
|
||||||
|
|
||||||
size_t JsonWriteUnsubscribeCommand(char *dest, size_t maxLen, int nonce, const char *evtName);
|
size_t JsonWriteUnsubscribeCommand(char *dest, size_t maxLen, int nonce, const char *evtName);
|
||||||
@@ -149,35 +170,44 @@ class JsonDocument : public JsonDocumentBase {
|
|||||||
using JsonValue = rapidjson::GenericValue<UTF8, PoolAllocator>;
|
using JsonValue = rapidjson::GenericValue<UTF8, PoolAllocator>;
|
||||||
|
|
||||||
inline JsonValue *GetObjMember(JsonValue *obj, const char *name) {
|
inline JsonValue *GetObjMember(JsonValue *obj, const char *name) {
|
||||||
|
|
||||||
if (obj) {
|
if (obj) {
|
||||||
auto member = obj->FindMember(name);
|
auto member = obj->FindMember(name);
|
||||||
if (member != obj->MemberEnd() && member->value.IsObject()) {
|
if (member != obj->MemberEnd() && member->value.IsObject()) {
|
||||||
return &member->value;
|
return &member->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int GetIntMember(JsonValue *obj, const char *name, int notFoundDefault = 0) {
|
inline int GetIntMember(JsonValue *obj, const char *name, int notFoundDefault = 0) {
|
||||||
|
|
||||||
if (obj) {
|
if (obj) {
|
||||||
auto member = obj->FindMember(name);
|
auto member = obj->FindMember(name);
|
||||||
if (member != obj->MemberEnd() && member->value.IsInt()) {
|
if (member != obj->MemberEnd() && member->value.IsInt()) {
|
||||||
return member->value.GetInt();
|
return member->value.GetInt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return notFoundDefault;
|
return notFoundDefault;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const char *GetStrMember(JsonValue *obj,
|
inline const char *GetStrMember(JsonValue *obj, const char *name, const char *notFoundDefault = nullptr) {
|
||||||
const char *name,
|
|
||||||
const char *notFoundDefault = nullptr) {
|
|
||||||
if (obj) {
|
if (obj) {
|
||||||
auto member = obj->FindMember(name);
|
auto member = obj->FindMember(name);
|
||||||
if (member != obj->MemberEnd() && member->value.IsString()) {
|
if (member != obj->MemberEnd() && member->value.IsString()) {
|
||||||
return member->value.GetString();
|
return member->value.GetString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return notFoundDefault;
|
return notFoundDefault;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace discord_rpc
|
} // namespace discord_rpc
|
||||||
|
|
||||||
|
#endif // DISCORD_SERIALIZATION_H
|
||||||
12
3rdparty/discord-rpc/include/discord_register.h
vendored
12
3rdparty/discord-rpc/include/discord_register.h
vendored
@@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void Discord_Register(const char* applicationId, const char* command);
|
|
||||||
void Discord_RegisterSteamGame(const char* applicationId, const char* steamId);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
77
3rdparty/discord-rpc/include/discord_rpc.h
vendored
77
3rdparty/discord-rpc/include/discord_rpc.h
vendored
@@ -1,77 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
namespace discord_rpc {
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct DiscordRichPresence {
|
|
||||||
int type;
|
|
||||||
const char* name; /* max 128 bytes */
|
|
||||||
const char* state; /* max 128 bytes */
|
|
||||||
const char* details; /* max 128 bytes */
|
|
||||||
int64_t startTimestamp;
|
|
||||||
int64_t endTimestamp;
|
|
||||||
const char* largeImageKey; /* max 32 bytes */
|
|
||||||
const char* largeImageText; /* max 128 bytes */
|
|
||||||
const char* smallImageKey; /* max 32 bytes */
|
|
||||||
const char* smallImageText; /* max 128 bytes */
|
|
||||||
const char* partyId; /* max 128 bytes */
|
|
||||||
int partySize;
|
|
||||||
int partyMax;
|
|
||||||
int partyPrivacy;
|
|
||||||
const char* matchSecret; /* max 128 bytes */
|
|
||||||
const char* joinSecret; /* max 128 bytes */
|
|
||||||
const char* spectateSecret; /* max 128 bytes */
|
|
||||||
int8_t instance;
|
|
||||||
} DiscordRichPresence;
|
|
||||||
|
|
||||||
typedef struct DiscordUser {
|
|
||||||
const char* userId;
|
|
||||||
const char* username;
|
|
||||||
const char* discriminator;
|
|
||||||
const char* avatar;
|
|
||||||
} DiscordUser;
|
|
||||||
|
|
||||||
typedef struct DiscordEventHandlers {
|
|
||||||
void (*ready)(const DiscordUser* request);
|
|
||||||
void (*disconnected)(int errorCode, const char* message);
|
|
||||||
void (*errored)(int errorCode, const char* message);
|
|
||||||
void (*joinGame)(const char* joinSecret);
|
|
||||||
void (*spectateGame)(const char* spectateSecret);
|
|
||||||
void (*joinRequest)(const DiscordUser* request);
|
|
||||||
} DiscordEventHandlers;
|
|
||||||
|
|
||||||
#define DISCORD_REPLY_NO 0
|
|
||||||
#define DISCORD_REPLY_YES 1
|
|
||||||
#define DISCORD_REPLY_IGNORE 2
|
|
||||||
#define DISCORD_PARTY_PRIVATE 0
|
|
||||||
#define DISCORD_PARTY_PUBLIC 1
|
|
||||||
|
|
||||||
void Discord_Initialize(const char* applicationId,
|
|
||||||
DiscordEventHandlers* handlers,
|
|
||||||
int autoRegister,
|
|
||||||
const char* optionalSteamId);
|
|
||||||
void Discord_Shutdown(void);
|
|
||||||
|
|
||||||
/* checks for incoming messages, dispatches callbacks */
|
|
||||||
void Discord_RunCallbacks(void);
|
|
||||||
|
|
||||||
void Discord_UpdatePresence(const DiscordRichPresence* presence);
|
|
||||||
void Discord_ClearPresence(void);
|
|
||||||
|
|
||||||
void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply);
|
|
||||||
|
|
||||||
void Discord_UpdateHandlers(DiscordEventHandlers* handlers);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* extern "C" */
|
|
||||||
} // namespace discord_rpc
|
|
||||||
|
|
||||||
#endif
|
|
||||||
41
3rdparty/discord-rpc/src/CMakeLists.txt
vendored
41
3rdparty/discord-rpc/src/CMakeLists.txt
vendored
@@ -1,41 +0,0 @@
|
|||||||
set(DISCORD_RPC_SOURCES
|
|
||||||
../include/discord_rpc.h
|
|
||||||
../include/discord_register.h
|
|
||||||
discord_rpc.cpp
|
|
||||||
rpc_connection.h
|
|
||||||
rpc_connection.cpp
|
|
||||||
serialization.h
|
|
||||||
serialization.cpp
|
|
||||||
connection.h
|
|
||||||
backoff.h
|
|
||||||
msg_queue.h
|
|
||||||
)
|
|
||||||
|
|
||||||
if(UNIX)
|
|
||||||
list(APPEND DISCORD_RPC_SOURCES connection_unix.cpp)
|
|
||||||
if(APPLE)
|
|
||||||
list(APPEND DISCORD_RPC_SOURCES discord_register_osx.m)
|
|
||||||
add_definitions(-DDISCORD_OSX)
|
|
||||||
else()
|
|
||||||
list(APPEND DISCORD_RPC_SOURCES discord_register_linux.cpp)
|
|
||||||
add_definitions(-DDISCORD_LINUX)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
list(APPEND DISCORD_RPC_SOURCES connection_win.cpp discord_register_win.cpp)
|
|
||||||
add_definitions(-DDISCORD_WINDOWS)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(discord-rpc STATIC ${DISCORD_RPC_SOURCES})
|
|
||||||
|
|
||||||
if(APPLE)
|
|
||||||
target_link_libraries(discord-rpc PRIVATE "-framework AppKit")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
target_link_libraries(discord-rpc PRIVATE psapi advapi32)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_include_directories(discord-rpc SYSTEM PRIVATE ${RapidJSON_INCLUDE_DIRS})
|
|
||||||
target_include_directories(discord-rpc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include)
|
|
||||||
44
3rdparty/discord-rpc/src/backoff.h
vendored
44
3rdparty/discord-rpc/src/backoff.h
vendored
@@ -1,44 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <random>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <ctime>
|
|
||||||
|
|
||||||
namespace discord_rpc {
|
|
||||||
|
|
||||||
struct Backoff {
|
|
||||||
int64_t minAmount;
|
|
||||||
int64_t maxAmount;
|
|
||||||
int64_t current;
|
|
||||||
int fails;
|
|
||||||
std::mt19937_64 randGenerator;
|
|
||||||
std::uniform_real_distribution<> randDistribution;
|
|
||||||
|
|
||||||
double rand01() { return randDistribution(randGenerator); }
|
|
||||||
|
|
||||||
Backoff(int64_t min, int64_t max)
|
|
||||||
: minAmount(min)
|
|
||||||
, maxAmount(max)
|
|
||||||
, current(min)
|
|
||||||
, fails(0)
|
|
||||||
, randGenerator(static_cast<uint64_t>(time(0)))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
fails = 0;
|
|
||||||
current = minAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t nextDelay()
|
|
||||||
{
|
|
||||||
++fails;
|
|
||||||
int64_t delay = static_cast<int64_t>(static_cast<double>(current) * 2.0 * rand01());
|
|
||||||
current = std::min(current + delay, maxAmount);
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace discord_rpc
|
|
||||||
22
3rdparty/discord-rpc/src/connection.h
vendored
22
3rdparty/discord-rpc/src/connection.h
vendored
@@ -1,22 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// This is to wrap the platform specific kinds of connect/read/write.
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
namespace discord_rpc {
|
|
||||||
|
|
||||||
// not really connectiony, but need per-platform
|
|
||||||
int GetProcessId();
|
|
||||||
|
|
||||||
struct BaseConnection {
|
|
||||||
static BaseConnection *Create();
|
|
||||||
static void Destroy(BaseConnection *&);
|
|
||||||
bool isOpen { false };
|
|
||||||
bool Open();
|
|
||||||
bool Close();
|
|
||||||
bool Write(const void *data, size_t length);
|
|
||||||
bool Read(void *data, size_t length);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace discord_rpc
|
|
||||||
104
3rdparty/discord-rpc/src/discord_register_linux.cpp
vendored
104
3rdparty/discord-rpc/src/discord_register_linux.cpp
vendored
@@ -1,104 +0,0 @@
|
|||||||
#include "discord_rpc.h"
|
|
||||||
#include "discord_register.h"
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
static bool Mkdir(const char *path) {
|
|
||||||
int result = mkdir(path, 0755);
|
|
||||||
if (result == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (errno == EEXIST) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
// we want to register games so we can run them from Discord client as discord-<appid>://
|
|
||||||
extern "C" void Discord_Register(const char *applicationId, const char *command) {
|
|
||||||
// Add a desktop file and update some mime handlers so that xdg-open does the right thing.
|
|
||||||
|
|
||||||
const char *home = getenv("HOME");
|
|
||||||
if (!home) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char exePath[1024];
|
|
||||||
if (!command || !command[0]) {
|
|
||||||
ssize_t size = readlink("/proc/self/exe", exePath, sizeof(exePath));
|
|
||||||
if (size <= 0 || size >= static_cast<ssize_t>(sizeof(exePath))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
exePath[size] = '\0';
|
|
||||||
command = exePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr char desktopFileFormat[] = "[Desktop Entry]\n"
|
|
||||||
"Name=Game %s\n"
|
|
||||||
"Exec=%s %%u\n" // note: it really wants that %u in there
|
|
||||||
"Type=Application\n"
|
|
||||||
"NoDisplay=true\n"
|
|
||||||
"Categories=Discord;Games;\n"
|
|
||||||
"MimeType=x-scheme-handler/discord-%s;\n";
|
|
||||||
char desktopFile[2048];
|
|
||||||
int fileLen = snprintf(
|
|
||||||
desktopFile, sizeof(desktopFile), desktopFileFormat, applicationId, command, applicationId);
|
|
||||||
if (fileLen <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char desktopFilename[256];
|
|
||||||
(void)snprintf(desktopFilename, sizeof(desktopFilename), "/discord-%s.desktop", applicationId);
|
|
||||||
|
|
||||||
char desktopFilePath[1024];
|
|
||||||
(void)snprintf(desktopFilePath, sizeof(desktopFilePath), "%s/.local", home);
|
|
||||||
if (!Mkdir(desktopFilePath)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
strcat(desktopFilePath, "/share");
|
|
||||||
if (!Mkdir(desktopFilePath)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
strcat(desktopFilePath, "/applications");
|
|
||||||
if (!Mkdir(desktopFilePath)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
strcat(desktopFilePath, desktopFilename);
|
|
||||||
|
|
||||||
FILE *fp = fopen(desktopFilePath, "w");
|
|
||||||
if (fp) {
|
|
||||||
fwrite(desktopFile, 1, fileLen, fp);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char xdgMimeCommand[1024];
|
|
||||||
snprintf(xdgMimeCommand,
|
|
||||||
sizeof(xdgMimeCommand),
|
|
||||||
"xdg-mime default discord-%s.desktop x-scheme-handler/discord-%s",
|
|
||||||
applicationId,
|
|
||||||
applicationId);
|
|
||||||
if (system(xdgMimeCommand) < 0) {
|
|
||||||
fprintf(stderr, "Failed to register mime handler\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void Discord_RegisterSteamGame(const char *applicationId,
|
|
||||||
const char *steamId) {
|
|
||||||
char command[256];
|
|
||||||
sprintf(command, "xdg-open steam://rungameid/%s", steamId);
|
|
||||||
Discord_Register(applicationId, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
80
3rdparty/discord-rpc/src/discord_register_osx.m
vendored
80
3rdparty/discord-rpc/src/discord_register_osx.m
vendored
@@ -1,80 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#import <AppKit/AppKit.h>
|
|
||||||
|
|
||||||
#include "discord_register.h"
|
|
||||||
|
|
||||||
static void RegisterCommand(const char* applicationId, const char* command)
|
|
||||||
{
|
|
||||||
// There does not appear to be a way to register arbitrary commands on OSX, so instead we'll save the command
|
|
||||||
// to a file in the Discord config path, and when it is needed, Discord can try to load the file there, open
|
|
||||||
// the command therein (will pass to js's window.open, so requires a url-like thing)
|
|
||||||
|
|
||||||
// Note: will not work for sandboxed apps
|
|
||||||
NSString *home = NSHomeDirectory();
|
|
||||||
if (!home) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSString *path = [[[[[[home stringByAppendingPathComponent:@"Library"]
|
|
||||||
stringByAppendingPathComponent:@"Application Support"]
|
|
||||||
stringByAppendingPathComponent:@"discord"]
|
|
||||||
stringByAppendingPathComponent:@"games"]
|
|
||||||
stringByAppendingPathComponent:[NSString stringWithUTF8String:applicationId]]
|
|
||||||
stringByAppendingPathExtension:@"json"];
|
|
||||||
[[NSFileManager defaultManager] createDirectoryAtPath:[path stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
|
|
||||||
|
|
||||||
NSString *jsonBuffer = [NSString stringWithFormat:@"{\"command\": \"%s\"}", command];
|
|
||||||
[jsonBuffer writeToFile:path atomically:NO encoding:NSUTF8StringEncoding error:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RegisterURL(const char* applicationId)
|
|
||||||
{
|
|
||||||
char url[256];
|
|
||||||
snprintf(url, sizeof(url), "discord-%s", applicationId);
|
|
||||||
CFStringRef cfURL = CFStringCreateWithCString(NULL, url, kCFStringEncodingUTF8);
|
|
||||||
|
|
||||||
NSString* myBundleId = [[NSBundle mainBundle] bundleIdentifier];
|
|
||||||
if (!myBundleId) {
|
|
||||||
fprintf(stderr, "No bundle id found\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSURL* myURL = [[NSBundle mainBundle] bundleURL];
|
|
||||||
if (!myURL) {
|
|
||||||
fprintf(stderr, "No bundle url found\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OSStatus status = LSSetDefaultHandlerForURLScheme(cfURL, (__bridge CFStringRef)myBundleId);
|
|
||||||
if (status != noErr) {
|
|
||||||
fprintf(stderr, "Error in LSSetDefaultHandlerForURLScheme: %d\n", (int)status);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = LSRegisterURL((__bridge CFURLRef)myURL, true);
|
|
||||||
if (status != noErr) {
|
|
||||||
fprintf(stderr, "Error in LSRegisterURL: %d\n", (int)status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Discord_Register(const char* applicationId, const char* command)
|
|
||||||
{
|
|
||||||
if (command) {
|
|
||||||
RegisterCommand(applicationId, command);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// raii lite
|
|
||||||
@autoreleasepool {
|
|
||||||
RegisterURL(applicationId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Discord_RegisterSteamGame(const char* applicationId, const char* steamId)
|
|
||||||
{
|
|
||||||
char command[256];
|
|
||||||
snprintf(command, 256, "steam://rungameid/%s", steamId);
|
|
||||||
Discord_Register(applicationId, command);
|
|
||||||
}
|
|
||||||
40
3rdparty/discord-rpc/src/msg_queue.h
vendored
40
3rdparty/discord-rpc/src/msg_queue.h
vendored
@@ -1,40 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
// A simple queue. No locks, but only works with a single thread as producer and a single thread as
|
|
||||||
// a consumer. Mutex up as needed.
|
|
||||||
|
|
||||||
namespace discord_rpc {
|
|
||||||
|
|
||||||
template <typename ElementType, std::size_t QueueSize>
|
|
||||||
class MsgQueue {
|
|
||||||
ElementType queue_[QueueSize];
|
|
||||||
std::atomic_uint nextAdd_{0};
|
|
||||||
std::atomic_uint nextSend_{0};
|
|
||||||
std::atomic_uint pendingSends_{0};
|
|
||||||
|
|
||||||
public:
|
|
||||||
MsgQueue() {}
|
|
||||||
|
|
||||||
ElementType* GetNextAddMessage()
|
|
||||||
{
|
|
||||||
// if we are falling behind, bail
|
|
||||||
if (pendingSends_.load() >= QueueSize) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
auto index = (nextAdd_++) % QueueSize;
|
|
||||||
return &queue_[index];
|
|
||||||
}
|
|
||||||
void CommitAdd() { ++pendingSends_; }
|
|
||||||
|
|
||||||
bool HavePendingSends() const { return pendingSends_.load() != 0; }
|
|
||||||
ElementType* GetNextSendMessage()
|
|
||||||
{
|
|
||||||
auto index = (nextSend_++) % QueueSize;
|
|
||||||
return &queue_[index];
|
|
||||||
}
|
|
||||||
void CommitSend() { --pendingSends_; }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace discord_rpc
|
|
||||||
64
3rdparty/discord-rpc/src/rpc_connection.h
vendored
64
3rdparty/discord-rpc/src/rpc_connection.h
vendored
@@ -1,64 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "connection.h"
|
|
||||||
#include "serialization.h"
|
|
||||||
|
|
||||||
namespace discord_rpc {
|
|
||||||
|
|
||||||
// I took this from the buffer size libuv uses for named pipes; I suspect ours would usually be much
|
|
||||||
// smaller.
|
|
||||||
constexpr size_t MaxRpcFrameSize = 64 * 1024;
|
|
||||||
|
|
||||||
struct RpcConnection {
|
|
||||||
enum class ErrorCode : int {
|
|
||||||
Success = 0,
|
|
||||||
PipeClosed = 1,
|
|
||||||
ReadCorrupt = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Opcode : uint32_t {
|
|
||||||
Handshake = 0,
|
|
||||||
Frame = 1,
|
|
||||||
Close = 2,
|
|
||||||
Ping = 3,
|
|
||||||
Pong = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MessageFrameHeader {
|
|
||||||
Opcode opcode;
|
|
||||||
uint32_t length;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MessageFrame : public MessageFrameHeader {
|
|
||||||
char message[MaxRpcFrameSize - sizeof(MessageFrameHeader)];
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class State : uint32_t {
|
|
||||||
Disconnected,
|
|
||||||
SentHandshake,
|
|
||||||
AwaitingResponse,
|
|
||||||
Connected,
|
|
||||||
};
|
|
||||||
|
|
||||||
BaseConnection *connection { nullptr };
|
|
||||||
State state { State::Disconnected };
|
|
||||||
void (*onConnect)(JsonDocument &message) { nullptr };
|
|
||||||
void (*onDisconnect)(int errorCode, const char *message) { nullptr };
|
|
||||||
char appId[64] {};
|
|
||||||
int lastErrorCode { 0 };
|
|
||||||
char lastErrorMessage[256] {};
|
|
||||||
RpcConnection::MessageFrame sendFrame;
|
|
||||||
|
|
||||||
static RpcConnection *Create(const char *applicationId);
|
|
||||||
static void Destroy(RpcConnection *&);
|
|
||||||
|
|
||||||
inline bool IsOpen() const { return state == State::Connected; }
|
|
||||||
|
|
||||||
void Open();
|
|
||||||
void Close();
|
|
||||||
bool Write(const void *data, size_t length);
|
|
||||||
bool Read(JsonDocument &message);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace discord_rpc
|
|
||||||
|
|
||||||
@@ -208,6 +208,15 @@ else()
|
|||||||
pkg_check_modules(TAGLIB REQUIRED IMPORTED_TARGET taglib>=1.12)
|
pkg_check_modules(TAGLIB REQUIRED IMPORTED_TARGET taglib>=1.12)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
find_package(projectM4 COMPONENTS Playlist)
|
||||||
|
if(projectM4_FOUND)
|
||||||
|
set(LIBPROJECTM_FOUND ON)
|
||||||
|
set(HAVE_PROJECTM4 ON)
|
||||||
|
set(LIBPROJECTM_LIBRARIES libprojectM::projectM libprojectM::playlist)
|
||||||
|
else()
|
||||||
|
pkg_check_modules(LIBPROJECTM libprojectM)
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(GTest)
|
find_package(GTest)
|
||||||
|
|
||||||
pkg_check_modules(LIBSPARSEHASH IMPORTED_TARGET libsparsehash)
|
pkg_check_modules(LIBSPARSEHASH IMPORTED_TARGET libsparsehash)
|
||||||
@@ -218,7 +227,7 @@ set(QT_VERSION_MAJOR 6)
|
|||||||
set(QT_MIN_VERSION 6.4.0)
|
set(QT_MIN_VERSION 6.4.0)
|
||||||
set(QT_DEFAULT_MAJOR_VERSION ${QT_VERSION_MAJOR})
|
set(QT_DEFAULT_MAJOR_VERSION ${QT_VERSION_MAJOR})
|
||||||
set(QT_COMPONENTS Core Concurrent Gui Widgets Network Sql)
|
set(QT_COMPONENTS Core Concurrent Gui Widgets Network Sql)
|
||||||
set(QT_OPTIONAL_COMPONENTS GuiPrivate LinguistTools Test)
|
set(QT_OPTIONAL_COMPONENTS GuiPrivate OpenGLWidgets LinguistTools Test)
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
list(APPEND QT_OPTIONAL_COMPONENTS DBus)
|
list(APPEND QT_OPTIONAL_COMPONENTS DBus)
|
||||||
endif()
|
endif()
|
||||||
@@ -259,7 +268,18 @@ if(APPLE)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
find_package(getopt-win REQUIRED)
|
find_package(getopt NAMES getopt getopt-win unofficial-getopt-win32 REQUIRED)
|
||||||
|
if(TARGET getopt::getopt)
|
||||||
|
set(GETOPT_LIBRARIES getopt::getopt)
|
||||||
|
elseif(TARGET getopt-win::getopt)
|
||||||
|
set(GETOPT_LIBRARIES getopt-win::getopt)
|
||||||
|
elseif(TARGET getopt::getopt_shared)
|
||||||
|
set(GETOPT_LIBRARIES getopt::getopt_shared)
|
||||||
|
elseif(TARGET unofficial::getopt-win32::getopt)
|
||||||
|
set(GETOPT_LIBRARIES unofficial::getopt-win32::getopt)
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Missing getopt")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(APPLE OR WIN32)
|
if(APPLE OR WIN32)
|
||||||
@@ -378,6 +398,11 @@ if(HAVE_X11_GLOBALSHORTCUTS OR HAVE_KGLOBALACCEL_GLOBALSHORTCUTS OR APPLE OR WIN
|
|||||||
set(HAVE_GLOBALSHORTCUTS ON)
|
set(HAVE_GLOBALSHORTCUTS ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
optional_component(VISUALIZATIONS ON "Visualizations"
|
||||||
|
DEPENDS "libprojectm" LIBPROJECTM_FOUND
|
||||||
|
DEPENDS "QtOpenGLWidgets" Qt${QT_VERSION_MAJOR}OpenGLWidgets_FOUND
|
||||||
|
)
|
||||||
|
|
||||||
if(NOT CMAKE_CROSSCOMPILING)
|
if(NOT CMAKE_CROSSCOMPILING)
|
||||||
# Check that we have Qt with sqlite driver
|
# Check that we have Qt with sqlite driver
|
||||||
set(CMAKE_REQUIRED_FLAGS "-std=c++17")
|
set(CMAKE_REQUIRED_FLAGS "-std=c++17")
|
||||||
@@ -690,6 +715,7 @@ set(SOURCES
|
|||||||
src/lyrics/elyricsnetlyricsprovider.cpp
|
src/lyrics/elyricsnetlyricsprovider.cpp
|
||||||
src/lyrics/letraslyricsprovider.cpp
|
src/lyrics/letraslyricsprovider.cpp
|
||||||
src/lyrics/lyricfindlyricsprovider.cpp
|
src/lyrics/lyricfindlyricsprovider.cpp
|
||||||
|
src/lyrics/lrcliblyricsprovider.cpp
|
||||||
|
|
||||||
src/settings/settingsdialog.cpp
|
src/settings/settingsdialog.cpp
|
||||||
src/settings/settingspage.cpp
|
src/settings/settingspage.cpp
|
||||||
@@ -783,9 +809,7 @@ set(SOURCES
|
|||||||
src/scrobbler/scrobblercache.cpp
|
src/scrobbler/scrobblercache.cpp
|
||||||
src/scrobbler/scrobblercacheitem.cpp
|
src/scrobbler/scrobblercacheitem.cpp
|
||||||
src/scrobbler/scrobblemetadata.cpp
|
src/scrobbler/scrobblemetadata.cpp
|
||||||
src/scrobbler/scrobblingapi20.cpp
|
|
||||||
src/scrobbler/lastfmscrobbler.cpp
|
src/scrobbler/lastfmscrobbler.cpp
|
||||||
src/scrobbler/librefmscrobbler.cpp
|
|
||||||
src/scrobbler/listenbrainzscrobbler.cpp
|
src/scrobbler/listenbrainzscrobbler.cpp
|
||||||
src/scrobbler/lastfmimport.cpp
|
src/scrobbler/lastfmimport.cpp
|
||||||
|
|
||||||
@@ -988,6 +1012,7 @@ set(HEADERS
|
|||||||
src/lyrics/elyricsnetlyricsprovider.h
|
src/lyrics/elyricsnetlyricsprovider.h
|
||||||
src/lyrics/letraslyricsprovider.h
|
src/lyrics/letraslyricsprovider.h
|
||||||
src/lyrics/lyricfindlyricsprovider.h
|
src/lyrics/lyricfindlyricsprovider.h
|
||||||
|
src/lyrics/lrcliblyricsprovider.h
|
||||||
|
|
||||||
src/settings/settingsdialog.h
|
src/settings/settingsdialog.h
|
||||||
src/settings/settingspage.h
|
src/settings/settingspage.h
|
||||||
@@ -1076,9 +1101,7 @@ set(HEADERS
|
|||||||
src/scrobbler/scrobblersettingsservice.h
|
src/scrobbler/scrobblersettingsservice.h
|
||||||
src/scrobbler/scrobblerservice.h
|
src/scrobbler/scrobblerservice.h
|
||||||
src/scrobbler/scrobblercache.h
|
src/scrobbler/scrobblercache.h
|
||||||
src/scrobbler/scrobblingapi20.h
|
|
||||||
src/scrobbler/lastfmscrobbler.h
|
src/scrobbler/lastfmscrobbler.h
|
||||||
src/scrobbler/librefmscrobbler.h
|
|
||||||
src/scrobbler/listenbrainzscrobbler.h
|
src/scrobbler/listenbrainzscrobbler.h
|
||||||
src/scrobbler/lastfmimport.h
|
src/scrobbler/lastfmimport.h
|
||||||
|
|
||||||
@@ -1454,6 +1477,7 @@ optional_source(HAVE_QOBUZ
|
|||||||
src/qobuz/qobuzrequest.cpp
|
src/qobuz/qobuzrequest.cpp
|
||||||
src/qobuz/qobuzstreamurlrequest.cpp
|
src/qobuz/qobuzstreamurlrequest.cpp
|
||||||
src/qobuz/qobuzfavoriterequest.cpp
|
src/qobuz/qobuzfavoriterequest.cpp
|
||||||
|
src/qobuz/qobuzcredentialfetcher.cpp
|
||||||
src/settings/qobuzsettingspage.cpp
|
src/settings/qobuzsettingspage.cpp
|
||||||
src/covermanager/qobuzcoverprovider.cpp
|
src/covermanager/qobuzcoverprovider.cpp
|
||||||
HEADERS
|
HEADERS
|
||||||
@@ -1463,12 +1487,33 @@ optional_source(HAVE_QOBUZ
|
|||||||
src/qobuz/qobuzrequest.h
|
src/qobuz/qobuzrequest.h
|
||||||
src/qobuz/qobuzstreamurlrequest.h
|
src/qobuz/qobuzstreamurlrequest.h
|
||||||
src/qobuz/qobuzfavoriterequest.h
|
src/qobuz/qobuzfavoriterequest.h
|
||||||
|
src/qobuz/qobuzcredentialfetcher.h
|
||||||
src/settings/qobuzsettingspage.h
|
src/settings/qobuzsettingspage.h
|
||||||
src/covermanager/qobuzcoverprovider.h
|
src/covermanager/qobuzcoverprovider.h
|
||||||
UI
|
UI
|
||||||
src/settings/qobuzsettingspage.ui
|
src/settings/qobuzsettingspage.ui
|
||||||
)
|
)
|
||||||
|
|
||||||
|
optional_source(HAVE_VISUALIZATIONS
|
||||||
|
SOURCES
|
||||||
|
src/visualizations/projectmpresetmodel.cpp
|
||||||
|
src/visualizations/projectmvisualization.cpp
|
||||||
|
src/visualizations/visualizationcontainer.cpp
|
||||||
|
src/visualizations/visualizationoverlay.cpp
|
||||||
|
src/visualizations/visualizationselector.cpp
|
||||||
|
src/visualizations/visualizationopenglwidget.cpp
|
||||||
|
HEADERS
|
||||||
|
src/visualizations/projectmpresetmodel.h
|
||||||
|
src/visualizations/projectmvisualization.h
|
||||||
|
src/visualizations/visualizationcontainer.h
|
||||||
|
src/visualizations/visualizationoverlay.h
|
||||||
|
src/visualizations/visualizationselector.h
|
||||||
|
src/visualizations/visualizationopenglwidget.h
|
||||||
|
UI
|
||||||
|
src/visualizations/visualizationoverlay.ui
|
||||||
|
src/visualizations/visualizationselector.ui
|
||||||
|
)
|
||||||
|
|
||||||
qt_wrap_cpp(SOURCES ${HEADERS})
|
qt_wrap_cpp(SOURCES ${HEADERS})
|
||||||
qt_wrap_ui(SOURCES ${UI})
|
qt_wrap_ui(SOURCES ${UI})
|
||||||
qt_add_resources(SOURCES data/data.qrc data/icons.qrc)
|
qt_add_resources(SOURCES data/data.qrc data/icons.qrc)
|
||||||
@@ -1494,7 +1539,7 @@ endif()
|
|||||||
|
|
||||||
if(HAVE_DISCORD_RPC)
|
if(HAVE_DISCORD_RPC)
|
||||||
add_subdirectory(3rdparty/discord-rpc)
|
add_subdirectory(3rdparty/discord-rpc)
|
||||||
target_include_directories(strawberry_lib PUBLIC 3rdparty/discord-rpc/include)
|
target_include_directories(strawberry_lib PUBLIC 3rdparty/discord-rpc)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_TRANSLATIONS)
|
if(HAVE_TRANSLATIONS)
|
||||||
@@ -1539,6 +1584,7 @@ target_link_libraries(strawberry_lib PUBLIC
|
|||||||
Qt${QT_VERSION_MAJOR}::Sql
|
Qt${QT_VERSION_MAJOR}::Sql
|
||||||
$<$<BOOL:${HAVE_DBUS}>:Qt${QT_VERSION_MAJOR}::DBus>
|
$<$<BOOL:${HAVE_DBUS}>:Qt${QT_VERSION_MAJOR}::DBus>
|
||||||
$<$<BOOL:${HAVE_QPA_QPLATFORMNATIVEINTERFACE}>:Qt${QT_VERSION_MAJOR}::GuiPrivate>
|
$<$<BOOL:${HAVE_QPA_QPLATFORMNATIVEINTERFACE}>:Qt${QT_VERSION_MAJOR}::GuiPrivate>
|
||||||
|
$<$<BOOL:${HAVE_VISUALIZATIONS}>:Qt${QT_VERSION_MAJOR}::OpenGLWidgets>
|
||||||
ICU::uc
|
ICU::uc
|
||||||
ICU::i18n
|
ICU::i18n
|
||||||
$<$<BOOL:${HAVE_STREAMTAGREADER}>:PkgConfig::LIBSPARSEHASH>
|
$<$<BOOL:${HAVE_STREAMTAGREADER}>:PkgConfig::LIBSPARSEHASH>
|
||||||
@@ -1554,9 +1600,11 @@ target_link_libraries(strawberry_lib PUBLIC
|
|||||||
$<$<BOOL:${HAVE_MTP}>:PkgConfig::LIBMTP>
|
$<$<BOOL:${HAVE_MTP}>:PkgConfig::LIBMTP>
|
||||||
$<$<BOOL:${HAVE_GPOD}>:PkgConfig::LIBGPOD PkgConfig::GDK_PIXBUF>
|
$<$<BOOL:${HAVE_GPOD}>:PkgConfig::LIBGPOD PkgConfig::GDK_PIXBUF>
|
||||||
$<$<BOOL:${HAVE_QTSPARKLE}>:qtsparkle-qt${QT_VERSION_MAJOR}::qtsparkle>
|
$<$<BOOL:${HAVE_QTSPARKLE}>:qtsparkle-qt${QT_VERSION_MAJOR}::qtsparkle>
|
||||||
$<$<BOOL:${WIN32}>:dsound dwmapi getopt-win::getopt>
|
$<$<BOOL:${HAVE_VISUALIZATIONS}>:${LIBPROJECTM_LIBRARIES}>
|
||||||
|
$<$<BOOL:${WIN32}>:dsound dwmapi ${GETOPT_LIBRARIES}>
|
||||||
$<$<BOOL:${MSVC}>:WindowsApp>
|
$<$<BOOL:${MSVC}>:WindowsApp>
|
||||||
KDAB::kdsingleapplication
|
KDAB::kdsingleapplication
|
||||||
|
$<$<BOOL:${HAVE_DISCORD_RPC}>:discord-rpc>
|
||||||
)
|
)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
@@ -1575,10 +1623,6 @@ if(APPLE)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_DISCORD_RPC)
|
|
||||||
target_link_libraries(strawberry_lib PRIVATE discord-rpc)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(strawberry PUBLIC strawberry_lib)
|
target_link_libraries(strawberry PUBLIC strawberry_lib)
|
||||||
|
|
||||||
if(NOT APPLE)
|
if(NOT APPLE)
|
||||||
|
|||||||
116
Changelog
116
Changelog
@@ -2,6 +2,122 @@ Strawberry Music Player
|
|||||||
=======================
|
=======================
|
||||||
ChangeLog
|
ChangeLog
|
||||||
|
|
||||||
|
Version 1.2.16 (2025.12.16):
|
||||||
|
|
||||||
|
* Make Discord Rich presence use filename if song title is missing
|
||||||
|
* Added better error message when a GStreamer plugin is missing
|
||||||
|
* Preserve track order in album shuffle mode when restarting playback (#1623)
|
||||||
|
* Possible fixes for context word wrap
|
||||||
|
* Added lyrics from lrclib.net
|
||||||
|
* Added option to turn off the use of sort tags for the collection
|
||||||
|
* Fixed Spotify login
|
||||||
|
* Fixed error dialog shown minimized if another Strawberry window than the mainwindow was active
|
||||||
|
* Fixed seeking to the end of the track and back causing seeking to stop working (#1675)
|
||||||
|
* Set current index when automatically selecting track (#1825)
|
||||||
|
* Make icon size for shuffle and repeat buttons adjust to screen resolution (#1838)
|
||||||
|
* Fixed song being removed from playlist when dragging to another application (#1815)
|
||||||
|
* Don't automatically scroll on dynamic playlists (#1427)
|
||||||
|
|
||||||
|
Version 1.2.15 (2025.11.25):
|
||||||
|
|
||||||
|
* Fixed system default language not respected
|
||||||
|
* Fixed length filter search
|
||||||
|
* Fixed playlist parser converting Spotify URL's
|
||||||
|
* Removed use of deprecated QStyle::State_Editing
|
||||||
|
* Ignore connection closed errors for ListenBrainz
|
||||||
|
* (Windows) Support building with vcpkg unofficial::getopt-win32::getopt
|
||||||
|
|
||||||
|
Version 1.2.14 (2025.10.25):
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed showing error dialog minimized when main window is not current active window (#1739)
|
||||||
|
* Fixed Discord timestamp update when seeking (#1813)
|
||||||
|
* Fixed CD metadata lookup to respect MusicBrainz rate limiting
|
||||||
|
* Fixed Tidal Open API cover provider
|
||||||
|
* (Windows) Fixed device selection with WASAPI2
|
||||||
|
|
||||||
|
Enhancements/Other:
|
||||||
|
* Removed libre.fm support
|
||||||
|
* Rewrote MusicBrainzClient to use Json instead of XML
|
||||||
|
* Subsonic will now use cover art from album when available
|
||||||
|
* Added option to remove "Remastered", etc from song titles for Tidal, Qobuz and Spotify
|
||||||
|
* Added webm to supported file extensions
|
||||||
|
* (Windows|MinGW) Added WASAPI2 support
|
||||||
|
* (Windows) Added experimental exclusive mode for WASAPI2
|
||||||
|
|
||||||
|
Version 1.2.13 (2025.08.31):
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed playlist alternating row colors no longer working with some styles (#1806)
|
||||||
|
* Fixed "Open Audio CD" no longer working (#1803)
|
||||||
|
* Fixed systemtray icon playback status not working with scaling (#1782)
|
||||||
|
* Fixed build without MusicBrainz (#1799)
|
||||||
|
* Fixed build without MTP (#1804)
|
||||||
|
|
||||||
|
Enhancements:
|
||||||
|
* Added Discord status text option (#1796)
|
||||||
|
* Read Vorbis/FLAC "Other" embedded covers if front cover is not available (#1793)
|
||||||
|
|
||||||
|
Version 1.2.12 (2025.08.12):
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed scrobbling for radio streams.
|
||||||
|
* Fixed CDDA memory leaks.
|
||||||
|
* Fixed device view CDDA loading (#1676).
|
||||||
|
* Fixed collection directory editing (#1767).
|
||||||
|
* Fixed devices sometimes being duplicated in the database.
|
||||||
|
* Fixed alternating playlist row colors with Windows 11 style.
|
||||||
|
* Fixed broken file filter for GME formats.
|
||||||
|
* Fixed collection scanning for GME formats.
|
||||||
|
* Fixed Chartlyrics.
|
||||||
|
* Fixed network cache file descriptor leak on lyrics search with workaround for QTBUG-135641.
|
||||||
|
* Fixed parsing Tidal urls with certain stream URL replies.
|
||||||
|
* Fixed pixelated window icon on Wayland (#1753).
|
||||||
|
* Fixed saving collection grouping with special characters in the name (#1758).
|
||||||
|
* Fixed Spotify token not automatically updated on renewal when playing (#1769).
|
||||||
|
* (macOS/Windows) Fixed network cache file descriptor leak with patch for QTBUG-135641.
|
||||||
|
* (Windows|MSVC) Fixed installer to not restart the computer after installing Visual C++ Redistributable.
|
||||||
|
|
||||||
|
Enhancements:
|
||||||
|
* Implemented edit tag dialog reset for year, track, disc and rating.
|
||||||
|
* Added ALAC to supported filetypes for iPods.
|
||||||
|
* Added CD-TEXT support.
|
||||||
|
* Added back Genius lyrics.
|
||||||
|
* Added support for reporting more info to ListenBrainz.
|
||||||
|
* Added support for BPM, mood and initial key tags.
|
||||||
|
* Added support for sort tags to collection, playlists and smart playlists.
|
||||||
|
|
||||||
|
Version 1.2.11 (2025.05.15):
|
||||||
|
|
||||||
|
* Fixed playlist songs sometimes not updated with new cover.
|
||||||
|
* Fixed context album cover showing even when it's disabled in the setting (#1744).
|
||||||
|
* Fixed crash when dragging songs to a closed playlist (#1741).
|
||||||
|
* Enable startup notify in desktop file.
|
||||||
|
* (Windows|MSVC) Add experimental support for native ARM64 builds.
|
||||||
|
* (Windows|MinGW) Fixed crash on exit.
|
||||||
|
|
||||||
|
Version 1.2.10 (2025.04.18):
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed Discord rich presence showing bogus artist and album.
|
||||||
|
* Fixed incorrect ID3v2 comment tag.
|
||||||
|
* (macOS|Windows MSVC) Fixed stuck playback of some streams.
|
||||||
|
|
||||||
|
Enhancements:
|
||||||
|
* Removed Genius lyrics (longer working properly because of website changes).
|
||||||
|
* (macOS|Windows MSVC) Added back Spotify
|
||||||
|
|
||||||
|
Version 1.2.9 (2025.04.08):
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed subsonic parse error (#1719).
|
||||||
|
* Fixed Deezer cover provider parse error (#1716).
|
||||||
|
* Fixed last.fm import progress.
|
||||||
|
* (Windows|MinGW) Switched from winpthreads to win32 threads, winpthreads are no longer working with Qt as of version 6.9 (QTBUG-131892).
|
||||||
|
|
||||||
|
Enhancements:
|
||||||
|
* Added option to disable playbin3.
|
||||||
|
|
||||||
Version 1.2.8 (2025.04.05):
|
Version 1.2.8 (2025.04.05):
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
|||||||
171
README.md
171
README.md
@@ -1,118 +1,137 @@
|
|||||||
:strawberry: Strawberry Music Player [](https://github.com/strawberrymusicplayer/strawberry/actions)
|
# :strawberry: Strawberry Music Player [](https://github.com/strawberrymusicplayer/strawberry/actions)
|
||||||
=======================
|
|
||||||
[](https://github.com/sponsors/jonaski)
|
[](https://github.com/sponsors/jonaski)
|
||||||
[](https://patreon.com/jonaskvinge)
|
[](https://patreon.com/jonaskvinge)
|
||||||
[](https://paypal.me/jonaskvinge)
|
[](https://paypal.me/jonaskvinge)
|
||||||
|
|
||||||
Strawberry is a music player and music collection organizer. It is a fork of Clementine released in 2018 aimed at music collectors and audiophiles. It's written in C++ using the Qt framework.
|
Strawberry is a **music player and music collection organizer**, originally forked from *Clementine* in 2018.
|
||||||
|
It’s written in **C++ using the Qt framework**, designed for **audiophiles and music collectors**.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Resources:
|
---
|
||||||
|
|
||||||
* Website: https://www.strawberrymusicplayer.org/
|
## :globe_with_meridians: Resources
|
||||||
* Wiki: https://wiki.strawberrymusicplayer.org/
|
|
||||||
* Forum: https://forum.strawberrymusicplayer.org/
|
|
||||||
* Github: https://github.com/strawberrymusicplayer/strawberry
|
|
||||||
* Latest builds: https://builds.strawberrymusicplayer.org/
|
|
||||||
* openSUSE buildservice: https://build.opensuse.org/package/show/home:jonaski:audio/strawberry
|
|
||||||
* Ubuntu PPA: https://launchpad.net/~jonaski/+archive/ubuntu/strawberry
|
|
||||||
* Ubuntu Unstable PPA: https://launchpad.net/~jonaski/+archive/ubuntu/strawberry-unstable
|
|
||||||
* Translations: https://crowdin.com/project/strawberrymusicplayer/
|
|
||||||
|
|
||||||
### :bangbang: Opening an issue
|
- **Website:** https://www.strawberrymusicplayer.org
|
||||||
|
- **Wiki:** https://wiki.strawberrymusicplayer.org
|
||||||
|
- **Forum:** https://forum.strawberrymusicplayer.org
|
||||||
|
- **GitHub:** https://github.com/strawberrymusicplayer/strawberry
|
||||||
|
- **Latest builds:** https://builds.strawberrymusicplayer.org
|
||||||
|
- **openSUSE Build Service:**
|
||||||
|
- Stable: https://build.opensuse.org/package/show/home:jonaski:strawberry/strawberry
|
||||||
|
- Unstable: https://build.opensuse.org/package/show/home:jonaski:strawberry-dev/strawberry
|
||||||
|
- **Ubuntu PPAs:**
|
||||||
|
- Stable: https://launchpad.net/~jonaski/+archive/ubuntu/strawberry
|
||||||
|
- Unstable: https://launchpad.net/~jonaski/+archive/ubuntu/strawberry-unstable
|
||||||
|
- **Translations:** https://crowdin.com/project/strawberrymusicplayer
|
||||||
|
|
||||||
* Read the FAQ: https://wiki.strawberrymusicplayer.org/wiki/FAQ
|
---
|
||||||
* Search for the issue to see if it is already solved, or if there is an open issue for it already. If there is an open issue already, you can comment on it if you have additional information that could be useful to us.
|
|
||||||
* For technical problems, discussion, questions and feature suggestions use the forum (https://forum.strawberrymusicplayer.org/) instead. The forum is better suited for discussion.
|
|
||||||
* We do not take feature requests from users on GitHub. Any issues related to feature requests will be closed. This does not necessarily mean that we won't add new features, but we don't have time to take feature requests or answer questions about new features from users. It is still possible to suggest or discuss new features on the forum (https://forum.strawberrymusicplayer.org/).
|
|
||||||
* We do not maintain the Flatpak package. Do not report issues related to Flatpak unless the issue can be reproduced with a native package, use Flatpak support instead https://flatpak.org/about/
|
|
||||||
|
|
||||||
### :moneybag: Sponsoring
|
## :warning: Opening an Issue
|
||||||
|
|
||||||
The program is free software, released under GPL. If you like this program and can make use of it, consider sponsoring or donating to help fund the project.
|
Before creating a new GitHub issue:
|
||||||
There are currently 4 options for sponsoring:
|
|
||||||
|
|
||||||
|
1. **Read the [FAQ](https://wiki.strawberrymusicplayer.org/wiki/FAQ)**.
|
||||||
|
2. **Search existing issues** to avoid duplicates. If one already exists, comment there with any additional information.
|
||||||
|
3. **Use the [forum](https://forum.strawberrymusicplayer.org/)** for technical problems, discussions or feature suggestions — it’s better suited for back-and-forth conversation.
|
||||||
|
4. **Feature requests are not accepted on GitHub.** Issues created for feature requests will be closed. You can still discuss ideas on the forum.
|
||||||
|
5. **Flatpak users:** We do **not** maintain the Flatpak package. Report Flatpak-specific issues via [Flatpak support](https://flatpak.org/about/).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## :moneybag: Sponsoring
|
||||||
|
|
||||||
|
Strawberry is **free software released under the GPL**.
|
||||||
|
If you enjoy using it, please consider **supporting development** through sponsorship or donation.
|
||||||
|
|
||||||
|
**Sponsorship options:**
|
||||||
1. [Patreon](https://www.patreon.com/jonaskvinge)
|
1. [Patreon](https://www.patreon.com/jonaskvinge)
|
||||||
2. [GitHub](https://github.com/sponsors/jonaski)
|
2. [GitHub](https://github.com/sponsors/jonaski)
|
||||||
3. [Ko-fi](https://ko-fi.com/jonaskvinge)
|
3. [Ko-fi](https://ko-fi.com/jonaskvinge)
|
||||||
4. [PayPal](https://paypal.me/jonaskvinge)
|
4. [PayPal](https://paypal.me/jonaskvinge)
|
||||||
|
|
||||||
Funding developers is a way to contribute to open source projects you appreciate, it helps developers get the resources they need, and recognize contributors working behind the scenes to make open source better for everyone.
|
Supporting open-source developers helps ensure continued maintenance and improvements.
|
||||||
|
|
||||||
### :heavy_check_mark: Features
|
---
|
||||||
|
|
||||||
* Play and organize music
|
## :white_check_mark: Features
|
||||||
* Supports WAV, FLAC, WavPack, Ogg FLAC, Ogg Vorbis, Ogg Opus, Ogg Speex, MPC, TrueAudio, AIFF, MP4, MP3, ASF and Monkey's Audio.
|
|
||||||
* Audio CD playback
|
|
||||||
* Native desktop notifications
|
|
||||||
* Playlist management
|
|
||||||
* Smart and dynamic playlists
|
|
||||||
* Advanced audio output and device configuration for bit-perfect playback on Linux
|
|
||||||
* In-player song loudness analysis and song playback loudness normalization, as per EBU R 128
|
|
||||||
* Edit tags on audio files
|
|
||||||
* Fetch tags from MusicBrainz
|
|
||||||
* Album cover art from [Last.fm](https://www.last.fm/), [Musicbrainz](https://musicbrainz.org/), [Discogs](https://www.discogs.com/), [Musixmatch](https://www.musixmatch.com/), [Deezer](https://www.deezer.com/), [Tidal](https://www.tidal.com/), [Qobuz](https://www.qobuz.com/) and [Spotify](https://www.spotify.com/)
|
|
||||||
* Song lyrics from [Genius](https://genius.com/), [Musixmatch](https://www.musixmatch.com/), [ChartLyrics](http://www.chartlyrics.com/), [lyrics.ovh](https://lyrics.ovh/), [lololyrics.com](https://www.lololyrics.com/), [songlyrics.com](https://www.songlyrics.com/), [azlyrics.com](https://www.azlyrics.com/) and [elyrics.net](https://www.elyrics.net/)
|
|
||||||
* Support for multiple backends
|
|
||||||
* Audio analyzer
|
|
||||||
* Audio equalizer
|
|
||||||
* Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
|
|
||||||
* Scrobbler with support for [Last.fm](https://www.last.fm/), [Libre.fm](https://libre.fm/) and [ListenBrainz](https://listenbrainz.org/)
|
|
||||||
* Streaming from Subsonic compatible servers
|
|
||||||
* Unofficial Tidal, Spotify and Qobuz integration
|
|
||||||
* Discord rich presence
|
|
||||||
|
|
||||||
|
- Play and organize your music collection
|
||||||
|
- Supports formats: WAV, FLAC, WavPack, Ogg Vorbis, Opus, MPC, TrueAudio, AIFF, MP4, MP3, ASF, and Monkey’s Audio
|
||||||
|
- Audio CD playback
|
||||||
|
- Bit-perfect playback on Linux
|
||||||
|
- Native desktop notifications
|
||||||
|
- Advanced playlist management
|
||||||
|
- Smart and dynamic playlists
|
||||||
|
- Loudness analysis and EBU R128 normalization
|
||||||
|
- Editing tags and fetching missing tags via [MusicBrainz](https://musicbrainz.org/)
|
||||||
|
- Album art from: [Last.fm](https://www.last.fm/), [MusicBrainz](https://musicbrainz.org/), [Discogs](https://www.discogs.com/), [Musixmatch](https://www.musixmatch.com/), [Deezer](https://www.deezer.com/), [Tidal](https://www.tidal.com/), [Qobuz](https://www.qobuz.com/), [Spotify](https://www.spotify.com/)
|
||||||
|
- Lyrics from: [Genius](https://genius.com/), [Musixmatch](https://www.musixmatch.com/), [ChartLyrics](http://www.chartlyrics.com/), [lyrics.ovh](https://lyrics.ovh/), [lololyrics](https://www.lololyrics.com/), [songlyrics](https://www.songlyrics.com/), [azlyrics](https://www.azlyrics.com/), [elyrics](https://www.elyrics.net/), [letras](https://www.letras.mus.br), [LyricFind](https://lyrics.lyricfind.com) and [lrclib.net](https://lrclib.net/)
|
||||||
|
- Audio analyzer and equalizer
|
||||||
|
- Transfer music to USB, MTP and iPod devices
|
||||||
|
- Scrobbling to [Last.fm](https://www.last.fm/) and [ListenBrainz](https://listenbrainz.org/)
|
||||||
|
- Streaming from Subsonic-compatible servers
|
||||||
|
- Unofficial integrations: Tidal, Spotify, and Qobuz
|
||||||
|
- Discord Rich Presence
|
||||||
|
|
||||||
It has so far been tested to work on Linux, OpenBSD, FreeBSD, macOS and Windows.
|
---
|
||||||
|
|
||||||
**Access to macOS and Windows releases are currently restricted to sponsors, a 5 USD monthly sponsorship is required. You can sponsor strawberry through <a href="https://www.patreon.com/jonaskvinge">Patreon</a> for direct access to new releases. If you are sponsoring through GitHub, Ko-fi or PayPal, please e-mail support AT strawberrymusicplayer.org for access to downloads.**
|
:white_check_mark: Tested on **Linux**, **OpenBSD**, **FreeBSD**, **macOS**, and **Windows**.
|
||||||
|
|
||||||
### :heavy_exclamation_mark: Requirements
|
> **Note:** macOS and Windows releases are currently **available to sponsors only**.
|
||||||
|
> A monthly sponsorship via [Patreon](https://www.patreon.com/jonaskvinge) grants direct access to new releases.
|
||||||
|
|
||||||
To build Strawberry from source you need the following installed on your system with the additional development packages/headers:
|
---
|
||||||
|
|
||||||
* [CMake 3.13 or higher](https://cmake.org/)
|
## :gear: Requirements
|
||||||
* C/C++ compiler ([GCC](https://gcc.gnu.org/), [Clang](https://clang.llvm.org/) or [MSVC](https://visualstudio.microsoft.com/vs/features/cplusplus/))
|
|
||||||
* [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) or [pkgconf](https://github.com/pkgconf/pkgconf)
|
|
||||||
* [Boost](https://www.boost.org/)
|
|
||||||
* [GLib](https://developer.gnome.org/glib/)
|
|
||||||
* [Qt 6.4.0 or higher with components Core, Concurrent, Gui, Widgets, Network, Sql and D-Bus](https://www.qt.io/)
|
|
||||||
* [SQLite 3.9 or newer](https://www.sqlite.org)
|
|
||||||
* [ALSA (Required on Linux)](https://www.alsa-project.org/)
|
|
||||||
* [GStreamer](https://gstreamer.freedesktop.org/)
|
|
||||||
* [TagLib 1.12 or higher](https://www.taglib.org/)
|
|
||||||
* [ICU](https://unicode-org.github.io/icu/)
|
|
||||||
* [KDSingleApplication 1.1.0 or higher](https://github.com/KDAB/KDSingleApplication)
|
|
||||||
|
|
||||||
Optional dependencies:
|
To build Strawberry from source, you’ll need:
|
||||||
|
|
||||||
* Song fingerprinting and MusicBrainz tagging: [Chromaprint](https://acoustid.org/chromaprint)
|
**Dependencies:**
|
||||||
* Moodbar: [fftw3](http://www.fftw.org/)
|
- [CMake ≥= 3.13](https://cmake.org/)
|
||||||
* PulseAudio integration: [PulseAudio](https://www.freedesktop.org/wiki/Software/PulseAudio/?)
|
- C/C++ compiler ([GCC](https://gcc.gnu.org/), [Clang](https://clang.llvm.org/), or [MSVC](https://visualstudio.microsoft.com/vs/features/cplusplus/))
|
||||||
* Audio CD: [libcdio](https://www.gnu.org/software/libcdio/)
|
- [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) or [pkgconf](https://github.com/pkgconf/pkgconf)
|
||||||
* MTP devices: [libmtp](http://libmtp.sourceforge.net/)
|
- [Boost](https://www.boost.org/)
|
||||||
* iPod Classic devices: [libgpod](http://www.gtkpod.org/libgpod/)
|
- [GLib](https://developer.gnome.org/glib/)
|
||||||
* EBU R 128 loudness normalization [libebur128](https://github.com/jiixyj/libebur128)
|
- [Qt ≥= 6.4](https://www.qt.io/) (Core, Concurrent, Gui, Widgets, Network, SQL, D-Bus)
|
||||||
* Discord rich presence [RapidJSON](https://rapidjson.org/)
|
- [SQLite ≥= 3.9](https://www.sqlite.org)
|
||||||
|
- [ALSA (Linux only)](https://www.alsa-project.org/)
|
||||||
|
- [GStreamer](https://gstreamer.freedesktop.org/)
|
||||||
|
- [TagLib ≥= 1.12](https://www.taglib.org/)
|
||||||
|
- [ICU](https://unicode-org.github.io/icu/)
|
||||||
|
- [KDSingleApplication ≥= 1.1.0](https://github.com/KDAB/KDSingleApplication)
|
||||||
|
|
||||||
You should also install the gstreamer plugins base and good, and optionally bad, ugly and libav to support all audio formats.
|
**Dependencies for optional features:**
|
||||||
|
- Fingerprinting & tagging: [Chromaprint](https://acoustid.org/chromaprint)
|
||||||
|
- Moodbar: [FFTW3](http://www.fftw.org/)
|
||||||
|
- PulseAudio integration: [PulseAudio](https://www.freedesktop.org/wiki/Software/PulseAudio/)
|
||||||
|
- Audio CD support: [libcdio](https://www.gnu.org/software/libcdio/)
|
||||||
|
- MTP devices: [libmtp](http://libmtp.sourceforge.net/)
|
||||||
|
- iPod Classic: [libgpod](http://www.gtkpod.org/libgpod/)
|
||||||
|
- EBU R128 normalization: [libebur128](https://github.com/jiixyj/libebur128)
|
||||||
|
- Discord presence: [RapidJSON](https://rapidjson.org/)
|
||||||
|
|
||||||
### :wrench: Build from source
|
Also install GStreamer plugins **base**, **good**, and optionally **bad**, **ugly** and **libav** for full codec support.
|
||||||
|
|
||||||
### Get the code:
|
---
|
||||||
|
|
||||||
|
## :wrench: Build from Source
|
||||||
|
|
||||||
|
**Get the code:**
|
||||||
|
|
||||||
git clone --recursive https://github.com/strawberrymusicplayer/strawberry
|
git clone --recursive https://github.com/strawberrymusicplayer/strawberry
|
||||||
|
|
||||||
### Build and install:
|
**Build and install:**
|
||||||
|
|
||||||
cd strawberry
|
cd strawberry
|
||||||
cmake -S . -B build
|
cmake -S . -B build
|
||||||
cmake --build build --parallel $(nproc)
|
cmake --build build --parallel $(nproc)
|
||||||
sudo cmake --install build
|
sudo cmake --install build
|
||||||
|
|
||||||
To build on Windows with Visual Studio 2022, see https://github.com/strawberrymusicplayer/strawberry-msvc
|
For building on Windows with Visual Studio 2022, see: :point_right: https://github.com/strawberrymusicplayer/strawberry-msvc
|
||||||
|
|
||||||
### :penguin: Packaging status
|
---
|
||||||
|
|
||||||
|
## :package: Packaging status
|
||||||
|
|
||||||
[](https://repology.org/metapackage/strawberry/versions)
|
[](https://repology.org/metapackage/strawberry/versions)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
set(STRAWBERRY_VERSION_MAJOR 1)
|
set(STRAWBERRY_VERSION_MAJOR 1)
|
||||||
set(STRAWBERRY_VERSION_MINOR 2)
|
set(STRAWBERRY_VERSION_MINOR 2)
|
||||||
set(STRAWBERRY_VERSION_PATCH 8)
|
set(STRAWBERRY_VERSION_PATCH 16)
|
||||||
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
||||||
|
|
||||||
set(INCLUDE_GIT_REVISION OFF)
|
set(INCLUDE_GIT_REVISION ON)
|
||||||
|
|
||||||
set(majorminorpatch "${STRAWBERRY_VERSION_MAJOR}.${STRAWBERRY_VERSION_MINOR}.${STRAWBERRY_VERSION_PATCH}")
|
set(majorminorpatch "${STRAWBERRY_VERSION_MAJOR}.${STRAWBERRY_VERSION_MINOR}.${STRAWBERRY_VERSION_PATCH}")
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
<file>schema/schema-18.sql</file>
|
<file>schema/schema-18.sql</file>
|
||||||
<file>schema/schema-19.sql</file>
|
<file>schema/schema-19.sql</file>
|
||||||
<file>schema/schema-20.sql</file>
|
<file>schema/schema-20.sql</file>
|
||||||
|
<file>schema/schema-21.sql</file>
|
||||||
<file>schema/device-schema.sql</file>
|
<file>schema/device-schema.sql</file>
|
||||||
<file>style/strawberry.css</file>
|
<file>style/strawberry.css</file>
|
||||||
<file>style/smartplaylistsearchterm.css</file>
|
<file>style/smartplaylistsearchterm.css</file>
|
||||||
|
|||||||
@@ -12,9 +12,13 @@ CREATE TABLE device_%deviceid_subdirectories (
|
|||||||
CREATE TABLE device_%deviceid_songs (
|
CREATE TABLE device_%deviceid_songs (
|
||||||
|
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
titlesort TEXT,
|
||||||
album TEXT,
|
album TEXT,
|
||||||
|
albumsort TEXT,
|
||||||
artist TEXT,
|
artist TEXT,
|
||||||
|
artistsort TEXT,
|
||||||
albumartist TEXT,
|
albumartist TEXT,
|
||||||
|
albumartistsort TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
@@ -22,7 +26,9 @@ CREATE TABLE device_%deviceid_songs (
|
|||||||
genre TEXT,
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT,
|
composer TEXT,
|
||||||
|
composersort TEXT,
|
||||||
performer TEXT,
|
performer TEXT,
|
||||||
|
performersort TEXT,
|
||||||
grouping TEXT,
|
grouping TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
lyrics TEXT,
|
lyrics TEXT,
|
||||||
@@ -86,7 +92,11 @@ CREATE TABLE device_%deviceid_songs (
|
|||||||
musicbrainz_work_id TEXT,
|
musicbrainz_work_id TEXT,
|
||||||
|
|
||||||
ebur128_integrated_loudness_lufs REAL,
|
ebur128_integrated_loudness_lufs REAL,
|
||||||
ebur128_loudness_range_lu REAL
|
ebur128_loudness_range_lu REAL,
|
||||||
|
|
||||||
|
bpm REAL,
|
||||||
|
mood TEXT,
|
||||||
|
initial_key TEXT
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -94,4 +104,4 @@ CREATE INDEX idx_device_%deviceid_songs_album ON device_%deviceid_songs (album);
|
|||||||
|
|
||||||
CREATE INDEX idx_device_%deviceid_songs_comp_artist ON device_%deviceid_songs (compilation_effective, artist);
|
CREATE INDEX idx_device_%deviceid_songs_comp_artist ON device_%deviceid_songs (compilation_effective, artist);
|
||||||
|
|
||||||
UPDATE devices SET schema_version=5 WHERE ROWID=%deviceid;
|
UPDATE devices SET schema_version=6 WHERE ROWID=%deviceid;
|
||||||
|
|||||||
43
data/schema/schema-21.sql
Normal file
43
data/schema/schema-21.sql
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
DROP INDEX IF EXISTS idx_albumartistsort;
|
||||||
|
|
||||||
|
DROP INDEX IF EXISTS idx_albumsort;
|
||||||
|
|
||||||
|
DROP INDEX IF EXISTS idx_artistsort;
|
||||||
|
|
||||||
|
DROP INDEX IF EXISTS idx_composersort;
|
||||||
|
|
||||||
|
DROP INDEX IF EXISTS idx_performersort;
|
||||||
|
|
||||||
|
DROP INDEX IF EXISTS idx_titlesort;
|
||||||
|
|
||||||
|
ALTER TABLE %allsongstables ADD COLUMN albumartistsort TEXT;
|
||||||
|
|
||||||
|
ALTER TABLE %allsongstables ADD COLUMN albumsort TEXT;
|
||||||
|
|
||||||
|
ALTER TABLE %allsongstables ADD COLUMN artistsort TEXT;
|
||||||
|
|
||||||
|
ALTER TABLE %allsongstables ADD COLUMN composersort TEXT;
|
||||||
|
|
||||||
|
ALTER TABLE %allsongstables ADD COLUMN performersort TEXT;
|
||||||
|
|
||||||
|
ALTER TABLE %allsongstables ADD COLUMN titlesort TEXT;
|
||||||
|
|
||||||
|
ALTER TABLE %allsongstables ADD COLUMN bpm REAL;
|
||||||
|
|
||||||
|
ALTER TABLE %allsongstables ADD COLUMN mood TEXT;
|
||||||
|
|
||||||
|
ALTER TABLE %allsongstables ADD COLUMN initial_key TEXT;
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_albumartistsort ON songs (albumartistsort);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_albumsort ON songs (album);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_artistsort ON songs (artistsort);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_composersort ON songs (title);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_performersort ON songs (title);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_titlesort ON songs (title);
|
||||||
|
|
||||||
|
UPDATE schema_version SET version=21;
|
||||||
@@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS schema_version (
|
|||||||
|
|
||||||
DELETE FROM schema_version;
|
DELETE FROM schema_version;
|
||||||
|
|
||||||
INSERT INTO schema_version (version) VALUES (20);
|
INSERT INTO schema_version (version) VALUES (21);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS directories (
|
CREATE TABLE IF NOT EXISTS directories (
|
||||||
path TEXT NOT NULL,
|
path TEXT NOT NULL,
|
||||||
@@ -20,9 +20,13 @@ CREATE TABLE IF NOT EXISTS subdirectories (
|
|||||||
CREATE TABLE IF NOT EXISTS songs (
|
CREATE TABLE IF NOT EXISTS songs (
|
||||||
|
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
titlesort TEXT,
|
||||||
album TEXT,
|
album TEXT,
|
||||||
|
albumsort TEXT,
|
||||||
artist TEXT,
|
artist TEXT,
|
||||||
|
artistsort TEXT,
|
||||||
albumartist TEXT,
|
albumartist TEXT,
|
||||||
|
albumartistsort TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
@@ -30,7 +34,9 @@ CREATE TABLE IF NOT EXISTS songs (
|
|||||||
genre TEXT,
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT,
|
composer TEXT,
|
||||||
|
composersort TEXT,
|
||||||
performer TEXT,
|
performer TEXT,
|
||||||
|
performersort TEXT,
|
||||||
grouping TEXT,
|
grouping TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
lyrics TEXT,
|
lyrics TEXT,
|
||||||
@@ -94,16 +100,24 @@ CREATE TABLE IF NOT EXISTS songs (
|
|||||||
musicbrainz_work_id TEXT,
|
musicbrainz_work_id TEXT,
|
||||||
|
|
||||||
ebur128_integrated_loudness_lufs REAL,
|
ebur128_integrated_loudness_lufs REAL,
|
||||||
ebur128_loudness_range_lu REAL
|
ebur128_loudness_range_lu REAL,
|
||||||
|
|
||||||
|
bpm REAL,
|
||||||
|
mood TEXT,
|
||||||
|
initial_key TEXT
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS subsonic_songs (
|
CREATE TABLE IF NOT EXISTS subsonic_songs (
|
||||||
|
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
titlesort TEXT,
|
||||||
album TEXT,
|
album TEXT,
|
||||||
|
albumsort TEXT,
|
||||||
artist TEXT,
|
artist TEXT,
|
||||||
|
artistsort TEXT,
|
||||||
albumartist TEXT,
|
albumartist TEXT,
|
||||||
|
albumartistsort TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
@@ -111,7 +125,9 @@ CREATE TABLE IF NOT EXISTS subsonic_songs (
|
|||||||
genre TEXT,
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT,
|
composer TEXT,
|
||||||
|
composersort TEXT,
|
||||||
performer TEXT,
|
performer TEXT,
|
||||||
|
performersort TEXT,
|
||||||
grouping TEXT,
|
grouping TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
lyrics TEXT,
|
lyrics TEXT,
|
||||||
@@ -175,16 +191,24 @@ CREATE TABLE IF NOT EXISTS subsonic_songs (
|
|||||||
musicbrainz_work_id TEXT,
|
musicbrainz_work_id TEXT,
|
||||||
|
|
||||||
ebur128_integrated_loudness_lufs REAL,
|
ebur128_integrated_loudness_lufs REAL,
|
||||||
ebur128_loudness_range_lu REAL
|
ebur128_loudness_range_lu REAL,
|
||||||
|
|
||||||
|
bpm REAL,
|
||||||
|
mood TEXT,
|
||||||
|
initial_key TEXT
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS tidal_artists_songs (
|
CREATE TABLE IF NOT EXISTS tidal_artists_songs (
|
||||||
|
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
titlesort TEXT,
|
||||||
album TEXT,
|
album TEXT,
|
||||||
|
albumsort TEXT,
|
||||||
artist TEXT,
|
artist TEXT,
|
||||||
|
artistsort TEXT,
|
||||||
albumartist TEXT,
|
albumartist TEXT,
|
||||||
|
albumartistsort TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
@@ -192,7 +216,9 @@ CREATE TABLE IF NOT EXISTS tidal_artists_songs (
|
|||||||
genre TEXT,
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT,
|
composer TEXT,
|
||||||
|
composersort TEXT,
|
||||||
performer TEXT,
|
performer TEXT,
|
||||||
|
performersort TEXT,
|
||||||
grouping TEXT,
|
grouping TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
lyrics TEXT,
|
lyrics TEXT,
|
||||||
@@ -256,16 +282,24 @@ CREATE TABLE IF NOT EXISTS tidal_artists_songs (
|
|||||||
musicbrainz_work_id TEXT,
|
musicbrainz_work_id TEXT,
|
||||||
|
|
||||||
ebur128_integrated_loudness_lufs REAL,
|
ebur128_integrated_loudness_lufs REAL,
|
||||||
ebur128_loudness_range_lu REAL
|
ebur128_loudness_range_lu REAL,
|
||||||
|
|
||||||
|
bpm REAL,
|
||||||
|
mood TEXT,
|
||||||
|
initial_key TEXT
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS tidal_albums_songs (
|
CREATE TABLE IF NOT EXISTS tidal_albums_songs (
|
||||||
|
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
titlesort TEXT,
|
||||||
album TEXT,
|
album TEXT,
|
||||||
|
albumsort TEXT,
|
||||||
artist TEXT,
|
artist TEXT,
|
||||||
|
artistsort TEXT,
|
||||||
albumartist TEXT,
|
albumartist TEXT,
|
||||||
|
albumartistsort TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
@@ -273,7 +307,9 @@ CREATE TABLE IF NOT EXISTS tidal_albums_songs (
|
|||||||
genre TEXT,
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT,
|
composer TEXT,
|
||||||
|
composersort TEXT,
|
||||||
performer TEXT,
|
performer TEXT,
|
||||||
|
performersort TEXT,
|
||||||
grouping TEXT,
|
grouping TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
lyrics TEXT,
|
lyrics TEXT,
|
||||||
@@ -337,16 +373,24 @@ CREATE TABLE IF NOT EXISTS tidal_albums_songs (
|
|||||||
musicbrainz_work_id TEXT,
|
musicbrainz_work_id TEXT,
|
||||||
|
|
||||||
ebur128_integrated_loudness_lufs REAL,
|
ebur128_integrated_loudness_lufs REAL,
|
||||||
ebur128_loudness_range_lu REAL
|
ebur128_loudness_range_lu REAL,
|
||||||
|
|
||||||
|
bpm REAL,
|
||||||
|
mood TEXT,
|
||||||
|
initial_key TEXT
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS tidal_songs (
|
CREATE TABLE IF NOT EXISTS tidal_songs (
|
||||||
|
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
titlesort TEXT,
|
||||||
album TEXT,
|
album TEXT,
|
||||||
|
albumsort TEXT,
|
||||||
artist TEXT,
|
artist TEXT,
|
||||||
|
artistsort TEXT,
|
||||||
albumartist TEXT,
|
albumartist TEXT,
|
||||||
|
albumartistsort TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
@@ -354,7 +398,9 @@ CREATE TABLE IF NOT EXISTS tidal_songs (
|
|||||||
genre TEXT,
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT,
|
composer TEXT,
|
||||||
|
composersort TEXT,
|
||||||
performer TEXT,
|
performer TEXT,
|
||||||
|
performersort TEXT,
|
||||||
grouping TEXT,
|
grouping TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
lyrics TEXT,
|
lyrics TEXT,
|
||||||
@@ -418,16 +464,24 @@ CREATE TABLE IF NOT EXISTS tidal_songs (
|
|||||||
musicbrainz_work_id TEXT,
|
musicbrainz_work_id TEXT,
|
||||||
|
|
||||||
ebur128_integrated_loudness_lufs REAL,
|
ebur128_integrated_loudness_lufs REAL,
|
||||||
ebur128_loudness_range_lu REAL
|
ebur128_loudness_range_lu REAL,
|
||||||
|
|
||||||
|
bpm REAL,
|
||||||
|
mood TEXT,
|
||||||
|
initial_key TEXT
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS spotify_artists_songs (
|
CREATE TABLE IF NOT EXISTS spotify_artists_songs (
|
||||||
|
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
titlesort TEXT,
|
||||||
album TEXT,
|
album TEXT,
|
||||||
|
albumsort TEXT,
|
||||||
artist TEXT,
|
artist TEXT,
|
||||||
|
artistsort TEXT,
|
||||||
albumartist TEXT,
|
albumartist TEXT,
|
||||||
|
albumartistsort TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
@@ -435,7 +489,9 @@ CREATE TABLE IF NOT EXISTS spotify_artists_songs (
|
|||||||
genre TEXT,
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT,
|
composer TEXT,
|
||||||
|
composersort TEXT,
|
||||||
performer TEXT,
|
performer TEXT,
|
||||||
|
performersort TEXT,
|
||||||
grouping TEXT,
|
grouping TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
lyrics TEXT,
|
lyrics TEXT,
|
||||||
@@ -499,16 +555,24 @@ CREATE TABLE IF NOT EXISTS spotify_artists_songs (
|
|||||||
musicbrainz_work_id TEXT,
|
musicbrainz_work_id TEXT,
|
||||||
|
|
||||||
ebur128_integrated_loudness_lufs REAL,
|
ebur128_integrated_loudness_lufs REAL,
|
||||||
ebur128_loudness_range_lu REAL
|
ebur128_loudness_range_lu REAL,
|
||||||
|
|
||||||
|
bpm REAL,
|
||||||
|
mood TEXT,
|
||||||
|
initial_key TEXT
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS spotify_albums_songs (
|
CREATE TABLE IF NOT EXISTS spotify_albums_songs (
|
||||||
|
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
titlesort TEXT,
|
||||||
album TEXT,
|
album TEXT,
|
||||||
|
albumsort TEXT,
|
||||||
artist TEXT,
|
artist TEXT,
|
||||||
|
artistsort TEXT,
|
||||||
albumartist TEXT,
|
albumartist TEXT,
|
||||||
|
albumartistsort TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
@@ -516,7 +580,9 @@ CREATE TABLE IF NOT EXISTS spotify_albums_songs (
|
|||||||
genre TEXT,
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT,
|
composer TEXT,
|
||||||
|
composersort TEXT,
|
||||||
performer TEXT,
|
performer TEXT,
|
||||||
|
performersort TEXT,
|
||||||
grouping TEXT,
|
grouping TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
lyrics TEXT,
|
lyrics TEXT,
|
||||||
@@ -580,16 +646,24 @@ CREATE TABLE IF NOT EXISTS spotify_albums_songs (
|
|||||||
musicbrainz_work_id TEXT,
|
musicbrainz_work_id TEXT,
|
||||||
|
|
||||||
ebur128_integrated_loudness_lufs REAL,
|
ebur128_integrated_loudness_lufs REAL,
|
||||||
ebur128_loudness_range_lu REAL
|
ebur128_loudness_range_lu REAL,
|
||||||
|
|
||||||
|
bpm REAL,
|
||||||
|
mood TEXT,
|
||||||
|
initial_key TEXT
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS spotify_songs (
|
CREATE TABLE IF NOT EXISTS spotify_songs (
|
||||||
|
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
titlesort TEXT,
|
||||||
album TEXT,
|
album TEXT,
|
||||||
|
albumsort TEXT,
|
||||||
artist TEXT,
|
artist TEXT,
|
||||||
|
artistsort TEXT,
|
||||||
albumartist TEXT,
|
albumartist TEXT,
|
||||||
|
albumartistsort TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
@@ -597,7 +671,9 @@ CREATE TABLE IF NOT EXISTS spotify_songs (
|
|||||||
genre TEXT,
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT,
|
composer TEXT,
|
||||||
|
composersort TEXT,
|
||||||
performer TEXT,
|
performer TEXT,
|
||||||
|
performersort TEXT,
|
||||||
grouping TEXT,
|
grouping TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
lyrics TEXT,
|
lyrics TEXT,
|
||||||
@@ -661,16 +737,24 @@ CREATE TABLE IF NOT EXISTS spotify_songs (
|
|||||||
musicbrainz_work_id TEXT,
|
musicbrainz_work_id TEXT,
|
||||||
|
|
||||||
ebur128_integrated_loudness_lufs REAL,
|
ebur128_integrated_loudness_lufs REAL,
|
||||||
ebur128_loudness_range_lu REAL
|
ebur128_loudness_range_lu REAL,
|
||||||
|
|
||||||
|
bpm REAL,
|
||||||
|
mood TEXT,
|
||||||
|
initial_key TEXT
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
|
CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
|
||||||
|
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
titlesort TEXT,
|
||||||
album TEXT,
|
album TEXT,
|
||||||
|
albumsort TEXT,
|
||||||
artist TEXT,
|
artist TEXT,
|
||||||
|
artistsort TEXT,
|
||||||
albumartist TEXT,
|
albumartist TEXT,
|
||||||
|
albumartistsort TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
@@ -678,7 +762,9 @@ CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
|
|||||||
genre TEXT,
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT,
|
composer TEXT,
|
||||||
|
composersort TEXT,
|
||||||
performer TEXT,
|
performer TEXT,
|
||||||
|
performersort TEXT,
|
||||||
grouping TEXT,
|
grouping TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
lyrics TEXT,
|
lyrics TEXT,
|
||||||
@@ -742,16 +828,24 @@ CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
|
|||||||
musicbrainz_work_id TEXT,
|
musicbrainz_work_id TEXT,
|
||||||
|
|
||||||
ebur128_integrated_loudness_lufs REAL,
|
ebur128_integrated_loudness_lufs REAL,
|
||||||
ebur128_loudness_range_lu REAL
|
ebur128_loudness_range_lu REAL,
|
||||||
|
|
||||||
|
bpm REAL,
|
||||||
|
mood TEXT,
|
||||||
|
initial_key TEXT
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
|
CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
|
||||||
|
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
titlesort TEXT,
|
||||||
album TEXT,
|
album TEXT,
|
||||||
|
albumsort TEXT,
|
||||||
artist TEXT,
|
artist TEXT,
|
||||||
|
artistsort TEXT,
|
||||||
albumartist TEXT,
|
albumartist TEXT,
|
||||||
|
albumartistsort TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
@@ -759,7 +853,9 @@ CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
|
|||||||
genre TEXT,
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT,
|
composer TEXT,
|
||||||
|
composersort TEXT,
|
||||||
performer TEXT,
|
performer TEXT,
|
||||||
|
performersort TEXT,
|
||||||
grouping TEXT,
|
grouping TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
lyrics TEXT,
|
lyrics TEXT,
|
||||||
@@ -823,16 +919,24 @@ CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
|
|||||||
musicbrainz_work_id TEXT,
|
musicbrainz_work_id TEXT,
|
||||||
|
|
||||||
ebur128_integrated_loudness_lufs REAL,
|
ebur128_integrated_loudness_lufs REAL,
|
||||||
ebur128_loudness_range_lu REAL
|
ebur128_loudness_range_lu REAL,
|
||||||
|
|
||||||
|
bpm REAL,
|
||||||
|
mood TEXT,
|
||||||
|
initial_key TEXT
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS qobuz_songs (
|
CREATE TABLE IF NOT EXISTS qobuz_songs (
|
||||||
|
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
titlesort TEXT,
|
||||||
album TEXT,
|
album TEXT,
|
||||||
|
albumsort TEXT,
|
||||||
artist TEXT,
|
artist TEXT,
|
||||||
|
artistsort TEXT,
|
||||||
albumartist TEXT,
|
albumartist TEXT,
|
||||||
|
albumartistsort TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
@@ -840,7 +944,9 @@ CREATE TABLE IF NOT EXISTS qobuz_songs (
|
|||||||
genre TEXT,
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT,
|
composer TEXT,
|
||||||
|
composersort TEXT,
|
||||||
performer TEXT,
|
performer TEXT,
|
||||||
|
performersort TEXT,
|
||||||
grouping TEXT,
|
grouping TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
lyrics TEXT,
|
lyrics TEXT,
|
||||||
@@ -904,7 +1010,11 @@ CREATE TABLE IF NOT EXISTS qobuz_songs (
|
|||||||
musicbrainz_work_id TEXT,
|
musicbrainz_work_id TEXT,
|
||||||
|
|
||||||
ebur128_integrated_loudness_lufs REAL,
|
ebur128_integrated_loudness_lufs REAL,
|
||||||
ebur128_loudness_range_lu REAL
|
ebur128_loudness_range_lu REAL,
|
||||||
|
|
||||||
|
bpm REAL,
|
||||||
|
mood TEXT,
|
||||||
|
initial_key TEXT
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -931,9 +1041,13 @@ CREATE TABLE IF NOT EXISTS playlist_items (
|
|||||||
playlist_url TEXT,
|
playlist_url TEXT,
|
||||||
|
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
titlesort TEXT,
|
||||||
album TEXT,
|
album TEXT,
|
||||||
|
albumsort TEXT,
|
||||||
artist TEXT,
|
artist TEXT,
|
||||||
|
artistsort TEXT,
|
||||||
albumartist TEXT,
|
albumartist TEXT,
|
||||||
|
albumartistsort TEXT,
|
||||||
track INTEGER,
|
track INTEGER,
|
||||||
disc INTEGER,
|
disc INTEGER,
|
||||||
year INTEGER,
|
year INTEGER,
|
||||||
@@ -941,7 +1055,9 @@ CREATE TABLE IF NOT EXISTS playlist_items (
|
|||||||
genre TEXT,
|
genre TEXT,
|
||||||
compilation INTEGER DEFAULT 0,
|
compilation INTEGER DEFAULT 0,
|
||||||
composer TEXT,
|
composer TEXT,
|
||||||
|
composersort TEXT,
|
||||||
performer TEXT,
|
performer TEXT,
|
||||||
|
performersort TEXT,
|
||||||
grouping TEXT,
|
grouping TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
lyrics TEXT,
|
lyrics TEXT,
|
||||||
@@ -1005,7 +1121,11 @@ CREATE TABLE IF NOT EXISTS playlist_items (
|
|||||||
musicbrainz_work_id TEXT,
|
musicbrainz_work_id TEXT,
|
||||||
|
|
||||||
ebur128_integrated_loudness_lufs REAL,
|
ebur128_integrated_loudness_lufs REAL,
|
||||||
ebur128_loudness_range_lu REAL
|
ebur128_loudness_range_lu REAL,
|
||||||
|
|
||||||
|
bpm REAL,
|
||||||
|
mood TEXT,
|
||||||
|
initial_key TEXT
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1032,10 +1152,22 @@ CREATE INDEX IF NOT EXISTS idx_comp_artist ON songs (compilation_effective, arti
|
|||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_albumartist ON songs (albumartist);
|
CREATE INDEX IF NOT EXISTS idx_albumartist ON songs (albumartist);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_albumartistsort ON songs (albumartistsort);
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_artist ON songs (artist);
|
CREATE INDEX IF NOT EXISTS idx_artist ON songs (artist);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_artistsort ON songs (artistsort);
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_album ON songs (album);
|
CREATE INDEX IF NOT EXISTS idx_album ON songs (album);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_albumsort ON songs (album);
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_title ON songs (title);
|
CREATE INDEX IF NOT EXISTS idx_title ON songs (title);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_titlesort ON songs (title);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_composersort ON songs (title);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_performersort ON songs (title);
|
||||||
|
|
||||||
CREATE VIEW IF NOT EXISTS duplicated_songs as select artist dup_artist, album dup_album, title dup_title from songs as inner_songs where artist != '' and album != '' and title != '' and unavailable = 0 group by artist, album , title having count(*) > 1;
|
CREATE VIEW IF NOT EXISTS duplicated_songs as select artist dup_artist, album dup_album, title dup_title from songs as inner_songs where artist != '' and album != '' and title != '' and unavailable = 0 group by artist, album , title having count(*) > 1;
|
||||||
|
|||||||
7
debian/control
vendored
7
debian/control
vendored
@@ -32,7 +32,8 @@ Build-Depends: debhelper-compat (= 12),
|
|||||||
libfftw3-dev,
|
libfftw3-dev,
|
||||||
libebur128-dev,
|
libebur128-dev,
|
||||||
libsparsehash-dev,
|
libsparsehash-dev,
|
||||||
rapidjson-dev
|
rapidjson-dev,
|
||||||
|
libprojectm-dev
|
||||||
Standards-Version: 4.7.0
|
Standards-Version: 4.7.0
|
||||||
|
|
||||||
Package: strawberry
|
Package: strawberry
|
||||||
@@ -60,11 +61,11 @@ Description: music player and music collection organizer
|
|||||||
- Edit tags on audio files
|
- Edit tags on audio files
|
||||||
- Automatically retrieve tags from MusicBrainz
|
- Automatically retrieve tags from MusicBrainz
|
||||||
- Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
|
- Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
|
||||||
- Song lyrics from Genius, Musixmatch, ChartLyrics, lyrics.ovh, lololyrics.com, songlyrics.com, azlyrics.com and elyrics.net
|
- Lyrics from multiple sources
|
||||||
- Audio analyzer
|
- Audio analyzer
|
||||||
- Audio equalizer
|
- Audio equalizer
|
||||||
- Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
|
- Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
|
||||||
- Scrobbler with support for Last.fm, Libre.fm and ListenBrainz
|
- Scrobbler with support for Last.fm and ListenBrainz
|
||||||
- Streaming support for Subsonic-compatible servers
|
- Streaming support for Subsonic-compatible servers
|
||||||
- Unofficial streaming support for Tidal and Qobuz
|
- Unofficial streaming support for Tidal and Qobuz
|
||||||
.
|
.
|
||||||
|
|||||||
22
dist/macos/macversion.sh
vendored
22
dist/macos/macversion.sh
vendored
@@ -1,22 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
macos_version=$(sw_vers -productVersion)
|
|
||||||
macos_version_major=$(echo $macos_version | awk -F '[.]' '{print $1}')
|
|
||||||
macos_version_minor=$(echo $macos_version | awk -F '[.]' '{print $2}')
|
|
||||||
|
|
||||||
if [ "${macos_version_major}" = "10" ]; then
|
|
||||||
macos_codenames=(
|
|
||||||
["13"]="highsierra"
|
|
||||||
["14"]="mojave"
|
|
||||||
["15"]="catalina"
|
|
||||||
)
|
|
||||||
if [[ -n "${macos_codenames[$macos_version_minor]}" ]]; then
|
|
||||||
echo "${macos_codenames[$macos_version_minor]}"
|
|
||||||
else
|
|
||||||
echo "unknown"
|
|
||||||
fi
|
|
||||||
elif [ "${macos_version_major}" = "11" ]; then
|
|
||||||
echo "bigsur"
|
|
||||||
else
|
|
||||||
echo "unknown"
|
|
||||||
fi
|
|
||||||
@@ -31,10 +31,10 @@
|
|||||||
<li>Edit tags on audio files</li>
|
<li>Edit tags on audio files</li>
|
||||||
<li>Automatically retrieve tags from MusicBrainz</li>
|
<li>Automatically retrieve tags from MusicBrainz</li>
|
||||||
<li>Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify</li>
|
<li>Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify</li>
|
||||||
<li>Song lyrics from Genius, Musixmatch, ChartLyrics, lyrics.ovh, lololyrics.com, songlyrics.com, azlyrics.com and elyrics.net</li>
|
<li>Lyrics from multiple sources</li>
|
||||||
<li>Audio analyzer and equalizer</li>
|
<li>Audio analyzer and equalizer</li>
|
||||||
<li>Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic</li>
|
<li>Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic</li>
|
||||||
<li>Scrobbler with support for Last.fm, Libre.fm and ListenBrainz</li>
|
<li>Scrobbler with support for Last.fm and ListenBrainz</li>
|
||||||
<li>Streaming support for Subsonic-compatible servers</li>
|
<li>Streaming support for Subsonic-compatible servers</li>
|
||||||
<li>Unofficial streaming support for Tidal, Spotify and Qobuz</li>
|
<li>Unofficial streaming support for Tidal, Spotify and Qobuz</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -51,6 +51,14 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
<update_contact>eclipseo@fedoraproject.org</update_contact>
|
<update_contact>eclipseo@fedoraproject.org</update_contact>
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="1.2.16" date="2025-12-16"/>
|
||||||
|
<release version="1.2.15" date="2025-11-25"/>
|
||||||
|
<release version="1.2.14" date="2025-10-25"/>
|
||||||
|
<release version="1.2.13" date="2025-08-31"/>
|
||||||
|
<release version="1.2.12" date="2025-08-12"/>
|
||||||
|
<release version="1.2.11" date="2025-05-15"/>
|
||||||
|
<release version="1.2.10" date="2025-04-18"/>
|
||||||
|
<release version="1.2.9" date="2025-04-08"/>
|
||||||
<release version="1.2.8" date="2025-04-05"/>
|
<release version="1.2.8" date="2025-04-05"/>
|
||||||
<release version="1.2.7" date="2025-01-31"/>
|
<release version="1.2.7" date="2025-01-31"/>
|
||||||
<release version="1.2.6" date="2025-01-17"/>
|
<release version="1.2.6" date="2025-01-17"/>
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ TryExec=strawberry
|
|||||||
Icon=strawberry
|
Icon=strawberry
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Categories=AudioVideo;Player;Qt;Audio;
|
Categories=AudioVideo;Player;Qt;Audio;
|
||||||
Keywords=Audio;Player;
|
Keywords=Audio;Player;Clementine;
|
||||||
StartupNotify=false
|
|
||||||
MimeType=x-content/audio-player;application/ogg;application/x-ogg;application/x-ogm-audio;audio/flac;audio/ogg;audio/vorbis;audio/aac;audio/mp4;audio/mpeg;audio/mpegurl;audio/vnd.rn-realaudio;audio/x-flac;audio/x-oggflac;audio/x-vorbis;audio/x-vorbis+ogg;audio/x-speex;audio/x-wav;audio/x-wavpack;audio/x-ape;audio/x-mp3;audio/x-mpeg;audio/x-mpegurl;audio/x-ms-wma;audio/x-musepack;audio/x-pn-realaudio;audio/x-scpls;video/x-ms-asf;x-scheme-handler/tidal;
|
MimeType=x-content/audio-player;application/ogg;application/x-ogg;application/x-ogm-audio;audio/flac;audio/ogg;audio/vorbis;audio/aac;audio/mp4;audio/mpeg;audio/mpegurl;audio/vnd.rn-realaudio;audio/x-flac;audio/x-oggflac;audio/x-vorbis;audio/x-vorbis+ogg;audio/x-speex;audio/x-wav;audio/x-wavpack;audio/x-ape;audio/x-mp3;audio/x-mpeg;audio/x-mpegurl;audio/x-ms-wma;audio/x-musepack;audio/x-pn-realaudio;audio/x-scpls;video/x-ms-asf;x-scheme-handler/tidal;
|
||||||
StartupWMClass=strawberry
|
StartupWMClass=strawberry
|
||||||
Actions=Play-Pause;Stop;StopAfterCurrent;Previous;Next;
|
Actions=Play-Pause;Stop;StopAfterCurrent;Previous;Next;
|
||||||
|
|||||||
6
dist/unix/strawberry.1
vendored
6
dist/unix/strawberry.1
vendored
@@ -29,9 +29,7 @@ Features:
|
|||||||
.br
|
.br
|
||||||
- Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
|
- Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
|
||||||
.br
|
.br
|
||||||
- Song lyrics from Lyrics.com, Genius, Musixmatch, ChartLyrics, lyrics.ovh and lololyrics.com
|
- Lyrics from multiple sources
|
||||||
.br
|
|
||||||
- Support for multiple backends
|
|
||||||
.br
|
.br
|
||||||
- Audio analyzer
|
- Audio analyzer
|
||||||
.br
|
.br
|
||||||
@@ -39,7 +37,7 @@ Features:
|
|||||||
.br
|
.br
|
||||||
- Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
|
- Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
|
||||||
.br
|
.br
|
||||||
- Scrobbler with support for Last.fm, Libre.fm and ListenBrainz
|
- Scrobbler with support for Last.fm and ListenBrainz
|
||||||
.br
|
.br
|
||||||
- Streaming support for Subsonic-compatible servers
|
- Streaming support for Subsonic-compatible servers
|
||||||
.br
|
.br
|
||||||
|
|||||||
8
dist/unix/strawberry.spec.in
vendored
8
dist/unix/strawberry.spec.in
vendored
@@ -43,6 +43,7 @@ BuildRequires: pkgconfig(taglib)
|
|||||||
BuildRequires: pkgconfig(fftw3)
|
BuildRequires: pkgconfig(fftw3)
|
||||||
BuildRequires: pkgconfig(icu-uc)
|
BuildRequires: pkgconfig(icu-uc)
|
||||||
BuildRequires: pkgconfig(icu-i18n)
|
BuildRequires: pkgconfig(icu-i18n)
|
||||||
|
BuildRequires: pkgconfig(libprojectM)
|
||||||
BuildRequires: cmake(Qt@QT_VERSION_MAJOR@Core)
|
BuildRequires: cmake(Qt@QT_VERSION_MAJOR@Core)
|
||||||
BuildRequires: cmake(Qt@QT_VERSION_MAJOR@Concurrent)
|
BuildRequires: cmake(Qt@QT_VERSION_MAJOR@Concurrent)
|
||||||
BuildRequires: cmake(Qt@QT_VERSION_MAJOR@Network)
|
BuildRequires: cmake(Qt@QT_VERSION_MAJOR@Network)
|
||||||
@@ -93,16 +94,15 @@ Features:
|
|||||||
- Edit tags on audio files
|
- Edit tags on audio files
|
||||||
- Automatically retrieve tags from MusicBrainz
|
- Automatically retrieve tags from MusicBrainz
|
||||||
- Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
|
- Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
|
||||||
- Song lyrics from Genius, Musixmatch, ChartLyrics, lyrics.ovh, lololyrics.com, songlyrics.com, azlyrics.com and elyrics.net
|
- Lyrics from multiple sources
|
||||||
- Support for multiple backends
|
|
||||||
- Audio analyzer
|
- Audio analyzer
|
||||||
- Audio equalizer
|
- Audio equalizer
|
||||||
- Scrobbler with support for Last.fm, Libre.fm and ListenBrainz
|
- Scrobbler with support for Last.fm and ListenBrainz
|
||||||
- Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
|
- Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
|
||||||
- Streaming support for Subsonic-compatible servers
|
- Streaming support for Subsonic-compatible servers
|
||||||
- Unofficial streaming support for Tidal and Qobuz
|
- Unofficial streaming support for Tidal and Qobuz
|
||||||
|
|
||||||
%if 0%{?suse_version} && 0%{?suse_version} <= 1600
|
%if 0%{?suse_version} && 0%{?suse_version} < 1600
|
||||||
%debug_package
|
%debug_package
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
|||||||
141
dist/windows/strawberry.nsi.in
vendored
141
dist/windows/strawberry.nsi.in
vendored
@@ -21,6 +21,10 @@
|
|||||||
!define arch_x64
|
!define arch_x64
|
||||||
!else if "@ARCH@" == "x86_64-w64-mingw32.shared"
|
!else if "@ARCH@" == "x86_64-w64-mingw32.shared"
|
||||||
!define arch_x64
|
!define arch_x64
|
||||||
|
!else if "@ARCH@" == "arm64"
|
||||||
|
!define arch_arm64
|
||||||
|
!else
|
||||||
|
!error "Missing ARCH"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
!ifdef arch_x86
|
!ifdef arch_x86
|
||||||
@@ -31,6 +35,10 @@
|
|||||||
!define arch "x64"
|
!define arch "x64"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
|
!ifdef arch_arm64
|
||||||
|
!define arch "arm64"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
|
||||||
!if "@CMAKE_BUILD_TYPE@" == "Release"
|
!if "@CMAKE_BUILD_TYPE@" == "Release"
|
||||||
!define release
|
!define release
|
||||||
@@ -38,6 +46,8 @@
|
|||||||
!define release
|
!define release
|
||||||
!else if "@CMAKE_BUILD_TYPE@" == "Debug"
|
!else if "@CMAKE_BUILD_TYPE@" == "Debug"
|
||||||
!define debug
|
!define debug
|
||||||
|
!else
|
||||||
|
!error "Missing CMAKE_BUILD_TYPE"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
!ifdef release
|
!ifdef release
|
||||||
@@ -70,7 +80,7 @@
|
|||||||
!ifdef arch_x86
|
!ifdef arch_x86
|
||||||
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES\Strawberry Music Player Debug"
|
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES\Strawberry Music Player Debug"
|
||||||
!endif
|
!endif
|
||||||
!ifdef arch_x64
|
!ifdef arch_x64 || arch_arm64
|
||||||
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES64\Strawberry Music Player Debug"
|
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES64\Strawberry Music Player Debug"
|
||||||
!endif
|
!endif
|
||||||
!else
|
!else
|
||||||
@@ -80,7 +90,7 @@
|
|||||||
!ifdef arch_x86
|
!ifdef arch_x86
|
||||||
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES\Strawberry Music Player"
|
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES\Strawberry Music Player"
|
||||||
!endif
|
!endif
|
||||||
!ifdef arch_x64
|
!ifdef arch_x64 || arch_arm64
|
||||||
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES64\Strawberry Music Player"
|
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES64\Strawberry Music Player"
|
||||||
!endif
|
!endif
|
||||||
!endif
|
!endif
|
||||||
@@ -214,7 +224,7 @@ Function InstallMSVCRuntime
|
|||||||
; ${If} $R0 == ""
|
; ${If} $R0 == ""
|
||||||
SetDetailsView hide
|
SetDetailsView hide
|
||||||
; inetc::get /caption "Downloading..." "https://aka.ms/vs/17/release/${vc_redist_file}" "$TEMP\${vc_redist_file}" /end
|
; inetc::get /caption "Downloading..." "https://aka.ms/vs/17/release/${vc_redist_file}" "$TEMP\${vc_redist_file}" /end
|
||||||
ExecWait '"$TEMP\${vc_redist_file}" /install /passive'
|
ExecWait '"$TEMP\${vc_redist_file}" /install /passive /norestart'
|
||||||
Delete "$TEMP\${vc_redist_file}"
|
Delete "$TEMP\${vc_redist_file}"
|
||||||
SetDetailsView show
|
SetDetailsView show
|
||||||
; ${EndIf}
|
; ${EndIf}
|
||||||
@@ -324,7 +334,7 @@ Section "Strawberry" Strawberry
|
|||||||
File "libqtsparkle-qt6.dll"
|
File "libqtsparkle-qt6.dll"
|
||||||
File "libsoup-3.0-0.dll"
|
File "libsoup-3.0-0.dll"
|
||||||
File "libspeex-1.dll"
|
File "libspeex-1.dll"
|
||||||
File "libsqlite3.dll"
|
File "libsqlite3-0.dll"
|
||||||
File "libssp-0.dll"
|
File "libssp-0.dll"
|
||||||
File "libstdc++-6.dll"
|
File "libstdc++-6.dll"
|
||||||
File "libtag.dll"
|
File "libtag.dll"
|
||||||
@@ -367,6 +377,10 @@ Section "Strawberry" Strawberry
|
|||||||
File "libcrypto-3-x64.dll"
|
File "libcrypto-3-x64.dll"
|
||||||
File "libssl-3-x64.dll"
|
File "libssl-3-x64.dll"
|
||||||
!endif
|
!endif
|
||||||
|
!ifdef arch_arm64
|
||||||
|
File "libcrypto-3-arm64.dll"
|
||||||
|
File "libssl-3-arm64.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
File "FLAC.dll"
|
File "FLAC.dll"
|
||||||
File "brotlicommon.dll"
|
File "brotlicommon.dll"
|
||||||
@@ -381,7 +395,6 @@ Section "Strawberry" Strawberry
|
|||||||
File "glib-2.0-0.dll"
|
File "glib-2.0-0.dll"
|
||||||
File "gme.dll"
|
File "gme.dll"
|
||||||
File "gmodule-2.0-0.dll"
|
File "gmodule-2.0-0.dll"
|
||||||
File "gnutls.dll"
|
|
||||||
File "gobject-2.0-0.dll"
|
File "gobject-2.0-0.dll"
|
||||||
File "gstadaptivedemux-1.0-0.dll"
|
File "gstadaptivedemux-1.0-0.dll"
|
||||||
File "gstapp-1.0-0.dll"
|
File "gstapp-1.0-0.dll"
|
||||||
@@ -402,14 +415,11 @@ Section "Strawberry" Strawberry
|
|||||||
File "gsttag-1.0-0.dll"
|
File "gsttag-1.0-0.dll"
|
||||||
File "gsturidownloader-1.0-0.dll"
|
File "gsturidownloader-1.0-0.dll"
|
||||||
File "gstvideo-1.0-0.dll"
|
File "gstvideo-1.0-0.dll"
|
||||||
File "gstwinrt-1.0-0.dll"
|
|
||||||
File "harfbuzz.dll"
|
File "harfbuzz.dll"
|
||||||
File "intl-8.dll"
|
File "intl-8.dll"
|
||||||
File "jpeg62.dll"
|
File "jpeg62.dll"
|
||||||
File "kdsingleapplication-qt6.dll"
|
File "kdsingleapplication-qt6.dll"
|
||||||
File "libbs2b.dll"
|
File "libbs2b.dll"
|
||||||
File "libfaac_dll.dll"
|
|
||||||
File "liblzma.dll"
|
|
||||||
File "libmp3lame.dll"
|
File "libmp3lame.dll"
|
||||||
File "libopenmpt.dll"
|
File "libopenmpt.dll"
|
||||||
File "mpcdec.dll"
|
File "mpcdec.dll"
|
||||||
@@ -427,6 +437,11 @@ Section "Strawberry" Strawberry
|
|||||||
File "vorbisfile.dll"
|
File "vorbisfile.dll"
|
||||||
File "wavpackdll.dll"
|
File "wavpackdll.dll"
|
||||||
|
|
||||||
|
!ifndef arch_arm64
|
||||||
|
File "gnutls.dll"
|
||||||
|
File "libfaac_dll.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
!ifdef release
|
!ifdef release
|
||||||
File "freetype.dll"
|
File "freetype.dll"
|
||||||
File "libiconv.dll"
|
File "libiconv.dll"
|
||||||
@@ -434,8 +449,10 @@ Section "Strawberry" Strawberry
|
|||||||
File "libspeex.dll"
|
File "libspeex.dll"
|
||||||
File "pcre2-8.dll"
|
File "pcre2-8.dll"
|
||||||
File "pcre2-16.dll"
|
File "pcre2-16.dll"
|
||||||
|
File "zlib1.dll"
|
||||||
|
!ifndef arch_arm64
|
||||||
File "twolame.dll"
|
File "twolame.dll"
|
||||||
File "zlib.dll"
|
!endif
|
||||||
!endif
|
!endif
|
||||||
!ifdef debug
|
!ifdef debug
|
||||||
File "freetyped.dll"
|
File "freetyped.dll"
|
||||||
@@ -444,8 +461,10 @@ Section "Strawberry" Strawberry
|
|||||||
File "libspeexd.dll"
|
File "libspeexd.dll"
|
||||||
File "pcre2-8d.dll"
|
File "pcre2-8d.dll"
|
||||||
File "pcre2-16d.dll"
|
File "pcre2-16d.dll"
|
||||||
|
File "zlibd1.dll"
|
||||||
|
!ifndef arch_arm64
|
||||||
File "twolamed.dll"
|
File "twolamed.dll"
|
||||||
File "zlibd.dll"
|
!endif
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
; Used by libfftw3-3.dll because fftw is compiled with MinGW.
|
; Used by libfftw3-3.dll because fftw is compiled with MinGW.
|
||||||
@@ -458,11 +477,15 @@ Section "Strawberry" Strawberry
|
|||||||
|
|
||||||
; Common files
|
; Common files
|
||||||
|
|
||||||
File "icudt77.dll"
|
File "icudt78.dll"
|
||||||
|
!ifdef msvc && arch_arm64
|
||||||
|
File "fftw3.dll"
|
||||||
|
!else
|
||||||
File "libfftw3-3.dll"
|
File "libfftw3-3.dll"
|
||||||
|
!endif
|
||||||
!ifdef msvc && debug
|
!ifdef msvc && debug
|
||||||
File "icuin77d.dll"
|
File "icuin78d.dll"
|
||||||
File "icuuc77d.dll"
|
File "icuuc78d.dll"
|
||||||
File "libxml2d.dll"
|
File "libxml2d.dll"
|
||||||
File "Qt6Concurrentd.dll"
|
File "Qt6Concurrentd.dll"
|
||||||
File "Qt6Cored.dll"
|
File "Qt6Cored.dll"
|
||||||
@@ -471,8 +494,8 @@ Section "Strawberry" Strawberry
|
|||||||
File "Qt6Sqld.dll"
|
File "Qt6Sqld.dll"
|
||||||
File "Qt6Widgetsd.dll"
|
File "Qt6Widgetsd.dll"
|
||||||
!else
|
!else
|
||||||
File "icuin77.dll"
|
File "icuin78.dll"
|
||||||
File "icuuc77.dll"
|
File "icuuc78.dll"
|
||||||
File "libxml2.dll"
|
File "libxml2.dll"
|
||||||
File "Qt6Concurrent.dll"
|
File "Qt6Concurrent.dll"
|
||||||
File "Qt6Core.dll"
|
File "Qt6Core.dll"
|
||||||
@@ -482,6 +505,7 @@ Section "Strawberry" Strawberry
|
|||||||
File "Qt6Widgets.dll"
|
File "Qt6Widgets.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
|
!ifdef msvc && arch_x86
|
||||||
File "avcodec-61.dll"
|
File "avcodec-61.dll"
|
||||||
File "avfilter-10.dll"
|
File "avfilter-10.dll"
|
||||||
File "avformat-61.dll"
|
File "avformat-61.dll"
|
||||||
@@ -489,6 +513,14 @@ Section "Strawberry" Strawberry
|
|||||||
File "postproc-58.dll"
|
File "postproc-58.dll"
|
||||||
File "swresample-5.dll"
|
File "swresample-5.dll"
|
||||||
File "swscale-8.dll"
|
File "swscale-8.dll"
|
||||||
|
!else
|
||||||
|
File "avcodec-62.dll"
|
||||||
|
File "avfilter-11.dll"
|
||||||
|
File "avformat-62.dll"
|
||||||
|
File "avutil-60.dll"
|
||||||
|
File "swresample-6.dll"
|
||||||
|
File "swscale-9.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
; Register Strawberry with Default Programs
|
; Register Strawberry with Default Programs
|
||||||
Var /GLOBAL AppIcon
|
Var /GLOBAL AppIcon
|
||||||
@@ -526,11 +558,13 @@ Section "GIO modules" gio-modules
|
|||||||
SetOutPath "$INSTDIR\gio-modules"
|
SetOutPath "$INSTDIR\gio-modules"
|
||||||
!ifdef mingw
|
!ifdef mingw
|
||||||
File "/oname=libgiognutls.dll" "gio-modules\libgiognutls.dll"
|
File "/oname=libgiognutls.dll" "gio-modules\libgiognutls.dll"
|
||||||
File "/oname=libgioopenssl.dll" "gio-modules\libgioopenssl.dll"
|
|
||||||
!endif
|
!endif
|
||||||
!ifdef msvc
|
!ifdef msvc
|
||||||
File "/oname=giognutls.dll" "gio-modules\giognutls.dll"
|
!ifdef arch_arm64
|
||||||
File "/oname=gioopenssl.dll" "gio-modules\gioopenssl.dll"
|
File "/oname=gioopenssl.dll" "gio-modules\gioopenssl.dll"
|
||||||
|
!else
|
||||||
|
File "/oname=giognutls.dll" "gio-modules\giognutls.dll"
|
||||||
|
!endif
|
||||||
!endif
|
!endif
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
@@ -647,6 +681,7 @@ Section "Gstreamer plugins" gstreamer-plugins
|
|||||||
File "/oname=libgstvolume.dll" "gstreamer-plugins\libgstvolume.dll"
|
File "/oname=libgstvolume.dll" "gstreamer-plugins\libgstvolume.dll"
|
||||||
File "/oname=libgstvorbis.dll" "gstreamer-plugins\libgstvorbis.dll"
|
File "/oname=libgstvorbis.dll" "gstreamer-plugins\libgstvorbis.dll"
|
||||||
File "/oname=libgstwasapi.dll" "gstreamer-plugins\libgstwasapi.dll"
|
File "/oname=libgstwasapi.dll" "gstreamer-plugins\libgstwasapi.dll"
|
||||||
|
File "/oname=libgstwasapi2.dll" "gstreamer-plugins\libgstwasapi2.dll"
|
||||||
File "/oname=libgstwaveform.dll" "gstreamer-plugins\libgstwaveform.dll"
|
File "/oname=libgstwaveform.dll" "gstreamer-plugins\libgstwaveform.dll"
|
||||||
File "/oname=libgstwavenc.dll" "gstreamer-plugins\libgstwavenc.dll"
|
File "/oname=libgstwavenc.dll" "gstreamer-plugins\libgstwavenc.dll"
|
||||||
File "/oname=libgstwavpack.dll" "gstreamer-plugins\libgstwavpack.dll"
|
File "/oname=libgstwavpack.dll" "gstreamer-plugins\libgstwavpack.dll"
|
||||||
@@ -674,7 +709,6 @@ Section "Gstreamer plugins" gstreamer-plugins
|
|||||||
File "/oname=gstdirectsound.dll" "gstreamer-plugins\gstdirectsound.dll"
|
File "/oname=gstdirectsound.dll" "gstreamer-plugins\gstdirectsound.dll"
|
||||||
File "/oname=gstdsd.dll" "gstreamer-plugins\gstdsd.dll"
|
File "/oname=gstdsd.dll" "gstreamer-plugins\gstdsd.dll"
|
||||||
File "/oname=gstequalizer.dll" "gstreamer-plugins\gstequalizer.dll"
|
File "/oname=gstequalizer.dll" "gstreamer-plugins\gstequalizer.dll"
|
||||||
File "/oname=gstfaac.dll" "gstreamer-plugins\gstfaac.dll"
|
|
||||||
File "/oname=gstfaad.dll" "gstreamer-plugins\gstfaad.dll"
|
File "/oname=gstfaad.dll" "gstreamer-plugins\gstfaad.dll"
|
||||||
File "/oname=gstfdkaac.dll" "gstreamer-plugins\gstfdkaac.dll"
|
File "/oname=gstfdkaac.dll" "gstreamer-plugins\gstfdkaac.dll"
|
||||||
File "/oname=gstflac.dll" "gstreamer-plugins\gstflac.dll"
|
File "/oname=gstflac.dll" "gstreamer-plugins\gstflac.dll"
|
||||||
@@ -707,7 +741,6 @@ Section "Gstreamer plugins" gstreamer-plugins
|
|||||||
File "/oname=gstspeex.dll" "gstreamer-plugins\gstspeex.dll"
|
File "/oname=gstspeex.dll" "gstreamer-plugins\gstspeex.dll"
|
||||||
File "/oname=gsttaglib.dll" "gstreamer-plugins\gsttaglib.dll"
|
File "/oname=gsttaglib.dll" "gstreamer-plugins\gsttaglib.dll"
|
||||||
File "/oname=gsttcp.dll" "gstreamer-plugins\gsttcp.dll"
|
File "/oname=gsttcp.dll" "gstreamer-plugins\gsttcp.dll"
|
||||||
File "/oname=gsttwolame.dll" "gstreamer-plugins\gsttwolame.dll"
|
|
||||||
File "/oname=gsttypefindfunctions.dll" "gstreamer-plugins\gsttypefindfunctions.dll"
|
File "/oname=gsttypefindfunctions.dll" "gstreamer-plugins\gsttypefindfunctions.dll"
|
||||||
File "/oname=gstudp.dll" "gstreamer-plugins\gstudp.dll"
|
File "/oname=gstudp.dll" "gstreamer-plugins\gstudp.dll"
|
||||||
File "/oname=gstvolume.dll" "gstreamer-plugins\gstvolume.dll"
|
File "/oname=gstvolume.dll" "gstreamer-plugins\gstvolume.dll"
|
||||||
@@ -719,8 +752,12 @@ Section "Gstreamer plugins" gstreamer-plugins
|
|||||||
File "/oname=gstwavpack.dll" "gstreamer-plugins\gstwavpack.dll"
|
File "/oname=gstwavpack.dll" "gstreamer-plugins\gstwavpack.dll"
|
||||||
File "/oname=gstwavparse.dll" "gstreamer-plugins\gstwavparse.dll"
|
File "/oname=gstwavparse.dll" "gstreamer-plugins\gstwavparse.dll"
|
||||||
File "/oname=gstxingmux.dll" "gstreamer-plugins\gstxingmux.dll"
|
File "/oname=gstxingmux.dll" "gstreamer-plugins\gstxingmux.dll"
|
||||||
|
!ifndef arch_arm64
|
||||||
|
File "/oname=gstfaac.dll" "gstreamer-plugins\gstfaac.dll"
|
||||||
|
File "/oname=gsttwolame.dll" "gstreamer-plugins\gsttwolame.dll"
|
||||||
|
!endif
|
||||||
!ifdef arch_x64
|
!ifdef arch_x64
|
||||||
;File "/oname=gstspotify.dll" "gstreamer-plugins\gstspotify.dll"
|
File "/oname=gstspotify.dll" "gstreamer-plugins\gstspotify.dll"
|
||||||
!endif
|
!endif
|
||||||
!endif ; MSVC
|
!endif ; MSVC
|
||||||
|
|
||||||
@@ -849,7 +886,7 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libqtsparkle-qt6.dll"
|
Delete "$INSTDIR\libqtsparkle-qt6.dll"
|
||||||
Delete "$INSTDIR\libsoup-3.0-0.dll"
|
Delete "$INSTDIR\libsoup-3.0-0.dll"
|
||||||
Delete "$INSTDIR\libspeex-1.dll"
|
Delete "$INSTDIR\libspeex-1.dll"
|
||||||
Delete "$INSTDIR\libsqlite3.dll"
|
Delete "$INSTDIR\libsqlite3-0.dll"
|
||||||
Delete "$INSTDIR\libssp-0.dll"
|
Delete "$INSTDIR\libssp-0.dll"
|
||||||
Delete "$INSTDIR\libstdc++-6.dll"
|
Delete "$INSTDIR\libstdc++-6.dll"
|
||||||
Delete "$INSTDIR\libtag.dll"
|
Delete "$INSTDIR\libtag.dll"
|
||||||
@@ -892,6 +929,10 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libcrypto-3-x64.dll"
|
Delete "$INSTDIR\libcrypto-3-x64.dll"
|
||||||
Delete "$INSTDIR\libssl-3-x64.dll"
|
Delete "$INSTDIR\libssl-3-x64.dll"
|
||||||
!endif
|
!endif
|
||||||
|
!ifdef arch_arm64
|
||||||
|
Delete "$INSTDIR\libcrypto-3-arm64.dll"
|
||||||
|
Delete "$INSTDIR\libssl-3-arm64.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
Delete "$INSTDIR\FLAC.dll"
|
Delete "$INSTDIR\FLAC.dll"
|
||||||
Delete "$INSTDIR\brotlicommon.dll"
|
Delete "$INSTDIR\brotlicommon.dll"
|
||||||
@@ -906,7 +947,6 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\glib-2.0-0.dll"
|
Delete "$INSTDIR\glib-2.0-0.dll"
|
||||||
Delete "$INSTDIR\gme.dll"
|
Delete "$INSTDIR\gme.dll"
|
||||||
Delete "$INSTDIR\gmodule-2.0-0.dll"
|
Delete "$INSTDIR\gmodule-2.0-0.dll"
|
||||||
Delete "$INSTDIR\gnutls.dll"
|
|
||||||
Delete "$INSTDIR\gobject-2.0-0.dll"
|
Delete "$INSTDIR\gobject-2.0-0.dll"
|
||||||
Delete "$INSTDIR\gstadaptivedemux-1.0-0.dll"
|
Delete "$INSTDIR\gstadaptivedemux-1.0-0.dll"
|
||||||
Delete "$INSTDIR\gstapp-1.0-0.dll"
|
Delete "$INSTDIR\gstapp-1.0-0.dll"
|
||||||
@@ -927,14 +967,11 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\gsttag-1.0-0.dll"
|
Delete "$INSTDIR\gsttag-1.0-0.dll"
|
||||||
Delete "$INSTDIR\gsturidownloader-1.0-0.dll"
|
Delete "$INSTDIR\gsturidownloader-1.0-0.dll"
|
||||||
Delete "$INSTDIR\gstvideo-1.0-0.dll"
|
Delete "$INSTDIR\gstvideo-1.0-0.dll"
|
||||||
Delete "$INSTDIR\gstwinrt-1.0-0.dll"
|
|
||||||
Delete "$INSTDIR\harfbuzz.dll"
|
Delete "$INSTDIR\harfbuzz.dll"
|
||||||
Delete "$INSTDIR\intl-8.dll"
|
Delete "$INSTDIR\intl-8.dll"
|
||||||
Delete "$INSTDIR\jpeg62.dll"
|
Delete "$INSTDIR\jpeg62.dll"
|
||||||
Delete "$INSTDIR\kdsingleapplication-qt6.dll"
|
Delete "$INSTDIR\kdsingleapplication-qt6.dll"
|
||||||
Delete "$INSTDIR\libbs2b.dll"
|
Delete "$INSTDIR\libbs2b.dll"
|
||||||
Delete "$INSTDIR\libfaac_dll.dll"
|
|
||||||
Delete "$INSTDIR\liblzma.dll"
|
|
||||||
Delete "$INSTDIR\libmp3lame.dll"
|
Delete "$INSTDIR\libmp3lame.dll"
|
||||||
Delete "$INSTDIR\libopenmpt.dll"
|
Delete "$INSTDIR\libopenmpt.dll"
|
||||||
Delete "$INSTDIR\mpcdec.dll"
|
Delete "$INSTDIR\mpcdec.dll"
|
||||||
@@ -952,6 +989,11 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\vorbisfile.dll"
|
Delete "$INSTDIR\vorbisfile.dll"
|
||||||
Delete "$INSTDIR\wavpackdll.dll"
|
Delete "$INSTDIR\wavpackdll.dll"
|
||||||
|
|
||||||
|
!ifndef arch_arm64
|
||||||
|
Delete "$INSTDIR\gnutls.dll"
|
||||||
|
Delete "$INSTDIR\libfaac_dll.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
!ifdef release
|
!ifdef release
|
||||||
Delete "$INSTDIR\freetype.dll"
|
Delete "$INSTDIR\freetype.dll"
|
||||||
Delete "$INSTDIR\libiconv.dll"
|
Delete "$INSTDIR\libiconv.dll"
|
||||||
@@ -959,8 +1001,10 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libspeex.dll"
|
Delete "$INSTDIR\libspeex.dll"
|
||||||
Delete "$INSTDIR\pcre2-8.dll"
|
Delete "$INSTDIR\pcre2-8.dll"
|
||||||
Delete "$INSTDIR\pcre2-16.dll"
|
Delete "$INSTDIR\pcre2-16.dll"
|
||||||
|
Delete "$INSTDIR\zlib1.dll"
|
||||||
|
!ifndef arch_arm64
|
||||||
Delete "$INSTDIR\twolame.dll"
|
Delete "$INSTDIR\twolame.dll"
|
||||||
Delete "$INSTDIR\zlib.dll"
|
!endif
|
||||||
!endif
|
!endif
|
||||||
!ifdef debug
|
!ifdef debug
|
||||||
Delete "$INSTDIR\freetyped.dll"
|
Delete "$INSTDIR\freetyped.dll"
|
||||||
@@ -969,8 +1013,10 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libspeexd.dll"
|
Delete "$INSTDIR\libspeexd.dll"
|
||||||
Delete "$INSTDIR\pcre2-8d.dll"
|
Delete "$INSTDIR\pcre2-8d.dll"
|
||||||
Delete "$INSTDIR\pcre2-16d.dll"
|
Delete "$INSTDIR\pcre2-16d.dll"
|
||||||
|
Delete "$INSTDIR\zlibd1.dll"
|
||||||
|
!ifndef arch_arm64
|
||||||
Delete "$INSTDIR\twolamed.dll"
|
Delete "$INSTDIR\twolamed.dll"
|
||||||
Delete "$INSTDIR\zlibd.dll"
|
!endif
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
!ifdef arch_x86
|
!ifdef arch_x86
|
||||||
@@ -982,11 +1028,15 @@ Section "Uninstall"
|
|||||||
|
|
||||||
; Common files
|
; Common files
|
||||||
|
|
||||||
Delete "$INSTDIR\icudt77.dll"
|
Delete "$INSTDIR\icudt78.dll"
|
||||||
|
!ifdef msvc && arch_arm64
|
||||||
|
Delete "$INSTDIR\fftw3.dll"
|
||||||
|
!else
|
||||||
Delete "$INSTDIR\libfftw3-3.dll"
|
Delete "$INSTDIR\libfftw3-3.dll"
|
||||||
|
!endif
|
||||||
!ifdef msvc && debug
|
!ifdef msvc && debug
|
||||||
Delete "$INSTDIR\icuin77d.dll"
|
Delete "$INSTDIR\icuin78d.dll"
|
||||||
Delete "$INSTDIR\icuuc77d.dll"
|
Delete "$INSTDIR\icuuc78d.dll"
|
||||||
Delete "$INSTDIR\libxml2d.dll"
|
Delete "$INSTDIR\libxml2d.dll"
|
||||||
Delete "$INSTDIR\Qt6Concurrentd.dll"
|
Delete "$INSTDIR\Qt6Concurrentd.dll"
|
||||||
Delete "$INSTDIR\Qt6Cored.dll"
|
Delete "$INSTDIR\Qt6Cored.dll"
|
||||||
@@ -995,8 +1045,8 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\Qt6Sqld.dll"
|
Delete "$INSTDIR\Qt6Sqld.dll"
|
||||||
Delete "$INSTDIR\Qt6Widgetsd.dll"
|
Delete "$INSTDIR\Qt6Widgetsd.dll"
|
||||||
!else
|
!else
|
||||||
Delete "$INSTDIR\icuin77.dll"
|
Delete "$INSTDIR\icuin78.dll"
|
||||||
Delete "$INSTDIR\icuuc77.dll"
|
Delete "$INSTDIR\icuuc78.dll"
|
||||||
Delete "$INSTDIR\libxml2.dll"
|
Delete "$INSTDIR\libxml2.dll"
|
||||||
Delete "$INSTDIR\Qt6Concurrent.dll"
|
Delete "$INSTDIR\Qt6Concurrent.dll"
|
||||||
Delete "$INSTDIR\Qt6Core.dll"
|
Delete "$INSTDIR\Qt6Core.dll"
|
||||||
@@ -1006,6 +1056,7 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\Qt6Widgets.dll"
|
Delete "$INSTDIR\Qt6Widgets.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
|
!ifdef msvc && arch_x86
|
||||||
Delete "$INSTDIR\avcodec-61.dll"
|
Delete "$INSTDIR\avcodec-61.dll"
|
||||||
Delete "$INSTDIR\avfilter-10.dll"
|
Delete "$INSTDIR\avfilter-10.dll"
|
||||||
Delete "$INSTDIR\avformat-61.dll"
|
Delete "$INSTDIR\avformat-61.dll"
|
||||||
@@ -1013,14 +1064,24 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\postproc-58.dll"
|
Delete "$INSTDIR\postproc-58.dll"
|
||||||
Delete "$INSTDIR\swresample-5.dll"
|
Delete "$INSTDIR\swresample-5.dll"
|
||||||
Delete "$INSTDIR\swscale-8.dll"
|
Delete "$INSTDIR\swscale-8.dll"
|
||||||
|
!else
|
||||||
|
Delete "$INSTDIR\avcodec-62.dll"
|
||||||
|
Delete "$INSTDIR\avfilter-11.dll"
|
||||||
|
Delete "$INSTDIR\avformat-62.dll"
|
||||||
|
Delete "$INSTDIR\avutil-60.dll"
|
||||||
|
Delete "$INSTDIR\swresample-6.dll"
|
||||||
|
Delete "$INSTDIR\swscale-9.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
!ifdef mingw
|
!ifdef mingw
|
||||||
Delete "$INSTDIR\gio-modules\libgiognutls.dll"
|
Delete "$INSTDIR\gio-modules\libgiognutls.dll"
|
||||||
Delete "$INSTDIR\gio-modules\libgioopenssl.dll"
|
|
||||||
!endif
|
!endif
|
||||||
!ifdef msvc
|
!ifdef msvc
|
||||||
Delete "$INSTDIR\gio-modules\giognutls.dll"
|
!ifdef arch_arm64
|
||||||
Delete "$INSTDIR\gio-modules\gioopenssl.dll"
|
Delete "$INSTDIR\gio-modules\gioopenssl.dll"
|
||||||
|
!else
|
||||||
|
Delete "$INSTDIR\gio-modules\giognutls.dll"
|
||||||
|
!endif
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
!ifdef msvc && debug
|
!ifdef msvc && debug
|
||||||
@@ -1104,6 +1165,7 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\gstreamer-plugins\libgstvolume.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstvolume.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstvorbis.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstvorbis.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstwasapi.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstwasapi.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstwasapi2.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstwaveform.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstwaveform.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstwavenc.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstwavenc.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstwavpack.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstwavpack.dll"
|
||||||
@@ -1133,7 +1195,6 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\gstreamer-plugins\gstdirectsound.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstdirectsound.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstdsd.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstdsd.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstequalizer.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstequalizer.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstfaac.dll"
|
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstfaad.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstfaad.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstfdkaac.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstfdkaac.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstflac.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstflac.dll"
|
||||||
@@ -1166,7 +1227,6 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\gstreamer-plugins\gstspeex.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstspeex.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gsttaglib.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gsttaglib.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gsttcp.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gsttcp.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gsttwolame.dll"
|
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gsttypefindfunctions.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gsttypefindfunctions.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstudp.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstudp.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstvolume.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstvolume.dll"
|
||||||
@@ -1178,9 +1238,14 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\gstreamer-plugins\gstwavpack.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstwavpack.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstwavparse.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstwavparse.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstxingmux.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstxingmux.dll"
|
||||||
!ifdef arch_x64
|
!ifndef arch_arm64
|
||||||
;Delete "$INSTDIR\gstreamer-plugins\gstspotify.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstfaac.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gsttwolame.dll"
|
||||||
!endif
|
!endif
|
||||||
|
!ifdef arch_x64
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstspotify.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
!endif ; msvc
|
!endif ; msvc
|
||||||
|
|
||||||
Delete "$INSTDIR\Uninstall.exe"
|
Delete "$INSTDIR\Uninstall.exe"
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ANALYZERBASE_H
|
#ifndef ANALYZERBASE_H
|
||||||
#define ANALYZERBASE_H
|
#define ANALYZERBASE_H
|
||||||
@@ -90,4 +90,3 @@ class AnalyzerBase : public QWidget {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif // ANALYZERBASE_H
|
#endif // ANALYZERBASE_H
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ constexpr int kLowFramerate = 20;
|
|||||||
constexpr int kMediumFramerate = 25;
|
constexpr int kMediumFramerate = 25;
|
||||||
constexpr int kHighFramerate = 30;
|
constexpr int kHighFramerate = 30;
|
||||||
constexpr int kSuperHighFramerate = 60;
|
constexpr int kSuperHighFramerate = 60;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
AnalyzerContainer::AnalyzerContainer(QWidget *parent)
|
AnalyzerContainer::AnalyzerContainer(QWidget *parent)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
@@ -73,7 +73,8 @@ AnalyzerContainer::AnalyzerContainer(QWidget *parent)
|
|||||||
double_click_timer_(new QTimer(this)),
|
double_click_timer_(new QTimer(this)),
|
||||||
ignore_next_click_(false),
|
ignore_next_click_(false),
|
||||||
current_analyzer_(nullptr),
|
current_analyzer_(nullptr),
|
||||||
engine_(nullptr) {
|
engine_(nullptr),
|
||||||
|
action_visualization_(nullptr) {
|
||||||
|
|
||||||
QHBoxLayout *layout = new QHBoxLayout(this);
|
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
@@ -118,6 +119,17 @@ void AnalyzerContainer::mouseReleaseEvent(QMouseEvent *e) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnalyzerContainer::mouseDoubleClickEvent(QMouseEvent *e) {
|
||||||
|
|
||||||
|
Q_UNUSED(e);
|
||||||
|
|
||||||
|
double_click_timer_->stop();
|
||||||
|
ignore_next_click_ = true;
|
||||||
|
|
||||||
|
if (action_visualization_) action_visualization_->trigger();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void AnalyzerContainer::ShowPopupMenu() {
|
void AnalyzerContainer::ShowPopupMenu() {
|
||||||
context_menu_->popup(last_click_pos_);
|
context_menu_->popup(last_click_pos_);
|
||||||
}
|
}
|
||||||
@@ -249,3 +261,10 @@ void AnalyzerContainer::AddFramerate(const QString &name, const int framerate) {
|
|||||||
QObject::connect(action, &QAction::triggered, this, [this, framerate]() { ChangeFramerate(framerate); } );
|
QObject::connect(action, &QAction::triggered, this, [this, framerate]() { ChangeFramerate(framerate); } );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnalyzerContainer::SetVisualizationsAction(QAction *visualization) {
|
||||||
|
|
||||||
|
action_visualization_ = visualization;
|
||||||
|
context_menu_->addAction(action_visualization_);
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ANALYZERCONTAINER_H
|
#ifndef ANALYZERCONTAINER_H
|
||||||
#define ANALYZERCONTAINER_H
|
#define ANALYZERCONTAINER_H
|
||||||
@@ -46,6 +46,7 @@ class AnalyzerContainer : public QWidget {
|
|||||||
explicit AnalyzerContainer(QWidget *parent);
|
explicit AnalyzerContainer(QWidget *parent);
|
||||||
|
|
||||||
void SetEngine(SharedPtr<EngineBase> engine);
|
void SetEngine(SharedPtr<EngineBase> engine);
|
||||||
|
void SetVisualizationsAction(QAction *visualization);
|
||||||
|
|
||||||
static const char *kSettingsGroup;
|
static const char *kSettingsGroup;
|
||||||
static const char *kSettingsFramerate;
|
static const char *kSettingsFramerate;
|
||||||
@@ -55,6 +56,7 @@ class AnalyzerContainer : public QWidget {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
|
void mouseDoubleClickEvent(QMouseEvent *e) override;
|
||||||
void wheelEvent(QWheelEvent *e) override;
|
void wheelEvent(QWheelEvent *e) override;
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
@@ -89,6 +91,8 @@ class AnalyzerContainer : public QWidget {
|
|||||||
|
|
||||||
AnalyzerBase *current_analyzer_;
|
AnalyzerBase *current_analyzer_;
|
||||||
SharedPtr<EngineBase> engine_;
|
SharedPtr<EngineBase> engine_;
|
||||||
|
|
||||||
|
QAction *action_visualization_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -101,8 +105,7 @@ void AnalyzerContainer::AddAnalyzerType() {
|
|||||||
group_->addAction(action);
|
group_->addAction(action);
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
actions_ << action;
|
actions_ << action;
|
||||||
QObject::connect(action, &QAction::triggered, [this, id]() { ChangeAnalyzer(id); } );
|
QObject::connect(action, &QAction::triggered, [this, id]() { ChangeAnalyzer(id); });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ANALYZERCONTAINER_H
|
#endif // ANALYZERCONTAINER_H
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "blockanalyzer.h"
|
#include "blockanalyzer.h"
|
||||||
|
|
||||||
@@ -61,11 +61,12 @@ BlockAnalyzer::BlockAnalyzer(QWidget *parent)
|
|||||||
fade_intensity_(1 << 8, 32),
|
fade_intensity_(1 << 8, 32),
|
||||||
step_(0) {
|
step_(0) {
|
||||||
|
|
||||||
setMinimumSize(kMinColumns * (kWidth + 1) - 1, kMinRows * (kHeight + 1) - 1); //-1 is padding, no drawing takes place there
|
setMinimumSize(kMinColumns * (kWidth + 1) - 1, kMinRows * (kHeight + 1) - 1); // -1 is padding, no drawing takes place there
|
||||||
setMaximumWidth(kMaxColumns * (kWidth + 1) - 1);
|
setMaximumWidth(kMaxColumns * (kWidth + 1) - 1);
|
||||||
|
|
||||||
// mxcl says null pixmaps cause crashes, so let's play it safe
|
// mxcl says null pixmaps cause crashes, so let's play it safe
|
||||||
std::fill(fade_bars_.begin(), fade_bars_.end(), QPixmap(1, 1));
|
std::fill(fade_bars_.begin(), fade_bars_.end(), QPixmap(1, 1));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockAnalyzer::resizeEvent(QResizeEvent *e) {
|
void BlockAnalyzer::resizeEvent(QResizeEvent *e) {
|
||||||
@@ -237,7 +238,7 @@ static inline void adjustToLimits(const int b, int &f, int &amount) {
|
|||||||
* Clever contrast function
|
* Clever contrast function
|
||||||
*
|
*
|
||||||
* It will try to adjust the foreground color such that it contrasts well with
|
* It will try to adjust the foreground color such that it contrasts well with
|
||||||
*the background
|
* the background
|
||||||
* It won't modify the hue of fg unless absolutely necessary
|
* It won't modify the hue of fg unless absolutely necessary
|
||||||
* @return the adjusted form of fg
|
* @return the adjusted form of fg
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef BLOCKANALYZER_H
|
#ifndef BLOCKANALYZER_H
|
||||||
#define BLOCKANALYZER_H
|
#define BLOCKANALYZER_H
|
||||||
@@ -41,14 +41,14 @@ class BlockAnalyzer : public AnalyzerBase {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE explicit BlockAnalyzer(QWidget*);
|
Q_INVOKABLE explicit BlockAnalyzer(QWidget *parent);
|
||||||
|
|
||||||
static const char *kName;
|
static const char *kName;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void transform(Scope&) override;
|
void transform(Scope &s) override;
|
||||||
void analyze(QPainter &p, const Scope &s, const bool new_frame) override;
|
void analyze(QPainter &p, const Scope &s, const bool new_frame) override;
|
||||||
void resizeEvent(QResizeEvent*) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
virtual void paletteChange(const QPalette &_palette);
|
virtual void paletteChange(const QPalette &_palette);
|
||||||
void framerateChanged() override;
|
void framerateChanged() override;
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "boomanalyzer.h"
|
#include "boomanalyzer.h"
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ void BoomAnalyzer::analyze(QPainter &p, const Scope &scope, const bool new_frame
|
|||||||
bar_height_[i] = std::max(0.0, bar_height_[i]);
|
bar_height_[i] = std::max(0.0, bar_height_[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
peak_handling:
|
peak_handling:
|
||||||
|
|
||||||
if (peak_height_[i] > 0.0) {
|
if (peak_height_[i] > 0.0) {
|
||||||
peak_height_[i] -= peak_speed_[i];
|
peak_height_[i] -= peak_speed_[i];
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef BOOMANALYZER_H
|
#ifndef BOOMANALYZER_H
|
||||||
#define BOOMANALYZER_H
|
#define BOOMANALYZER_H
|
||||||
@@ -40,7 +40,7 @@ class BoomAnalyzer : public AnalyzerBase {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE explicit BoomAnalyzer(QWidget*);
|
Q_INVOKABLE explicit BoomAnalyzer(QWidget *parent);
|
||||||
|
|
||||||
static const char *kName;
|
static const char *kName;
|
||||||
|
|
||||||
@@ -70,7 +70,6 @@ class BoomAnalyzer : public AnalyzerBase {
|
|||||||
|
|
||||||
QPixmap barPixmap_;
|
QPixmap barPixmap_;
|
||||||
QPixmap canvas_;
|
QPixmap canvas_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BOOMANALYZER_H
|
#endif // BOOMANALYZER_H
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fht.h"
|
#include "fht.h"
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FHT_H
|
#ifndef FHT_H
|
||||||
#define FHT_H
|
#define FHT_H
|
||||||
@@ -55,20 +55,20 @@ class FHT {
|
|||||||
/**
|
/**
|
||||||
* Recursive in-place Hartley transform. For internal use only!
|
* Recursive in-place Hartley transform. For internal use only!
|
||||||
*/
|
*/
|
||||||
void _transform(float*, int, int);
|
void _transform(float *p, int n, int k);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Prepare transform for data sets with @f$2^n@f$ numbers, whereby @f$n@f$
|
* Prepare transform for data sets with @f$2^n@f$ numbers, whereby @f$n@f$
|
||||||
* should be at least 3. Values of more than 3 need a trigonometry table.
|
* should be at least 3. Values of more than 3 need a trigonometry table.
|
||||||
* @see makeCasTable()
|
* @see makeCasTable()
|
||||||
*/
|
*/
|
||||||
explicit FHT(uint);
|
explicit FHT(uint);
|
||||||
|
|
||||||
~FHT();
|
~FHT();
|
||||||
int sizeExp() const;
|
int sizeExp() const;
|
||||||
int size() const;
|
int size() const;
|
||||||
void scale(float*, float) const;
|
void scale(float *p, float d) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exponentially Weighted Moving Average (EWMA) filter.
|
* Exponentially Weighted Moving Average (EWMA) filter.
|
||||||
@@ -90,12 +90,12 @@ class FHT {
|
|||||||
/**
|
/**
|
||||||
* Semi-logarithmic audio spectrum.
|
* Semi-logarithmic audio spectrum.
|
||||||
*/
|
*/
|
||||||
void semiLogSpectrum(float*);
|
void semiLogSpectrum(float *p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fourier spectrum.
|
* Fourier spectrum.
|
||||||
*/
|
*/
|
||||||
void spectrum(float*);
|
void spectrum(float *p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates a mathematically correct FFT power spectrum.
|
* Calculates a mathematically correct FFT power spectrum.
|
||||||
@@ -103,7 +103,7 @@ class FHT {
|
|||||||
* and factor the 0.5 in the final scaling factor.
|
* and factor the 0.5 in the final scaling factor.
|
||||||
* @see FHT::power2()
|
* @see FHT::power2()
|
||||||
*/
|
*/
|
||||||
void power(float*);
|
void power(float *p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates an FFT power spectrum with doubled values as a
|
* Calculates an FFT power spectrum with doubled values as a
|
||||||
@@ -112,14 +112,14 @@ class FHT {
|
|||||||
* of @f$2^n@f$ input values. This is the fastest transform.
|
* of @f$2^n@f$ input values. This is the fastest transform.
|
||||||
* @see FHT::power()
|
* @see FHT::power()
|
||||||
*/
|
*/
|
||||||
void power2(float*);
|
void power2(float *p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Discrete Hartley transform of data sets with 8 values.
|
* Discrete Hartley transform of data sets with 8 values.
|
||||||
*/
|
*/
|
||||||
static void transform8(float*);
|
static void transform8(float *p);
|
||||||
|
|
||||||
void transform(float*);
|
void transform(float *p);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FHT_H
|
#endif // FHT_H
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "rainbowanalyzer.h"
|
#include "rainbowanalyzer.h"
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RAINBOWANALYZER_H
|
#ifndef RAINBOWANALYZER_H
|
||||||
#define RAINBOWANALYZER_H
|
#define RAINBOWANALYZER_H
|
||||||
@@ -85,7 +85,7 @@ class RainbowAnalyzer : public AnalyzerBase {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// "constants" that get initialized in the constructor
|
// "constants" that get initialized in the constructor
|
||||||
float band_scale_[kRainbowBands] {};
|
float band_scale_[kRainbowBands]{};
|
||||||
QPen colors_[kRainbowBands];
|
QPen colors_[kRainbowBands];
|
||||||
|
|
||||||
// Rainbow Nyancat & Dash
|
// Rainbow Nyancat & Dash
|
||||||
@@ -96,7 +96,7 @@ class RainbowAnalyzer : public AnalyzerBase {
|
|||||||
int frame_;
|
int frame_;
|
||||||
|
|
||||||
// The y positions of each point on the rainbow.
|
// The y positions of each point on the rainbow.
|
||||||
float history_[kHistorySize * kRainbowBands] {};
|
float history_[kHistorySize * kRainbowBands]{};
|
||||||
|
|
||||||
// A cache of the last frame's rainbow,
|
// A cache of the last frame's rainbow,
|
||||||
// so it can be used in the next frame.
|
// so it can be used in the next frame.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SONOGRAMANALYZER_H
|
#ifndef SONOGRAMANALYZER_H
|
||||||
#define SONOGRAMANALYZER_H
|
#define SONOGRAMANALYZER_H
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ void TurbineAnalyzer::analyze(QPainter &p, const Scope &scope, const bool new_fr
|
|||||||
bar_height_[i] = std::max(0.0, bar_height_[i]);
|
bar_height_[i] = std::max(0.0, bar_height_[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
peak_handling:
|
peak_handling:
|
||||||
if (peak_height_[i] > 0.0) {
|
if (peak_height_[i] > 0.0) {
|
||||||
peak_height_[i] -= peak_speed_[i];
|
peak_height_[i] -= peak_speed_[i];
|
||||||
peak_speed_[i] *= F_peakSpeed_; // 1.12
|
peak_speed_[i] *= F_peakSpeed_; // 1.12
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TURBINEANALYZER_H
|
#ifndef TURBINEANALYZER_H
|
||||||
#define TURBINEANALYZER_H
|
#define TURBINEANALYZER_H
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
|
|||||||
@@ -623,6 +623,7 @@ void CollectionBackend::AddOrUpdateSongs(const SongList &songs) {
|
|||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
|
|
||||||
|
CollectionTask task(task_manager_, tr("Updating %1 database.").arg(Song::TextForSource(source_)));
|
||||||
ScopedTransaction transaction(&db);
|
ScopedTransaction transaction(&db);
|
||||||
|
|
||||||
SongList added_songs;
|
SongList added_songs;
|
||||||
|
|||||||
@@ -140,7 +140,6 @@ class CollectionBackend : public CollectionBackendInterface {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Q_INVOKABLE explicit CollectionBackend(QObject *parent = nullptr);
|
Q_INVOKABLE explicit CollectionBackend(QObject *parent = nullptr);
|
||||||
|
|
||||||
~CollectionBackend();
|
~CollectionBackend();
|
||||||
@@ -331,4 +330,3 @@ class CollectionBackend : public CollectionBackendInterface {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif // COLLECTIONBACKEND_H
|
#endif // COLLECTIONBACKEND_H
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
|
|
||||||
class CollectionFilterOptions {
|
class CollectionFilterOptions {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit CollectionFilterOptions();
|
explicit CollectionFilterOptions();
|
||||||
|
|
||||||
// Filter mode:
|
// Filter mode:
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <QUrl>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
@@ -295,19 +296,21 @@ QActionGroup *CollectionFilterWidget::CreateGroupByActions(const QString &saved_
|
|||||||
if (version == 1) {
|
if (version == 1) {
|
||||||
QStringList saved = s.childKeys();
|
QStringList saved = s.childKeys();
|
||||||
for (int i = 0; i < saved.size(); ++i) {
|
for (int i = 0; i < saved.size(); ++i) {
|
||||||
if (saved.at(i) == "version"_L1) continue;
|
const QString &name = saved.at(i);
|
||||||
QByteArray bytes = s.value(saved.at(i)).toByteArray();
|
if (name == "version"_L1) continue;
|
||||||
|
QByteArray bytes = s.value(name).toByteArray();
|
||||||
QDataStream ds(&bytes, QIODevice::ReadOnly);
|
QDataStream ds(&bytes, QIODevice::ReadOnly);
|
||||||
CollectionModel::Grouping g;
|
CollectionModel::Grouping g;
|
||||||
ds >> g;
|
ds >> g;
|
||||||
ret->addAction(CreateGroupByAction(saved.at(i), parent, g));
|
ret->addAction(CreateGroupByAction(QUrl::fromPercentEncoding(name.toUtf8()), parent, g));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
QStringList saved = s.childKeys();
|
QStringList saved = s.childKeys();
|
||||||
for (int i = 0; i < saved.size(); ++i) {
|
for (int i = 0; i < saved.size(); ++i) {
|
||||||
if (saved.at(i) == "version"_L1) continue;
|
const QString &name = saved.at(i);
|
||||||
s.remove(saved.at(i));
|
if (name == "version"_L1) continue;
|
||||||
|
s.remove(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
@@ -339,7 +342,7 @@ void CollectionFilterWidget::SaveGroupBy() {
|
|||||||
|
|
||||||
if (!model_) return;
|
if (!model_) return;
|
||||||
|
|
||||||
QString name = QInputDialog::getText(this, tr("Grouping Name"), tr("Grouping name:"));
|
const QString name = QInputDialog::getText(this, tr("Grouping Name"), tr("Grouping name:"));
|
||||||
if (name.isEmpty()) return;
|
if (name.isEmpty()) return;
|
||||||
|
|
||||||
qLog(Debug) << "Saving current grouping to" << name;
|
qLog(Debug) << "Saving current grouping to" << name;
|
||||||
@@ -355,7 +358,7 @@ void CollectionFilterWidget::SaveGroupBy() {
|
|||||||
QDataStream datastream(&buffer, QIODevice::WriteOnly);
|
QDataStream datastream(&buffer, QIODevice::WriteOnly);
|
||||||
datastream << model_->GetGroupBy();
|
datastream << model_->GetGroupBy();
|
||||||
s.setValue("version", u"1"_s);
|
s.setValue("version", u"1"_s);
|
||||||
s.setValue(name, buffer);
|
s.setValue(QUrl::toPercentEncoding(name), buffer);
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
UpdateGroupByActions();
|
UpdateGroupByActions();
|
||||||
|
|||||||
@@ -135,4 +135,3 @@ class CollectionFilterWidget : public QWidget {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif // COLLECTIONFILTERWIDGET_H
|
#endif // COLLECTIONFILTERWIDGET_H
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
* Copyright 2018-2021, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2018-2025, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -78,6 +78,8 @@ CollectionLibrary::CollectionLibrary(const SharedPtr<Database> database,
|
|||||||
|
|
||||||
model_ = new CollectionModel(backend_, albumcover_loader, this);
|
model_ = new CollectionModel(backend_, albumcover_loader, this);
|
||||||
|
|
||||||
|
full_rescan_revisions_[21] = tr("Support for sort tags artist, album, album artist, title, composer, and performer");
|
||||||
|
|
||||||
ReloadSettings();
|
ReloadSettings();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -187,6 +189,26 @@ void CollectionLibrary::ReloadSettings() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CollectionLibrary::CurrentSongChanged(const Song &song) {
|
||||||
|
|
||||||
|
current_song_url_ = song.url();
|
||||||
|
|
||||||
|
if (!pending_song_saves_.isEmpty()) {
|
||||||
|
SavePendingPlaycountsAndRatings();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectionLibrary::Stopped() {
|
||||||
|
|
||||||
|
current_song_url_ = QUrl();
|
||||||
|
|
||||||
|
if (!pending_song_saves_.isEmpty()) {
|
||||||
|
SavePendingPlaycountsAndRatings();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void CollectionLibrary::SyncPlaycountAndRatingToFilesAsync() {
|
void CollectionLibrary::SyncPlaycountAndRatingToFilesAsync() {
|
||||||
|
|
||||||
(void)QtConcurrent::run(&CollectionLibrary::SyncPlaycountAndRatingToFiles, this);
|
(void)QtConcurrent::run(&CollectionLibrary::SyncPlaycountAndRatingToFiles, this);
|
||||||
@@ -210,18 +232,85 @@ void CollectionLibrary::SyncPlaycountAndRatingToFiles() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionLibrary::SongsPlaycountChanged(const SongList &songs, const bool save_tags) const {
|
void CollectionLibrary::SongsPlaycountChanged(const SongList &songs, const bool save_tags) {
|
||||||
|
|
||||||
if (save_tags || save_playcounts_to_files_) {
|
if (save_tags || save_playcounts_to_files_) {
|
||||||
tagreader_client_->SaveSongsPlaycountAsync(songs);
|
SongList songs_to_save_now;
|
||||||
|
for (const Song &song : songs) {
|
||||||
|
if (song.url().isLocalFile() && song.url() == current_song_url_ &&
|
||||||
|
(song.filetype() == Song::FileType::OggFlac || song.filetype() == Song::FileType::OggVorbis || song.filetype() == Song::FileType::OggOpus)) {
|
||||||
|
qLog(Debug) << "Deferring playcount save for currently playing file" << song.url().toLocalFile();
|
||||||
|
if (pending_song_saves_.contains(song.url())) {
|
||||||
|
SharedPtr<PendingSongSave> pending_song_save = pending_song_saves_[song.url()];
|
||||||
|
pending_song_save->save_playcount = true;
|
||||||
|
pending_song_save->song.set_playcount(song.playcount());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SharedPtr<PendingSongSave> pending_song_save = make_shared<PendingSongSave>();
|
||||||
|
pending_song_save->save_playcount = true;
|
||||||
|
pending_song_save->song = song;
|
||||||
|
pending_song_saves_.insert(song.url(), pending_song_save);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
songs_to_save_now << song;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!songs_to_save_now.isEmpty()) {
|
||||||
|
tagreader_client_->SaveSongsPlaycountAsync(songs_to_save_now);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionLibrary::SongsRatingChanged(const SongList &songs, const bool save_tags) const {
|
void CollectionLibrary::SongsRatingChanged(const SongList &songs, const bool save_tags) {
|
||||||
|
|
||||||
if (save_tags || save_ratings_to_files_) {
|
if (save_tags || save_ratings_to_files_) {
|
||||||
tagreader_client_->SaveSongsRatingAsync(songs);
|
SongList songs_to_save_now;
|
||||||
|
for (const Song &song : songs) {
|
||||||
|
if (song.url().isLocalFile() && song.url() == current_song_url_ &&
|
||||||
|
(song.filetype() == Song::FileType::OggFlac || song.filetype() == Song::FileType::OggVorbis || song.filetype() == Song::FileType::OggOpus)) {
|
||||||
|
qLog(Debug) << "Deferring rating save for currently playing file" << song.url().toLocalFile();
|
||||||
|
if (pending_song_saves_.contains(song.url())) {
|
||||||
|
SharedPtr<PendingSongSave> pending_song_save = pending_song_saves_[song.url()];
|
||||||
|
pending_song_save->save_rating = true;
|
||||||
|
pending_song_save->song.set_rating(song.rating());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SharedPtr<PendingSongSave> pending_song_save = make_shared<PendingSongSave>();
|
||||||
|
pending_song_save->save_rating = true;
|
||||||
|
pending_song_save->song = song;
|
||||||
|
pending_song_saves_.insert(song.url(), pending_song_save);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
songs_to_save_now << song;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!songs_to_save_now.isEmpty()) {
|
||||||
|
tagreader_client_->SaveSongsRatingAsync(songs_to_save_now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectionLibrary::SavePendingPlaycountsAndRatings() {
|
||||||
|
|
||||||
|
for (auto it = pending_song_saves_.constBegin(); it != pending_song_saves_.constEnd();) {
|
||||||
|
const QUrl url = it.key();
|
||||||
|
SharedPtr<PendingSongSave> pending_song_save = it.value();
|
||||||
|
if (url == current_song_url_) {
|
||||||
|
++it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
qLog(Debug) << "Saving deferred playcount/rating for" << url.toLocalFile();
|
||||||
|
if (pending_song_save->save_playcount) {
|
||||||
|
tagreader_client_->SaveSongsPlaycountAsync(SongList() << pending_song_save->song);
|
||||||
|
}
|
||||||
|
if (pending_song_save->save_rating) {
|
||||||
|
tagreader_client_->SaveSongsRatingAsync(SongList() << pending_song_save->song);
|
||||||
|
}
|
||||||
|
it = pending_song_saves_.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
* Copyright 2018-2021, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2018-2025, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
#include <QMap>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include "includes/shared_ptr.h"
|
#include "includes/shared_ptr.h"
|
||||||
@@ -71,6 +72,7 @@ class CollectionLibrary : public QObject {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void SyncPlaycountAndRatingToFiles();
|
void SyncPlaycountAndRatingToFiles();
|
||||||
|
void SavePendingPlaycountsAndRatings();
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
@@ -84,16 +86,26 @@ class CollectionLibrary : public QObject {
|
|||||||
|
|
||||||
void IncrementalScan();
|
void IncrementalScan();
|
||||||
|
|
||||||
|
void CurrentSongChanged(const Song &song);
|
||||||
|
void Stopped();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void ExitReceived();
|
void ExitReceived();
|
||||||
void SongsPlaycountChanged(const SongList &songs, const bool save_tags = false) const;
|
void SongsPlaycountChanged(const SongList &songs, const bool save_tags = false);
|
||||||
void SongsRatingChanged(const SongList &songs, const bool save_tags = false) const;
|
void SongsRatingChanged(const SongList &songs, const bool save_tags = false);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void Error(const QString &error);
|
void Error(const QString &error);
|
||||||
void ExitFinished();
|
void ExitFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class PendingSongSave {
|
||||||
|
public:
|
||||||
|
Song song;
|
||||||
|
bool save_playcount = false;
|
||||||
|
bool save_rating = false;
|
||||||
|
};
|
||||||
|
|
||||||
const SharedPtr<TaskManager> task_manager_;
|
const SharedPtr<TaskManager> task_manager_;
|
||||||
const SharedPtr<TagReaderClient> tagreader_client_;
|
const SharedPtr<TagReaderClient> tagreader_client_;
|
||||||
|
|
||||||
@@ -111,6 +123,10 @@ class CollectionLibrary : public QObject {
|
|||||||
|
|
||||||
bool save_playcounts_to_files_;
|
bool save_playcounts_to_files_;
|
||||||
bool save_ratings_to_files_;
|
bool save_ratings_to_files_;
|
||||||
|
|
||||||
|
QUrl current_song_url_;
|
||||||
|
|
||||||
|
QMap<QUrl, SharedPtr<PendingSongSave>> pending_song_saves_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2018-2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2018-2025, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -54,6 +54,7 @@
|
|||||||
|
|
||||||
#include "includes/scoped_ptr.h"
|
#include "includes/scoped_ptr.h"
|
||||||
#include "includes/shared_ptr.h"
|
#include "includes/shared_ptr.h"
|
||||||
|
#include "constants/collectionsettings.h"
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "core/standardpaths.h"
|
#include "core/standardpaths.h"
|
||||||
#include "core/database.h"
|
#include "core/database.h"
|
||||||
@@ -71,12 +72,12 @@
|
|||||||
#include "covermanager/albumcoverloaderoptions.h"
|
#include "covermanager/albumcoverloaderoptions.h"
|
||||||
#include "covermanager/albumcoverloaderresult.h"
|
#include "covermanager/albumcoverloaderresult.h"
|
||||||
#include "covermanager/albumcoverloader.h"
|
#include "covermanager/albumcoverloader.h"
|
||||||
#include "constants/collectionsettings.h"
|
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
using namespace Qt::Literals::StringLiterals;
|
using namespace Qt::Literals::StringLiterals;
|
||||||
|
|
||||||
const int CollectionModel::kPrettyCoverSize = 32;
|
const int CollectionModel::kPrettyCoverSize = 32;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr char kPixmapDiskCacheDir[] = "pixmapcache";
|
constexpr char kPixmapDiskCacheDir[] = "pixmapcache";
|
||||||
constexpr char kVariousArtists[] = QT_TR_NOOP("Various artists");
|
constexpr char kVariousArtists[] = QT_TR_NOOP("Various artists");
|
||||||
@@ -88,7 +89,6 @@ CollectionModel::CollectionModel(const SharedPtr<CollectionBackend> backend, con
|
|||||||
albumcover_loader_(albumcover_loader),
|
albumcover_loader_(albumcover_loader),
|
||||||
dir_model_(new CollectionDirectoryModel(backend, this)),
|
dir_model_(new CollectionDirectoryModel(backend, this)),
|
||||||
filter_(new CollectionFilter(this)),
|
filter_(new CollectionFilter(this)),
|
||||||
timer_reload_(new QTimer(this)),
|
|
||||||
timer_update_(new QTimer(this)),
|
timer_update_(new QTimer(this)),
|
||||||
icon_artist_(IconLoader::Load(u"folder-sound"_s)),
|
icon_artist_(IconLoader::Load(u"folder-sound"_s)),
|
||||||
use_disk_cache_(false),
|
use_disk_cache_(false),
|
||||||
@@ -130,10 +130,6 @@ CollectionModel::CollectionModel(const SharedPtr<CollectionBackend> backend, con
|
|||||||
backend_->UpdateTotalArtistCountAsync();
|
backend_->UpdateTotalArtistCountAsync();
|
||||||
backend_->UpdateTotalAlbumCountAsync();
|
backend_->UpdateTotalAlbumCountAsync();
|
||||||
|
|
||||||
timer_reload_->setSingleShot(true);
|
|
||||||
timer_reload_->setInterval(300ms);
|
|
||||||
QObject::connect(timer_reload_, &QTimer::timeout, this, &CollectionModel::Reload);
|
|
||||||
|
|
||||||
timer_update_->setSingleShot(false);
|
timer_update_->setSingleShot(false);
|
||||||
timer_update_->setInterval(20ms);
|
timer_update_->setInterval(20ms);
|
||||||
QObject::connect(timer_update_, &QTimer::timeout, this, &CollectionModel::ProcessUpdate);
|
QObject::connect(timer_update_, &QTimer::timeout, this, &CollectionModel::ProcessUpdate);
|
||||||
@@ -191,13 +187,9 @@ void CollectionModel::EndReset() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionModel::Reload() {
|
void CollectionModel::ResetInternal() {
|
||||||
|
|
||||||
loading_ = true;
|
loading_ = true;
|
||||||
if (timer_reload_->isActive()) {
|
|
||||||
timer_reload_->stop();
|
|
||||||
}
|
|
||||||
updates_.clear();
|
|
||||||
|
|
||||||
options_active_ = options_current_;
|
options_active_ = options_current_;
|
||||||
|
|
||||||
@@ -211,22 +203,16 @@ void CollectionModel::Reload() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionModel::ScheduleReset() {
|
|
||||||
|
|
||||||
if (!timer_reload_->isActive()) {
|
|
||||||
timer_reload_->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CollectionModel::ReloadSettings() {
|
void CollectionModel::ReloadSettings() {
|
||||||
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings.beginGroup(CollectionSettings::kSettingsGroup);
|
settings.beginGroup(CollectionSettings::kSettingsGroup);
|
||||||
const bool show_pretty_covers = settings.value(CollectionSettings::kPrettyCovers, true).toBool();
|
const bool show_pretty_covers = settings.value(CollectionSettings::kPrettyCovers, true).toBool();
|
||||||
const bool show_dividers= settings.value(CollectionSettings::kShowDividers, true).toBool();
|
const bool show_dividers = settings.value(CollectionSettings::kShowDividers, true).toBool();
|
||||||
const bool show_various_artists = settings.value(CollectionSettings::kVariousArtists, true).toBool();
|
const bool show_various_artists = settings.value(CollectionSettings::kVariousArtists, true).toBool();
|
||||||
const bool sort_skips_articles = settings.value(CollectionSettings::kSortSkipsArticles, true).toBool();
|
const bool sort_skip_articles_for_artists = settings.value(CollectionSettings::kSkipArticlesForArtists, true).toBool();
|
||||||
|
const bool sort_skip_articles_for_albums = settings.value(CollectionSettings::kSkipArticlesForAlbums, false).toBool();
|
||||||
|
const bool use_sort_tags = settings.value(CollectionSettings::kUseSortTags, true).toBool();
|
||||||
|
|
||||||
use_disk_cache_ = settings.value(CollectionSettings::kSettingsDiskCacheEnable, false).toBool();
|
use_disk_cache_ = settings.value(CollectionSettings::kSettingsDiskCacheEnable, false).toBool();
|
||||||
QPixmapCache::setCacheLimit(static_cast<int>(MaximumCacheSize(&settings, CollectionSettings::kSettingsCacheSize, CollectionSettings::kSettingsCacheSizeUnit, CollectionSettings::kSettingsCacheSizeDefault) / 1024));
|
QPixmapCache::setCacheLimit(static_cast<int>(MaximumCacheSize(&settings, CollectionSettings::kSettingsCacheSize, CollectionSettings::kSettingsCacheSizeUnit, CollectionSettings::kSettingsCacheSizeDefault) / 1024));
|
||||||
@@ -241,11 +227,15 @@ void CollectionModel::ReloadSettings() {
|
|||||||
if (show_pretty_covers != options_current_.show_pretty_covers ||
|
if (show_pretty_covers != options_current_.show_pretty_covers ||
|
||||||
show_dividers != options_current_.show_dividers ||
|
show_dividers != options_current_.show_dividers ||
|
||||||
show_various_artists != options_current_.show_various_artists ||
|
show_various_artists != options_current_.show_various_artists ||
|
||||||
sort_skips_articles != options_current_.sort_skips_articles) {
|
sort_skip_articles_for_artists != options_current_.sort_skip_articles_for_artists ||
|
||||||
|
sort_skip_articles_for_albums != options_current_.sort_skip_articles_for_albums ||
|
||||||
|
use_sort_tags != options_current_.use_sort_tags) {
|
||||||
options_current_.show_pretty_covers = show_pretty_covers;
|
options_current_.show_pretty_covers = show_pretty_covers;
|
||||||
options_current_.show_dividers = show_dividers;
|
options_current_.show_dividers = show_dividers;
|
||||||
options_current_.show_various_artists = show_various_artists;
|
options_current_.show_various_artists = show_various_artists;
|
||||||
options_current_.sort_skips_articles = sort_skips_articles;
|
options_current_.sort_skip_articles_for_artists = sort_skip_articles_for_artists;
|
||||||
|
options_current_.sort_skip_articles_for_albums = sort_skip_articles_for_albums;
|
||||||
|
options_current_.use_sort_tags = use_sort_tags;
|
||||||
ScheduleReset();
|
ScheduleReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,10 +411,15 @@ void CollectionModel::RemoveSongs(const SongList &songs) {
|
|||||||
|
|
||||||
void CollectionModel::ScheduleUpdate(const CollectionModelUpdate::Type type, const SongList &songs) {
|
void CollectionModel::ScheduleUpdate(const CollectionModelUpdate::Type type, const SongList &songs) {
|
||||||
|
|
||||||
for (qint64 i = 0; i < songs.count(); i += 400LL) {
|
if (type == CollectionModelUpdate::Type::Reset) {
|
||||||
const qint64 number = std::min(songs.count() - i, 400LL);
|
updates_.enqueue(CollectionModelUpdate(type));
|
||||||
const SongList songs_to_queue = songs.mid(i, number);
|
}
|
||||||
updates_.enqueue(CollectionModelUpdate(type, songs_to_queue));
|
else {
|
||||||
|
for (qint64 i = 0; i < songs.count(); i += 400LL) {
|
||||||
|
const qint64 number = std::min(songs.count() - i, 400LL);
|
||||||
|
const SongList songs_to_queue = songs.mid(i, number);
|
||||||
|
updates_.enqueue(CollectionModelUpdate(type, songs_to_queue));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!timer_update_->isActive()) {
|
if (!timer_update_->isActive()) {
|
||||||
@@ -433,6 +428,14 @@ void CollectionModel::ScheduleUpdate(const CollectionModelUpdate::Type type, con
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CollectionModel::ScheduleReset() {
|
||||||
|
|
||||||
|
if (!updates_.isEmpty() && updates_.first().type == CollectionModelUpdate::Type::Reset) return;
|
||||||
|
|
||||||
|
ScheduleUpdate(CollectionModelUpdate::Type::Reset);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void CollectionModel::ScheduleAddSongs(const SongList &songs) {
|
void CollectionModel::ScheduleAddSongs(const SongList &songs) {
|
||||||
|
|
||||||
ScheduleUpdate(CollectionModelUpdate::Type::Add, songs);
|
ScheduleUpdate(CollectionModelUpdate::Type::Add, songs);
|
||||||
@@ -465,6 +468,9 @@ void CollectionModel::ProcessUpdate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (update.type) {
|
switch (update.type) {
|
||||||
|
case CollectionModelUpdate::Type::Reset:
|
||||||
|
ResetInternal();
|
||||||
|
break;
|
||||||
case CollectionModelUpdate::Type::AddReAddOrUpdate:
|
case CollectionModelUpdate::Type::AddReAddOrUpdate:
|
||||||
AddReAddOrUpdateSongsInternal(update.songs);
|
AddReAddOrUpdateSongsInternal(update.songs);
|
||||||
break;
|
break;
|
||||||
@@ -539,7 +545,10 @@ void CollectionModel::AddSongsInternal(const SongList &songs) {
|
|||||||
// Sanity check to make sure we don't add songs that are outside the user's filter
|
// Sanity check to make sure we don't add songs that are outside the user's filter
|
||||||
if (!options_active_.filter_options.Matches(song)) continue;
|
if (!options_active_.filter_options.Matches(song)) continue;
|
||||||
|
|
||||||
if (song_nodes_.contains(song.id())) continue;
|
if (song_nodes_.contains(song.id())) {
|
||||||
|
qLog(Debug) << song.id() << song.title() << "already exists, skipping";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Before we can add each song we need to make sure the required container items already exist in the tree.
|
// Before we can add each song we need to make sure the required container items already exist in the tree.
|
||||||
// These depend on which "group by" settings the user has on the collection.
|
// These depend on which "group by" settings the user has on the collection.
|
||||||
@@ -680,8 +689,8 @@ void CollectionModel::RemoveSongsInternal(const SongList &songs) {
|
|||||||
if (!divider_nodes_.contains(divider_key)) continue;
|
if (!divider_nodes_.contains(divider_key)) continue;
|
||||||
|
|
||||||
// Look to see if there are any other items still under this divider
|
// Look to see if there are any other items still under this divider
|
||||||
QList<CollectionItem*> container_nodes = container_nodes_[0].values();
|
QList<CollectionItem *> container_nodes = container_nodes_[0].values();
|
||||||
if (std::any_of(container_nodes.begin(), container_nodes.end(), [this, divider_key](CollectionItem *node){ return DividerKey(options_active_.group_by[0], node->metadata, node->sort_text) == divider_key; })) {
|
if (std::any_of(container_nodes.begin(), container_nodes.end(), [this, divider_key](CollectionItem *node) { return DividerKey(options_active_.group_by[0], node->metadata, node->sort_text) == divider_key; })) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,7 +708,7 @@ CollectionItem *CollectionModel::CreateContainerItem(const GroupBy group_by, con
|
|||||||
|
|
||||||
QString divider_key;
|
QString divider_key;
|
||||||
if (options_active_.show_dividers && container_level == 0) {
|
if (options_active_.show_dividers && container_level == 0) {
|
||||||
divider_key = DividerKey(group_by, song, SortText(group_by, song, options_active_.sort_skips_articles));
|
divider_key = DividerKey(group_by, song, SortText(group_by, song, options_active_.sort_skip_articles_for_artists, options_active_.sort_skip_articles_for_albums, options_active_.use_sort_tags));
|
||||||
if (!divider_key.isEmpty()) {
|
if (!divider_key.isEmpty()) {
|
||||||
if (!divider_nodes_.contains(divider_key)) {
|
if (!divider_nodes_.contains(divider_key)) {
|
||||||
CreateDividerItem(divider_key, DividerDisplayText(group_by, divider_key), parent);
|
CreateDividerItem(divider_key, DividerDisplayText(group_by, divider_key), parent);
|
||||||
@@ -713,7 +722,7 @@ CollectionItem *CollectionModel::CreateContainerItem(const GroupBy group_by, con
|
|||||||
item->container_level = container_level;
|
item->container_level = container_level;
|
||||||
item->container_key = container_key;
|
item->container_key = container_key;
|
||||||
item->display_text = DisplayText(group_by, song);
|
item->display_text = DisplayText(group_by, song);
|
||||||
item->sort_text = SortText(group_by, song, options_active_.sort_skips_articles);
|
item->sort_text = SortText(group_by, song, options_active_.sort_skip_articles_for_artists, options_active_.sort_skip_articles_for_albums, options_active_.use_sort_tags);
|
||||||
if (!divider_key.isEmpty()) {
|
if (!divider_key.isEmpty()) {
|
||||||
item->sort_text.prepend(divider_key + QLatin1Char(' '));
|
item->sort_text.prepend(divider_key + QLatin1Char(' '));
|
||||||
}
|
}
|
||||||
@@ -1068,39 +1077,39 @@ QString CollectionModel::PrettyFormat(const Song &song) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CollectionModel::SortText(const GroupBy group_by, const Song &song, const bool sort_skips_articles) {
|
QString CollectionModel::SortText(const GroupBy group_by, const Song &song, const bool sort_skip_articles_for_artists, const bool sort_skip_articles_for_albums, const bool use_sort_tags) {
|
||||||
|
|
||||||
switch (group_by) {
|
switch (group_by) {
|
||||||
case GroupBy::AlbumArtist:
|
case GroupBy::AlbumArtist:
|
||||||
return SortTextForArtist(song.effective_albumartist(), sort_skips_articles);
|
return SortTextForName(use_sort_tags ? song.effective_albumartistsort() : song.effective_albumartist(), sort_skip_articles_for_artists);
|
||||||
case GroupBy::Artist:
|
case GroupBy::Artist:
|
||||||
return SortTextForArtist(song.artist(), sort_skips_articles);
|
return SortTextForName(use_sort_tags ? song.effective_artistsort() : song.artist(), sort_skip_articles_for_artists);
|
||||||
case GroupBy::Album:
|
case GroupBy::Album:
|
||||||
return SortText(song.album());
|
return SortTextForName(use_sort_tags ? song.effective_albumsort() : song.album(), sort_skip_articles_for_albums);
|
||||||
case GroupBy::AlbumDisc:
|
case GroupBy::AlbumDisc:
|
||||||
return song.album() + SortTextForNumber(std::max(0, song.disc()));
|
return SortTextForName(use_sort_tags ? song.effective_albumsort() : song.album(), sort_skip_articles_for_albums) + SortTextForNumber(std::max(0, song.disc()));
|
||||||
case GroupBy::YearAlbum:
|
case GroupBy::YearAlbum:
|
||||||
return SortTextForNumber(std::max(0, song.year())) + song.grouping() + song.album();
|
return SortTextForYear(song.year()) + song.grouping() + SortTextForName(use_sort_tags ? song.effective_albumsort() : song.album(), sort_skip_articles_for_albums);
|
||||||
case GroupBy::YearAlbumDisc:
|
case GroupBy::YearAlbumDisc:
|
||||||
return SortTextForNumber(std::max(0, song.year())) + song.album() + SortTextForNumber(std::max(0, song.disc()));
|
return SortTextForYear(song.year()) + SortTextForName(use_sort_tags ? song.effective_albumsort() : song.album(), sort_skip_articles_for_albums) + SortTextForNumber(std::max(0, song.disc()));
|
||||||
case GroupBy::OriginalYearAlbum:
|
case GroupBy::OriginalYearAlbum:
|
||||||
return SortTextForNumber(std::max(0, song.effective_originalyear())) + song.grouping() + song.album();
|
return SortTextForYear(song.effective_originalyear()) + song.grouping() + SortTextForName(use_sort_tags ? song.effective_albumsort() : song.album(), sort_skip_articles_for_albums);
|
||||||
case GroupBy::OriginalYearAlbumDisc:
|
case GroupBy::OriginalYearAlbumDisc:
|
||||||
return SortTextForNumber(std::max(0, song.effective_originalyear())) + song.album() + SortTextForNumber(std::max(0, song.disc()));
|
return SortTextForYear(song.effective_originalyear()) + SortTextForName(use_sort_tags ? song.effective_albumsort() : song.album(), sort_skip_articles_for_albums) + SortTextForNumber(std::max(0, song.disc()));
|
||||||
case GroupBy::Disc:
|
case GroupBy::Disc:
|
||||||
return SortTextForNumber(std::max(0, song.disc()));
|
return SortTextForNumber(std::max(0, song.disc()));
|
||||||
case GroupBy::Year:
|
case GroupBy::Year:
|
||||||
return SortTextForNumber(std::max(0, song.year())) + QLatin1Char(' ');
|
return SortTextForYear(song.year()) + QLatin1Char(' ');
|
||||||
case GroupBy::OriginalYear:
|
case GroupBy::OriginalYear:
|
||||||
return SortTextForNumber(std::max(0, song.effective_originalyear())) + QLatin1Char(' ');
|
return SortTextForYear(song.effective_originalyear()) + QLatin1Char(' ');
|
||||||
case GroupBy::Genre:
|
case GroupBy::Genre:
|
||||||
return SortTextForArtist(song.genre(), sort_skips_articles);
|
return SortText(song.genre());
|
||||||
case GroupBy::Composer:
|
case GroupBy::Composer:
|
||||||
return SortTextForArtist(song.composer(), sort_skips_articles);
|
return SortTextForName(use_sort_tags ? song.effective_composersort() : song.composer(), sort_skip_articles_for_artists);
|
||||||
case GroupBy::Performer:
|
case GroupBy::Performer:
|
||||||
return SortTextForArtist(song.performer(), sort_skips_articles);
|
return SortTextForName(use_sort_tags ? song.effective_performersort() : song.performer(), sort_skip_articles_for_artists);
|
||||||
case GroupBy::Grouping:
|
case GroupBy::Grouping:
|
||||||
return SortTextForArtist(song.grouping(), sort_skips_articles);
|
return SortText(song.grouping());
|
||||||
case GroupBy::FileType:
|
case GroupBy::FileType:
|
||||||
return song.TextForFiletype();
|
return song.TextForFiletype();
|
||||||
case GroupBy::Format:
|
case GroupBy::Format:
|
||||||
@@ -1135,21 +1144,9 @@ QString CollectionModel::SortText(QString text) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CollectionModel::SortTextForArtist(QString artist, const bool skip_articles) {
|
QString CollectionModel::SortTextForName(const QString &name, const bool sort_skip_articles) {
|
||||||
|
|
||||||
artist = SortText(artist);
|
return sort_skip_articles ? SkipArticles(SortText(name)) : SortText(name);
|
||||||
|
|
||||||
if (skip_articles) {
|
|
||||||
for (const auto &i : Song::kArticles) {
|
|
||||||
if (artist.startsWith(i)) {
|
|
||||||
qint64 ilen = i.length();
|
|
||||||
artist = artist.right(artist.length() - ilen) + ", "_L1 + i.left(ilen - 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return artist;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1168,18 +1165,32 @@ QString CollectionModel::SortTextForSong(const Song &song) {
|
|||||||
|
|
||||||
QString CollectionModel::SortTextForYear(const int year) {
|
QString CollectionModel::SortTextForYear(const int year) {
|
||||||
|
|
||||||
QString str = QString::number(year);
|
const QString str = QString::number(std::max(year, 0));
|
||||||
return QStringLiteral("0").repeated(qMax(0, 4 - str.length())) + str;
|
return QStringLiteral("0").repeated(qMax(0, 4 - str.length())) + str;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CollectionModel::SortTextForBitrate(const int bitrate) {
|
QString CollectionModel::SortTextForBitrate(const int bitrate) {
|
||||||
|
|
||||||
QString str = QString::number(bitrate);
|
const QString str = QString::number(bitrate);
|
||||||
return QStringLiteral("0").repeated(qMax(0, 3 - str.length())) + str;
|
return QStringLiteral("0").repeated(qMax(0, 3 - str.length())) + str;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString CollectionModel::SkipArticles(QString name) {
|
||||||
|
|
||||||
|
for (const auto &i : Song::kArticles) {
|
||||||
|
if (name.startsWith(i)) {
|
||||||
|
qint64 ilen = i.length();
|
||||||
|
name = name.right(name.length() - ilen) + ", "_L1 + i.left(ilen - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool CollectionModel::IsSongTitleDataChanged(const Song &song1, const Song &song2) {
|
bool CollectionModel::IsSongTitleDataChanged(const Song &song1, const Song &song2) {
|
||||||
|
|
||||||
return song1.url() != song2.url() ||
|
return song1.url() != song2.url() ||
|
||||||
@@ -1210,27 +1221,30 @@ QString CollectionModel::ContainerKey(const GroupBy group_by, const Song &song,
|
|||||||
if (options_active_.separate_albums_by_grouping && !song.grouping().isEmpty()) key.append(QLatin1Char('-') + song.grouping());
|
if (options_active_.separate_albums_by_grouping && !song.grouping().isEmpty()) key.append(QLatin1Char('-') + song.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy::AlbumDisc:
|
case GroupBy::AlbumDisc:
|
||||||
key = PrettyAlbumDisc(song.album(), song.disc());
|
key = TextOrUnknown(song.album());
|
||||||
|
key.append(QLatin1Char('-') + SortTextForNumber(song.disc()));
|
||||||
if (!song.album_id().isEmpty()) key.append(QLatin1Char('-') + song.album_id());
|
if (!song.album_id().isEmpty()) key.append(QLatin1Char('-') + song.album_id());
|
||||||
if (options_active_.separate_albums_by_grouping && !song.grouping().isEmpty()) key.append(QLatin1Char('-') + song.grouping());
|
if (options_active_.separate_albums_by_grouping && !song.grouping().isEmpty()) key.append(QLatin1Char('-') + song.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy::YearAlbum:
|
case GroupBy::YearAlbum:
|
||||||
key = PrettyYearAlbum(song.year(), song.album());
|
key = SortTextForYear(song.year()) + QLatin1Char('-') + TextOrUnknown(song.album());
|
||||||
if (!song.album_id().isEmpty()) key.append(QLatin1Char('-') + song.album_id());
|
if (!song.album_id().isEmpty()) key.append(QLatin1Char('-') + song.album_id());
|
||||||
if (options_active_.separate_albums_by_grouping && !song.grouping().isEmpty()) key.append(QLatin1Char('-') + song.grouping());
|
if (options_active_.separate_albums_by_grouping && !song.grouping().isEmpty()) key.append(QLatin1Char('-') + song.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy::YearAlbumDisc:
|
case GroupBy::YearAlbumDisc:
|
||||||
key = PrettyYearAlbumDisc(song.year(), song.album(), song.disc());
|
key = SortTextForYear(song.year()) + QLatin1Char('-') + TextOrUnknown(song.album());
|
||||||
|
key.append(QLatin1Char('-') + SortTextForNumber(song.disc()));
|
||||||
if (!song.album_id().isEmpty()) key.append(QLatin1Char('-') + song.album_id());
|
if (!song.album_id().isEmpty()) key.append(QLatin1Char('-') + song.album_id());
|
||||||
if (options_active_.separate_albums_by_grouping && !song.grouping().isEmpty()) key.append(QLatin1Char('-') + song.grouping());
|
if (options_active_.separate_albums_by_grouping && !song.grouping().isEmpty()) key.append(QLatin1Char('-') + song.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy::OriginalYearAlbum:
|
case GroupBy::OriginalYearAlbum:
|
||||||
key = PrettyYearAlbum(song.effective_originalyear(), song.album());
|
key = SortTextForYear(song.effective_originalyear()) + QLatin1Char('-') + TextOrUnknown(song.album());
|
||||||
if (!song.album_id().isEmpty()) key.append(QLatin1Char('-') + song.album_id());
|
if (!song.album_id().isEmpty()) key.append(QLatin1Char('-') + song.album_id());
|
||||||
if (options_active_.separate_albums_by_grouping && !song.grouping().isEmpty()) key.append(QLatin1Char('-') + song.grouping());
|
if (options_active_.separate_albums_by_grouping && !song.grouping().isEmpty()) key.append(QLatin1Char('-') + song.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy::OriginalYearAlbumDisc:
|
case GroupBy::OriginalYearAlbumDisc:
|
||||||
key = PrettyYearAlbumDisc(song.effective_originalyear(), song.album(), song.disc());
|
key = SortTextForYear(song.effective_originalyear()) + QLatin1Char('-') + TextOrUnknown(song.album());
|
||||||
|
key.append(QLatin1Char('-') + SortTextForNumber(song.disc()));
|
||||||
if (!song.album_id().isEmpty()) key.append(QLatin1Char('-') + song.album_id());
|
if (!song.album_id().isEmpty()) key.append(QLatin1Char('-') + song.album_id());
|
||||||
if (options_active_.separate_albums_by_grouping && !song.grouping().isEmpty()) key.append(QLatin1Char('-') + song.grouping());
|
if (options_active_.separate_albums_by_grouping && !song.grouping().isEmpty()) key.append(QLatin1Char('-') + song.grouping());
|
||||||
break;
|
break;
|
||||||
@@ -1238,10 +1252,10 @@ QString CollectionModel::ContainerKey(const GroupBy group_by, const Song &song,
|
|||||||
key = PrettyDisc(song.disc());
|
key = PrettyDisc(song.disc());
|
||||||
break;
|
break;
|
||||||
case GroupBy::Year:
|
case GroupBy::Year:
|
||||||
key = QString::number(std::max(0, song.year()));
|
key = SortTextForYear(song.year());
|
||||||
break;
|
break;
|
||||||
case GroupBy::OriginalYear:
|
case GroupBy::OriginalYear:
|
||||||
key = QString::number(std::max(0, song.effective_originalyear()));
|
key = SortTextForYear(song.effective_originalyear());
|
||||||
break;
|
break;
|
||||||
case GroupBy::Genre:
|
case GroupBy::Genre:
|
||||||
key = TextOrUnknown(song.genre());
|
key = TextOrUnknown(song.genre());
|
||||||
@@ -1333,7 +1347,7 @@ QString CollectionModel::DividerKey(const GroupBy group_by, const Song &song, co
|
|||||||
case GroupBy::Bitdepth:
|
case GroupBy::Bitdepth:
|
||||||
return SortTextForNumber(song.bitdepth());
|
return SortTextForNumber(song.bitdepth());
|
||||||
case GroupBy::Bitrate:
|
case GroupBy::Bitrate:
|
||||||
return SortTextForNumber(song.bitrate());
|
return SortTextForBitrate(song.bitrate());
|
||||||
case GroupBy::None:
|
case GroupBy::None:
|
||||||
case GroupBy::GroupByCount:
|
case GroupBy::GroupByCount:
|
||||||
return QString();
|
return QString();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2018-2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2018-2025, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -129,14 +129,18 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
show_dividers(true),
|
show_dividers(true),
|
||||||
show_pretty_covers(true),
|
show_pretty_covers(true),
|
||||||
show_various_artists(true),
|
show_various_artists(true),
|
||||||
sort_skips_articles(true),
|
sort_skip_articles_for_artists(false),
|
||||||
|
sort_skip_articles_for_albums(false),
|
||||||
|
use_sort_tags(true),
|
||||||
separate_albums_by_grouping(false) {}
|
separate_albums_by_grouping(false) {}
|
||||||
|
|
||||||
Grouping group_by;
|
Grouping group_by;
|
||||||
bool show_dividers;
|
bool show_dividers;
|
||||||
bool show_pretty_covers;
|
bool show_pretty_covers;
|
||||||
bool show_various_artists;
|
bool show_various_artists;
|
||||||
bool sort_skips_articles;
|
bool sort_skip_articles_for_artists;
|
||||||
|
bool sort_skip_articles_for_albums;
|
||||||
|
bool use_sort_tags;
|
||||||
bool separate_albums_by_grouping;
|
bool separate_albums_by_grouping;
|
||||||
CollectionFilterOptions filter_options;
|
CollectionFilterOptions filter_options;
|
||||||
};
|
};
|
||||||
@@ -183,13 +187,14 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
static QString PrettyYearAlbumDisc(const int year, const QString &album, const int disc);
|
static QString PrettyYearAlbumDisc(const int year, const QString &album, const int disc);
|
||||||
static QString PrettyDisc(const int disc);
|
static QString PrettyDisc(const int disc);
|
||||||
static QString PrettyFormat(const Song &song);
|
static QString PrettyFormat(const Song &song);
|
||||||
QString SortText(const GroupBy group_by, const Song &song, const bool sort_skips_articles);
|
static QString SortText(const GroupBy group_by, const Song &song, const bool sort_skip_articles_for_artists, const bool sort_skip_articles_for_albums, const bool use_sort_tags);
|
||||||
static QString SortText(QString text);
|
static QString SortText(QString text);
|
||||||
|
static QString SortTextForName(const QString &name, const bool sort_skip_articles);
|
||||||
static QString SortTextForNumber(const int number);
|
static QString SortTextForNumber(const int number);
|
||||||
static QString SortTextForArtist(QString artist, const bool skip_articles);
|
|
||||||
static QString SortTextForSong(const Song &song);
|
static QString SortTextForSong(const Song &song);
|
||||||
static QString SortTextForYear(const int year);
|
static QString SortTextForYear(const int year);
|
||||||
static QString SortTextForBitrate(const int bitrate);
|
static QString SortTextForBitrate(const int bitrate);
|
||||||
|
static QString SkipArticles(QString name);
|
||||||
static bool IsSongTitleDataChanged(const Song &song1, const Song &song2);
|
static bool IsSongTitleDataChanged(const Song &song1, const Song &song2);
|
||||||
QString ContainerKey(const GroupBy group_by, const Song &song, bool &has_unique_album_identifier) const;
|
QString ContainerKey(const GroupBy group_by, const Song &song, bool &has_unique_album_identifier) const;
|
||||||
|
|
||||||
@@ -228,7 +233,7 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
|
|
||||||
QVariant data(CollectionItem *item, const int role) const;
|
QVariant data(CollectionItem *item, const int role) const;
|
||||||
|
|
||||||
void ScheduleUpdate(const CollectionModelUpdate::Type type, const SongList &songs);
|
void ScheduleUpdate(const CollectionModelUpdate::Type type, const SongList &songs = SongList());
|
||||||
void ScheduleAddSongs(const SongList &songs);
|
void ScheduleAddSongs(const SongList &songs);
|
||||||
void ScheduleUpdateSongs(const SongList &songs);
|
void ScheduleUpdateSongs(const SongList &songs);
|
||||||
void ScheduleRemoveSongs(const SongList &songs);
|
void ScheduleRemoveSongs(const SongList &songs);
|
||||||
@@ -259,7 +264,7 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
static qint64 MaximumCacheSize(Settings *s, const char *size_id, const char *size_unit_id, const qint64 cache_size_default);
|
static qint64 MaximumCacheSize(Settings *s, const char *size_id, const char *size_unit_id, const qint64 cache_size_default);
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void Reload();
|
void ResetInternal();
|
||||||
void ScheduleReset();
|
void ScheduleReset();
|
||||||
void ProcessUpdate();
|
void ProcessUpdate();
|
||||||
void LoadSongsFromSqlAsyncFinished();
|
void LoadSongsFromSqlAsyncFinished();
|
||||||
@@ -278,7 +283,6 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
const SharedPtr<AlbumCoverLoader> albumcover_loader_;
|
const SharedPtr<AlbumCoverLoader> albumcover_loader_;
|
||||||
CollectionDirectoryModel *dir_model_;
|
CollectionDirectoryModel *dir_model_;
|
||||||
CollectionFilter *filter_;
|
CollectionFilter *filter_;
|
||||||
QTimer *timer_reload_;
|
|
||||||
QTimer *timer_update_;
|
QTimer *timer_update_;
|
||||||
|
|
||||||
QPixmap pixmap_no_cover_;
|
QPixmap pixmap_no_cover_;
|
||||||
|
|||||||
@@ -25,12 +25,13 @@
|
|||||||
class CollectionModelUpdate {
|
class CollectionModelUpdate {
|
||||||
public:
|
public:
|
||||||
enum class Type {
|
enum class Type {
|
||||||
|
Reset,
|
||||||
AddReAddOrUpdate,
|
AddReAddOrUpdate,
|
||||||
Add,
|
Add,
|
||||||
Update,
|
Update,
|
||||||
Remove,
|
Remove,
|
||||||
};
|
};
|
||||||
explicit CollectionModelUpdate(const Type _type, const SongList &_songs);
|
explicit CollectionModelUpdate(const Type _type, const SongList &_songs = SongList());
|
||||||
Type type;
|
Type type;
|
||||||
SongList songs;
|
SongList songs;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ CollectionPlaylistItem::CollectionPlaylistItem(const Song::Source source) : Play
|
|||||||
|
|
||||||
CollectionPlaylistItem::CollectionPlaylistItem(const Song &song) : PlaylistItem(song.source()), song_(song) {}
|
CollectionPlaylistItem::CollectionPlaylistItem(const Song &song) : PlaylistItem(song.source()), song_(song) {}
|
||||||
|
|
||||||
QUrl CollectionPlaylistItem::Url() const { return song_.url(); }
|
|
||||||
|
|
||||||
bool CollectionPlaylistItem::InitFromQuery(const SqlRow &query) {
|
bool CollectionPlaylistItem::InitFromQuery(const SqlRow &query) {
|
||||||
|
|
||||||
int col = 0;
|
int col = 0;
|
||||||
@@ -62,7 +60,7 @@ void CollectionPlaylistItem::Reload() {
|
|||||||
qLog(Error) << "Could not reload file" << song_.url() << result.error_string();
|
qLog(Error) << "Could not reload file" << song_.url() << result.error_string();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
UpdateTemporaryMetadata(song_);
|
UpdateStreamMetadata(song_);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -78,16 +76,9 @@ QVariant CollectionPlaylistItem::DatabaseValue(const DatabaseColumn database_col
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Song CollectionPlaylistItem::Metadata() const {
|
|
||||||
|
|
||||||
if (HasTemporaryMetadata()) return temp_metadata_;
|
|
||||||
return song_;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CollectionPlaylistItem::SetArtManual(const QUrl &cover_url) {
|
void CollectionPlaylistItem::SetArtManual(const QUrl &cover_url) {
|
||||||
|
|
||||||
song_.set_art_manual(cover_url);
|
song_.set_art_manual(cover_url);
|
||||||
if (HasTemporaryMetadata()) temp_metadata_.set_art_manual(cover_url);
|
if (HasStreamMetadata()) stream_song_.set_art_manual(cover_url);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,19 +35,17 @@ class CollectionPlaylistItem : public PlaylistItem {
|
|||||||
explicit CollectionPlaylistItem(const Song::Source source);
|
explicit CollectionPlaylistItem(const Song::Source source);
|
||||||
explicit CollectionPlaylistItem(const Song &song);
|
explicit CollectionPlaylistItem(const Song &song);
|
||||||
|
|
||||||
QUrl Url() const override;
|
Song OriginalMetadata() const override { return song_; }
|
||||||
|
void SetOriginalMetadata(const Song &song) override { song_ = song; }
|
||||||
|
|
||||||
|
QUrl OriginalUrl() const override { return song_.url(); }
|
||||||
|
bool IsLocalCollectionItem() const override { return song_.source() == Song::Source::Collection; }
|
||||||
|
|
||||||
bool InitFromQuery(const SqlRow &query) override;
|
bool InitFromQuery(const SqlRow &query) override;
|
||||||
void Reload() override;
|
void Reload() override;
|
||||||
|
|
||||||
Song Metadata() const override;
|
|
||||||
Song OriginalMetadata() const override { return song_; }
|
|
||||||
void SetMetadata(const Song &song) override { song_ = song; }
|
|
||||||
|
|
||||||
void SetArtManual(const QUrl &cover_url) override;
|
void SetArtManual(const QUrl &cover_url) override;
|
||||||
|
|
||||||
bool IsLocalCollectionItem() const override { return song_.source() == Song::Source::Collection; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QVariant DatabaseValue(const DatabaseColumn database_column) const override;
|
QVariant DatabaseValue(const DatabaseColumn database_column) const override;
|
||||||
Song DatabaseSongMetadata() const override { return Song(source_); }
|
Song DatabaseSongMetadata() const override { return Song(source_); }
|
||||||
@@ -60,4 +58,3 @@ class CollectionPlaylistItem : public PlaylistItem {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif // COLLECTIONPLAYLISTITEM_H
|
#endif // COLLECTIONPLAYLISTITEM_H
|
||||||
|
|
||||||
|
|||||||
@@ -101,9 +101,9 @@ void CollectionQuery::AddCompilationRequirement(const bool compilation) {
|
|||||||
QString CollectionQuery::GetInnerQuery() const {
|
QString CollectionQuery::GetInnerQuery() const {
|
||||||
return duplicates_only_
|
return duplicates_only_
|
||||||
? QStringLiteral(" INNER JOIN (select * from duplicated_songs) dsongs "
|
? QStringLiteral(" INNER JOIN (select * from duplicated_songs) dsongs "
|
||||||
"ON (%songs_table.artist = dsongs.dup_artist "
|
"ON (%songs_table.artist = dsongs.dup_artist "
|
||||||
"AND %songs_table.album = dsongs.dup_album "
|
"AND %songs_table.album = dsongs.dup_album "
|
||||||
"AND %songs_table.title = dsongs.dup_title) ")
|
"AND %songs_table.title = dsongs.dup_title) ")
|
||||||
: QString();
|
: QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,10 +65,8 @@
|
|||||||
#include "collectionitem.h"
|
#include "collectionitem.h"
|
||||||
#include "collectionitemdelegate.h"
|
#include "collectionitemdelegate.h"
|
||||||
#include "collectionview.h"
|
#include "collectionview.h"
|
||||||
#ifndef Q_OS_WIN32
|
#include "device/devicemanager.h"
|
||||||
# include "device/devicemanager.h"
|
#include "device/devicestatefiltermodel.h"
|
||||||
# include "device/devicestatefiltermodel.h"
|
|
||||||
#endif
|
|
||||||
#include "dialogs/edittagdialog.h"
|
#include "dialogs/edittagdialog.h"
|
||||||
#include "dialogs/deleteconfirmationdialog.h"
|
#include "dialogs/deleteconfirmationdialog.h"
|
||||||
#include "organize/organizedialog.h"
|
#include "organize/organizedialog.h"
|
||||||
@@ -95,9 +93,7 @@ CollectionView::CollectionView(QWidget *parent)
|
|||||||
action_open_in_new_playlist_(nullptr),
|
action_open_in_new_playlist_(nullptr),
|
||||||
action_organize_(nullptr),
|
action_organize_(nullptr),
|
||||||
action_search_for_this_(nullptr),
|
action_search_for_this_(nullptr),
|
||||||
#ifndef Q_OS_WIN32
|
|
||||||
action_copy_to_device_(nullptr),
|
action_copy_to_device_(nullptr),
|
||||||
#endif
|
|
||||||
action_edit_track_(nullptr),
|
action_edit_track_(nullptr),
|
||||||
action_edit_tracks_(nullptr),
|
action_edit_tracks_(nullptr),
|
||||||
action_rescan_songs_(nullptr),
|
action_rescan_songs_(nullptr),
|
||||||
@@ -417,9 +413,7 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
|
|
||||||
context_menu_->addSeparator();
|
context_menu_->addSeparator();
|
||||||
action_organize_ = context_menu_->addAction(IconLoader::Load(u"edit-copy"_s), tr("Organize files..."), this, &CollectionView::Organize);
|
action_organize_ = context_menu_->addAction(IconLoader::Load(u"edit-copy"_s), tr("Organize files..."), this, &CollectionView::Organize);
|
||||||
#ifndef Q_OS_WIN32
|
|
||||||
action_copy_to_device_ = context_menu_->addAction(IconLoader::Load(u"device"_s), tr("Copy to device..."), this, &CollectionView::CopyToDevice);
|
action_copy_to_device_ = context_menu_->addAction(IconLoader::Load(u"device"_s), tr("Copy to device..."), this, &CollectionView::CopyToDevice);
|
||||||
#endif
|
|
||||||
action_delete_files_ = context_menu_->addAction(IconLoader::Load(u"edit-delete"_s), tr("Delete from disk..."), this, &CollectionView::Delete);
|
action_delete_files_ = context_menu_->addAction(IconLoader::Load(u"edit-delete"_s), tr("Delete from disk..."), this, &CollectionView::Delete);
|
||||||
|
|
||||||
context_menu_->addSeparator();
|
context_menu_->addSeparator();
|
||||||
@@ -439,10 +433,8 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
|
|
||||||
context_menu_->addMenu(filter_widget_->menu());
|
context_menu_->addMenu(filter_widget_->menu());
|
||||||
|
|
||||||
#ifndef Q_OS_WIN32
|
|
||||||
action_copy_to_device_->setDisabled(device_manager_->connected_devices_model()->rowCount() == 0);
|
action_copy_to_device_->setDisabled(device_manager_->connected_devices_model()->rowCount() == 0);
|
||||||
QObject::connect(device_manager_->connected_devices_model(), &DeviceStateFilterModel::IsEmptyChanged, action_copy_to_device_, &QAction::setDisabled);
|
QObject::connect(device_manager_->connected_devices_model(), &DeviceStateFilterModel::IsEmptyChanged, action_copy_to_device_, &QAction::setDisabled);
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,9 +473,7 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
action_rescan_songs_->setEnabled(regular_editable > 0);
|
action_rescan_songs_->setEnabled(regular_editable > 0);
|
||||||
|
|
||||||
action_organize_->setVisible(regular_elements == regular_editable);
|
action_organize_->setVisible(regular_elements == regular_editable);
|
||||||
#ifndef Q_OS_WIN32
|
|
||||||
action_copy_to_device_->setVisible(regular_elements == regular_editable);
|
action_copy_to_device_->setVisible(regular_elements == regular_editable);
|
||||||
#endif
|
|
||||||
|
|
||||||
action_delete_files_->setVisible(delete_files_);
|
action_delete_files_->setVisible(delete_files_);
|
||||||
|
|
||||||
@@ -492,9 +482,7 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
|
|
||||||
// only when all selected items are editable
|
// only when all selected items are editable
|
||||||
action_organize_->setEnabled(regular_elements == regular_editable);
|
action_organize_->setEnabled(regular_elements == regular_editable);
|
||||||
#ifndef Q_OS_WIN32
|
|
||||||
action_copy_to_device_->setEnabled(regular_elements == regular_editable);
|
action_copy_to_device_->setEnabled(regular_elements == regular_editable);
|
||||||
#endif
|
|
||||||
|
|
||||||
action_delete_files_->setEnabled(delete_files_);
|
action_delete_files_->setEnabled(delete_files_);
|
||||||
|
|
||||||
@@ -759,7 +747,6 @@ void CollectionView::RescanSongs() {
|
|||||||
|
|
||||||
void CollectionView::CopyToDevice() {
|
void CollectionView::CopyToDevice() {
|
||||||
|
|
||||||
#ifndef Q_OS_WIN32
|
|
||||||
if (!organize_dialog_) {
|
if (!organize_dialog_) {
|
||||||
organize_dialog_ = make_unique<OrganizeDialog>(task_manager_, tagreader_client_, nullptr, this);
|
organize_dialog_ = make_unique<OrganizeDialog>(task_manager_, tagreader_client_, nullptr, this);
|
||||||
}
|
}
|
||||||
@@ -768,7 +755,6 @@ void CollectionView::CopyToDevice() {
|
|||||||
organize_dialog_->SetCopy(true);
|
organize_dialog_->SetCopy(true);
|
||||||
organize_dialog_->SetSongs(GetSelectedSongs());
|
organize_dialog_->SetSongs(GetSelectedSongs());
|
||||||
organize_dialog_->show();
|
organize_dialog_->show();
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -138,7 +138,6 @@ class CollectionView : public AutoExpandingTreeView {
|
|||||||
void DeleteFilesFinished(const SongList &songs_with_errors);
|
void DeleteFilesFinished(const SongList &songs_with_errors);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void RecheckIsEmpty();
|
|
||||||
void SetShowInVarious(const bool on);
|
void SetShowInVarious(const bool on);
|
||||||
bool RestoreLevelFocus(const QModelIndex &parent = QModelIndex());
|
bool RestoreLevelFocus(const QModelIndex &parent = QModelIndex());
|
||||||
void SaveContainerPath(const QModelIndex &child);
|
void SaveContainerPath(const QModelIndex &child);
|
||||||
@@ -176,9 +175,7 @@ class CollectionView : public AutoExpandingTreeView {
|
|||||||
QAction *action_organize_;
|
QAction *action_organize_;
|
||||||
QAction *action_search_for_this_;
|
QAction *action_search_for_this_;
|
||||||
|
|
||||||
#ifndef Q_OS_WIN32
|
|
||||||
QAction *action_copy_to_device_;
|
QAction *action_copy_to_device_;
|
||||||
#endif
|
|
||||||
QAction *action_edit_track_;
|
QAction *action_edit_track_;
|
||||||
QAction *action_edit_tracks_;
|
QAction *action_edit_tracks_;
|
||||||
QAction *action_rescan_songs_;
|
QAction *action_rescan_songs_;
|
||||||
|
|||||||
@@ -706,8 +706,14 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const CollectionSu
|
|||||||
qLog(Debug) << file << "is missing EBU R 128 loudness characteristics.";
|
qLog(Debug) << file << "is missing EBU R 128 loudness characteristics.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the song is unavailable and nothing has changed, just mark it as available without re-scanning
|
||||||
|
// For CUE files with multiple sections, all sections share the same file and would have the same availability status
|
||||||
|
if (matching_song.unavailable() && !changed && !missing_fingerprint && !missing_loudness_characteristics) {
|
||||||
|
qLog(Debug) << "Unavailable song" << file << "restored without re-scanning.";
|
||||||
|
t->readded_songs << matching_songs;
|
||||||
|
}
|
||||||
// The song's changed or missing fingerprint - create fingerprint and reread the metadata from file.
|
// The song's changed or missing fingerprint - create fingerprint and reread the metadata from file.
|
||||||
if (t->ignores_mtime() || changed || missing_fingerprint || missing_loudness_characteristics) {
|
else if (t->ignores_mtime() || changed || missing_fingerprint || missing_loudness_characteristics) {
|
||||||
|
|
||||||
QString fingerprint;
|
QString fingerprint;
|
||||||
#ifdef HAVE_SONGFINGERPRINTING
|
#ifdef HAVE_SONGFINGERPRINTING
|
||||||
@@ -728,12 +734,6 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const CollectionSu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nothing has changed - mark the song available without re-scanning
|
|
||||||
else if (matching_song.unavailable()) {
|
|
||||||
qLog(Debug) << "Unavailable song" << file << "restored.";
|
|
||||||
t->readded_songs << matching_songs;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else { // Search the DB by fingerprint.
|
else { // Search the DB by fingerprint.
|
||||||
QString fingerprint;
|
QString fingerprint;
|
||||||
@@ -999,6 +999,18 @@ void CollectionWatcher::AddChangedSong(const QString &file, const Song &matching
|
|||||||
changes << u"file path"_s;
|
changes << u"file path"_s;
|
||||||
notify_new = true;
|
notify_new = true;
|
||||||
}
|
}
|
||||||
|
if (matching_song.filetype() != new_song.filetype()) {
|
||||||
|
changes << u"filetype"_s;
|
||||||
|
notify_new = true;
|
||||||
|
}
|
||||||
|
if (matching_song.filesize() != new_song.filesize()) {
|
||||||
|
changes << u"filesize"_s;
|
||||||
|
notify_new = true;
|
||||||
|
}
|
||||||
|
if (matching_song.length_nanosec() != new_song.length_nanosec()) {
|
||||||
|
changes << u"length"_s;
|
||||||
|
notify_new = true;
|
||||||
|
}
|
||||||
if (matching_song.fingerprint() != new_song.fingerprint()) {
|
if (matching_song.fingerprint() != new_song.fingerprint()) {
|
||||||
changes << u"fingerprint"_s;
|
changes << u"fingerprint"_s;
|
||||||
notify_new = true;
|
notify_new = true;
|
||||||
@@ -1034,6 +1046,9 @@ void CollectionWatcher::AddChangedSong(const QString &file, const Song &matching
|
|||||||
if (matching_song.mtime() != new_song.mtime()) {
|
if (matching_song.mtime() != new_song.mtime()) {
|
||||||
changes << u"mtime"_s;
|
changes << u"mtime"_s;
|
||||||
}
|
}
|
||||||
|
if (matching_song.ctime() != new_song.ctime()) {
|
||||||
|
changes << u"ctime"_s;
|
||||||
|
}
|
||||||
|
|
||||||
if (changes.isEmpty()) {
|
if (changes.isEmpty()) {
|
||||||
qLog(Debug) << "Song" << file << "unchanged.";
|
qLog(Debug) << "Song" << file << "unchanged.";
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ class CollectionWatcher : public QObject {
|
|||||||
QStringList files_changed_path_;
|
QStringList files_changed_path_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ScanTransaction &operator=(const ScanTransaction&) { return *this; }
|
ScanTransaction &operator=(const ScanTransaction &transaction) { Q_UNUSED(transaction); return *this; }
|
||||||
|
|
||||||
int task_id_;
|
int task_id_;
|
||||||
quint64 progress_;
|
quint64 progress_;
|
||||||
@@ -261,7 +261,6 @@ class CollectionWatcher : public QObject {
|
|||||||
static QStringList sValidImages;
|
static QStringList sValidImages;
|
||||||
|
|
||||||
qint64 last_scan_time_;
|
qint64 last_scan_time_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline QString CollectionWatcher::NoExtensionPart(const QString &fileName) {
|
inline QString CollectionWatcher::NoExtensionPart(const QString &fileName) {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <QUrl>
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QKeySequence>
|
#include <QKeySequence>
|
||||||
@@ -167,14 +168,20 @@ void SavedGroupingManager::UpdateModel() {
|
|||||||
if (version == 1) {
|
if (version == 1) {
|
||||||
QStringList saved = s.childKeys();
|
QStringList saved = s.childKeys();
|
||||||
for (int i = 0; i < saved.size(); ++i) {
|
for (int i = 0; i < saved.size(); ++i) {
|
||||||
if (saved.at(i) == "version"_L1) continue;
|
const QString &name = saved.at(i);
|
||||||
QByteArray bytes = s.value(saved.at(i)).toByteArray();
|
if (name == "version"_L1) continue;
|
||||||
|
QByteArray bytes = s.value(name).toByteArray();
|
||||||
QDataStream ds(&bytes, QIODevice::ReadOnly);
|
QDataStream ds(&bytes, QIODevice::ReadOnly);
|
||||||
CollectionModel::Grouping g;
|
CollectionModel::Grouping g;
|
||||||
ds >> g;
|
ds >> g;
|
||||||
|
|
||||||
QList<QStandardItem*> list;
|
QList<QStandardItem*> list;
|
||||||
list << new QStandardItem(saved.at(i))
|
|
||||||
|
QStandardItem *item = new QStandardItem();
|
||||||
|
item->setText(QUrl::fromPercentEncoding(name.toUtf8()));
|
||||||
|
item->setData(name);
|
||||||
|
|
||||||
|
list << item
|
||||||
<< new QStandardItem(GroupByToString(g.first))
|
<< new QStandardItem(GroupByToString(g.first))
|
||||||
<< new QStandardItem(GroupByToString(g.second))
|
<< new QStandardItem(GroupByToString(g.second))
|
||||||
<< new QStandardItem(GroupByToString(g.third));
|
<< new QStandardItem(GroupByToString(g.third));
|
||||||
@@ -185,8 +192,9 @@ void SavedGroupingManager::UpdateModel() {
|
|||||||
else {
|
else {
|
||||||
QStringList saved = s.childKeys();
|
QStringList saved = s.childKeys();
|
||||||
for (int i = 0; i < saved.size(); ++i) {
|
for (int i = 0; i < saved.size(); ++i) {
|
||||||
if (saved.at(i) == "version"_L1) continue;
|
const QString &name = saved.at(i);
|
||||||
s.remove(saved.at(i));
|
if (name == "version"_L1) continue;
|
||||||
|
s.remove(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
@@ -202,7 +210,7 @@ void SavedGroupingManager::Remove() {
|
|||||||
for (const QModelIndex &idx : indexes) {
|
for (const QModelIndex &idx : indexes) {
|
||||||
if (idx.isValid()) {
|
if (idx.isValid()) {
|
||||||
qLog(Debug) << "Remove saved grouping: " << model_->item(idx.row(), 0)->text();
|
qLog(Debug) << "Remove saved grouping: " << model_->item(idx.row(), 0)->text();
|
||||||
s.remove(model_->item(idx.row(), 0)->text());
|
s.remove(model_->item(idx.row(), 0)->data().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|||||||
@@ -48,4 +48,7 @@
|
|||||||
|
|
||||||
#cmakedefine ENABLE_WIN32_CONSOLE
|
#cmakedefine ENABLE_WIN32_CONSOLE
|
||||||
|
|
||||||
|
#cmakedefine HAVE_VISUALIZATIONS
|
||||||
|
#cmakedefine HAVE_PROJECTM4
|
||||||
|
|
||||||
#endif // CONFIG_H_IN
|
#endif // CONFIG_H_IN
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef APPEARANCESETTINGS_H
|
#ifndef APPEARANCESETTINGS_H
|
||||||
#define APPEARANCESETTINGS_H
|
#define APPEARANCESETTINGS_H
|
||||||
@@ -70,6 +70,6 @@ enum class BackgroundImagePosition {
|
|||||||
BottomRight = 5
|
BottomRight = 5
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace AppearanceSettings
|
||||||
|
|
||||||
#endif // APPEARANCESETTINGS_H
|
#endif // APPEARANCESETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef BACKENDSETTINGS_H
|
#ifndef BACKENDSETTINGS_H
|
||||||
#define BACKENDSETTINGS_H
|
#define BACKENDSETTINGS_H
|
||||||
@@ -33,6 +33,7 @@ constexpr char kOutputU[] = "Output";
|
|||||||
constexpr char kDevice[] = "device";
|
constexpr char kDevice[] = "device";
|
||||||
constexpr char kDeviceU[] = "Device";
|
constexpr char kDeviceU[] = "Device";
|
||||||
constexpr char kALSAPlugin[] = "alsaplugin";
|
constexpr char kALSAPlugin[] = "alsaplugin";
|
||||||
|
constexpr char kPlaybin3[] = "playbin3";
|
||||||
constexpr char kExclusiveMode[] = "exclusive_mode";
|
constexpr char kExclusiveMode[] = "exclusive_mode";
|
||||||
constexpr char kVolumeControl[] = "volume_control";
|
constexpr char kVolumeControl[] = "volume_control";
|
||||||
constexpr char kChannelsEnabled[] = "channels_enabled";
|
constexpr char kChannelsEnabled[] = "channels_enabled";
|
||||||
@@ -62,6 +63,6 @@ constexpr qint64 kDefaultBufferDuration = 4000;
|
|||||||
constexpr double kDefaultBufferLowWatermark = 0.33;
|
constexpr double kDefaultBufferLowWatermark = 0.33;
|
||||||
constexpr double kDefaultBufferHighWatermark = 0.99;
|
constexpr double kDefaultBufferHighWatermark = 0.99;
|
||||||
|
|
||||||
} // namespace
|
} // namespace BackendSettings
|
||||||
|
|
||||||
#endif // BACKENDSETTINGS_H
|
#endif // BACKENDSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef BEHAVIOURSETTINGS_H
|
#ifndef BEHAVIOURSETTINGS_H
|
||||||
#define BEHAVIOURSETTINGS_H
|
#define BEHAVIOURSETTINGS_H
|
||||||
@@ -71,6 +71,6 @@ constexpr char kDoubleClickPlaylistAddMode[] = "doubleclick_playlist_addmode";
|
|||||||
constexpr char kSeekStepSec[] = "seek_step_sec";
|
constexpr char kSeekStepSec[] = "seek_step_sec";
|
||||||
constexpr char kVolumeIncrement[] = "volume_increment";
|
constexpr char kVolumeIncrement[] = "volume_increment";
|
||||||
|
|
||||||
} // namespace
|
} // namespace BehaviourSettings
|
||||||
|
|
||||||
#endif // BEHAVIOURSETTINGS_H
|
#endif // BEHAVIOURSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024-2025, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef COLLECTIONSETTINGS_H
|
#ifndef COLLECTIONSETTINGS_H
|
||||||
#define COLLECTIONSETTINGS_H
|
#define COLLECTIONSETTINGS_H
|
||||||
@@ -24,18 +24,20 @@ namespace CollectionSettings {
|
|||||||
|
|
||||||
constexpr char kSettingsGroup[] = "Collection";
|
constexpr char kSettingsGroup[] = "Collection";
|
||||||
|
|
||||||
|
constexpr char kStartupScan[] = "startup_scan";
|
||||||
|
constexpr char kMonitor[] = "monitor";
|
||||||
|
constexpr char kSongTracking[] = "song_tracking";
|
||||||
|
constexpr char kMarkSongsUnavailable[] = "mark_songs_unavailable";
|
||||||
|
constexpr char kSongENUR128LoudnessAnalysis[] = "song_ebur128_loudness_analysis";
|
||||||
|
constexpr char kExpireUnavailableSongs[] = "expire_unavailable_songs";
|
||||||
|
constexpr char kCoverArtPatterns[] = "cover_art_patterns";
|
||||||
constexpr char kAutoOpen[] = "auto_open";
|
constexpr char kAutoOpen[] = "auto_open";
|
||||||
constexpr char kShowDividers[] = "show_dividers";
|
constexpr char kShowDividers[] = "show_dividers";
|
||||||
constexpr char kPrettyCovers[] = "pretty_covers";
|
constexpr char kPrettyCovers[] = "pretty_covers";
|
||||||
constexpr char kVariousArtists[] = "various_artists";
|
constexpr char kVariousArtists[] = "various_artists";
|
||||||
constexpr char kSortSkipsArticles[] = "sort_skips_articles";
|
constexpr char kSkipArticlesForArtists[] = "skip_articles_for_artists";
|
||||||
constexpr char kStartupScan[] = "startup_scan";
|
constexpr char kSkipArticlesForAlbums[] = "skip_articles_for_albums";
|
||||||
constexpr char kMonitor[] = "monitor";
|
constexpr char kUseSortTags[] = "use_short_tags";
|
||||||
constexpr char kSongTracking[] = "song_tracking";
|
|
||||||
constexpr char kSongENUR128LoudnessAnalysis[] = "song_ebur128_loudness_analysis";
|
|
||||||
constexpr char kMarkSongsUnavailable[] = "mark_songs_unavailable";
|
|
||||||
constexpr char kExpireUnavailableSongs[] = "expire_unavailable_songs";
|
|
||||||
constexpr char kCoverArtPatterns[] = "cover_art_patterns";
|
|
||||||
constexpr char kSettingsCacheSize[] = "cache_size";
|
constexpr char kSettingsCacheSize[] = "cache_size";
|
||||||
constexpr char kSettingsCacheSizeUnit[] = "cache_size_unit";
|
constexpr char kSettingsCacheSizeUnit[] = "cache_size_unit";
|
||||||
constexpr char kSettingsDiskCacheEnable[] = "disk_cache_enable";
|
constexpr char kSettingsDiskCacheEnable[] = "disk_cache_enable";
|
||||||
@@ -57,6 +59,6 @@ enum class CacheSizeUnit {
|
|||||||
TB
|
TB
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace CollectionSettings
|
||||||
|
|
||||||
#endif // COLLECTIONSETTINGS_H
|
#endif // COLLECTIONSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CONTEXTSETTINGS_H
|
#ifndef CONTEXTSETTINGS_H
|
||||||
#define CONTEXTSETTINGS_H
|
#define CONTEXTSETTINGS_H
|
||||||
@@ -43,6 +43,6 @@ constexpr char kSettingsSummaryFmt[] = "SummaryFmt";
|
|||||||
constexpr char kDefaultFontFamily[] = "Noto Sans";
|
constexpr char kDefaultFontFamily[] = "Noto Sans";
|
||||||
constexpr qreal kDefaultFontSizeHeadline = 11;
|
constexpr qreal kDefaultFontSizeHeadline = 11;
|
||||||
|
|
||||||
} // namespace
|
} // namespace ContextSettings
|
||||||
|
|
||||||
#endif // CONTEXTSETTINGS_H
|
#endif // CONTEXTSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef COVERSSETTINGS_H
|
#ifndef COVERSSETTINGS_H
|
||||||
#define COVERSSETTINGS_H
|
#define COVERSSETTINGS_H
|
||||||
@@ -32,6 +32,6 @@ constexpr char kSaveOverwrite[] = "save_overwrite";
|
|||||||
constexpr char kSaveLowercase[] = "save_lowercase";
|
constexpr char kSaveLowercase[] = "save_lowercase";
|
||||||
constexpr char kSaveReplaceSpaces[] = "save_replace_spaces";
|
constexpr char kSaveReplaceSpaces[] = "save_replace_spaces";
|
||||||
|
|
||||||
} // namespace
|
} // namespace CoversSettings
|
||||||
|
|
||||||
#endif // COVERSSETTINGS_H
|
#endif // COVERSSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FILEFILTERCONSTANTS_H
|
#ifndef FILEFILTERCONSTANTS_H
|
||||||
#define FILEFILTERCONSTANTS_H
|
#define FILEFILTERCONSTANTS_H
|
||||||
@@ -27,10 +27,10 @@ constexpr char kAllFilesFilterSpec[] = QT_TRANSLATE_NOOP("FileFilter", "All File
|
|||||||
constexpr char kFileFilter[] =
|
constexpr char kFileFilter[] =
|
||||||
"*.wav *.flac *.wv *.ogg *.oga *.opus *.spx *.ape *.mpc "
|
"*.wav *.flac *.wv *.ogg *.oga *.opus *.spx *.ape *.mpc "
|
||||||
"*.mp2 *.mp3 *.m4a *.mp4 *.aac *.asf *.asx *.wma "
|
"*.mp2 *.mp3 *.m4a *.mp4 *.aac *.asf *.asx *.wma "
|
||||||
"*.aif *.aiff *.mka *.tta *.dsf *.dsd "
|
"*.aif *.aiff *.mka *.tta *.dsf *.dsd *.webm "
|
||||||
"*.cue *.m3u *.m3u8 *.pls *.xspf *.asxini "
|
"*.cue *.m3u *.m3u8 *.pls *.xspf *.asxini "
|
||||||
"*.ac3 *.dts "
|
"*.ac3 *.dts "
|
||||||
"*.mod *.s3m *.xm *.it"
|
"*.mod *.s3m *.xm *.it "
|
||||||
"*.spc *.vgm";
|
"*.spc *.vgm";
|
||||||
|
|
||||||
constexpr char kLoadImageFileFilter[] = QT_TRANSLATE_NOOP("FileFilter", "Images (*.png *.jpg *.jpeg *.bmp *.gif *.xpm *.pbm *.pgm *.ppm *.xbm)");
|
constexpr char kLoadImageFileFilter[] = QT_TRANSLATE_NOOP("FileFilter", "Images (*.png *.jpg *.jpeg *.bmp *.gif *.xpm *.pbm *.pgm *.ppm *.xbm)");
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2023, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2023, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FILENAMECONSTANTS_H
|
#ifndef FILENAMECONSTANTS_H
|
||||||
#define FILENAMECONSTANTS_H
|
#define FILENAMECONSTANTS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2025, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2025, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FILESYSTEMCONSTANTS_H
|
#ifndef FILESYSTEMCONSTANTS_H
|
||||||
#define FILESYSTEMCONSTANTS_H
|
#define FILESYSTEMCONSTANTS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef GLOBALSHORTCUTSSETTINGS_H
|
#ifndef GLOBALSHORTCUTSSETTINGS_H
|
||||||
#define GLOBALSHORTCUTSSETTINGS_H
|
#define GLOBALSHORTCUTSSETTINGS_H
|
||||||
@@ -26,6 +26,6 @@ constexpr char kSettingsGroup[] = "GlobalShortcuts";
|
|||||||
constexpr char kUseKGlobalAccel[] = "use_kglobalaccel";
|
constexpr char kUseKGlobalAccel[] = "use_kglobalaccel";
|
||||||
constexpr char kUseX11[] = "use_x11";
|
constexpr char kUseX11[] = "use_x11";
|
||||||
|
|
||||||
} // namespace
|
} // namespace GlobalShortcutsSettings
|
||||||
|
|
||||||
#endif // GLOBALSHORTCUTSSETTINGS_H
|
#endif // GLOBALSHORTCUTSSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LYRICSSETTINGS_H
|
#ifndef LYRICSSETTINGS_H
|
||||||
#define LYRICSSETTINGS_H
|
#define LYRICSSETTINGS_H
|
||||||
@@ -25,6 +25,6 @@ namespace LyricsSettings {
|
|||||||
constexpr char kSettingsGroup[] = "Lyrics";
|
constexpr char kSettingsGroup[] = "Lyrics";
|
||||||
constexpr char kProviders[] = "providers";
|
constexpr char kProviders[] = "providers";
|
||||||
|
|
||||||
} // namespace
|
} // namespace LyricsSettings
|
||||||
|
|
||||||
#endif // LYRICSSETTINGS_H
|
#endif // LYRICSSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MAINWINDOWSETTINGS_H
|
#ifndef MAINWINDOWSETTINGS_H
|
||||||
#define MAINWINDOWSETTINGS_H
|
#define MAINWINDOWSETTINGS_H
|
||||||
@@ -32,6 +32,6 @@ constexpr char kGeometry[] = "geometry";
|
|||||||
constexpr char kSplitterState[] = "splitter_state";
|
constexpr char kSplitterState[] = "splitter_state";
|
||||||
constexpr char kDoNotShowSponsorMessage[] = "do_not_show_sponsor_message";
|
constexpr char kDoNotShowSponsorMessage[] = "do_not_show_sponsor_message";
|
||||||
|
|
||||||
} // namespace
|
} // namespace MainWindowSettings
|
||||||
|
|
||||||
#endif // MAINWINDOWSETTINGS_H
|
#endif // MAINWINDOWSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MOODBARSETTINGS_H
|
#ifndef MOODBARSETTINGS_H
|
||||||
#define MOODBARSETTINGS_H
|
#define MOODBARSETTINGS_H
|
||||||
@@ -38,6 +38,6 @@ constexpr char kShow[] = "show";
|
|||||||
constexpr char kStyle[] = "style";
|
constexpr char kStyle[] = "style";
|
||||||
constexpr char kSave[] = "save";
|
constexpr char kSave[] = "save";
|
||||||
|
|
||||||
} // namespace
|
} // namespace MoodbarSettings
|
||||||
|
|
||||||
#endif // MOODBARSETTINGS_H
|
#endif // MOODBARSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef NETWORKPROXYSETTINGS_H
|
#ifndef NETWORKPROXYSETTINGS_H
|
||||||
#define NETWORKPROXYSETTINGS_H
|
#define NETWORKPROXYSETTINGS_H
|
||||||
@@ -32,6 +32,6 @@ constexpr char kUsername[] = "username";
|
|||||||
constexpr char kPassword[] = "password";
|
constexpr char kPassword[] = "password";
|
||||||
constexpr char kEngine[] = "engine";
|
constexpr char kEngine[] = "engine";
|
||||||
|
|
||||||
} // namespace
|
} // namespace NetworkProxySettings
|
||||||
|
|
||||||
#endif // NETWORKPROXYSETTINGS_H
|
#endif // NETWORKPROXYSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef NOTIFICATIONSSETTINGS_H
|
#ifndef NOTIFICATIONSSETTINGS_H
|
||||||
#define NOTIFICATIONSSETTINGS_H
|
#define NOTIFICATIONSSETTINGS_H
|
||||||
@@ -45,7 +45,7 @@ constexpr char kCustomTextEnabled[] = "CustomTextEnabled";
|
|||||||
constexpr char kCustomText1[] = "CustomText1";
|
constexpr char kCustomText1[] = "CustomText1";
|
||||||
constexpr char kCustomText2[] = "CustomText2";
|
constexpr char kCustomText2[] = "CustomText2";
|
||||||
|
|
||||||
} // namespace
|
} // namespace OSDSettings
|
||||||
|
|
||||||
namespace OSDPrettySettings {
|
namespace OSDPrettySettings {
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ constexpr char kFading[] = "fading";
|
|||||||
constexpr QRgb kPresetBlue = qRgb(102, 150, 227);
|
constexpr QRgb kPresetBlue = qRgb(102, 150, 227);
|
||||||
constexpr QRgb kPresetRed = qRgb(202, 22, 16);
|
constexpr QRgb kPresetRed = qRgb(202, 22, 16);
|
||||||
|
|
||||||
} // namespace
|
} // namespace OSDPrettySettings
|
||||||
|
|
||||||
namespace DiscordRPCSettings {
|
namespace DiscordRPCSettings {
|
||||||
|
|
||||||
@@ -71,6 +71,14 @@ constexpr char kSettingsGroup[] = "DiscordRPC";
|
|||||||
|
|
||||||
constexpr char kEnabled[] = "enabled";
|
constexpr char kEnabled[] = "enabled";
|
||||||
|
|
||||||
} // namespace
|
constexpr char kStatusDisplayType[] = "StatusDisplayType";
|
||||||
|
|
||||||
|
enum class StatusDisplayType {
|
||||||
|
App = 0,
|
||||||
|
Artist,
|
||||||
|
Song
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace DiscordRPCSettings
|
||||||
|
|
||||||
#endif // NOTIFICATIONSSETTINGS_H
|
#endif // NOTIFICATIONSSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef PLAYLISTSETTINGS_H
|
#ifndef PLAYLISTSETTINGS_H
|
||||||
#define PLAYLISTSETTINGS_H
|
#define PLAYLISTSETTINGS_H
|
||||||
@@ -63,7 +63,7 @@ constexpr char kLastSaveExtension[] = "last_save_extension";
|
|||||||
constexpr char kLastSaveAllPath[] = "last_save_all_path";
|
constexpr char kLastSaveAllPath[] = "last_save_all_path";
|
||||||
constexpr char kLastSaveAllExtension[] = "last_save_all_extension";
|
constexpr char kLastSaveAllExtension[] = "last_save_all_extension";
|
||||||
|
|
||||||
} // namespace
|
} // namespace PlaylistSettings
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(PlaylistSettings::PathType)
|
Q_DECLARE_METATYPE(PlaylistSettings::PathType)
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef QOBUZSETTINGS_H
|
#ifndef QOBUZSETTINGS_H
|
||||||
#define QOBUZSETTINGS_H
|
#define QOBUZSETTINGS_H
|
||||||
@@ -36,12 +36,13 @@ constexpr char kAlbumsSearchLimit[] = "albumssearchlimit";
|
|||||||
constexpr char kSongsSearchLimit[] = "songssearchlimit";
|
constexpr char kSongsSearchLimit[] = "songssearchlimit";
|
||||||
constexpr char kBase64Secret[] = "base64secret";
|
constexpr char kBase64Secret[] = "base64secret";
|
||||||
constexpr char kDownloadAlbumCovers[] = "downloadalbumcovers";
|
constexpr char kDownloadAlbumCovers[] = "downloadalbumcovers";
|
||||||
|
constexpr char kRemoveRemastered[] = "remove_remastered";
|
||||||
|
|
||||||
constexpr char kUserId[] = "user_id";
|
constexpr char kUserId[] = "user_id";
|
||||||
constexpr char kCredentialsId[] = "credentials_id";
|
constexpr char kCredentialsId[] = "credentials_id";
|
||||||
constexpr char kDeviceId[] = "device_id";
|
constexpr char kDeviceId[] = "device_id";
|
||||||
constexpr char kUserAuthToken[] = "user_auth_token";
|
constexpr char kUserAuthToken[] = "user_auth_token";
|
||||||
|
|
||||||
} // namespace
|
} // namespace QobuzSettings
|
||||||
|
|
||||||
#endif // QOBUZSETTINGS_H
|
#endif // QOBUZSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SCROBBLERSETTINGS_H
|
#ifndef SCROBBLERSETTINGS_H
|
||||||
#define SCROBBLERSETTINGS_H
|
#define SCROBBLERSETTINGS_H
|
||||||
@@ -35,6 +35,6 @@ constexpr char kStripRemastered[] = "strip_remastered";
|
|||||||
constexpr char kSources[] = "sources";
|
constexpr char kSources[] = "sources";
|
||||||
constexpr char kUserToken[] = "user_token";
|
constexpr char kUserToken[] = "user_token";
|
||||||
|
|
||||||
} // namespace
|
} // namespace ScrobblerSettings
|
||||||
|
|
||||||
#endif // SCROBBLERSETTINGS_H
|
#endif // SCROBBLERSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SPOTIFYSETTINGS_H
|
#ifndef SPOTIFYSETTINGS_H
|
||||||
#define SPOTIFYSETTINGS_H
|
#define SPOTIFYSETTINGS_H
|
||||||
@@ -31,12 +31,13 @@ constexpr char kAlbumsSearchLimit[] = "albumssearchlimit";
|
|||||||
constexpr char kSongsSearchLimit[] = "songssearchlimit";
|
constexpr char kSongsSearchLimit[] = "songssearchlimit";
|
||||||
constexpr char kFetchAlbums[] = "fetchalbums";
|
constexpr char kFetchAlbums[] = "fetchalbums";
|
||||||
constexpr char kDownloadAlbumCovers[] = "downloadalbumcovers";
|
constexpr char kDownloadAlbumCovers[] = "downloadalbumcovers";
|
||||||
|
constexpr char kRemoveRemastered[] = "remove_remastered";
|
||||||
|
|
||||||
constexpr char kAccessToken[] = "access_token";
|
constexpr char kAccessToken[] = "access_token";
|
||||||
constexpr char kRefreshToken[] = "refresh_token";
|
constexpr char kRefreshToken[] = "refresh_token";
|
||||||
constexpr char kExpiresIn[] = "expires_in";
|
constexpr char kExpiresIn[] = "expires_in";
|
||||||
constexpr char kLoginTime[] = "login_time";
|
constexpr char kLoginTime[] = "login_time";
|
||||||
|
|
||||||
} // namespace
|
} // namespace SpotifySettings
|
||||||
|
|
||||||
#endif // SPOTIFYSETTINGS_H
|
#endif // SPOTIFYSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef SUBSONICETTINGS_H
|
#ifndef SUBSONICETTINGS_H
|
||||||
@@ -41,6 +41,6 @@ constexpr char kUseAlbumIdForAlbumCovers[] = "usealbumidforalbumcovers";
|
|||||||
constexpr char kServerSideScrobbling[] = "serversidescrobbling";
|
constexpr char kServerSideScrobbling[] = "serversidescrobbling";
|
||||||
constexpr char kAuthMethod[] = "authmethod";
|
constexpr char kAuthMethod[] = "authmethod";
|
||||||
|
|
||||||
} // namespace
|
} // namespace SubsonicSettings
|
||||||
|
|
||||||
#endif // SUBSONICETTINGS_H
|
#endif // SUBSONICETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TIDALSETTINGS_H
|
#ifndef TIDALSETTINGS_H
|
||||||
#define TIDALSETTINGS_H
|
#define TIDALSETTINGS_H
|
||||||
@@ -40,6 +40,7 @@ constexpr char kDownloadAlbumCovers[] = "downloadalbumcovers";
|
|||||||
constexpr char kCoverSize[] = "coversize";
|
constexpr char kCoverSize[] = "coversize";
|
||||||
constexpr char kStreamUrl[] = "streamurl";
|
constexpr char kStreamUrl[] = "streamurl";
|
||||||
constexpr char kAlbumExplicit[] = "album_explicit";
|
constexpr char kAlbumExplicit[] = "album_explicit";
|
||||||
|
constexpr char kRemoveRemastered[] = "remove_remastered";
|
||||||
|
|
||||||
enum class StreamUrlMethod {
|
enum class StreamUrlMethod {
|
||||||
StreamUrl,
|
StreamUrl,
|
||||||
@@ -47,6 +48,6 @@ enum class StreamUrlMethod {
|
|||||||
PlaybackInfoPostPaywall
|
PlaybackInfoPostPaywall
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace TidalSettings
|
||||||
|
|
||||||
#endif // TIDALSETTINGS_H
|
#endif // TIDALSETTINGS_H
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Strawberry is distributed in the hope that it wiLL be useful,
|
* Strawberry is distributed in the hope that it wiLL be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TIMECONSTANTS_H
|
#ifndef TIMECONSTANTS_H
|
||||||
#define TIMECONSTANTS_H
|
#define TIMECONSTANTS_H
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user