Compare commits

...

108 Commits

Author SHA1 Message Date
Jonas Kvinge
38d49ceb64 Split into separate libraries 2025-01-22 18:34:04 +01:00
Jonas Kvinge
58fc8c82bb MainWindow: Maximize error dialog when window is shown 2025-01-22 17:51:16 +01:00
Jonas Kvinge
02bb875bb3 ErrorDialog: Only raise window if parent is maximized
Fixes #1627
2025-01-22 17:50:41 +01:00
Jonas Kvinge
5db01482eb Lazy: Fix bool 2025-01-22 17:49:52 +01:00
Jonas Kvinge
719fa6ffb3 MainWindow: Only hide window when system tray and keep running is enabled 2025-01-22 17:26:08 +01:00
Jonas Kvinge
159be5d79e MainWindow: Change close() to hide() in SetHiddenInTray
Otherwise close event is triggered causing Strawberry to quit.
2025-01-19 09:45:13 +01:00
Jonas Kvinge
911237e281 AnalyzerBase: Add missing parameter names 2025-01-19 09:42:00 +01:00
Jonas Kvinge
ae89ca8123 Turn on git revision 2025-01-17 12:34:43 +01:00
Jonas Kvinge
b832675893 Release 1.2.6 2025-01-17 10:27:48 +01:00
Jonas Kvinge
b4cfe636c9 TranscodeDialog: Fix mismatched definition 2025-01-17 09:15:55 +01:00
Jonas Kvinge
e6a0945dfa Call QObject::metaObject 2025-01-17 09:08:59 +01:00
Jonas Kvinge
726c105ed6 MoodbarItemDelegate: Remove delete of data
Memory is deleted in QCache::insert
2025-01-17 08:29:17 +01:00
Jonas Kvinge
d73cbc3a1d EngineBase: Fix mismatched definition 2025-01-17 08:26:11 +01:00
Jonas Kvinge
121f45d3b6 Playlist: Use sizeof playlist pointer to pointer 2025-01-17 07:22:49 +01:00
Jonas Kvinge
3a9ea81929 Queue: Fix sizeof, should be the pointer not the class 2025-01-17 07:12:25 +01:00
Jonas Kvinge
b919472241 Playlist: Correct sizeof 2025-01-17 06:56:08 +01:00
Jonas Kvinge
e8c8b39410 Turn on git revision 2025-01-17 04:29:05 +01:00
Jonas Kvinge
6904efef47 Release 1.2.5 2025-01-17 01:40:38 +01:00
Jonas Kvinge
fafa89baff CI: Disable GIO on Windows 2025-01-16 07:18:31 +01:00
Strawberry Bot
d9062446f5 New translations 2025-01-16 06:39:23 +01:00
Jonas Kvinge
9256b92d8f Update Changelog 2025-01-16 06:32:35 +01:00
Jonas Kvinge
f66459f3cb Make optional feature required unless disabled, add QtSparkle for macOS 2025-01-16 06:22:13 +01:00
Jonas Kvinge
f8ea9631ca Add sparkle 2025-01-15 23:03:40 +01:00
Jonas Kvinge
ab558f87b5 GstEnginePipeline: Use SetStateAsync in finish if needed 2025-01-15 07:01:43 +01:00
Jonas Kvinge
ab73eda2be Add mutex_protected_test 2025-01-15 07:00:28 +01:00
Jonas Kvinge
92f34ff36e mutex_protected: Add more operators 2025-01-15 07:00:16 +01:00
Strawberry Bot
d0bf2d7a9c New translations 2025-01-14 07:10:07 +01:00
Jonas Kvinge
b2cd3afe55 TagReaderClient: Add [[nodiscard]] 2025-01-14 06:36:15 +01:00
Jonas Kvinge
decd0a1dc6 TagReaderClient: Connect TagReaderReplyPtr
Makes sure TagReaderReplyPtr is not deleted too early.

Partial fix for #1633
2025-01-14 06:35:51 +01:00
Jonas Kvinge
3e0a9fa388 SettingsProvider: Use Settings
Fixes #1649
2025-01-13 12:22:31 +01:00
Jonas Kvinge
e5b6c5959f CMake: Use find_package for qtsparkle 2025-01-12 04:16:17 +01:00
Jonas Kvinge
8a9db5440d rpm: Enable unit tests on Fedora 2025-01-11 01:39:26 +01:00
Jonas Kvinge
28a25c5763 CMake: Fix add_test 2025-01-11 01:37:06 +01:00
dependabot[bot]
ea49fbcbee Bump vmactions/openbsd-vm from 1.1.5 to 1.1.6
Bumps [vmactions/openbsd-vm](https://github.com/vmactions/openbsd-vm) from 1.1.5 to 1.1.6.
- [Release notes](https://github.com/vmactions/openbsd-vm/releases)
- [Commits](https://github.com/vmactions/openbsd-vm/compare/v1.1.5...v1.1.6)

---
updated-dependencies:
- dependency-name: vmactions/openbsd-vm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-11 00:37:52 +01:00
Jonas Kvinge
d9807b358e GioLister: Fix use of deprecated functions 2025-01-11 00:35:24 +01:00
Jonas Kvinge
3e53d2b237 CI: Add -Wno-maybe-uninitialized for Fedora 2025-01-11 00:35:24 +01:00
Jonas Kvinge
9122881f74 CI: Bump GCC on openSUSE Leap 2025-01-11 00:35:24 +01:00
Jonas Kvinge
9c36d7fd43 rpm: Add BUILD_WERROR 2025-01-11 00:35:24 +01:00
Jonas Kvinge
a4a365cbee CI: Set RPM_BUILD_NCPUS to 4 2025-01-11 00:35:24 +01:00
Jonas Kvinge
00f06b22b8 CMake: Check for gmock 2025-01-11 00:35:24 +01:00
Jonas Kvinge
e2d8838fca rpm: Run unit tests 2025-01-11 00:35:24 +01:00
Jonas Kvinge
9427691f39 CI: Install gtest and gmock for openSUSE, Fedora and Mageia 2025-01-11 00:35:24 +01:00
Jonas Kvinge
bebdcc4e7f CollectionModel: Simply data function 2025-01-10 17:47:30 +01:00
Jonas Kvinge
041f761921 test_utils: Fix Q_ASSERT 2025-01-10 15:35:15 +01:00
Jonas Kvinge
1435ae6dc0 Turn on git revision 2025-01-10 15:08:04 +01:00
Jonas Kvinge
33ae53a90f Release 1.2.4 2025-01-10 02:26:41 +01:00
Strawberry Bot
01c28867b7 New translations 2025-01-10 02:10:44 +01:00
Jonas Kvinge
08fb2ae331 Update Changelog 2025-01-10 01:58:19 +01:00
Jonas Kvinge
99970f9e52 Update strawberry_en_US.ts 2025-01-10 01:58:19 +01:00
Jonas Kvinge
bc206f43b4 TranscodeDialog: Minor adjustments 2025-01-10 01:58:19 +01:00
dependabot[bot]
018448159c Bump vmactions/freebsd-vm from 1.1.7 to 1.1.8
Bumps [vmactions/freebsd-vm](https://github.com/vmactions/freebsd-vm) from 1.1.7 to 1.1.8.
- [Release notes](https://github.com/vmactions/freebsd-vm/releases)
- [Commits](https://github.com/vmactions/freebsd-vm/compare/v1.1.7...v1.1.8)

---
updated-dependencies:
- dependency-name: vmactions/freebsd-vm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-10 01:27:57 +01:00
Jonas Kvinge
81fe90bdef Update Changelog 2025-01-10 01:07:32 +01:00
Jonas Kvinge
319558c535 tests: Fixed ignored return value 2025-01-10 00:58:41 +01:00
Jonas Kvinge
9095b0d6b2 Always run MSVC runtime installer 2025-01-08 19:34:27 +01:00
Jonas Kvinge
558eae1ca1 Remove unneeded slots 2025-01-08 04:57:17 +01:00
Jonas Kvinge
2c64f05cea MoodbarProxyStyle: Add const 2025-01-08 04:54:45 +01:00
Jonas Kvinge
c80e7071a1 StandardPaths: Fix namespace 2025-01-07 22:13:24 +01:00
Jonas Kvinge
038e679000 SmartPlaylistWizard: Apply dark mode workaround for all styles except vista
Fixes #1639
2025-01-07 22:04:28 +01:00
Jonas Kvinge
72447fecfb StandardPaths: Remove inheritance 2025-01-07 21:40:06 +01:00
Jonas Kvinge
c7830f6f05 MoodbarPipeline: Cleanup on finish 2025-01-07 01:09:49 +01:00
Jonas Kvinge
af525e42b6 MoodbarPipeline: Remove Q_ASSERT 2025-01-06 21:28:44 +01:00
Jonas Kvinge
eb83f23125 MoodbarPipeline: Use bytearray directly 2025-01-06 21:28:33 +01:00
Jonas Kvinge
7527d2ea9a MoodbarLoader: Set object name 2025-01-06 18:11:38 +01:00
Jonas Kvinge
69d38879d2 Use QCoreApplication::applicationName() directly 2025-01-06 00:38:51 +01:00
Jonas Kvinge
cbce9f7191 Override config, data and cache location 2025-01-05 23:45:29 +01:00
Jonas Kvinge
f938129d81 CI: Fix deb copy command 2025-01-05 21:22:08 +01:00
Jonas Kvinge
415a40ea04 FilterParser: Ignore space after operator 2025-01-05 20:25:48 +01:00
Jonas Kvinge
6e7aaed4ee Use QSharedPointer for GstEnginePipeline 2025-01-05 19:03:16 +01:00
Jonas Kvinge
7afae70bb0 GstEnginePipeline: Make sure all set states are finished before finishing pipeline 2025-01-05 18:58:03 +01:00
Jonas Kvinge
be8097919b mutex_protected: Add operator ++ and -- 2025-01-05 18:56:22 +01:00
Jonas Kvinge
1990a42e1d CI: Don't run build on l10n_master branch 2025-01-05 18:53:19 +01:00
Kyle Hopkins
8fcee4511d TranscodeDialog: update to optionally preserve directory structure 2025-01-05 18:34:14 +01:00
Leandro Matheus
24af1be666 Subsonic: Add support for using album id to retrieve album covers 2025-01-05 18:30:24 +01:00
Jonas Kvinge
8302a95bc1 Use shared pointers for moodbar pipelines
Possible fix for #1633
2025-01-05 18:28:41 +01:00
Jonas Kvinge
36a8ab49a0 MoodbarItemDelegate: Format comment 2025-01-05 03:51:00 +01:00
Jonas Kvinge
5c64dc9c4d MoodbarItemDelegate: Delete data if it fails to insert to cache 2025-01-05 03:50:51 +01:00
Strawberry Bot
c271743208 New translations 2025-01-05 00:22:50 +01:00
Jonas Kvinge
ee49b1ddc8 Update strawberry_en_US.ts 2025-01-04 04:56:08 +01:00
Jonas Kvinge
bf98633f16 Load XSPF title as playlist name 2025-01-04 04:52:17 +01:00
Jonas Kvinge
e2a928f2dc Save XSPF playlist with title
Fixes #1624
2025-01-04 03:48:53 +01:00
Jonas Kvinge
47d3312a6b PlaylistManager: Remove slash from playlist filename 2025-01-04 03:46:03 +01:00
Jonas Kvinge
4f97325953 CollectionSettingsPage: Fix string conversion 2025-01-04 03:32:50 +01:00
Jonas Kvinge
91e8fe0943 ScrobblerSettingsPage: Add tooltip 2025-01-04 03:15:38 +01:00
Jonas Kvinge
dc5894b38a CollectionWatcher: Ignore special filesystem paths
Fixes #1615
2025-01-04 03:06:46 +01:00
Jonas Kvinge
52ee50a2a4 CollectionSettingsPage: Add check for filesystem type 2025-01-04 02:58:59 +01:00
Jonas Kvinge
f545b028ee Add filesystem constants 2025-01-04 02:58:17 +01:00
Jonas Kvinge
a96627c5a9 Playlist: Invalidate deleted songs in main thread
Fixes #1625
2025-01-04 00:16:36 +01:00
Jonas Kvinge
a13fc31f83 PlaylistManager: Remove unused InvalidateDeletedSongs function 2025-01-04 00:09:26 +01:00
Jonas Kvinge
9ee5c8dc17 Playlist: Update copyright 2025-01-03 23:41:43 +01:00
Jonas Kvinge
82cd425ece Playlist: Add const 2025-01-03 23:41:30 +01:00
Jonas Kvinge
3b02d364ba Playlist: Rename some variables 2025-01-03 23:41:15 +01:00
dependabot[bot]
73e7947487 Bump vmactions/openbsd-vm from 1.1.4 to 1.1.5
Bumps [vmactions/openbsd-vm](https://github.com/vmactions/openbsd-vm) from 1.1.4 to 1.1.5.
- [Release notes](https://github.com/vmactions/openbsd-vm/releases)
- [Commits](https://github.com/vmactions/openbsd-vm/compare/v1.1.4...v1.1.5)

---
updated-dependencies:
- dependency-name: vmactions/openbsd-vm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-30 17:38:02 +01:00
dependabot[bot]
cfc9a43b88 Bump vmactions/freebsd-vm from 1.1.6 to 1.1.7
Bumps [vmactions/freebsd-vm](https://github.com/vmactions/freebsd-vm) from 1.1.6 to 1.1.7.
- [Release notes](https://github.com/vmactions/freebsd-vm/releases)
- [Commits](https://github.com/vmactions/freebsd-vm/compare/v1.1.6...v1.1.7)

---
updated-dependencies:
- dependency-name: vmactions/freebsd-vm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-30 17:37:32 +01:00
dependabot[bot]
969500023a Bump vmactions/freebsd-vm from 1.1.5 to 1.1.6
Bumps [vmactions/freebsd-vm](https://github.com/vmactions/freebsd-vm) from 1.1.5 to 1.1.6.
- [Release notes](https://github.com/vmactions/freebsd-vm/releases)
- [Commits](https://github.com/vmactions/freebsd-vm/compare/v1.1.5...v1.1.6)

---
updated-dependencies:
- dependency-name: vmactions/freebsd-vm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-26 00:44:32 +01:00
Jonas Kvinge
53c72d4f8e CollectionModel: Don't use artist sort text for album 2024-12-17 22:38:04 +01:00
Jonas Kvinge
f971c92f32 Move debian back to source dir
PPA failed to build
2024-12-17 21:57:37 +01:00
Strawberry Bot
82156e8a13 New translations 2024-12-17 00:01:04 +01:00
dependabot[bot]
6a6285861e Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 23:59:25 +01:00
Jonas Kvinge
dae8c8730b debian: Remove whitespaces 2024-12-14 18:33:40 +01:00
Jonas Kvinge
20b47eae8f CI: Use -j 4 for Ubuntu 2024-12-14 18:33:29 +01:00
Jonas Kvinge
2ce8220d88 Move generated files to binary directory 2024-12-14 17:59:26 +01:00
Jonas Kvinge
35b0b5df57 CMake: Fix backtrace linking 2024-12-14 15:47:45 +01:00
Jonas Kvinge
63631d6b0c CMake: Fix backtrace linking 2024-12-14 05:30:31 +01:00
Jonas Kvinge
21ab2ef1a7 CI: Add FreeBSD and OpenBSD 2024-12-14 05:01:40 +01:00
Jonas Kvinge
a3f96d2b85 CMake: Link Backtrace 2024-12-14 05:01:14 +01:00
Jonas Kvinge
e2c1cb0116 Formatting 2024-12-14 00:55:53 +01:00
Jonas Kvinge
07e295776b Add Spotify to scrobbler 2024-12-10 01:29:57 +01:00
Jonas Kvinge
8604a39d94 Turn on git revision 2024-12-08 17:29:14 +01:00
282 changed files with 7248 additions and 5671 deletions

View File

@@ -10,7 +10,7 @@ jobs:
build-opensuse:
name: Build openSUSE
if: github.repository != 'strawberrymusicplayer/strawberry-private' && (!(github.event.pusher.name == 'strawbsbot' && contains(github.event.head_commit.message, 'New translations')))
if: github.repository != 'strawberrymusicplayer/strawberry-private' && github.ref != 'refs/heads/l10n_master'
runs-on: ubuntu-latest
strategy:
fail-fast: false
@@ -21,18 +21,18 @@ jobs:
steps:
- name: Refresh repositories
run: zypper -n --gpg-auto-import-keys ref
- name: Upgrade packages
- name: Upgrade packages (Tumbleweed)
if: matrix.opensuse_version == 'tumbleweed'
run: zypper -n --gpg-auto-import-keys dup
- name: Upgrade packages
- name: Upgrade packages (Leap)
if: matrix.opensuse_version != 'tumbleweed'
run: zypper -n --gpg-auto-import-keys up
- name: Install gcc
- name: Install gcc (Tumbleweed)
if: matrix.opensuse_version == 'tumbleweed'
run: zypper -n --gpg-auto-import-keys in gcc gcc-c++
- name: Install gcc 13
- name: Install gcc (Leap)
if: matrix.opensuse_version != 'tumbleweed'
run: zypper -n --gpg-auto-import-keys in gcc13 gcc13-c++
run: zypper -n --gpg-auto-import-keys in gcc14 gcc14-c++
- name: Install packages
run: >
zypper -n --gpg-auto-import-keys in
@@ -77,6 +77,8 @@ jobs:
qt6-base-common-devel
qt6-sql-sqlite
qt6-linguist-devel
gtest
gmock
- name: Install kdsingleapplication-qt6-devel
if: matrix.opensuse_version == 'tumbleweed'
run: zypper -n --gpg-auto-import-keys in kdsingleapplication-qt6-devel
@@ -101,15 +103,18 @@ jobs:
run: cp strawberry-*.tar.xz /usr/src/packages/SOURCES/
- name: Build RPM (Tumbleweed)
if: matrix.opensuse_version == 'tumbleweed'
env:
RPM_BUILD_NCPUS: 4
working-directory: build
run: rpmbuild -ba ../dist/unix/strawberry.spec
run: rpmbuild -ba strawberry.spec
- name: Build RPM (Leap)
if: matrix.opensuse_version != 'tumbleweed'
working-directory: build
env:
CC: gcc-13
CXX: g++-13
run: rpmbuild -ba ../dist/unix/strawberry.spec
RPM_BUILD_NCPUS: 4
CC: gcc-14
CXX: g++-14
working-directory: build
run: rpmbuild -ba strawberry.spec
- name: Set subdir
id: set-subdir
run: echo "subdir=$(echo ${{matrix.opensuse_version}} | sed 's/leap:/lp/g' | sed 's/\.//g')" > $GITHUB_OUTPUT
@@ -132,7 +137,7 @@ jobs:
build-fedora:
name: Build Fedora
if: github.repository != 'strawberrymusicplayer/strawberry-private' && (!(github.event.pusher.name == 'strawbsbot' && contains(github.event.head_commit.message, 'New translations')))
if: github.repository != 'strawberrymusicplayer/strawberry-private' && github.ref != 'refs/heads/l10n_master'
runs-on: ubuntu-latest
strategy:
fail-fast: false
@@ -185,6 +190,8 @@ jobs:
libappstream-glib
hicolor-icon-theme
kdsingleapplication-qt6-devel
gtest-devel
gmock-devel
- name: Checkout
uses: actions/checkout@v4
with:
@@ -207,9 +214,9 @@ jobs:
run: cp strawberry-*.tar.xz ~/rpmbuild/SOURCES/
- name: Build RPM
env:
RPM_BUILD_NCPUS: "2"
RPM_BUILD_NCPUS: 4
working-directory: build
run: rpmbuild -ba ../dist/unix/strawberry.spec
run: rpmbuild -ba strawberry.spec
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
@@ -221,7 +228,7 @@ jobs:
build-openmandriva:
name: Build OpenMandriva
if: github.repository != 'strawberrymusicplayer/strawberry-private' && false
if: github.repository != 'strawberrymusicplayer/strawberry-private' && github.ref != 'refs/heads/l10n_master' && false
runs-on: ubuntu-latest
strategy:
fail-fast: false
@@ -300,9 +307,9 @@ jobs:
run: cp strawberry-*.tar.xz ~/rpmbuild/SOURCES/
- name: Build RPM
env:
RPM_BUILD_NCPUS: "2"
RPM_BUILD_NCPUS: 4
working-directory: build
run: rpmbuild -ba ../dist/unix/strawberry.spec
run: rpmbuild -ba strawberry.spec
- name: Upload artifacts
if: matrix.openmandriva_version != 'cooker'
uses: actions/upload-artifact@v4
@@ -315,7 +322,7 @@ jobs:
build-mageia:
name: Build Mageia
if: github.repository != 'strawberrymusicplayer/strawberry-private' && (!(github.event.pusher.name == 'strawbsbot' && contains(github.event.head_commit.message, 'New translations')))
if: github.repository != 'strawberrymusicplayer/strawberry-private' && github.ref != 'refs/heads/l10n_master'
runs-on: ubuntu-latest
strategy:
fail-fast: false
@@ -374,6 +381,7 @@ jobs:
desktop-file-utils
appstream-util
hicolor-icon-theme
gtest
- name: Checkout
uses: actions/checkout@v4
with:
@@ -396,9 +404,9 @@ jobs:
run: cp strawberry-*.tar.xz ~/rpmbuild/SOURCES/
- name: Build RPM
env:
RPM_BUILD_NCPUS: "2"
RPM_BUILD_NCPUS: 4
working-directory: build
run: rpmbuild -ba ../dist/unix/strawberry.spec
run: rpmbuild -ba strawberry.spec
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
@@ -410,7 +418,7 @@ jobs:
build-debian:
name: Build Debian
if: github.repository != 'strawberrymusicplayer/strawberry-private' && (!(github.event.pusher.name == 'strawbsbot' && contains(github.event.head_commit.message, 'New translations')))
if: github.repository != 'strawberrymusicplayer/strawberry-private' && github.ref != 'refs/heads/l10n_master'
runs-on: ubuntu-latest
strategy:
fail-fast: false
@@ -471,21 +479,24 @@ jobs:
- name: Create Build Environment
run: cmake -E make_directory build
- name: Configure CMake
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DBUILD_WERROR=ON
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_WERROR=ON
- name: Delete build directory
run: rm -rf build
- name: make deb
run: dpkg-buildpackage -b -d -uc -us -nc -j2
run: dpkg-buildpackage -b -d -uc -us -nc -j4
- name: Copy deb
run: cp ../*.deb .
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: debian-${{matrix.debian_version}}
path: "*.deb"
path: |
*.deb
build-ubuntu:
name: Build Ubuntu
if: github.repository != 'strawberrymusicplayer/strawberry-private' && (!(github.event.pusher.name == 'strawbsbot' && contains(github.event.head_commit.message, 'New translations')))
if: github.repository != 'strawberrymusicplayer/strawberry-private' && github.ref != 'refs/heads/l10n_master'
runs-on: ubuntu-latest
strategy:
fail-fast: false
@@ -549,9 +560,11 @@ jobs:
- name: Create Build Environment
run: cmake -E make_directory build
- name: Configure CMake
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DBUILD_WERROR=ON
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_WERROR=ON
- name: Delete build directory
run: rm -rf build
- name: make deb
run: dpkg-buildpackage -b -d -uc -us -nc -j2
run: dpkg-buildpackage -b -d -uc -us -nc -j4
- name: Copy deb
run: cp ../*.deb ../*.ddeb .
- name: Upload artifacts
@@ -565,7 +578,7 @@ jobs:
upload-ubuntu-ppa:
name: Upload Ubuntu PPA
if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false && (github.event_name == 'release' || (github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/ci' || github.ref == 'refs/heads/1.1'))) && (!(github.event.pusher.name == 'strawbsbot' && contains(github.event.head_commit.message, 'New translations')))
if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false && (github.event_name == 'release' || (github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/ci' || github.ref == 'refs/heads/1.1')))
runs-on: ubuntu-latest
strategy:
fail-fast: false
@@ -634,7 +647,7 @@ jobs:
- name: Create Build Environment
run: cmake -E make_directory build
- name: Configure CMake
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DBUILD_WERROR=ON
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_WERROR=ON
- name: Delete build directory
run: rm -rf build
- name: Import Ubuntu PPA GPG private key
@@ -651,9 +664,60 @@ jobs:
run: dput ppa:jonaski/strawberry ../*_source.changes
build-freebsd:
name: Build FreeBSD
if: github.repository != 'strawberrymusicplayer/strawberry-private' && github.ref != 'refs/heads/l10n_master'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
- name: Build FreeBSD
id: build-freebsd
uses: vmactions/freebsd-vm@v1.1.8
with:
usesh: true
mem: 4096
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
run: |
set -e
git config --global --add safe.directory ${GITHUB_WORKSPACE}
cmake -E make_directory build
cmake -S . -B build -DCMAKE_BUILD_TYPE="Debug"
cmake --build build --config Debug --parallel 4
build-openbsd:
name: Build OpenBSD
if: github.repository != 'strawberrymusicplayer/strawberry-private' && github.ref != 'refs/heads/l10n_master'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
- name: Build OpenBSD
id: build-openbsd
uses: vmactions/openbsd-vm@v1.1.6
with:
usesh: true
mem: 4096
prepare: pkg_add git cmake pkgconf boost glib2 qt6-qtbase qt6-qttools sqlite gstreamer1 gstreamer1-plugins-base chromaprint libebur128 taglib libcdio libmtp gdk-pixbuf libgpod fftw3 icu4c kdsingleapplication pulseaudio
run: |
set -e
export LDFLAGS="-L/usr/local/lib"
git config --global --add safe.directory ${GITHUB_WORKSPACE}
cmake -E make_directory build
cmake -S . -B build -DCMAKE_BUILD_TYPE="Debug" -DENABLE_ALSA=OFF
cmake --build build --config Debug --parallel 4
build-macos-public:
name: Build macOS Public
if: github.repository != 'strawberrymusicplayer/strawberry-private' && (!(github.event.pusher.name == 'strawbsbot' && contains(github.event.head_commit.message, 'New translations')))
if: github.repository != 'strawberrymusicplayer/strawberry-private' && github.ref != 'refs/heads/l10n_master'
strategy:
fail-fast: false
@@ -737,10 +801,12 @@ jobs:
-DCMAKE_PREFIX_PATH="${{env.prefix_path}}/lib/cmake"
-DBUILD_WERROR=ON
-DUSE_BUNDLE=ON
-DENABLE_DBUS=OFF
-DICU_ROOT="${{env.prefix_path}}"
-DAPPLE_DEVELOPER_ID=$(test '${{github.repository}}' = 'strawberrymusicplayer/strawberry' && test '${{github.event.pull_request.base.repo.full_name}}' = '${{github.event.pull_request.head.repo.full_name}}' && echo "383J84DVB6" || echo "")
-DARCH="${{env.arch}}"
-DENABLE_SPOTIFY=$(test -f "${{env.prefix_path}}/lib/gstreamer-1.0/libgstspotify.dylib" && echo "ON" || echo "OFF")
-DENABLE_SPARKLE=ON
-DENABLE_QTSPARKLE=OFF
- name: Build
run: cmake --build build --config Release --parallel 4
@@ -876,10 +942,12 @@ jobs:
-DCMAKE_PREFIX_PATH="${{env.prefix_path}}/lib/cmake"
-DBUILD_WERROR=ON
-DUSE_BUNDLE=ON
-DENABLE_DBUS=OFF
-DICU_ROOT="${{env.prefix_path}}"
-DAPPLE_DEVELOPER_ID="383J84DVB6"
-DARCH="${{env.arch}}"
-DENABLE_SPOTIFY=$(test -f "${{env.prefix_path}}/lib/gstreamer-1.0/libgstspotify.dylib" && echo "ON" || echo "OFF")
-DENABLE_SPARKLE=ON
-DENABLE_QTSPARKLE=OFF
- name: Build
run: cmake --build build --config Release --parallel 4
@@ -931,7 +999,7 @@ jobs:
build-windows-mingw:
name: Build Windows MinGW
if: github.repository != 'strawberrymusicplayer/strawberry-private' && (!(github.event.pusher.name == 'strawbsbot' && contains(github.event.head_commit.message, 'New translations')))
if: github.repository != 'strawberrymusicplayer/strawberry-private' && github.ref != 'refs/heads/l10n_master'
runs-on: ubuntu-latest
strategy:
fail-fast: false
@@ -974,7 +1042,7 @@ jobs:
-DBUILD_WERROR=ON
-DARCH="${{matrix.arch}}"
-DENABLE_WIN32_CONSOLE=$(test "${{matrix.buildtype}}" = "debug" && echo "ON" || echo "OFF")
-DENABLE_DBUS=OFF
-DENABLE_GIO=OFF
-DENABLE_AUDIOCD=OFF
-DENABLE_MTP=OFF
-DENABLE_GPOD=OFF
@@ -1120,7 +1188,7 @@ jobs:
build-windows-msvc:
name: Build Windows MSVC
if: github.repository != 'strawberrymusicplayer/strawberry-private' && (!(github.event.pusher.name == 'strawbsbot' && contains(github.event.head_commit.message, 'New translations')))
if: github.repository != 'strawberrymusicplayer/strawberry-private' && github.ref != 'refs/heads/l10n_master'
runs-on: windows-2022
strategy:
fail-fast: false
@@ -1262,6 +1330,10 @@ jobs:
-DENABLE_WIN32_CONSOLE=${{env.win32_console}}
-DPKG_CONFIG_EXECUTABLE="${{env.prefix_path_forwardslash}}/bin/pkg-config.exe"
-DICU_ROOT="${{env.prefix_path_forwardslash}}"
-DENABLE_GIO=OFF
-DENABLE_AUDIOCD=OFF
-DENABLE_MTP=OFF
-DENABLE_GPOD=OFF
-DENABLE_SPOTIFY=ON
- name: Run Make
@@ -1396,6 +1468,11 @@ jobs:
exit 1
fi
- name: Download MSVC runtime
shell: bash
working-directory: build
run: curl -f -O -L https://aka.ms/vs/17/release/vc_redist.$(test "${{matrix.arch}}" = "x86_64" && echo "x64" || echo "${{matrix.arch}}").exe
- name: Create nsis installer
shell: cmd
working-directory: build

2
.gitignore vendored
View File

@@ -11,6 +11,4 @@
/out
/CMakeSettings.json
/dist/scripts/maketarball.sh
/dist/unix/strawberry.spec
/debian/changelog
/dist/macos/Info.plist

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,40 @@ Strawberry Music Player
=======================
ChangeLog
Version 1.2.6 (2025.01.17):
Bugfixes:
* Fixed dragging songs from playlist to queue.
Version 1.2.5 (2025.01.17):
Bugfixes:
* Fixed crash when saving playcount or rating to file (#1633).
* Fixed QFile::open failing in unit tests.
* Fixed playlist sequence settings saved to wrong configuration file (#1649).
Enhancements:
* Fixed use of deprecated GIO functions with GLib 2.84 and newer.
* (macOS) Added back Sparkle updater to check for new releases.
Version 1.2.4 (2025.01.10):
Bugfixes:
* Fixed Spotify songs not being available for scrobbling.
* Fixed leading "A" and "The" articles being skipped for album sort text.
* Fixed thread safety issue when validating playlist songs on startup.
* Fixed filter search not ignoring space after colon when using column based search.
* Fixed KGlobalAccel to use capitalized application name.
* Fixed slash not properly handled when saving a playlist (#1624).
* (Unix) Fixed collection scanner so it ignores special filesystem paths (/sys, /proc, /run, etc) (#1615).
* (Windows) Fixed smart playlist wizard not respecting dark mode with Windows 11 style (#1639).
Enhancements:
* Use XSPF "title" as playlist name when loading and saving playlists (#1624).
* Added support for using album ID when receving album covers for Subsonic songs (#1636).
* Added option for preserving directory structure when trascoding songs (#1637).
* (Windows) Always run MSVC runtime installer to possible fix issues when there is an older runtime installed.
Version 1.2.3 (2024.12.08):
Bugfixes:

View File

@@ -2,5 +2,5 @@ find_program(LSB_RELEASE_EXEC lsb_release)
find_program(DPKG_BUILDPACKAGE dpkg-buildpackage)
if (LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
add_custom_target(deb WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${DPKG_BUILDPACKAGE} -b -d -uc -us)
add_custom_target(deb WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${DPKG_BUILDPACKAGE} -b -d -uc -us -nc -j4)
endif()

View File

@@ -31,7 +31,7 @@ if(MACDEPLOYQT_EXECUTABLE)
add_custom_target(deploy
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/strawberry.app/Contents/{Frameworks,Resources}
COMMAND cp -v ${CMAKE_SOURCE_DIR}/dist/macos/Info.plist ${CMAKE_BINARY_DIR}/strawberry.app/Contents/
COMMAND cp -v ${CMAKE_BINARY_DIR}/dist/macos/Info.plist ${CMAKE_BINARY_DIR}/strawberry.app/Contents/
COMMAND cp -v ${CMAKE_SOURCE_DIR}/dist/macos/strawberry.icns ${CMAKE_BINARY_DIR}/strawberry.app/Contents/Resources/
COMMAND ${CMAKE_SOURCE_DIR}/dist/macos/macgstcopy.sh ${CMAKE_BINARY_DIR}/strawberry.app
COMMAND ${MACDEPLOYQT_EXECUTABLE} strawberry.app -verbose=3 -executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/gst-plugin-scanner ${MACDEPLOYQT_CODESIGN}

View File

@@ -1,15 +1,15 @@
set(summary_willbuild "")
set(summary_willnotbuild "")
macro(summary_add name test)
macro(optional_component_summary_add name test)
if (${test})
list(APPEND summary_willbuild ${name})
else (${test})
list(APPEND summary_willnotbuild "${name}")
endif (${test})
endmacro(summary_add)
endmacro(optional_component_summary_add)
macro(summary_show_part variable title)
macro(optional_component_summary_show_part variable title)
list(LENGTH ${variable} _len)
if (_len)
message("")
@@ -18,19 +18,20 @@ macro(summary_show_part variable title)
message(" ${_item}")
endforeach (_item)
endif (_len)
endmacro(summary_show_part)
endmacro(optional_component_summary_show_part)
macro(summary_show)
macro(optional_component_summary_show)
list(SORT summary_willbuild)
list(SORT summary_willnotbuild)
message("")
message("Building strawberry version: ${STRAWBERRY_VERSION_DISPLAY}, Qt version ${Qt${QT_VERSION_MAJOR}Core_VERSION}")
summary_show_part(summary_willbuild "The following components will be built:")
summary_show_part(summary_willnotbuild "The following components WILL NOT be built:")
optional_component_summary_show_part(summary_willbuild "The following components will be built:")
optional_component_summary_show_part(summary_willnotbuild "The following components WILL NOT be built:")
message("")
endmacro(summary_show)
endmacro(optional_component_summary_show)
function(optional_component name default description)
set(option_variable "ENABLE_${name}")
set(have_variable "HAVE_${name}")
set(${have_variable} OFF)
@@ -79,6 +80,9 @@ function(optional_component name default description)
set(text "${description} (missing ${deplist_text})")
set(summary_willnotbuild "${summary_willnotbuild};${text}" PARENT_SCOPE)
message(FATAL_ERROR "${text}, to disable this optional feature, pass -D${option_variable}=OFF to CMake")
else()
set(${have_variable} ON PARENT_SCOPE)
set(summary_willbuild "${summary_willbuild};${description}" PARENT_SCOPE)

View File

@@ -64,7 +64,7 @@ if (LSB_RELEASE_EXEC AND RPMBUILD_EXEC)
add_custom_target(rpm
COMMAND ${CMAKE_SOURCE_DIR}/dist/scripts/maketarball.sh
COMMAND ${CMAKE_COMMAND} -E copy strawberry-${STRAWBERRY_VERSION_PACKAGE}.tar.xz ${RPMBUILD_DIR}/SOURCES/
COMMAND ${RPMBUILD_EXEC} -ba ${CMAKE_SOURCE_DIR}/dist/unix/strawberry.spec
COMMAND ${RPMBUILD_EXEC} -ba ${CMAKE_BINARY_DIR}/strawberry.spec
)
endif()

View File

@@ -1,9 +1,9 @@
set(STRAWBERRY_VERSION_MAJOR 1)
set(STRAWBERRY_VERSION_MINOR 2)
set(STRAWBERRY_VERSION_PATCH 3)
set(STRAWBERRY_VERSION_PATCH 6)
#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}")

3
debian/clean vendored Normal file
View File

@@ -0,0 +1,3 @@
dist/scripts/maketarball.sh
CMakeCache.txt
CMakeFiles/

1
debian/compat vendored
View File

@@ -1 +0,0 @@
11

4
debian/control vendored
View File

@@ -2,7 +2,7 @@ Source: strawberry
Section: sound
Priority: optional
Maintainer: Jonas Kvinge <jonas@jkvinge.net>
Build-Depends: debhelper (>= 11),
Build-Depends: debhelper-compat (= 12),
git,
make,
cmake,
@@ -28,7 +28,7 @@ Build-Depends: debhelper (>= 11),
libchromaprint-dev,
libfftw3-dev,
libebur128-dev
Standards-Version: 4.6.1
Standards-Version: 4.7.0
Package: strawberry
Architecture: any

15
debian/rules vendored
View File

@@ -1,17 +1,10 @@
#!/usr/bin/make -f
%:
dh $@ --buildsystem=cmake -builddirectory=build
override_dh_auto_clean:
rm -f dist/macos/Info.plist
rm -f dist/unix/strawberry.spec
rm -f dist/scripts/maketarball.sh
rm -f dist/windows/strawberry.nsi
rm -f src/translations/translations.pot
dh_auto_clean
export DH_VERBOSE=1
export DEB_BUILD_MAINT_OPTIONS=hardening=+all
override_dh_installchangelogs:
dh_installchangelogs Changelog
override_dh_auto_test:
%:
dh $@

14
dist/CMakeLists.txt vendored
View File

@@ -1,7 +1,7 @@
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/maketarball.sh.in ${CMAKE_CURRENT_SOURCE_DIR}/scripts/maketarball.sh @ONLY)
if(RPM_DISTRO AND RPM_DATE)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec @ONLY)
endif(RPM_DISTRO AND RPM_DATE)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec.in ${CMAKE_BINARY_DIR}/strawberry.spec @ONLY)
endif()
if(APPLE)
if(DEFINED ENV{MACOSX_DEPLOYMENT_TARGET})
@@ -9,13 +9,13 @@ if(APPLE)
else()
set(LSMinimumSystemVersion 12.0)
endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist.in ${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist)
endif(APPLE)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist.in ${CMAKE_CURRENT_BINARY_DIR}/macos/Info.plist)
endif()
if(WIN32)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/windres.rc.in ${CMAKE_BINARY_DIR}/windres.rc)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry.nsi.in ${CMAKE_BINARY_DIR}/strawberry.nsi @ONLY)
endif(WIN32)
endif()
if(UNIX AND NOT APPLE)
install(FILES ../data/icons/48x48/strawberry.png DESTINATION share/icons/hicolor/48x48/apps/)
@@ -24,9 +24,9 @@ if(UNIX AND NOT APPLE)
install(FILES unix/org.strawberrymusicplayer.strawberry.desktop DESTINATION share/applications)
install(FILES unix/org.strawberrymusicplayer.strawberry.appdata.xml DESTINATION share/metainfo)
install(FILES unix/strawberry.1 DESTINATION share/man/man1)
endif(UNIX AND NOT APPLE)
endif()
if(APPLE)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist" DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/macos/Info.plist" DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents")
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/macos/strawberry.icns" DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents/Resources")
endif()

View File

@@ -35,9 +35,9 @@
<key>LSMinimumSystemVersion</key>
<string>@LSMinimumSystemVersion@</string>
<key>SUFeedURL</key>
<string>https://www.strawberrymusicplayer.org/sparkle-macos</string>
<string>https://www.strawberrymusicplayer.org/sparkle-macos-@ARCH@</string>
<key>SUPublicEDKey</key>
<string>3IRScV8YtNVnx7zoeJAXvg28Kh1gN/Pyl2iPM467pG8=</string>
<string>/OydhYVfypuO2Mf7G6DUqVZWW9G19eFV74qaDCBTOUk=</string>
<key>CFBundleURLTypes</key>
<array>
<dict>

View File

@@ -51,6 +51,9 @@
</screenshots>
<update_contact>eclipseo@fedoraproject.org</update_contact>
<releases>
<release version="1.2.6" date="2025-01-17"/>
<release version="1.2.5" date="2025-01-17"/>
<release version="1.2.4" date="2025-01-10"/>
<release version="1.2.3" date="2024-12-08"/>
<release version="1.2.2" date="2024-11-23"/>
<release version="1.2.1" date="2024-11-21"/>

View File

@@ -63,6 +63,8 @@ BuildRequires: pkgconfig(libcdio)
BuildRequires: pkgconfig(libebur128)
BuildRequires: pkgconfig(libgpod-1.0)
BuildRequires: pkgconfig(libmtp)
BuildRequires: cmake(GTest)
BuildRequires: pkgconfig(gmock)
%if 0%{?suse_version}
Requires: qt6-sql-sqlite
@@ -103,13 +105,13 @@ Features:
%build
%if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos}
export CXXFLAGS="-fPIC $RPM_OPT_FLAGS"
export CXXFLAGS="-fPIC -Wno-maybe-uninitialized $RPM_OPT_FLAGS"
%endif
%if "%{?_vendor}" == "openmandriva"
%{cmake} -DQT_VERSION_MAJOR=@QT_VERSION_MAJOR@ -DENABLE_TRANSLATIONS=OFF
%{cmake} -DBUILD_WERROR=ON
%make_build
%else
%{cmake} -DQT_VERSION_MAJOR=@QT_VERSION_MAJOR@
%{cmake} -DBUILD_WERROR=ON
%cmake_build
%endif
@@ -120,11 +122,13 @@ Features:
%cmake_install
%endif
%if 0%{?suse_version}
%suse_update_desktop_file org.strawberrymusicplayer.strawberry Qt AudioVideo Audio Player
%endif
%check
export QT_QPA_PLATFORM="offscreen"
%if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos}
%{cmake_build} -t strawberry_tests
%else
%{make_build} -j $(nproc) -C build strawberry_tests
%endif
desktop-file-validate %{buildroot}%{_datadir}/applications/org.strawberrymusicplayer.strawberry.desktop
%if 0%{?suse_version}
appstream-util validate-relax --nonet %{buildroot}%{_datadir}/metainfo/org.strawberrymusicplayer.strawberry.appdata.xml

View File

@@ -208,14 +208,16 @@ FunctionEnd
!ifdef msvc
!define vc_redist_file "vc_redist.${arch}.exe"
Function InstallMSVCRuntime
${registry::Read} "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\${arch}" "Version" $R0 $R1
${If} $R0 == ""
SetOutPath "$TEMP"
File "${vc_redist_file}"
; ${registry::Read} "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\${arch}" "Version" $R0 $R1
; ${If} $R0 == ""
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'
Delete "$TEMP\${vc_redist_file}"
SetDetailsView show
${EndIf}
; ${EndIf}
FunctionEnd
!endif

View File

@@ -1,2 +1,71 @@
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
add_subdirectory(utilities)
add_subdirectory(core)
add_subdirectory(mimedata)
add_subdirectory(osd)
add_subdirectory(tagreader)
add_subdirectory(widgets)
add_subdirectory(dialogs)
add_subdirectory(engine)
add_subdirectory(lyrics)
add_subdirectory(filterparser)
add_subdirectory(analyzer)
add_subdirectory(transcoder)
add_subdirectory(collection)
add_subdirectory(playlist)
add_subdirectory(playlistparsers)
add_subdirectory(equalizer)
add_subdirectory(edittagdialog)
add_subdirectory(smartplaylists)
add_subdirectory(settings)
add_subdirectory(device)
add_subdirectory(covermanager)
add_subdirectory(fileview)
add_subdirectory(player)
add_subdirectory(radios)
add_subdirectory(streaming)
add_subdirectory(scrobbler)
add_subdirectory(organize)
add_subdirectory(context)
add_subdirectory(queue)
add_subdirectory(providers)
add_subdirectory(songloader)
add_subdirectory(systemtrayicon)
if(HAVE_MUSICBRAINZ)
add_subdirectory(musicbrainz)
endif()
if(HAVE_GLOBALSHORTCUTS)
add_subdirectory(globalshortcuts)
endif()
if(HAVE_MOODBAR)
add_subdirectory(moodbar)
endif()
if(HAVE_MPRIS2)
add_subdirectory(mpris2)
endif()
if(HAVE_SUBSONIC)
add_subdirectory(subsonic)
endif()
if(HAVE_TIDAL)
add_subdirectory(tidal)
endif()
if(HAVE_SPOTIFY)
add_subdirectory(spotify)
endif()
if(HAVE_QOBUZ)
add_subdirectory(qobuz)
endif()
if(APPLE)
add_subdirectory(macstartup)
endif()

View File

@@ -0,0 +1,41 @@
set(ANALYZER_SOURCES
fht.cpp
analyzerbase.cpp
analyzercontainer.cpp
blockanalyzer.cpp
boomanalyzer.cpp
turbineanalyzer.cpp
sonogramanalyzer.cpp
waverubberanalyzer.cpp
rainbowanalyzer.cpp
)
set(ANALYZER_HEADERS
analyzerbase.h
analyzercontainer.h
blockanalyzer.h
boomanalyzer.h
turbineanalyzer.h
sonogramanalyzer.h
waverubberanalyzer.h
rainbowanalyzer.h
)
qt_wrap_cpp(ANALYZER_SOURCES ${ANALYZER_HEADERS})
add_library(strawberry_analyzer STATIC ${ANALYZER_SOURCES})
target_include_directories(strawberry_analyzer PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_analyzer PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets
strawberry_core
strawberry_engine
)

View File

@@ -50,9 +50,9 @@
// Make an INSTRUCTIONS file
// can't mod scope in analyze you have to use transform for 2D use setErasePixmap Qt function insetead of m_background
AnalyzerBase::AnalyzerBase(QWidget *parent, const uint scopeSize)
AnalyzerBase::AnalyzerBase(QWidget *parent, const uint scope_size)
: QWidget(parent),
fht_(new FHT(scopeSize)),
fht_(new FHT(scope_size)),
engine_(nullptr),
lastscope_(512),
new_frame_(false),
@@ -211,28 +211,28 @@ void AnalyzerBase::demo(QPainter &p) {
}
void AnalyzerBase::interpolate(const Scope &inVec, Scope &outVec) {
void AnalyzerBase::interpolate(const Scope &in_scope, Scope &out_scope) {
double pos = 0.0;
const double step = static_cast<double>(inVec.size()) / static_cast<double>(outVec.size());
const double step = static_cast<double>(in_scope.size()) / static_cast<double>(out_scope.size());
for (uint i = 0; i < outVec.size(); ++i, pos += step) {
for (uint i = 0; i < out_scope.size(); ++i, pos += step) {
const double error = pos - std::floor(pos);
const uint64_t offset = static_cast<uint64_t>(pos);
uint64_t indexLeft = offset + 0;
if (indexLeft >= inVec.size()) {
indexLeft = inVec.size() - 1;
if (indexLeft >= in_scope.size()) {
indexLeft = in_scope.size() - 1;
}
uint64_t indexRight = offset + 1;
if (indexRight >= inVec.size()) {
indexRight = inVec.size() - 1;
if (indexRight >= in_scope.size()) {
indexRight = in_scope.size() - 1;
}
outVec[i] = inVec[indexLeft] * (1.0F - static_cast<float>(error)) + inVec[indexRight] * static_cast<float>(error);
out_scope[i] = in_scope[indexLeft] * (1.0F - static_cast<float>(error)) + in_scope[indexRight] * static_cast<float>(error);
}
}

View File

@@ -61,7 +61,7 @@ class AnalyzerBase : public QWidget {
protected:
using Scope = std::vector<float>;
explicit AnalyzerBase(QWidget*, const uint scopeSize = 7);
explicit AnalyzerBase(QWidget *parent, const uint scope_size = 7);
void hideEvent(QHideEvent *e) override;
void showEvent(QShowEvent *e) override;
@@ -71,12 +71,12 @@ class AnalyzerBase : public QWidget {
int resizeExponent(int exp);
int resizeForBands(const int bands);
virtual void init() {}
virtual void transform(Scope&);
virtual void analyze(QPainter &p, const Scope&, const bool new_frame) = 0;
virtual void transform(Scope &scope);
virtual void analyze(QPainter &p, const Scope &s, const bool new_frame) = 0;
virtual void demo(QPainter &p);
void interpolate(const Scope&, Scope&);
void initSin(Scope&, const uint = 6000);
void interpolate(const Scope &in_scope, Scope &out_scope);
void initSin(Scope &v, const uint size = 6000);
protected:
QBasicTimer timer_;

View File

@@ -0,0 +1,82 @@
set(COLLECTION_SOURCES
collectionlibrary.cpp
collectionmodel.cpp
collectionbackend.cpp
collectionwatcher.cpp
collectionview.cpp
collectionitemdelegate.cpp
collectionviewcontainer.cpp
collectiondirectorymodel.cpp
collectionfilteroptions.cpp
collectionfilterwidget.cpp
collectionfilter.cpp
collectionplaylistitem.cpp
collectionquery.cpp
savedgroupingmanager.cpp
groupbydialog.cpp
collectiontask.cpp
collectionmodelupdate.cpp
collectionitem.cpp
)
set(COLLECTION_HEADERS
collectionlibrary.h
collectionmodel.h
collectionbackend.h
collectionwatcher.h
collectionview.h
collectionitemdelegate.h
collectionviewcontainer.h
collectiondirectorymodel.h
collectionfilterwidget.h
collectionfilter.h
savedgroupingmanager.h
groupbydialog.h
)
set(COLLECTION_UI
groupbydialog.ui
collectionfilterwidget.ui
collectionviewcontainer.ui
savedgroupingmanager.ui
)
qt_wrap_cpp(COLLECTION_SOURCES ${COLLECTION_HEADERS})
qt_wrap_ui(COLLECTION_SOURCES ${COLLECTION_UI})
add_library(strawberry_collection STATIC ${COLLECTION_SOURCES})
target_include_directories(strawberry_collection PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_collection PRIVATE
PkgConfig::GLIB
PkgConfig::GOBJECT
PkgConfig::GSTREAMER
PkgConfig::GSTREAMER_BASE
PkgConfig::GSTREAMER_AUDIO
PkgConfig::GSTREAMER_APP
PkgConfig::GSTREAMER_TAG
PkgConfig::GSTREAMER_PBUTILS
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Concurrent
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Sql
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets
strawberry_utilities
strawberry_core
strawberry_mimedata
strawberry_engine
strawberry_tagreader
strawberry_covermanager
strawberry_filterparser
strawberry_dialogs
strawberry_edittagdialog
strawberry_organize
strawberry_playlistparsers
)

View File

@@ -78,7 +78,7 @@ CollectionBackend::~CollectionBackend() {
void CollectionBackend::Init(SharedPtr<Database> db, SharedPtr<TaskManager> task_manager, const Song::Source source, const QString &songs_table, const QString &dirs_table, const QString &subdirs_table) {
setObjectName(source == Song::Source::Collection ? QLatin1String(metaObject()->className()) : QStringLiteral("%1%2").arg(Song::DescriptionForSource(source), QLatin1String(metaObject()->className())));
setObjectName(source == Song::Source::Collection ? QLatin1String(QObject::metaObject()->className()) : QStringLiteral("%1%2").arg(Song::DescriptionForSource(source), QLatin1String(QObject::metaObject()->className())));
db_ = db;
task_manager_ = task_manager;

View File

@@ -28,7 +28,7 @@
#include <QUrl>
#include "core/song.h"
#include "core/songmimedata.h"
#include "mimedata/songmimedata.h"
#include "filterparser/filterparser.h"
#include "filterparser/filtertree.h"
#include "collectionbackend.h"

View File

@@ -53,7 +53,7 @@
#include "savedgroupingmanager.h"
#include "collectionfilterwidget.h"
#include "groupbydialog.h"
#include "ui_collectionfilterwidget.h"
#include "collection/ui_collectionfilterwidget.h"
#include "widgets/searchfield.h"
#include "constants/collectionsettings.h"
#include "constants/appearancesettings.h"

View File

@@ -66,7 +66,7 @@ CollectionLibrary::CollectionLibrary(const SharedPtr<Database> database,
save_playcounts_to_files_(false),
save_ratings_to_files_(false) {
setObjectName(QLatin1String(metaObject()->className()));
setObjectName(QLatin1String(QObject::metaObject()->className()));
original_thread_ = thread();

View File

@@ -50,16 +50,16 @@
#include <QPixmapCache>
#include <QNetworkDiskCache>
#include <QSettings>
#include <QStandardPaths>
#include <QTimer>
#include "includes/scoped_ptr.h"
#include "includes/shared_ptr.h"
#include "core/logging.h"
#include "core/standardpaths.h"
#include "core/database.h"
#include "core/iconloader.h"
#include "core/logging.h"
#include "core/settings.h"
#include "core/songmimedata.h"
#include "mimedata/songmimedata.h"
#include "collectionfilteroptions.h"
#include "collectionquery.h"
#include "collectionbackend.h"
@@ -98,7 +98,7 @@ CollectionModel::CollectionModel(const SharedPtr<CollectionBackend> backend, con
loading_(false),
icon_disk_cache_(new QNetworkDiskCache(this)) {
setObjectName(backend_->source() == Song::Source::Collection ? QLatin1String(metaObject()->className()) : QStringLiteral("%1%2").arg(Song::DescriptionForSource(backend_->source()), QLatin1String(metaObject()->className())));
setObjectName(backend_->source() == Song::Source::Collection ? QLatin1String(QObject::metaObject()->className()) : QStringLiteral("%1%2").arg(Song::DescriptionForSource(backend_->source()), QLatin1String(QObject::metaObject()->className())));
filter_->setSourceModel(this);
filter_->setSortRole(Role_SortText);
@@ -114,7 +114,7 @@ CollectionModel::CollectionModel(const SharedPtr<CollectionBackend> backend, con
pixmap_no_cover_ = nocover.pixmap(nocover_sizes.last()).scaled(kPrettyCoverSize, kPrettyCoverSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
icon_disk_cache_->setCacheDirectory(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + u'/' + QLatin1String(kPixmapDiskCacheDir) + u'-' + Song::TextForSource(backend_->source()));
icon_disk_cache_->setCacheDirectory(StandardPaths::WritableLocation(StandardPaths::StandardLocation::CacheLocation) + u'/' + QLatin1String(kPixmapDiskCacheDir) + u'-' + Song::TextForSource(backend_->source()));
QObject::connect(&*backend_, &CollectionBackend::SongsAdded, this, &CollectionModel::AddReAddOrUpdate);
QObject::connect(&*backend_, &CollectionBackend::SongsChanged, this, &CollectionModel::AddReAddOrUpdate);
@@ -288,29 +288,11 @@ void CollectionModel::SetFilterMaxAge(const int filter_max_age) {
QVariant CollectionModel::data(const QModelIndex &idx, const int role) const {
const CollectionItem *item = IndexToItem(idx);
// Handle a special case for returning album artwork instead of a generic CD icon.
// this is here instead of in the other data() function to let us use the
// QModelIndex& version of GetChildSongs, which satisfies const-ness, instead
// of the CollectionItem *version, which doesn't.
if (options_active_.show_pretty_covers) {
bool is_album_node = false;
if (role == Qt::DecorationRole && item->type == CollectionItem::Type::Container) {
GroupBy container_group_by = options_active_.group_by[item->container_level];
is_album_node = IsAlbumGroupBy(container_group_by);
}
if (is_album_node) {
// It has const behaviour some of the time - that's ok right?
return const_cast<CollectionModel*>(this)->AlbumIcon(idx);
}
}
return data(item, role);
return data(IndexToItem(idx), role);
}
QVariant CollectionModel::data(const CollectionItem *item, const int role) const {
QVariant CollectionModel::data(CollectionItem *item, const int role) const {
GroupBy container_group_by = item->type == CollectionItem::Type::Container ? options_active_.group_by[item->container_level] : GroupBy::None;
@@ -329,7 +311,7 @@ QVariant CollectionModel::data(const CollectionItem *item, const int role) const
case GroupBy::YearAlbumDisc:
case GroupBy::OriginalYearAlbum:
case GroupBy::OriginalYearAlbumDisc:
return QVariant();
return options_active_.show_pretty_covers ? const_cast<CollectionModel*>(this)->AlbumIcon(item) : QVariant();
case GroupBy::Artist:
case GroupBy::AlbumArtist:
return icon_artist_;
@@ -408,17 +390,17 @@ QMimeData *CollectionModel::mimeData(const QModelIndexList &indexes) const {
if (indexes.isEmpty()) return nullptr;
SongMimeData *data = new SongMimeData;
QList<QUrl> urls;
SongList songs;
QSet<int> song_ids;
data->backend = backend_;
QList<QUrl> urls;
for (const QModelIndex &idx : indexes) {
GetChildSongs(IndexToItem(idx), &urls, &data->songs, &song_ids);
GetChildSongs(IndexToItem(idx), songs, song_ids, urls);
}
SongMimeData *data = new SongMimeData;
data->setUrls(urls);
data->backend = backend_;
data->songs = songs;
data->name_for_new_playlist_ = Song::GetNameForNewPlaylist(data->songs);
return data;
@@ -854,9 +836,9 @@ void CollectionModel::LoadSongsFromSqlAsyncFinished() {
}
QString CollectionModel::AlbumIconPixmapCacheKey(const QModelIndex &idx) const {
QString CollectionModel::AlbumIconPixmapCacheKey(const CollectionItem *item) const {
return Song::TextForSource(backend_->source()) + QLatin1Char('/') + idx.data(Role_ContainerKey).toString();
return Song::TextForSource(backend_->source()) + QLatin1Char('/') + item->container_key;
}
@@ -869,7 +851,7 @@ QUrl CollectionModel::AlbumIconPixmapDiskCacheKey(const QString &cache_key) {
void CollectionModel::ClearItemPixmapCache(CollectionItem *item) {
// Remove from pixmap cache
const QString cache_key = AlbumIconPixmapCacheKey(ItemToIndex(item));
const QString cache_key = AlbumIconPixmapCacheKey(item);
QPixmapCache::remove(cache_key);
if (use_disk_cache_ && icon_disk_cache_) icon_disk_cache_->remove(AlbumIconPixmapDiskCacheKey(cache_key));
if (pending_cache_keys_.contains(cache_key)) {
@@ -888,13 +870,12 @@ void CollectionModel::ClearItemPixmapCache(CollectionItem *item) {
}
QVariant CollectionModel::AlbumIcon(const QModelIndex &idx) {
QVariant CollectionModel::AlbumIcon(CollectionItem *item) {
CollectionItem *item = IndexToItem(idx);
if (!item) return pixmap_no_cover_;
// Check the cache for a pixmap we already loaded.
const QString cache_key = AlbumIconPixmapCacheKey(idx);
const QString cache_key = AlbumIconPixmapCacheKey(item);
QPixmap cached_pixmap;
if (QPixmapCache::find(cache_key, &cached_pixmap)) {
@@ -919,7 +900,7 @@ QVariant CollectionModel::AlbumIcon(const QModelIndex &idx) {
}
// No art is cached and we're not loading it already. Load art for the first song in the album.
SongList songs = GetChildSongs(idx);
const SongList songs = GetChildSongs(item);
if (!songs.isEmpty()) {
AlbumCoverLoaderOptions cover_loader_options(AlbumCoverLoaderOptions::Option::ScaledImage | AlbumCoverLoaderOptions::Option::PadScaledImage);
cover_loader_options.desired_scaled_size = QSize(kPrettyCoverSize, kPrettyCoverSize);
@@ -1095,7 +1076,7 @@ QString CollectionModel::SortText(const GroupBy group_by, const Song &song, cons
case GroupBy::Artist:
return SortTextForArtist(song.artist(), sort_skips_articles);
case GroupBy::Album:
return SortTextForArtist(song.album(), sort_skips_articles);
return SortText(song.album());
case GroupBy::AlbumDisc:
return song.album() + SortTextForNumber(std::max(0, song.disc()));
case GroupBy::YearAlbum:
@@ -1412,7 +1393,7 @@ QString CollectionModel::DividerDisplayText(const GroupBy group_by, const QStrin
}
bool CollectionModel::CompareItems(const CollectionItem *a, const CollectionItem *b) const {
bool CollectionModel::CompareItems(CollectionItem *a, CollectionItem *b) const {
QVariant left = data(a, CollectionModel::Role_SortText);
QVariant right = data(b, CollectionModel::Role_SortText);
@@ -1453,24 +1434,23 @@ qint64 CollectionModel::MaximumCacheSize(Settings *s, const char *size_id, const
}
void CollectionModel::GetChildSongs(CollectionItem *item, QList<QUrl> *urls, SongList *songs, QSet<int> *song_ids) const {
void CollectionModel::GetChildSongs(CollectionItem *item, SongList &songs, QSet<int> &song_ids, QList<QUrl> &urls) const {
switch (item->type) {
case CollectionItem::Type::Container: {
QList<CollectionItem*> children = item->children;
std::sort(children.begin(), children.end(), std::bind(&CollectionModel::CompareItems, this, std::placeholders::_1, std::placeholders::_2));
for (CollectionItem *child : children) {
GetChildSongs(child, urls, songs, song_ids);
GetChildSongs(child, songs, song_ids, urls);
}
break;
}
case CollectionItem::Type::Song:
urls->append(item->metadata.url());
if (!song_ids->contains(item->metadata.id())) {
songs->append(item->metadata);
song_ids->insert(item->metadata.id());
urls << item->metadata.url();
if (!song_ids.contains(item->metadata.id())) {
songs << item->metadata;
song_ids << item->metadata.id();
}
break;
@@ -1480,16 +1460,33 @@ void CollectionModel::GetChildSongs(CollectionItem *item, QList<QUrl> *urls, Son
}
SongList CollectionModel::GetChildSongs(const QList<CollectionItem*> items) const {
SongList songs;
QSet<int> song_ids;
QList<QUrl> urls;
for (CollectionItem *item : items) {
GetChildSongs(item, songs, song_ids, urls);
}
return songs;
}
SongList CollectionModel::GetChildSongs(CollectionItem *item) const {
return GetChildSongs(QList<CollectionItem*>() << item);
}
SongList CollectionModel::GetChildSongs(const QModelIndexList &indexes) const {
QList<QUrl> dontcare;
SongList ret;
SongList songs;
QSet<int> song_ids;
QList<QUrl> urls;
for (const QModelIndex &idx : indexes) {
GetChildSongs(IndexToItem(idx), &dontcare, &ret, &song_ids);
GetChildSongs(IndexToItem(idx), songs, song_ids, urls);
}
return ret;
return songs;
}

View File

@@ -194,11 +194,13 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
QString ContainerKey(const GroupBy group_by, const Song &song, bool &has_unique_album_identifier) const;
// Get information about the collection
void GetChildSongs(CollectionItem *item, QList<QUrl> *urls, SongList *songs, QSet<int> *song_ids) const;
void GetChildSongs(CollectionItem *item, SongList &songs, QSet<int> &song_ids, QList<QUrl> &urls) const;
SongList GetChildSongs(const QList<CollectionItem*> items) const;
SongList GetChildSongs(CollectionItem *item) const;
SongList GetChildSongs(const QModelIndex &idx) const;
SongList GetChildSongs(const QModelIndexList &indexes) const;
bool CompareItems(const CollectionItem *a, const CollectionItem *b) const;
bool CompareItems(CollectionItem *a, CollectionItem *b) const;
bool HasParentAlbumGroupBy(CollectionItem *item) const;
@@ -224,7 +226,7 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
void BeginReset();
void EndReset();
QVariant data(const CollectionItem *item, const int role) const;
QVariant data(CollectionItem *item, const int role) const;
void ScheduleUpdate(const CollectionModelUpdate::Type type, const SongList &songs);
void ScheduleAddSongs(const SongList &songs);
@@ -250,9 +252,9 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
// Helpers
static bool IsCompilationArtistNode(const CollectionItem *node) { return node == node->parent->compilation_artist_node_; }
QString AlbumIconPixmapCacheKey(const QModelIndex &idx) const;
QString AlbumIconPixmapCacheKey(const CollectionItem *item) const;
static QUrl AlbumIconPixmapDiskCacheKey(const QString &cache_key);
QVariant AlbumIcon(const QModelIndex &idx);
QVariant AlbumIcon(CollectionItem *item);
void ClearItemPixmapCache(CollectionItem *item);
static qint64 MaximumCacheSize(Settings *s, const char *size_id, const char *size_unit_id, const qint64 cache_size_default);

View File

@@ -51,7 +51,7 @@
#include <QContextMenuEvent>
#include "core/iconloader.h"
#include "core/mimedata.h"
#include "mimedata/mimedata.h"
#include "core/musicstorage.h"
#include "core/deletefiles.h"
#include "core/settings.h"
@@ -69,7 +69,7 @@
# include "device/devicemanager.h"
# include "device/devicestatefiltermodel.h"
#endif
#include "dialogs/edittagdialog.h"
#include "edittagdialog/edittagdialog.h"
#include "dialogs/deleteconfirmationdialog.h"
#include "organize/organizedialog.h"
#include "organize/organizeerrordialog.h"
@@ -108,7 +108,7 @@ CollectionView::CollectionView(QWidget *parent)
is_in_keyboard_search_(false),
delete_files_(false) {
setObjectName(QLatin1String(metaObject()->className()));
setObjectName(QLatin1String(QObject::metaObject()->className()));
setItemDelegate(new CollectionItemDelegate(this));
setAttribute(Qt::WA_MacShowFocusRect, false);

View File

@@ -26,7 +26,7 @@
#include "collectionfilterwidget.h"
#include "collectionview.h"
#include "collectionviewcontainer.h"
#include "ui_collectionviewcontainer.h"
#include "collection/ui_collectionviewcontainer.h"
CollectionViewContainer::CollectionViewContainer(QWidget *parent) : QWidget(parent), ui_(new Ui_CollectionViewContainer) {

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2023, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2025, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
#include <QObject>
#include <QThread>
#include <QIODevice>
#include <QStorageInfo>
#include <QDir>
#include <QDirIterator>
#include <QFile>
@@ -51,6 +52,7 @@
#include "core/settings.h"
#include "utilities/imageutils.h"
#include "constants/timeconstants.h"
#include "constants/filesystemconstants.h"
#include "tagreader/tagreaderclient.h"
#include "collectiondirectory.h"
#include "collectionbackend.h"
@@ -104,7 +106,7 @@ CollectionWatcher::CollectionWatcher(const Song::Source source,
cue_parser_(new CueParser(tagreader_client, backend, this)),
last_scan_time_(0) {
setObjectName(source_ == Song::Source::Collection ? QLatin1String(metaObject()->className()) : QStringLiteral("%1%2").arg(Song::DescriptionForSource(source_), QLatin1String(metaObject()->className())));
setObjectName(source_ == Song::Source::Collection ? QLatin1String(QObject::metaObject()->className()) : QStringLiteral("%1%2").arg(Song::DescriptionForSource(source_), QLatin1String(QObject::metaObject()->className())));
original_thread_ = thread();
@@ -464,6 +466,24 @@ CollectionSubdirectoryList CollectionWatcher::ScanTransaction::GetAllSubdirs() {
void CollectionWatcher::AddDirectory(const CollectionDirectory &dir, const CollectionSubdirectoryList &subdirs) {
{
const QFileInfo path_info(dir.path);
if (path_info.isSymbolicLink()) {
const QStorageInfo storage_info(path_info.symLinkTarget());
if (kRejectedFileSystems.contains(storage_info.fileSystemType())) {
qLog(Warning) << "Ignoring collection directory path" << dir.path << "which is a symbolic link to path" << path_info.symLinkTarget() << "with rejected filesystem type" << storage_info.fileSystemType();
return;
}
}
else {
const QStorageInfo storage_info(dir.path);
if (kRejectedFileSystems.contains(storage_info.fileSystemType())) {
qLog(Warning) << "Ignoring collection directory path" << dir.path << "with rejected filesystem type" << storage_info.fileSystemType();
return;
}
}
}
CancelStop();
watched_dirs_[dir.id] = dir;
@@ -506,17 +526,29 @@ void CollectionWatcher::AddDirectory(const CollectionDirectory &dir, const Colle
void CollectionWatcher::ScanSubdirectory(const QString &path, const CollectionSubdirectory &subdir, const quint64 files_count, ScanTransaction *t, const bool force_noincremental) {
QFileInfo path_info(path);
const QFileInfo path_info(path);
// Do not scan symlinked dirs that are already in collection
if (path_info.isSymLink()) {
QString real_path = path_info.symLinkTarget();
const QString real_path = path_info.symLinkTarget();
const QStorageInfo storage_info(real_path);
if (kRejectedFileSystems.contains(storage_info.fileSystemType())) {
qLog(Warning) << "Ignoring symbolic link" << path << "which links to" << real_path << "with rejected filesystem type" << storage_info.fileSystemType();
return;
}
// Do not scan symlinked dirs that are already in collection
for (const CollectionDirectory &dir : std::as_const(watched_dirs_)) {
if (real_path.startsWith(dir.path)) {
return;
}
}
}
else {
const QStorageInfo storage_info(path);
if (kRejectedFileSystems.contains(storage_info.fileSystemType())) {
qLog(Warning) << "Ignoring path" << path << "with rejected filesystem type" << storage_info.fileSystemType();
return;
}
}
bool songs_missing_fingerprint = false;
bool songs_missing_loudness_characteristics = false;
@@ -556,32 +588,40 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const CollectionSu
if (stop_or_abort_requested()) return;
QString child(it.next());
QFileInfo child_info(child);
const QString child_filepath = it.next();
const QFileInfo child_fileinfo(child_filepath);
if (child_info.isDir()) {
if (!t->HasSeenSubdir(child)) {
if (child_fileinfo.isSymLink()) {
QStorageInfo storage_info(child_fileinfo.symLinkTarget());
if (kRejectedFileSystems.contains(storage_info.fileSystemType())) {
qLog(Warning) << "Ignoring symbolic link" << child_filepath << "which links to" << child_fileinfo.symLinkTarget() << "with rejected filesystem type" << storage_info.fileSystemType();
continue;
}
}
if (child_fileinfo.isDir()) {
if (!t->HasSeenSubdir(child_filepath)) {
// We haven't seen this subdirectory before - add it to a list, and later we'll tell the backend about it and scan it.
CollectionSubdirectory new_subdir;
new_subdir.directory_id = -1;
new_subdir.path = child;
new_subdir.mtime = child_info.lastModified().toSecsSinceEpoch();
new_subdir.path = child_filepath;
new_subdir.mtime = child_fileinfo.lastModified().toSecsSinceEpoch();
my_new_subdirs << new_subdir;
}
t->AddToProgress(1);
}
else {
QString ext_part(ExtensionPart(child));
QString dir_part(DirectoryPart(child));
if (Song::kRejectedExtensions.contains(child_info.suffix(), Qt::CaseInsensitive) || child_info.baseName() == "qt_temp"_L1) {
QString ext_part(ExtensionPart(child_filepath));
QString dir_part(DirectoryPart(child_filepath));
if (Song::kRejectedExtensions.contains(child_fileinfo.suffix(), Qt::CaseInsensitive) || child_fileinfo.baseName() == "qt_temp"_L1) {
t->AddToProgress(1);
}
else if (sValidImages.contains(ext_part)) {
album_art[dir_part] << child;
album_art[dir_part] << child_filepath;
t->AddToProgress(1);
}
else if (tagreader_client_->IsMediaFileBlocking(child)) {
files_on_disk << child;
else if (tagreader_client_->IsMediaFileBlocking(child_filepath)) {
files_on_disk << child_filepath;
}
else {
t->AddToProgress(1);
@@ -828,7 +868,7 @@ void CollectionWatcher::UpdateCueAssociatedSongs(const QString &file,
qLog(Error) << "Could not open CUE file" << matching_cue << "for reading:" << cue_file.errorString();
return;
}
const SongList songs = cue_parser_->Load(&cue_file, matching_cue, path, false);
const SongList songs = cue_parser_->Load(&cue_file, matching_cue, path, false).songs;
cue_file.close();
// Update every song that's in the CUE and collection
@@ -915,7 +955,7 @@ SongList CollectionWatcher::ScanNewFile(const QString &file, const QString &path
// Also, watch out for incorrect media files.
// Playlist parser for CUEs considers every entry in sheet valid, and we don't want invalid media getting into collection!
QString file_nfd = file.normalized(QString::NormalizationForm_D);
SongList cue_songs = cue_parser_->Load(&cue_file, matching_cue, path, false);
SongList cue_songs = cue_parser_->Load(&cue_file, matching_cue, path, false).songs;
cue_file.close();
songs.reserve(cue_songs.count());
for (Song &cue_song : cue_songs) {
@@ -1153,7 +1193,7 @@ void CollectionWatcher::RescanPathsNow() {
QMap<QString, quint64> subdir_files_count;
for (const QString &path : paths) {
quint64 files_count = FilesCountForPath(&transaction, path);
const quint64 files_count = FilesCountForPath(&transaction, path);
subdir_files_count[path] = files_count;
transaction.AddToProgressMax(files_count);
}
@@ -1316,18 +1356,45 @@ void CollectionWatcher::PerformScan(const bool incremental, const bool ignore_mt
quint64 CollectionWatcher::FilesCountForPath(ScanTransaction *t, const QString &path) {
const QFileInfo path_info(path);
if (path_info.isSymLink()) {
const QString real_path = path_info.symLinkTarget();
const QStorageInfo storage_info(real_path);
if (kRejectedFileSystems.contains(storage_info.fileSystemType())) {
return 0;
}
for (const CollectionDirectory &dir : std::as_const(watched_dirs_)) {
if (real_path.startsWith(dir.path)) {
return 0;
}
}
}
else {
const QStorageInfo storage_info(path);
if (kRejectedFileSystems.contains(storage_info.fileSystemType())) {
return 0;
}
}
quint64 i = 0;
QDirIterator it(path, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
while (it.hasNext()) {
if (stop_or_abort_requested()) break;
QString child = it.next();
QFileInfo path_info(child);
const QString child_filepath = it.next();
const QFileInfo child_fileinfo(child_filepath);
if (child_fileinfo.isDir()) {
if (child_fileinfo.isSymLink()) {
const QString real_path = child_fileinfo.symLinkTarget();
QStorageInfo storage_info(real_path);
if (kRejectedFileSystems.contains(storage_info.fileSystemType())) {
continue;
}
if (path_info.isDir()) {
if (path_info.isSymLink()) {
QString real_path = path_info.symLinkTarget();
for (const CollectionDirectory &dir : std::as_const(watched_dirs_)) {
if (real_path.startsWith(dir.path)) {
continue;
@@ -1335,9 +1402,9 @@ quint64 CollectionWatcher::FilesCountForPath(ScanTransaction *t, const QString &
}
}
if (!t->HasSeenSubdir(child) && !path_info.isHidden()) {
if (!t->HasSeenSubdir(child_filepath) && !child_fileinfo.isHidden()) {
// We haven't seen this subdirectory before, so we need to include the file count for this directory too.
i += FilesCountForPath(t, child);
i += FilesCountForPath(t, child_filepath);
}
}
@@ -1385,7 +1452,7 @@ void CollectionWatcher::RescanSongs(const SongList &songs) {
if (stop_or_abort_requested()) break;
if (subdir.path != song_path) continue;
qLog(Debug) << "Rescan for directory ID" << song.directory_id() << "directory" << subdir.path;
quint64 files_count = FilesCountForPath(&transaction, subdir.path);
const quint64 files_count = FilesCountForPath(&transaction, subdir.path);
ScanSubdirectory(song_path, subdir, files_count, &transaction);
scanned_paths << subdir.path;
}

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2023, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2025, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -18,6 +18,7 @@
#cmakedefine HAVE_AUDIOCD
#cmakedefine HAVE_MTP
#cmakedefine HAVE_GPOD
#cmakedefine HAVE_SPARKLE
#cmakedefine HAVE_QTSPARKLE
#cmakedefine HAVE_SONGFINGERPRINTING
#cmakedefine HAVE_MUSICBRAINZ

View File

@@ -0,0 +1,31 @@
/*
* Strawberry Music Player
* Copyright 2025, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef FILESYSTEMCONSTANTS_H
#define FILESYSTEMCONSTANTS_H
#include <QByteArrayList>
const QByteArrayList kRejectedFileSystems = QByteArrayList() << "proc"
<< "sysfs"
<< "tmpfs"
<< "devtmpfs";
#endif // FILESYSTEMCONSTANTS_H

View File

@@ -37,6 +37,7 @@ constexpr char kPassword[] = "password";
constexpr char kHTTP2[] = "http2";
constexpr char kVerifyCertificate[] = "verifycertificate";
constexpr char kDownloadAlbumCovers[] = "downloadalbumcovers";
constexpr char kUseAlbumIdForAlbumCovers[] = "usealbumidforalbumcovers";
constexpr char kServerSideScrobbling[] = "serversidescrobbling";
constexpr char kAuthMethod[] = "authmethod";

View File

@@ -0,0 +1,32 @@
set(CONTEXT_SOURCES
contextview.cpp
contextalbum.cpp
)
set(CONTEXT_HEADERS
contextview.h
contextalbum.h
)
qt_wrap_cpp(CONTEXT_SOURCES ${CONTEXT_HEADERS})
add_library(strawberry_context STATIC ${CONTEXT_SOURCES})
target_include_directories(strawberry_context PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_context PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Widgets
strawberry_utilities
strawberry_core
strawberry_collection
strawberry_covermanager
strawberry_lyrics
strawberry_widgets
)

95
src/core/CMakeLists.txt Normal file
View File

@@ -0,0 +1,95 @@
set(CORE_SOURCES
logging.cpp
commandlineoptions.cpp
database.cpp
memorydatabase.cpp
sqlquery.cpp
sqlrow.cpp
deletefiles.cpp
filesystemmusicstorage.cpp
filesystemwatcherinterface.cpp
mergedproxymodel.cpp
multisortfilterproxy.cpp
musicstorage.cpp
networkaccessmanager.cpp
threadsafenetworkdiskcache.cpp
networktimeouts.cpp
networkproxyfactory.cpp
qtfslistener.cpp
settings.cpp
settingsprovider.cpp
signalchecker.cpp
song.cpp
stylehelper.cpp
stylesheetloader.cpp
taskmanager.cpp
thread.cpp
urlhandlers.cpp
urlhandler.cpp
iconloader.cpp
standarditemiconloader.cpp
scopedtransaction.cpp
localredirectserver.cpp
temporaryfile.cpp
enginemetadata.cpp
platforminterface.cpp
)
set(CORE_HEADERS
logging.h
database.h
memorydatabase.h
deletefiles.h
filesystemwatcherinterface.h
mergedproxymodel.h
multisortfilterproxy.h
networkaccessmanager.h
threadsafenetworkdiskcache.h
networktimeouts.h
qtfslistener.h
settings.h
taskmanager.h
thread.h
urlhandlers.h
urlhandler.h
standarditemiconloader.h
stylesheetloader.h
localredirectserver.h
)
if(APPLE)
list(APPEND CORE_SOURCES scoped_nsautorelease_pool.mm)
endif()
if(WIN32)
list(APPEND CORE_SOURCES windows7thumbbar.cpp)
list(APPEND CORE_HEADERS windows7thumbbar.h)
endif()
qt_wrap_cpp(CORE_SOURCES ${CORE_HEADERS})
add_library(strawberry_core STATIC ${CORE_SOURCES})
target_include_directories(strawberry_core PRIVATE
${CMAKE_SOURCE_DIR}
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_core PRIVATE
PkgConfig::GLIB
PkgConfig::GOBJECT
PkgConfig::SQLITE
${TAGLIB_LIBRARIES}
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Concurrent
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Sql
$<$<BOOL:${HAVE_DBUS}>:Qt${QT_VERSION_MAJOR}::DBus>
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets
$<$<BOOL:${HAVE_GPOD}>:PkgConfig::LIBGPOD PkgConfig::GDK_PIXBUF>
$<$<BOOL:${WIN32}>:getopt-win::getopt>
strawberry_utilities
)

View File

@@ -39,10 +39,10 @@
#include <QSqlDriver>
#include <QSqlDatabase>
#include <QSqlError>
#include <QStandardPaths>
#include <QScopeGuard>
#include "core/logging.h"
#include "logging.h"
#include "standardpaths.h"
#include "taskmanager.h"
#include "database.h"
#include "sqlquery.h"
@@ -69,7 +69,7 @@ Database::Database(SharedPtr<TaskManager> task_manager, QObject *parent, const Q
startup_schema_version_(-1),
original_thread_(nullptr) {
setObjectName(QLatin1String(metaObject()->className()));
setObjectName(QLatin1String(QObject::metaObject()->className()));
original_thread_ = thread();
@@ -78,7 +78,7 @@ Database::Database(SharedPtr<TaskManager> task_manager, QObject *parent, const Q
connection_id_ = sNextConnectionId++;
}
directory_ = QDir::toNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
directory_ = QDir::toNativeSeparators(StandardPaths::WritableLocation(StandardPaths::StandardLocation::AppLocalDataLocation)).replace(u"Strawberry"_s, u"strawberry"_s);
QMutexLocker l(&mutex_);
Connect();

View File

@@ -27,10 +27,10 @@
#include <QString>
#include <QIcon>
#include <QSize>
#include <QStandardPaths>
#include <QSettings>
#include "logging.h"
#include "standardpaths.h"
#include "settings.h"
#include "includes/iconmapper.h"
#include "iconloader.h"
@@ -51,7 +51,7 @@ void IconLoader::Init() {
#endif
QDir dir;
if (dir.exists(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + u"/icons"_s)) {
if (dir.exists(StandardPaths::WritableLocation(StandardPaths::StandardLocation::AppLocalDataLocation) + u"/icons"_s)) {
custom_icons_ = true;
}
@@ -125,7 +125,7 @@ QIcon IconLoader::Load(const QString &name, const bool system_icon, const int fi
}
if (custom_icons_) {
QString custom_icon_path = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + u"/icons/%1x%2/%3.png"_s;
QString custom_icon_path = StandardPaths::WritableLocation(StandardPaths::StandardLocation::AppLocalDataLocation) + u"/icons/%1x%2/%3.png"_s;
for (int s : std::as_const(sizes)) {
QString filename(custom_icon_path.arg(s).arg(s).arg(name));
if (QFile::exists(filename)) ret.addFile(filename, QSize(s, s));

View File

@@ -1,6 +1,6 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@@ -18,13 +18,26 @@
*/
#include <QSettings>
#include <QVariant>
#include <QString>
#include <QCoreApplication>
#include "settings.h"
using namespace Qt::Literals::StringLiterals;
Settings::Settings(QObject *parent)
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
: QSettings(QCoreApplication::organizationName().toLower(), QCoreApplication::applicationName().toLower(), parent) {}
#else
: QSettings(parent) {}
#endif
Settings::Settings(const QSettings::Scope scope, QObject *parent)
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
: QSettings(scope, QCoreApplication::organizationName().toLower(), QCoreApplication::applicationName().toLower(), parent) {}
#else
: QSettings(scope, parent) {}
#endif
Settings::Settings(const QString &filename, const Format format, QObject *parent)
: QSettings(filename, format, parent) {}

View File

@@ -1,6 +1,6 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@@ -21,14 +21,14 @@
#define SETTINGS_H
#include <QSettings>
#include <QObject>
#include <QVariant>
#include <QString>
class Settings : public QSettings {
Q_OBJECT
public:
explicit Settings(QObject *parent = nullptr);
explicit Settings(const QSettings::Scope scope, QObject *parent = nullptr);
explicit Settings(const QString &filename, const Format format, QObject *parent = nullptr);
};

View File

@@ -26,7 +26,8 @@
#include <QVariant>
#include <QString>
#include <QSettings>
#include "core/settings.h"
class SettingsProvider {
public:
@@ -60,7 +61,7 @@ class DefaultSettingsProvider : public SettingsProvider {
void endArray() override;
private:
QSettings backend_;
Settings backend_;
Q_DISABLE_COPY(DefaultSettingsProvider)
};

View File

@@ -45,11 +45,11 @@
#include <QRegularExpression>
#include <QUrl>
#include <QIcon>
#include <QStandardPaths>
#include <QSqlRecord>
#include <taglib/tstring.h>
#include "core/standardpaths.h"
#include "core/iconloader.h"
#include "core/enginemetadata.h"
#include "utilities/strutils.h"
@@ -1335,24 +1335,24 @@ QString Song::ImageCacheDir(const Source source) {
switch (source) {
case Source::Collection:
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + u"/collectionalbumcovers"_s;
return StandardPaths::WritableLocation(StandardPaths::StandardLocation::AppLocalDataLocation) + u"/collectionalbumcovers"_s;
case Source::Subsonic:
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + u"/subsonicalbumcovers"_s;
return StandardPaths::WritableLocation(StandardPaths::StandardLocation::AppLocalDataLocation) + u"/subsonicalbumcovers"_s;
case Source::Tidal:
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + u"/tidalalbumcovers"_s;
return StandardPaths::WritableLocation(StandardPaths::StandardLocation::AppLocalDataLocation) + u"/tidalalbumcovers"_s;
case Source::Spotify:
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + u"/spotifyalbumcovers"_s;
return StandardPaths::WritableLocation(StandardPaths::StandardLocation::AppLocalDataLocation) + u"/spotifyalbumcovers"_s;
case Source::Qobuz:
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + u"/qobuzalbumcovers"_s;
return StandardPaths::WritableLocation(StandardPaths::StandardLocation::AppLocalDataLocation) + u"/qobuzalbumcovers"_s;
case Source::Device:
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + u"/devicealbumcovers"_s;
return StandardPaths::WritableLocation(StandardPaths::StandardLocation::AppLocalDataLocation) + u"/devicealbumcovers"_s;
case Source::LocalFile:
case Source::CDDA:
case Source::Stream:
case Source::SomaFM:
case Source::RadioParadise:
case Source::Unknown:
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + u"/albumcovers"_s;
return StandardPaths::WritableLocation(StandardPaths::StandardLocation::AppLocalDataLocation) + u"/albumcovers"_s;
}
return QString();

48
src/core/sparkleupdater.h Normal file
View File

@@ -0,0 +1,48 @@
/*
* Strawberry Music Player
* Copyright 2025, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef SPARKLEUPDATER_H
#define SPARKLEUPDATER_H
#include <QObject>
class QAction;
#ifdef __OBJC__
@class AppUpdaterDelegate;
#endif
class SparkleUpdater : public QObject {
Q_OBJECT
public:
explicit SparkleUpdater(QAction *action_check_updates, QObject *parent = nullptr);
public Q_SLOTS:
void CheckForUpdates();
private:
#ifdef __OBJC__
AppUpdaterDelegate *updater_delegate_;
#else
void *updater_delegate_;
#endif
};
#endif // SPARKLEUPDATER_H

View File

@@ -0,0 +1,79 @@
/*
* Strawberry Music Player
* Copyright 2025, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#import <Sparkle/Sparkle.h>
#include <QObject>
#include <QAction>
#include "sparkleupdater.h"
@interface AppUpdaterDelegate : NSObject <SPUUpdaterDelegate>
@property(nonatomic, assign) SPUStandardUpdaterController *updater_controller;
@end
@implementation AppUpdaterDelegate
- (void)observeCanCheckForUpdatesWithAction:(QAction*)action_check_updates {
[_updater_controller.updater addObserver:self forKeyPath:NSStringFromSelector(@selector(canCheckForUpdates)) options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:(void*)action_check_updates];
}
- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey, id>*)change context:(void*)context {
if ([keyPath isEqualToString:NSStringFromSelector(@selector(canCheckForUpdates))]) {
QAction *action = reinterpret_cast<QAction*>(context);
action->setEnabled(_updater_controller.updater.canCheckForUpdates);
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)dealloc {
@autoreleasepool {
[_updater_controller.updater removeObserver:self forKeyPath:NSStringFromSelector(@selector(canCheckForUpdates))];
}
[super dealloc];
}
@end
SparkleUpdater::SparkleUpdater(QAction *action_check_updates, QObject *parent) : QObject(parent) {
@autoreleasepool {
updater_delegate_ = [[AppUpdaterDelegate alloc] init];
updater_delegate_.updater_controller = [[SPUStandardUpdaterController alloc] initWithStartingUpdater:YES updaterDelegate:updater_delegate_ userDriverDelegate:nil];
[updater_delegate_ observeCanCheckForUpdatesWithAction:action_check_updates];
}
}
void SparkleUpdater::CheckForUpdates() {
@autoreleasepool {
[updater_delegate_.updater_controller checkForUpdates:nil];
}
}

View File

@@ -0,0 +1,82 @@
/*
* Strawberry Music Player
* Copyright 2025, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <QtGlobal>
#include <QString>
#include <QDir>
#include <QCoreApplication>
#include "standardpaths.h"
using namespace Qt::StringLiterals;
void StandardPaths::AppendOrganizationAndApplication(QString &path) {
const QString organization_name = QCoreApplication::organizationName().toLower();
if (!organization_name.isEmpty()) {
path += u'/' + organization_name;
}
const QString application_name = QCoreApplication::applicationName().toLower();
if (!application_name.isEmpty()) {
path += u'/' + application_name;
}
}
QString StandardPaths::WritableLocation(const StandardLocation type) {
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
switch (type) {
case StandardLocation::CacheLocation:
case StandardLocation::GenericCacheLocation:{
QString cache_location = qEnvironmentVariable("XDG_CACHE_HOME");
if (!cache_location.startsWith(u'/')) {
cache_location.clear();
}
if (cache_location.isEmpty()) {
cache_location = QDir::homePath() + "/.cache"_L1;
}
if (type == QStandardPaths::CacheLocation) {
AppendOrganizationAndApplication(cache_location);
}
return cache_location;
}
case StandardLocation::AppDataLocation:
case StandardLocation::AppLocalDataLocation:
case StandardLocation::GenericDataLocation:{
QString data_location = qEnvironmentVariable("XDG_DATA_HOME");
if (!data_location.startsWith(u'/')) {
data_location.clear();
}
if (data_location.isEmpty()) {
data_location = QDir::homePath() + "/.local/share"_L1;
}
if (type == StandardLocation::AppDataLocation || type == StandardLocation::AppLocalDataLocation) {
AppendOrganizationAndApplication(data_location);
}
return data_location;
}
default:
break;
}
#endif
return QStandardPaths::writableLocation(type);
}

36
src/core/standardpaths.h Normal file
View File

@@ -0,0 +1,36 @@
/*
* Strawberry Music Player
* Copyright 2025, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef STANDARDPATHS_H
#define STANDARDPATHS_H
#include <QStandardPaths>
class StandardPaths {
Q_GADGET
public:
using StandardLocation = QStandardPaths::StandardLocation;
static QString WritableLocation(const StandardLocation type);
private:
static void AppendOrganizationAndApplication(QString &path);
};
#endif // STANDARDPATHS_H

View File

@@ -34,7 +34,7 @@ using namespace Qt::Literals::StringLiterals;
TaskManager::TaskManager(QObject *parent) : QObject(parent), next_task_id_(1) {
setObjectName(QLatin1String(metaObject()->className()));
setObjectName(QLatin1String(QObject::metaObject()->className()));
}

View File

@@ -24,7 +24,6 @@
#include <QtGlobal>
#include <QObject>
#include <QCoreApplication>
#include <QStandardPaths>
#include <QIODevice>
#include <QMutex>
#include <QNetworkDiskCache>
@@ -32,6 +31,7 @@
#include <QAbstractNetworkCache>
#include <QUrl>
#include "standardpaths.h"
#include "threadsafenetworkdiskcache.h"
using namespace Qt::Literals::StringLiterals;
@@ -48,9 +48,9 @@ ThreadSafeNetworkDiskCache::ThreadSafeNetworkDiskCache(QObject *parent) : QAbstr
if (!sCache) {
sCache = new QNetworkDiskCache;
#ifdef Q_OS_WIN32
sCache->setCacheDirectory(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + u"/strawberry/networkcache"_s);
sCache->setCacheDirectory(StandardPaths::WritableLocation(StandardPaths::StandardLocation::TempLocation) + u"/strawberry/networkcache"_s);
#else
sCache->setCacheDirectory(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + u"/networkcache"_s);
sCache->setCacheDirectory(StandardPaths::WritableLocation(StandardPaths::StandardLocation::CacheLocation) + u"/networkcache"_s);
#endif
}

View File

@@ -0,0 +1,119 @@
set(COVERMANAGER_SOURCES
albumcovermanager.cpp
albumcovermanagerlist.cpp
albumcoverloader.cpp
albumcoverloaderoptions.cpp
albumcoverfetcher.cpp
albumcoverfetchersearch.cpp
albumcoversearcher.cpp
albumcoverexport.cpp
albumcoverexporter.cpp
albumcoverchoicecontroller.cpp
coverprovider.cpp
coverproviders.cpp
coversearchstatistics.cpp
coversearchstatisticsdialog.cpp
coverexportrunnable.cpp
currentalbumcoverloader.cpp
coverfromurldialog.cpp
jsoncoverprovider.cpp
lastfmcoverprovider.cpp
musicbrainzcoverprovider.cpp
discogscoverprovider.cpp
deezercoverprovider.cpp
musixmatchcoverprovider.cpp
opentidalcoverprovider.cpp
)
set(COVERMANAGER_HEADERS
albumcovermanager.h
albumcovermanagerlist.h
albumcoverloader.h
albumcoverfetcher.h
albumcoverfetchersearch.h
albumcoversearcher.h
albumcoverexport.h
albumcoverexporter.h
albumcoverchoicecontroller.h
coverprovider.h
coverproviders.h
coversearchstatisticsdialog.h
coverexportrunnable.h
currentalbumcoverloader.h
coverfromurldialog.h
jsoncoverprovider.h
lastfmcoverprovider.h
musicbrainzcoverprovider.h
discogscoverprovider.h
deezercoverprovider.h
musixmatchcoverprovider.h
opentidalcoverprovider.h
)
set(COVERMANAGER_UI
albumcoverexport.ui
albumcovermanager.ui
albumcoversearcher.ui
coversearchstatisticsdialog.ui
coverfromurldialog.ui
)
if(HAVE_TIDAL)
list(APPEND COVERMANAGER_SOURCES tidalcoverprovider.cpp)
list(APPEND COVERMANAGER_HEADERS tidalcoverprovider.h)
endif()
if(HAVE_SPOTIFY)
list(APPEND COVERMANAGER_SOURCES spotifycoverprovider.cpp)
list(APPEND COVERMANAGER_HEADERS spotifycoverprovider.h)
endif()
if(HAVE_QOBUZ)
list(APPEND COVERMANAGER_SOURCES qobuzcoverprovider.cpp)
list(APPEND COVERMANAGER_HEADERS qobuzcoverprovider.h)
endif()
qt_wrap_cpp(COVERMANAGER_SOURCES ${COVERMANAGER_HEADERS})
qt_wrap_ui(COVERMANAGER_SOURCES ${COVERMANAGER_UI})
add_library(strawberry_covermanager STATIC ${COVERMANAGER_SOURCES})
target_include_directories(strawberry_covermanager PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_covermanager PRIVATE
PkgConfig::GLIB
PkgConfig::GOBJECT
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Concurrent
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Sql
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets
strawberry_utilities
strawberry_core
strawberry_tagreader
strawberry_collection
strawberry_streaming
strawberry_widgets
)
if(HAVE_SUBSONIC)
target_link_libraries(strawberry_covermanager PRIVATE strawberry_subsonic)
endif()
if(HAVE_TIDAL)
target_link_libraries(strawberry_covermanager PRIVATE strawberry_tidal)
endif()
if(HAVE_SPOTIFY)
target_link_libraries(strawberry_covermanager PRIVATE strawberry_spotify)
endif()
if(HAVE_QOBUZ)
target_link_libraries(strawberry_covermanager PRIVATE strawberry_qobuz)
endif()

View File

@@ -64,7 +64,7 @@ AlbumCoverLoader::AlbumCoverLoader(const SharedPtr<TagReaderClient> tagreader_cl
load_image_async_id_(1),
original_thread_(nullptr) {
setObjectName(QLatin1String(metaObject()->className()));
setObjectName(QLatin1String(QObject::metaObject()->className()));
original_thread_ = thread();

View File

@@ -69,7 +69,7 @@
#include "core/settings.h"
#include "core/database.h"
#include "core/networkaccessmanager.h"
#include "core/songmimedata.h"
#include "mimedata/songmimedata.h"
#include "utilities/strutils.h"
#include "utilities/fileutils.h"
#include "utilities/imageutils.h"

View File

@@ -35,7 +35,7 @@
#include "includes/scoped_ptr.h"
#include "core/song.h"
#include "core/songmimedata.h"
#include "mimedata/songmimedata.h"
#include "collection/collectionbackend.h"
#include "albumcovermanager.h"
#include "albumcovermanagerlist.h"

View File

@@ -27,9 +27,9 @@
#include <QObject>
#include <QDir>
#include <QImage>
#include <QStandardPaths>
#include "core/logging.h"
#include "core/standardpaths.h"
#include "core/song.h"
#include "core/temporaryfile.h"
#include "albumcoverloader.h"
@@ -42,10 +42,10 @@ using namespace Qt::Literals::StringLiterals;
CurrentAlbumCoverLoader::CurrentAlbumCoverLoader(const SharedPtr<AlbumCoverLoader> albumcover_loader, QObject *parent)
: QObject(parent),
albumcover_loader_(albumcover_loader),
temp_file_pattern_(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + u"/strawberry-cover-XXXXXX.jpg"_s),
temp_file_pattern_(StandardPaths::WritableLocation(StandardPaths::StandardLocation::TempLocation) + u"/strawberry-cover-XXXXXX.jpg"_s),
id_(0) {
setObjectName(QLatin1String(metaObject()->className()));
setObjectName(QLatin1String(QObject::metaObject()->className()));
options_.options = AlbumCoverLoaderOptions::Option::RawImageData | AlbumCoverLoaderOptions::Option::OriginalImage | AlbumCoverLoaderOptions::Option::ScaledImage;
options_.desired_scaled_size = QSize(120, 120);

115
src/device/CMakeLists.txt Normal file
View File

@@ -0,0 +1,115 @@
set(DEVICE_SOURCES
connecteddevice.cpp
devicedatabasebackend.cpp
devicelister.cpp
devicemanager.cpp
devicestatefiltermodel.cpp
filesystemdevice.cpp
deviceviewcontainer.cpp
deviceview.cpp
deviceproperties.cpp
deviceinfo.cpp
)
set(DEVICE_HEADERS
connecteddevice.h
devicedatabasebackend.h
devicelister.h
devicemanager.h
devicestatefiltermodel.h
filesystemdevice.h
deviceviewcontainer.h
deviceview.h
deviceproperties.h
)
set(DEVICE_UI
deviceproperties.ui
deviceviewcontainer.ui
)
if(APPLE)
list(APPEND DEVICE_SOURCES macosdevicelister.mm)
list(APPEND DEVICE_HEADERS macosdevicelister.h)
endif()
if(UNIX)
list(APPEND DEVICE_SOURCES giolister.cpp)
list(APPEND DEVICE_HEADERS giolister.h)
endif()
if(HAVE_UDISKS2)
list(APPEND DEVICE_SOURCES udisks2lister.cpp)
list(APPEND DEVICE_HEADERS udisks2lister.h)
set_source_files_properties(org.freedesktop.DBus.ObjectManager.xml PROPERTIES NO_NAMESPACE objectmanager INCLUDE includes/dbus_metatypes.h)
set_source_files_properties(org.freedesktop.UDisks2.Filesystem.xml PROPERTIES NO_NAMESPACE udisks2filesystem INCLUDE includes/dbus_metatypes.h)
set_source_files_properties(org.freedesktop.UDisks2.Block.xml PROPERTIES NO_NAMESPACE udisks2block INCLUDE includes/dbus_metatypes.h)
set_source_files_properties(org.freedesktop.UDisks2.Drive.xml PROPERTIES NO_NAMESPACE udisks2drive INCLUDE includes/dbus_metatypes.h)
set_source_files_properties(org.freedesktop.UDisks2.Job.xml PROPERTIES NO_NAMESPACE udisks2job INCLUDE includes/dbus_metatypes.h)
qt_add_dbus_interface(DEVICE_SOURCES org.freedesktop.DBus.ObjectManager.xml objectmanager)
qt_add_dbus_interface(DEVICE_SOURCES org.freedesktop.UDisks2.Filesystem.xml udisks2filesystem)
qt_add_dbus_interface(DEVICE_SOURCES org.freedesktop.UDisks2.Block.xml udisks2block)
qt_add_dbus_interface(DEVICE_SOURCES org.freedesktop.UDisks2.Drive.xml udisks2drive)
qt_add_dbus_interface(DEVICE_SOURCES org.freedesktop.UDisks2.Job.xml udisks2job)
endif()
if(HAVE_MTP)
list(APPEND DEVICE_SOURCES mtpconnection.cpp mtpdevice.cpp mtploader.cpp)
list(APPEND DEVICE_HEADERS mtpconnection.h mtpdevice.h mtploader.h)
endif()
if(HAVE_AUDIOCD)
list(APPEND DEVICE_SOURCES cddadevice.cpp cddalister.cpp cddasongloader.cpp)
list(APPEND DEVICE_HEADERS cddadevice.h cddalister.h cddasongloader.h)
endif()
if(HAVE_GPOD)
list(APPEND DEVICE_SOURCES gpoddevice.cpp gpodloader.cpp)
list(APPEND DEVICE_HEADERS gpoddevice.h gpodloader.h)
endif()
qt_wrap_cpp(DEVICE_SOURCES ${DEVICE_HEADERS})
qt_wrap_ui(DEVICE_SOURCES ${DEVICE_UI})
add_library(strawberry_device STATIC ${DEVICE_SOURCES})
target_include_directories(strawberry_device PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_device PRIVATE
PkgConfig::GLIB
PkgConfig::GOBJECT
PkgConfig::GSTREAMER
PkgConfig::GSTREAMER_BASE
PkgConfig::GSTREAMER_AUDIO
PkgConfig::GSTREAMER_APP
PkgConfig::GSTREAMER_TAG
PkgConfig::GSTREAMER_PBUTILS
$<$<BOOL:${HAVE_GIO}>:PkgConfig::GIO>
$<$<BOOL:${HAVE_GIO_UNIX}>:PkgConfig::GIO_UNIX>
$<$<BOOL:${HAVE_AUDIOCD}>:PkgConfig::LIBCDIO>
$<$<BOOL:${HAVE_MTP}>:PkgConfig::LIBMTP>
$<$<BOOL:${HAVE_GPOD}>:PkgConfig::LIBGPOD PkgConfig::GDK_PIXBUF>
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Concurrent
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Sql
$<$<BOOL:${HAVE_DBUS}>:Qt${QT_VERSION_MAJOR}::DBus>
Qt${QT_VERSION_MAJOR}::Widgets
strawberry_utilities
strawberry_core
strawberry_collection
strawberry_widgets
strawberry_musicbrainz
)
if(APPLE)
target_link_libraries(strawberry_device PRIVATE
"-framework IOKit"
"-framework DiskArbitration"
)
endif()

View File

@@ -49,7 +49,7 @@ DeviceDatabaseBackend::DeviceDatabaseBackend(QObject *parent)
db_(nullptr),
original_thread_(nullptr) {
setObjectName(QLatin1String(metaObject()->className()));
setObjectName(QLatin1String(QObject::metaObject()->className()));
original_thread_ = thread();

View File

@@ -45,7 +45,7 @@ DeviceLister::DeviceLister(QObject *parent)
original_thread_(nullptr),
next_mount_request_id_(0) {
setObjectName(QLatin1String(metaObject()->className()));
setObjectName(QLatin1String(QObject::metaObject()->className()));
original_thread_ = thread();

View File

@@ -99,7 +99,7 @@ DeviceManager::DeviceManager(const SharedPtr<TaskManager> task_manager,
albumcover_loader_(albumcover_loader),
not_connected_overlay_(IconLoader::Load(u"edit-delete"_s)) {
setObjectName(QLatin1String(metaObject()->className()));
setObjectName(QLatin1String(QObject::metaObject()->className()));
thread_pool_.setMaxThreadCount(1);
QObject::connect(&*task_manager, &TaskManager::TasksChanged, this, &DeviceManager::TasksChanged);

View File

@@ -53,7 +53,7 @@
#include "core/iconloader.h"
#include "core/deletefiles.h"
#include "core/mergedproxymodel.h"
#include "core/mimedata.h"
#include "mimedata/mimedata.h"
#include "core/musicstorage.h"
#include "utilities/colorutils.h"
#include "organize/organizedialog.h"

View File

@@ -484,16 +484,22 @@ void GioLister::DeviceInfo::ReadMountInfo(GMount *mount) {
}
#ifdef HAVE_GIO_UNIX
#ifdef GLIB_VERSION_2_84
GUnixMountEntry *unix_mount = g_unix_mount_entry_for(g_file_get_path(root), nullptr);
#else
GUnixMountEntry *unix_mount = g_unix_mount_for(g_file_get_path(root), nullptr);
#endif
if (unix_mount) {
// the GIO's definition of system internal mounts include filesystems like
// autofs, tmpfs, sysfs, etc, and various system directories, including the root,
// /boot, /var, /home, etc.
// The GIO's definition of system internal mounts include filesystems like autofs, tmpfs, sysfs, etc,
// and various system directories, including the root, /boot, /var, /home, etc.
#ifdef GLIB_VERSION_2_84
is_system_internal = g_unix_mount_entry_is_system_internal(unix_mount);
g_unix_mount_entry_free(unix_mount);
#else
is_system_internal = g_unix_mount_is_system_internal(unix_mount);
g_unix_mount_free(unix_mount);
// Although checking most of the internal mounts is safe,
// we really don't want to touch autofs filesystems, as that would
// trigger automounting.
#endif
// Although checking most of the internal mounts is safe, we really don't want to touch autofs filesystems, as that would trigger automounting.
if (is_system_internal) return;
}
#endif

View File

@@ -36,10 +36,10 @@
#include <QString>
#include <QUrl>
#include <QImage>
#include <QStandardPaths>
#include "includes/shared_ptr.h"
#include "core/logging.h"
#include "core/standardpaths.h"
#include "core/temporaryfile.h"
#include "core/taskmanager.h"
#include "core/database.h"
@@ -211,9 +211,9 @@ bool GPodDevice::CopyToStorage(const CopyJob &job, QString &error_text) {
bool result = false;
if (!job.cover_image_.isNull()) {
#ifdef Q_OS_LINUX
QString temp_path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + u"/organize"_s;
QString temp_path = StandardPaths::WritableLocation(StandardPaths::StandardLocation::CacheLocation) + u"/organize"_s;
#else
QString temp_path = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
QString temp_path = StandardPaths::WritableLocation(StandardPaths::StandardLocation::TempLocation);
#endif
if (!QDir(temp_path).exists()) QDir().mkpath(temp_path);
SharedPtr<TemporaryFile> cover_file = make_shared<TemporaryFile>(temp_path + u"/track-albumcover-XXXXXX.jpg"_s);

View File

@@ -0,0 +1,59 @@
set(DIALOGS_SOURCES
about.cpp
console.cpp
errordialog.cpp
addstreamdialog.cpp
userpassdialog.cpp
deleteconfirmationdialog.cpp
lastfmimportdialog.cpp
messagedialog.cpp
snapdialog.cpp
saveplaylistsdialog.cpp
)
set(DIALOGS_HEADERS
about.h
errordialog.h
console.h
addstreamdialog.h
userpassdialog.h
deleteconfirmationdialog.h
lastfmimportdialog.h
messagedialog.h
snapdialog.h
saveplaylistsdialog.h
)
set(DIALOGS_UI
about.ui
errordialog.ui
console.ui
addstreamdialog.ui
userpassdialog.ui
lastfmimportdialog.ui
messagedialog.ui
saveplaylistsdialog.ui
)
qt_wrap_cpp(DIALOGS_SOURCES ${DIALOGS_HEADERS})
qt_wrap_ui(DIALOGS_SOURCES ${DIALOGS_UI})
add_library(strawberry_dialogs STATIC ${DIALOGS_SOURCES})
target_include_directories(strawberry_dialogs PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_dialogs PRIVATE
PkgConfig::GLIB
PkgConfig::GOBJECT
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Sql
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets
strawberry_utilities
strawberry_core
)

View File

@@ -29,7 +29,7 @@
#include <QList>
#include <QString>
#include "ui_about.h"
#include "dialogs/ui_about.h"
class QWidget;

View File

@@ -25,7 +25,7 @@
#include <QUrl>
#include <QLineEdit>
#include "ui_addstreamdialog.h"
#include "dialogs/ui_addstreamdialog.h"
class AddStreamDialog : public QDialog {
Q_OBJECT

View File

@@ -29,7 +29,7 @@
#include <QDialog>
#include <QString>
#include "ui_console.h"
#include "dialogs/ui_console.h"
#include "includes/shared_ptr.h"

View File

@@ -39,6 +39,7 @@ using namespace Qt::Literals::StringLiterals;
ErrorDialog::ErrorDialog(QWidget *parent)
: QDialog(parent),
parent_(parent),
ui_(new Ui_ErrorDialog) {
ui_->setupUi(this);
@@ -66,8 +67,11 @@ void ErrorDialog::ShowMessage(const QString &message) {
UpdateContent();
show();
raise();
activateWindow();
if (parent_ && parent_->isMaximized()) {
raise();
activateWindow();
}
}

View File

@@ -48,6 +48,7 @@ class ErrorDialog : public QDialog {
private:
void UpdateContent();
QWidget *parent_;
Ui_ErrorDialog *ui_;
QStringList current_messages_;

View File

@@ -28,7 +28,7 @@
#include "includes/shared_ptr.h"
#include "ui_lastfmimportdialog.h"
#include "dialogs/ui_lastfmimportdialog.h"
class QCloseEvent;
class LastFMImport;

View File

@@ -25,7 +25,7 @@
#include <QLineEdit>
#include <QComboBox>
#include "ui_saveplaylistsdialog.h"
#include "dialogs/ui_saveplaylistsdialog.h"
class SavePlaylistsDialog : public QDialog {
Q_OBJECT

View File

@@ -0,0 +1,44 @@
set(EDITTAGDIALOG_SOURCES
edittagdialog.cpp
trackselectiondialog.cpp
)
set(EDITTAGDIALOG_HEADERS
edittagdialog.h
trackselectiondialog.h
)
set(EDITTAGDIALOG_UI
edittagdialog.ui
trackselectiondialog.ui
)
qt_wrap_cpp(EDITTAGDIALOG_SOURCES ${EDITTAGDIALOG_HEADERS})
qt_wrap_ui(EDITTAGDIALOG_SOURCES ${EDITTAGDIALOG_UI})
add_library(strawberry_edittagdialog STATIC ${EDITTAGDIALOG_SOURCES})
target_include_directories(strawberry_edittagdialog PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_edittagdialog PRIVATE
PkgConfig::GLIB
PkgConfig::GOBJECT
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Concurrent
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Sql
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets
strawberry_core
strawberry_utilities
strawberry_tagreader
strawberry_covermanager
strawberry_widgets
strawberry_collection
strawberry_lyrics
)

89
src/engine/CMakeLists.txt Normal file
View File

@@ -0,0 +1,89 @@
set(ENGINE_SOURCES
enginebase.cpp
enginedevice.cpp
devicefinders.cpp
devicefinder.cpp
gststartup.cpp
gstengine.cpp
gstenginepipeline.cpp
)
set(ENGINE_HEADERS
enginebase.h
devicefinders.h
gststartup.h
gstengine.h
gstenginepipeline.h
)
if(HAVE_ALSA)
list(APPEND ENGINE_SOURCES alsadevicefinder.cpp alsapcmdevicefinder.cpp)
endif()
if(HAVE_PULSE)
list(APPEND ENGINE_SOURCES pulsedevicefinder.cpp)
endif()
if(MSVC)
list(APPEND ENGINE_SOURCES uwpdevicefinder.cpp asiodevicefinder.cpp)
endif()
if(HAVE_SONGFINGERPRINTING OR HAVE_MUSICBRAINZ)
list(APPEND ENGINE_SOURCES chromaprinter.cpp)
endif()
if(HAVE_EBUR128)
list(APPEND ENGINE_SOURCES ebur128analysis.cpp)
endif()
if(HAVE_MOODBAR)
list(APPEND ENGINE_SOURCES gstfastspectrumplugin.cpp gstfastspectrum.cpp)
endif()
if(APPLE)
list(APPEND ENGINE_SOURCES macosdevicefinder.cpp)
endif()
if(WIN32)
list(APPEND ENGINE_SOURCES directsounddevicefinder.cpp mmdevicefinder.cpp)
endif()
qt_wrap_cpp(ENGINE_SOURCES ${ENGINE_HEADERS})
add_library(strawberry_engine STATIC ${ENGINE_SOURCES})
target_include_directories(strawberry_engine PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_engine PRIVATE
PkgConfig::GLIB
PkgConfig::GOBJECT
$<$<BOOL:${HAVE_ALSA}>:ALSA::ALSA>
$<$<BOOL:${HAVE_PULSE}>:PkgConfig::LIBPULSE>
$<$<BOOL:${WIN32}>:dsound>
$<$<BOOL:${MSVC}>:WindowsApp>
PkgConfig::GSTREAMER
PkgConfig::GSTREAMER_BASE
PkgConfig::GSTREAMER_AUDIO
PkgConfig::GSTREAMER_APP
PkgConfig::GSTREAMER_TAG
PkgConfig::GSTREAMER_PBUTILS
$<$<BOOL:${HAVE_SONGFINGERPRINTING} OR ${HAVE_MUSICBRAINZ}>:PkgConfig::CHROMAPRINT>
$<$<BOOL:${HAVE_EBUR128}>:PkgConfig::LIBEBUR128>
$<$<BOOL:${HAVE_MOODBAR}>:PkgConfig::FFTW3>
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Concurrent
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Gui
strawberry_core
)
if(APPLE)
target_link_libraries(strawberry_engine PRIVATE
"-framework CoreAudio"
)
endif()

View File

@@ -53,7 +53,7 @@ using namespace Qt::Literals::StringLiterals;
DeviceFinders::DeviceFinders(QObject *parent) : QObject(parent) {
setObjectName(QLatin1String(metaObject()->className()));
setObjectName(QLatin1String(QObject::metaObject()->className()));
}

View File

@@ -120,7 +120,7 @@ class EngineBase : public QObject {
// Plays a media stream represented with the URL 'u' from the given 'beginning' to the given 'end' (usually from 0 to a song's length).
// Both markers should be passed in nanoseconds. 'end' can be negative, indicating that the real length of 'u' stream is unknown.
bool Play(const QUrl &media_url, const QUrl &stream_url, const bool pause, const TrackChangeFlags flags, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec, const quint64 offset_nanosec, const std::optional<double> ebur128_integrated_loudness_lufs);
bool Play(const QUrl &media_url, const QUrl &stream_url, const bool pause, const TrackChangeFlags flags, const bool force_stop_at_end, const quint64 beginning_offset_nanosec, const qint64 end_offset_nanosec, const quint64 offset_nanosec, const std::optional<double> ebur128_integrated_loudness_lufs);
void SetVolume(const uint volume);
public Q_SLOTS:

View File

@@ -62,7 +62,6 @@
#include "gstbufferconsumer.h"
using namespace Qt::Literals::StringLiterals;
using std::make_shared;
#ifdef __clang__
# pragma clang diagnostic push
@@ -897,7 +896,7 @@ void GstEngine::StopTimers() {
GstEnginePipelinePtr GstEngine::CreatePipeline() {
GstEnginePipelinePtr pipeline = make_shared<GstEnginePipeline>();
GstEnginePipelinePtr pipeline = GstEnginePipelinePtr(new GstEnginePipeline);
pipeline->set_output_device(output_, device_);
pipeline->set_exclusive_mode(exclusive_mode_);
pipeline->set_volume_enabled(volume_control_);

View File

@@ -174,7 +174,11 @@ GstEnginePipeline::GstEnginePipeline(QObject *parent)
logged_unsupported_analyzer_format_(false),
about_to_finish_(false),
finish_requested_(false),
finished_(false) {
finished_(false),
set_state_in_progress_(0),
set_state_async_in_progress_(0),
last_set_state_in_progress_(GST_STATE_VOID_PENDING),
last_set_state_async_in_progress_(GST_STATE_VOID_PENDING) {
eq_band_gains_.reserve(kEqBandCount);
for (int i = 0; i < kEqBandCount; ++i) eq_band_gains_ << 0;
@@ -419,11 +423,16 @@ bool GstEnginePipeline::Finish() {
Disconnect();
if (IsStateNull()) {
if (IsStateNull() && set_state_async_in_progress_ == 0 && set_state_in_progress_ == 0) {
finished_ = true;
}
else {
SetState(GST_STATE_NULL);
if (set_state_async_in_progress_ > 0 && last_set_state_async_in_progress_ != GST_STATE_NULL) {
SetStateAsync(GST_STATE_NULL);
}
else if ((!IsStateNull() || set_state_in_progress_ > 0) && last_set_state_in_progress_ != GST_STATE_NULL) {
SetState(GST_STATE_NULL);
}
}
return finished_.value();
@@ -1792,7 +1801,19 @@ bool GstEnginePipeline::IsStateNull() const {
void GstEnginePipeline::SetStateAsync(const GstState state) {
QMetaObject::invokeMethod(this, "SetState", Qt::QueuedConnection, Q_ARG(GstState, state));
last_set_state_async_in_progress_ = state;
++set_state_async_in_progress_;
QMetaObject::invokeMethod(this, "SetStateAsyncSlot", Qt::QueuedConnection, Q_ARG(GstState, state));
}
void GstEnginePipeline::SetStateAsyncSlot(const GstState state) {
last_set_state_async_in_progress_ = GST_STATE_VOID_PENDING;
--set_state_async_in_progress_;
SetState(state);
}
@@ -1800,6 +1821,9 @@ QFuture<GstStateChangeReturn> GstEnginePipeline::SetState(const GstState state)
qLog(Debug) << "Setting pipeline" << id() << "state to" << GstStateText(state);
last_set_state_in_progress_ = state;
++set_state_in_progress_;
QFutureWatcher<GstStateChangeReturn> *watcher = new QFutureWatcher<GstStateChangeReturn>();
QObject::connect(watcher, &QFutureWatcher<GstStateChangeReturn>::finished, this, [this, watcher, state]() {
const GstStateChangeReturn state_change_return = watcher->result();
@@ -1815,13 +1839,16 @@ QFuture<GstStateChangeReturn> GstEnginePipeline::SetState(const GstState state)
void GstEnginePipeline::SetStateFinishedSlot(const GstState state, const GstStateChangeReturn state_change_return) {
last_set_state_in_progress_ = GST_STATE_VOID_PENDING;
--set_state_in_progress_;
switch (state_change_return) {
case GST_STATE_CHANGE_SUCCESS:
case GST_STATE_CHANGE_ASYNC:
case GST_STATE_CHANGE_NO_PREROLL:
qLog(Debug) << "Pipeline" << id() << "state successfully set to" << GstStateText(state);
Q_EMIT SetStateFinished(state_change_return);
if (!finished_.value() && finish_requested_.value()) {
if (!finished_.value() && finish_requested_.value() && set_state_async_in_progress_ == 0 && set_state_in_progress_ == 0) {
finished_ = true;
Q_EMIT Finished();
}

View File

@@ -41,6 +41,7 @@
#include <QVariant>
#include <QString>
#include <QUrl>
#include <QSharedPointer>
#include "includes/shared_ptr.h"
#include "includes/mutex_protected.h"
@@ -197,6 +198,7 @@ class GstEnginePipeline : public QObject {
void ProcessPendingSeek(const GstState state);
private Q_SLOTS:
void SetStateAsyncSlot(const GstState state);
void SetStateFinishedSlot(const GstState state, const GstStateChangeReturn state_change_return);
void SetFaderVolume(const qreal volume);
void FaderTimelineStateChanged(const QTimeLine::State state);
@@ -368,8 +370,14 @@ class GstEnginePipeline : public QObject {
mutex_protected<bool> about_to_finish_;
mutex_protected<bool> finish_requested_;
mutex_protected<bool> finished_;
mutex_protected<int> set_state_in_progress_;
mutex_protected<int> set_state_async_in_progress_;
mutex_protected<GstState> last_set_state_in_progress_;
mutex_protected<GstState> last_set_state_async_in_progress_;
};
using GstEnginePipelinePtr = SharedPtr<GstEnginePipeline>;
using GstEnginePipelinePtr = QSharedPointer<GstEnginePipeline>;
#endif // GSTENGINEPIPELINE_H

View File

@@ -26,12 +26,12 @@
#include <gst/pbutils/pbutils.h>
#include <QCoreApplication>
#include <QStandardPaths>
#include <QString>
#include <QDir>
#include <QFile>
#include "core/logging.h"
#include "core/standardpaths.h"
#include "utilities/envutils.h"
#ifdef HAVE_MOODBAR
@@ -145,7 +145,7 @@ void SetEnvironment() {
#endif // USE_BUNDLE
#if defined(Q_OS_WIN32) || defined(Q_OS_MACOS)
QString gst_registry_filename = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QStringLiteral("/gst-registry-%1-bin").arg(QCoreApplication::applicationVersion());
QString gst_registry_filename = StandardPaths::WritableLocation(StandardPaths::StandardLocation::AppLocalDataLocation) + QStringLiteral("/gst-registry-%1-bin").arg(QCoreApplication::applicationVersion());
qLog(Debug) << "Setting GStreamer registry file to" << gst_registry_filename;
Utilities::SetEnv("GST_REGISTRY", gst_registry_filename);
#endif

View File

@@ -0,0 +1,36 @@
set(EQUALIZER_SOURCES
equalizer.cpp
equalizerslider.cpp
)
set(EQUALIZER_HEADERS
equalizer.h
equalizerslider.h
)
set(EQUALIZER_UI
equalizer.ui
equalizerslider.ui
)
qt_wrap_cpp(EQUALIZER_SOURCES ${EQUALIZER_HEADERS})
qt_wrap_ui(EQUALIZER_SOURCES ${EQUALIZER_UI})
add_library(strawberry_equalizer STATIC ${EQUALIZER_SOURCES})
target_include_directories(strawberry_equalizer PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_equalizer PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets
strawberry_core
strawberry_widgets
)

View File

@@ -0,0 +1,35 @@
set(FILEVIEW_SOURCES
fileview.cpp
fileviewlist.cpp
)
set(FILEVIEW_HEADERS
fileview.h
fileviewlist.h
)
set(FILEVIEW_UI
fileview.ui
)
qt_wrap_cpp(FILEVIEW_SOURCES ${FILEVIEW_HEADERS})
qt_wrap_ui(FILEVIEW_SOURCES ${FILEVIEW_UI})
add_library(strawberry_fileview STATIC ${FILEVIEW_SOURCES})
target_include_directories(strawberry_fileview PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_fileview PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Widgets
strawberry_utilities
strawberry_core
strawberry_mimedata
strawberry_dialogs
strawberry_organize
)

View File

@@ -41,7 +41,7 @@
#include "core/filesystemmusicstorage.h"
#include "core/iconloader.h"
#include "core/settings.h"
#include "core/mimedata.h"
#include "mimedata/mimedata.h"
#include "dialogs/deleteconfirmationdialog.h"
#include "fileview.h"
#include "fileviewlist.h"

View File

@@ -32,7 +32,7 @@
#include <QtEvents>
#include "core/iconloader.h"
#include "core/mimedata.h"
#include "mimedata/mimedata.h"
#include "utilities/filemanagerutils.h"
#include "fileviewlist.h"

View File

@@ -0,0 +1,52 @@
set(SOURCES
filterparser.cpp
filtertree.cpp
filtertreeand.cpp
filtertreecolumnterm.cpp
filtertreenop.cpp
filtertreenot.cpp
filtertreeor.cpp
filtertreeterm.cpp
filterparserfloateqcomparator.cpp
filterparserfloatgecomparator.cpp
filterparserfloatgtcomparator.cpp
filterparserfloatlecomparator.cpp
filterparserfloatltcomparator.cpp
filterparserfloatnecomparator.cpp
filterparserint64eqcomparator.cpp
filterparserint64gecomparator.cpp
filterparserint64gtcomparator.cpp
filterparserint64lecomparator.cpp
filterparserint64ltcomparator.cpp
filterparserint64necomparator.cpp
filterparserinteqcomparator.cpp
filterparserintgecomparator.cpp
filterparserintgtcomparator.cpp
filterparserintlecomparator.cpp
filterparserintltcomparator.cpp
filterparserintnecomparator.cpp
filterparsersearchtermcomparator.cpp
filterparsertextcontainscomparator.cpp
filterparsertexteqcomparator.cpp
filterparsertextnecomparator.cpp
filterparseruinteqcomparator.cpp
filterparseruintgecomparator.cpp
filterparseruintgtcomparator.cpp
filterparseruintlecomparator.cpp
filterparseruintltcomparator.cpp
filterparseruintnecomparator.cpp
)
add_library(strawberry_filterparser STATIC ${SOURCES})
target_include_directories(strawberry_filterparser PRIVATE
${CMAKE_SOURCE_DIR}
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_filterparser PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Gui
)

View File

@@ -188,8 +188,15 @@ FilterTree *FilterParser::parseSearchTerm() {
QString value;
bool in_quotes = false;
bool previous_char_operator = false;
for (; iter_ != end_; ++iter_) {
if (previous_char_operator) {
if (iter_->isSpace()) {
continue;
}
previous_char_operator = false;
}
if (in_quotes) {
if (*iter_ == u'"') {
in_quotes = false;
@@ -206,6 +213,7 @@ FilterTree *FilterParser::parseSearchTerm() {
column = buf_.toLower();
buf_.clear();
prefix.clear(); // Prefix isn't allowed here - let's ignore it
previous_char_operator = true;
}
else if (iter_->isSpace() || *iter_ == u'(' || *iter_ == u')' || *iter_ == u'-') {
break;
@@ -214,9 +222,11 @@ FilterTree *FilterParser::parseSearchTerm() {
// We don't know whether there is a column part in this search term thus we assume the latter and just try and read a prefix
if (prefix.isEmpty() && (*iter_ == u'>' || *iter_ == u'<' || *iter_ == u'=' || *iter_ == u'!')) {
prefix += *iter_;
previous_char_operator = true;
}
else if (prefix != u'=' && *iter_ == u'=') {
prefix += *iter_;
previous_char_operator = true;
}
else {
buf_ += *iter_;

View File

@@ -0,0 +1,64 @@
set(GLOBALSHORTCUTS_SOURCES globalshortcutsmanager.cpp globalshortcutsbackend.cpp globalshortcutgrabber.cpp)
set(GLOBALSHORTCUTS_HEADERS globalshortcutsmanager.h globalshortcutsbackend.h globalshortcutgrabber.h)
set(GLOBALSHORTCUTS_UI globalshortcutgrabber.ui)
if(HAVE_KDE_GLOBALSHORTCUTS)
list(APPEND GLOBALSHORTCUTS_SOURCES globalshortcutsbackend-kde.cpp globalshortcutsbackend-gnome.cpp globalshortcutsbackend-mate.cpp)
list(APPEND GLOBALSHORTCUTS_HEADERS globalshortcutsbackend-kde.h globalshortcutsbackend-gnome.h globalshortcutsbackend-mate.h)
endif()
if(HAVE_X11_GLOBALSHORTCUTS)
list(APPEND GLOBALSHORTCUTS_SOURCES globalshortcutsbackend-x11.cpp globalshortcut.cpp globalshortcut-x11.cpp)
list(APPEND GLOBALSHORTCUTS_HEADERS globalshortcutsbackend-x11.h globalshortcut.h)
endif()
if(APPLE)
list(APPEND GLOBALSHORTCUTS_SOURCES globalshortcutsbackend-macos.mm globalshortcutgrabber.mm)
list(APPEND GLOBALSHORTCUTS_HEADERS globalshortcutsbackend-macos.h globalshortcutgrabber.h)
endif()
if(WIN32)
list(APPEND GLOBALSHORTCUTS_SOURCES globalshortcutsbackend-win.cpp globalshortcut.cpp globalshortcut-win.cpp)
list(APPEND GLOBALSHORTCUTS_HEADERS globalshortcutsbackend-win.h globalshortcut.h)
endif()
if(HAVE_KDE_GLOBALSHORTCUTS)
qt_add_dbus_interface(GLOBALSHORTCUTS_SOURCES org.kde.KGlobalAccel.xml kglobalaccel)
qt_add_dbus_interface(GLOBALSHORTCUTS_SOURCES org.kde.KGlobalAccel.Component.xml kglobalaccelcomponent)
endif()
if(HAVE_GNOME_GLOBALSHORTCUTS)
qt_add_dbus_interface(GLOBALSHORTCUTS_SOURCES org.gnome.SettingsDaemon.MediaKeys.xml gnomesettingsdaemon)
endif()
if(HAVE_MATE_GLOBALSHORTCUTS)
qt_add_dbus_interface(GLOBALSHORTCUTS_SOURCES org.mate.SettingsDaemon.MediaKeys.xml matesettingsdaemon)
endif()
qt_wrap_cpp(GLOBALSHORTCUTS_SOURCES ${GLOBALSHORTCUTS_HEADERS})
qt_wrap_ui(GLOBALSHORTCUTS_SOURCES ${GLOBALSHORTCUTS_UI})
add_library(strawberry_globalshortcuts STATIC ${GLOBALSHORTCUTS_SOURCES})
target_include_directories(strawberry_globalshortcuts PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_globalshortcuts PRIVATE
$<$<BOOL:${HAVE_X11_GLOBALSHORTCUTS}>:X11::X11_xcb>
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets
$<$<BOOL:${HAVE_DBUS}>:Qt${QT_VERSION_MAJOR}::DBus>
strawberry_core
)
if(APPLE)
target_link_libraries(strawberry_globalshortcuts PRIVATE
"-framework ScriptingBridge"
strawberry_macstartup
)
endif()

View File

@@ -32,7 +32,7 @@
#include <QKeyEvent>
#include "globalshortcutgrabber.h"
#include "ui_globalshortcutgrabber.h"
#include "globalshortcuts/ui_globalshortcutgrabber.h"
using namespace Qt::Literals::StringLiterals;

View File

@@ -29,7 +29,7 @@
#include <QKeySequence>
#import "core/mac_startup.h"
#import "macstartup/mac_startup.h"
class MacMonitorWrapper {
public:

View File

@@ -35,8 +35,8 @@
#include "globalshortcutsbackend-kglobalaccel.h"
#include "kglobalaccel.h"
#include "kglobalaccelcomponent.h"
#include "globalshortcuts/kglobalaccel.h"
#include "globalshortcuts/kglobalaccelcomponent.h"
using namespace Qt::Literals::StringLiterals;

View File

@@ -38,7 +38,7 @@
#include "globalshortcutsmanager.h"
#include "core/logging.h"
#include "core/mac_startup.h"
#include "macstartup/mac_startup.h"
#import "includes/SBSystemPreferences.h"

View File

@@ -54,8 +54,8 @@ class Lazy {
T* operator->() const { return get(); }
// Returns true if the object is not yet initialized.
explicit operator bool() const { return ptr_; }
// Returns true if the object is initialized.
explicit operator bool() const { return ptr_ != nullptr; }
// Deletes the underlying object and will re-run the initialization function if the object is requested again.
void reset() { ptr_.reset(); }

View File

@@ -47,6 +47,56 @@ class mutex_protected : public boost::noncopyable {
return value == value_;
}
bool operator!=(const mutex_protected &value) const {
QMutexLocker l(&mutex_);
return value.value() != value_;
}
bool operator!=(const T value) const {
QMutexLocker l(&mutex_);
return value != value_;
}
bool operator>(const mutex_protected &value) const {
QMutexLocker l(&mutex_);
return value_ > value.value();
}
bool operator>(const T value) const {
QMutexLocker l(&mutex_);
return value_ > value;
}
bool operator>=(const mutex_protected &value) const {
QMutexLocker l(&mutex_);
return value_ >= value.value();
}
bool operator>=(const T value) const {
QMutexLocker l(&mutex_);
return value_ >= value;
}
bool operator<(const mutex_protected &value) const {
QMutexLocker l(&mutex_);
return value_ < value.value();
}
bool operator<(const T value) const {
QMutexLocker l(&mutex_);
return value_ < value;
}
bool operator<=(const mutex_protected &value) const {
QMutexLocker l(&mutex_);
return value_ <= value.value();
}
bool operator<=(const T value) const {
QMutexLocker l(&mutex_);
return value_ <= value;
}
void operator=(const mutex_protected &value) {
QMutexLocker l(&mutex_);
value_ = value.value();
@@ -57,6 +107,36 @@ class mutex_protected : public boost::noncopyable {
value_ = value;
}
void operator++() {
QMutexLocker l(&mutex_);
++value_;
}
void operator+=(const T value) {
QMutexLocker l(&mutex_);
value_ += value;
}
void operator+=(const mutex_protected value) {
QMutexLocker l(&mutex_);
value_ += value.value();
}
void operator--() {
QMutexLocker l(&mutex_);
--value_;
}
void operator-=(const T value) {
QMutexLocker l(&mutex_);
value_ -= value;
}
void operator-=(const mutex_protected value) {
QMutexLocker l(&mutex_);
value_ -= value.value();
}
private:
T value_;
mutable QMutex mutex_;

60
src/lyrics/CMakeLists.txt Normal file
View File

@@ -0,0 +1,60 @@
set(LYRICS_SOURCES
lyricsproviders.cpp
lyricsprovider.cpp
lyricssearchrequest.h
lyricssearchresult.h
lyricsfetcher.cpp
lyricsfetchersearch.cpp
jsonlyricsprovider.cpp
htmllyricsprovider.cpp
ovhlyricsprovider.cpp
lololyricsprovider.cpp
geniuslyricsprovider.cpp
musixmatchlyricsprovider.cpp
chartlyricsprovider.cpp
songlyricscomlyricsprovider.cpp
azlyricscomlyricsprovider.cpp
elyricsnetlyricsprovider.cpp
letraslyricsprovider.cpp
lyricfindlyricsprovider.cpp
)
set(LYRICS_HEADERS
lyricsproviders.h
lyricsprovider.h
lyricsfetcher.h
lyricsfetchersearch.h
jsonlyricsprovider.h
htmllyricsprovider.h
ovhlyricsprovider.h
lololyricsprovider.h
geniuslyricsprovider.h
musixmatchlyricsprovider.h
chartlyricsprovider.h
songlyricscomlyricsprovider.h
azlyricscomlyricsprovider.h
elyricsnetlyricsprovider.h
letraslyricsprovider.h
lyricfindlyricsprovider.h
)
qt_wrap_cpp(LYRICS_SOURCES ${LYRICS_HEADERS})
add_library(strawberry_lyrics STATIC ${LYRICS_SOURCES})
target_include_directories(strawberry_lyrics PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_lyrics PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets
strawberry_utilities
strawberry_core
strawberry_providers
)

View File

@@ -44,7 +44,7 @@ using std::make_shared;
LyricsProviders::LyricsProviders(QObject *parent) : QObject(parent), thread_(new QThread(this)), network_(make_shared<NetworkAccessManager>()) {
setObjectName(QLatin1String(metaObject()->className()));
setObjectName(QLatin1String(QObject::metaObject()->className()));
thread_->setObjectName(objectName());
network_->moveToThread(thread_);
thread_->start();

View File

@@ -0,0 +1,22 @@
set(MACSTARTUP_SOURCES mac_startup.mm)
add_library(strawberry_macstartup STATIC ${MACSTARTUP_SOURCES})
target_include_directories(strawberry_macstartup PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
)
target_link_libraries(strawberry_macstartup PRIVATE
"-framework Foundation"
"-framework AppKit"
"-framework IOKit"
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Widgets
SPMediaKeyTap
strawberry_utilities
strawberry_core
strawberry_globalshortcuts
)

Some files were not shown because too many files have changed in this diff Show More