Compare commits

...

51 Commits
0.9.1 ... 0.9.2

Author SHA1 Message Date
Jonas Kvinge
ae5da12afb Release 0.9.2 2021-03-25 23:24:16 +01:00
Jonas Kvinge
a3042b8f79 Update Changelog 2021-03-25 23:23:35 +01:00
Jonas Kvinge
29cbfe7c1a Change last played to qint64 2021-03-25 23:23:13 +01:00
Strawbs Bot
1ddc3292cc Update translations 2021-03-25 01:03:59 +01:00
Jonas Kvinge
658e1d122e Remove set current to all artists when opening cover manager
Caused sluggish opening
2021-03-24 22:30:58 +01:00
Jonas Kvinge
d936a080db Check for empty image 2021-03-24 22:30:37 +01:00
Jonas Kvinge
2a92af1e09 Change static_cast 2021-03-24 22:29:56 +01:00
Jonas Kvinge
9cde537066 Fix moodbar 2021-03-23 01:44:00 +01:00
Strawbs Bot
ffc5446914 Update translations 2021-03-22 01:23:51 +01:00
Jonas Kvinge
5f70b32795 Remove unused using std::shared_ptr 2021-03-21 20:23:42 +01:00
Jonas Kvinge
6b6117653a Allow audio formats unsupported by taglib to be added
Fixes #669
2021-03-21 19:19:35 +01:00
Jonas Kvinge
59bffed47f Use static_cast 2021-03-21 18:53:02 +01:00
Jonas Kvinge
f91a679cdf Add override 2021-03-21 18:40:33 +01:00
Jonas Kvinge
66b8d27d66 Change to QList 2021-03-21 06:26:48 +01:00
Jonas Kvinge
1219f504ea Update CI 2021-03-21 06:09:24 +01:00
Jonas Kvinge
ee5a191e39 Change to qint64 2021-03-21 06:07:11 +01:00
Jonas Kvinge
f577aa8d4f Update Changelog 2021-03-21 04:55:59 +01:00
Jonas Kvinge
2436c87372 Use variable 2021-03-21 04:55:00 +01:00
Jonas Kvinge
e90b5e63e5 Move variable 2021-03-21 04:49:22 +01:00
Jonas Kvinge
78588d8cdf Fix various clazy warnings 2021-03-21 04:47:11 +01:00
Jonas Kvinge
20c1c1d4be Remove unused variables 2021-03-21 04:43:55 +01:00
Jonas Kvinge
329dfb21b9 These don't need to be slots 2021-03-21 04:38:47 +01:00
Jonas Kvinge
02c30211a7 Call AbstractMessageHandler::AbortAll 2021-03-21 04:37:30 +01:00
Jonas Kvinge
645da2713d Remove emit from slots 2021-03-21 04:36:54 +01:00
Jonas Kvinge
20c5a79efa Fix playlist tabbar close and save 2021-03-21 04:28:22 +01:00
Jonas Kvinge
b224aeb0d8 Use 4arg connects for networkreplies 2021-03-21 00:37:17 +01:00
Jonas Kvinge
73eebd6162 Set album cover filename by pattern as default when saving cover to album directory 2021-03-20 23:13:54 +01:00
Strawbs Bot
99a1851f4d Update translations 2021-03-20 23:02:12 +01:00
Jonas Kvinge
d9d89d0927 Update Changelog 2021-03-20 21:21:36 +01:00
Jonas Kvinge
54f2aa5f77 Update copyrights 2021-03-20 21:14:47 +01:00
Jonas Kvinge
d022e9dd00 Close the file 2021-03-20 19:23:33 +01:00
Jonas Kvinge
17cf8ec1c6 Move declaration 2021-03-20 19:11:05 +01:00
Jonas Kvinge
c4a6d81cda Fix copying album covers to iPod
Cover file was deleted too soon.
File needs to be accessible until itdb_write is called.

Fixes #663
2021-03-20 19:00:42 +01:00
Jonas Kvinge
66ed485803 Check for existence of directory 2021-03-20 18:58:38 +01:00
Jonas Kvinge
6de585d1c8 Make sure process files isn't again called after finishing 2021-03-20 15:22:21 +01:00
Jonas Kvinge
9498638988 Make macdeployqt use environment variables for gstreamer 2021-03-20 14:19:49 +01:00
Jonas Kvinge
87dad82210 Update README.md 2021-03-19 00:35:13 +01:00
Jonas Kvinge
e37aec16ac Enable tumbleweed 2021-03-19 00:25:33 +01:00
Jonas Kvinge
6fb48af598 Fix macOS deployment 2021-03-18 23:08:50 +01:00
Jonas Kvinge
8193be36e5 Use a modified version of macdeployqt 2021-03-17 21:12:12 +01:00
Jonas Kvinge
a7df2bc4fb Use original file when loading cover from file in album cover manager 2021-03-16 17:18:11 +01:00
Jonas Kvinge
5eda028af3 Minor code improvements to album cover loader 2021-03-16 17:17:22 +01:00
Jonas Kvinge
f77475dbfe Specifically set get image 2021-03-16 17:16:40 +01:00
Jonas Kvinge
96c1a35c8e Use macdeploy.py for Qt plugins 2021-03-16 17:13:33 +01:00
Jonas Kvinge
0ef26be03f Remove DEBUG define 2021-03-16 17:12:44 +01:00
Jonas Kvinge
f5bb15f72e Fix QSearchField on macOS 2021-03-15 22:38:06 +01:00
Jonas Kvinge
d84aebd8f4 Format code 2021-03-15 22:37:49 +01:00
Jonas Kvinge
7d8d9f4c4d Format code 2021-03-14 23:20:16 +01:00
Jonas Kvinge
61b201810d Fix marking songs available 2021-03-14 23:08:05 +01:00
Jonas Kvinge
c75db8dc60 Turn back git revision 2021-03-14 02:32:42 +01:00
Jonas Kvinge
e0bf4091dd Update Changelog 2021-03-13 16:17:06 +01:00
517 changed files with 9702 additions and 7541 deletions

View File

@@ -72,83 +72,6 @@ jobs:
run: ../dist/scripts/maketarball.sh
build_opensuse_lp151:
name: Build openSUSE Leap 15.1
runs-on: ubuntu-latest
container:
image: opensuse/leap:15.1
steps:
- uses: actions/checkout@v1.2.0
- name: Update packages
run: zypper --non-interactive --gpg-auto-import-keys ref
- name: Install openSUSE dependencies
run: >
zypper --non-interactive --gpg-auto-import-keys install
lsb-release
rpm-build
git
tar
make
cmake
gcc
gcc-c++
gettext-tools
glibc-devel
libboost_headers-devel
boost-devel
glib2-devel
glib2-tools
dbus-1-devel
alsa-devel
libnotify-devel
libgnutls-devel
protobuf-devel
sqlite3-devel
libpulse-devel
gstreamer-devel
gstreamer-plugins-base-devel
vlc-devel
taglib-devel
libQt5Core-devel
libQt5Gui-devel
libQt5Widgets-devel
libQt5Concurrent-devel
libQt5Network-devel
libQt5Sql-devel
libQt5DBus-devel
libQt5Test-devel
libqt5-qtx11extras-devel
libqt5-qtbase-common-devel
libQt5Sql5-sqlite
libqt5-linguist-devel
libcdio-devel
libgpod-devel
libmtp-devel
libchromaprint-devel
desktop-file-utils
update-desktop-files
appstream-glib
hicolor-icon-theme
- name: Create Build Environment
shell: bash
run: cmake -E make_directory build
- name: Configure CMake
shell: bash
working-directory: build
run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_WERROR=ON
- name: Create source tarball
working-directory: build
run: ../dist/scripts/maketarball.sh
- name: Create RPM build sources directories
run: mkdir -p ~/rpmbuild/SOURCES /usr/src/packages/SOURCES
- name: Copy source tarball
working-directory: build
run: cp strawberry-*.tar.xz /usr/src/packages/SOURCES/
- name: Build RPM
working-directory: build
run: rpmbuild -ba ../dist/unix/strawberry.spec
build_opensuse_lp152_qt5:
name: Build openSUSE Leap 15.2 Qt 5
runs-on: ubuntu-latest
@@ -225,6 +148,7 @@ jobs:
working-directory: build
run: rpmbuild -ba ../dist/unix/strawberry.spec
build_opensuse_lp152_qt6:
name: Build openSUSE Leap 15.2 Qt 6
runs-on: ubuntu-latest
@@ -302,165 +226,317 @@ jobs:
working-directory: build
run: rpmbuild -ba ../dist/unix/strawberry.spec
#build_opensuse_tumbleweed_qt5:
#name: Build openSUSE Tumbleweed Qt 5
#runs-on: ubuntu-latest
#container:
#image: opensuse/tumbleweed
#steps:
#- uses: actions/checkout@v1.2.0
#- name: Lock packages
#run: zypper --non-interactive --gpg-auto-import-keys addlock openssh-server
#- name: Update packages
#run: zypper --non-interactive --gpg-auto-import-keys ref
#- name: Upgrade packages
#run: zypper --non-interactive --gpg-auto-import-keys dup
#- name: Install openSUSE dependencies
#run: >
#zypper --non-interactive --gpg-auto-import-keys install
#lsb-release
#rpm-build
#git
#tar
#make
#cmake
#gcc
#gcc-c++
#gettext-tools
#glibc-devel
#libboost_headers-devel
#boost-devel
#glib2-devel
#glib2-tools
#dbus-1-devel
#alsa-devel
#libnotify-devel
#libgnutls-devel
#protobuf-devel
#sqlite3-devel
#libpulse-devel
#gstreamer-devel
#gstreamer-plugins-base-devel
#vlc-devel
#taglib-devel
#libQt5Core-devel
#libQt5Gui-devel
#libQt5Widgets-devel
#libQt5Concurrent-devel
#libQt5Network-devel
#libQt5Sql-devel
#libQt5DBus-devel
#libQt5Test-devel
#libqt5-qtx11extras-devel
#libqt5-qtbase-common-devel
#libQt5Sql5-sqlite
#libqt5-linguist-devel
#libcdio-devel
#libgpod-devel
#libmtp-devel
#libchromaprint-devel
#desktop-file-utils
#update-desktop-files
#appstream-glib
#hicolor-icon-theme
#- name: Create Build Environment
#shell: bash
#run: cmake -E make_directory build
#- name: Configure CMake
#shell: bash
#working-directory: build
#run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_WERROR=ON -DBUILD_WITH_QT5=ON
#- name: Create source tarball
#working-directory: build
#run: ../dist/scripts/maketarball.sh
#- name: Create RPM build sources directories
#run: mkdir -p ~/rpmbuild/SOURCES /usr/src/packages/SOURCES
#- name: Copy source tarball
#working-directory: build
#run: cp strawberry-*.tar.xz /usr/src/packages/SOURCES/
#- name: Build RPM
#working-directory: build
#run: rpmbuild -ba ../dist/unix/strawberry.spec
build_opensuse_lp153_qt5:
name: Build openSUSE Leap 15.3 Qt 5
runs-on: ubuntu-latest
container:
image: opensuse/leap:15.3
steps:
- uses: actions/checkout@v1.2.0
- name: Update packages
run: zypper --non-interactive --gpg-auto-import-keys ref
- name: Install openSUSE dependencies
run: >
zypper --non-interactive --gpg-auto-import-keys install
lsb-release
rpm-build
git
tar
make
cmake
gcc
gcc-c++
gettext-tools
glibc-devel
libboost_headers-devel
boost-devel
glib2-devel
glib2-tools
dbus-1-devel
alsa-devel
libnotify-devel
libgnutls-devel
protobuf-devel
sqlite3-devel
libpulse-devel
gstreamer-devel
gstreamer-plugins-base-devel
vlc-devel
taglib-devel
libQt5Core-devel
libQt5Gui-devel
libQt5Widgets-devel
libQt5Concurrent-devel
libQt5Network-devel
libQt5Sql-devel
libQt5DBus-devel
libQt5Test-devel
libqt5-qtx11extras-devel
libqt5-qtbase-common-devel
libQt5Sql5-sqlite
libqt5-linguist-devel
libcdio-devel
libgpod-devel
libmtp-devel
libchromaprint-devel
desktop-file-utils
update-desktop-files
appstream-glib
hicolor-icon-theme
- name: Create Build Environment
shell: bash
run: cmake -E make_directory build
- name: Configure CMake
shell: bash
working-directory: build
run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_WERROR=ON -DBUILD_WITH_QT5=ON
- name: Create source tarball
working-directory: build
run: ../dist/scripts/maketarball.sh
- name: Create RPM build sources directories
run: mkdir -p ~/rpmbuild/SOURCES /usr/src/packages/SOURCES
- name: Copy source tarball
working-directory: build
run: cp strawberry-*.tar.xz /usr/src/packages/SOURCES/
- name: Build RPM
working-directory: build
run: rpmbuild -ba ../dist/unix/strawberry.spec
#build_opensuse_tumbleweed_qt6:
#name: Build openSUSE Tumbleweed Qt 6
#runs-on: ubuntu-latest
#container:
#image: opensuse/tumbleweed
#steps:
#- uses: actions/checkout@v1.2.0
#- name: Lock packages
#run: zypper --non-interactive --gpg-auto-import-keys addlock openssh-server
#- name: Update packages
#run: zypper --non-interactive --gpg-auto-import-keys ref
#- name: Upgrade packages
#run: zypper --non-interactive --gpg-auto-import-keys dup
#- name: Install openSUSE dependencies
#run: >
#zypper --non-interactive --gpg-auto-import-keys install
#lsb-release
#rpm-build
#git
#tar
#make
#cmake
#gcc
#gcc-c++
#gettext-tools
#glibc-devel
#libboost_headers-devel
#boost-devel
#glib2-devel
#glib2-tools
#dbus-1-devel
#alsa-devel
#libnotify-devel
#libgnutls-devel
#protobuf-devel
#sqlite3-devel
#libpulse-devel
#gstreamer-devel
#gstreamer-plugins-base-devel
#vlc-devel
#taglib-devel
#qt6-core-devel
#qt6-gui-devel
#qt6-widgets-devel
#qt6-concurrent-devel
#qt6-network-devel
#qt6-sql-devel
#qt6-dbus-devel
#qt6-test-devel
#qt6-base-common-devel
#qt6-sql-sqlite
#qt6-linguist-devel
#libcdio-devel
#libgpod-devel
#libmtp-devel
#libchromaprint-devel
#desktop-file-utils
#update-desktop-files
#appstream-glib
#hicolor-icon-theme
#- name: Create Build Environment
#shell: bash
#run: cmake -E make_directory build
#- name: Configure CMake
#shell: bash
#working-directory: build
#run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_WERROR=ON -DBUILD_WITH_QT6=ON
#- name: Create source tarball
#working-directory: build
#run: ../dist/scripts/maketarball.sh
#- name: Create RPM build sources directories
#run: mkdir -p ~/rpmbuild/SOURCES /usr/src/packages/SOURCES
#- name: Copy source tarball
#working-directory: build
#run: cp strawberry-*.tar.xz /usr/src/packages/SOURCES/
#- name: Build RPM
#working-directory: build
#run: rpmbuild -ba ../dist/unix/strawberry.spec
build_opensuse_lp153_qt6:
name: Build openSUSE Leap 15.3 Qt 6
runs-on: ubuntu-latest
container:
image: opensuse/leap:15.3
steps:
- uses: actions/checkout@v1.2.0
- name: Add Qt 6 repo
run: zypper -n ar -c -f -n 'repo-qt6' https://download.opensuse.org/repositories/home:/jonaski:/qt6/openSUSE_Leap_15.3/ repo-qt6
- name: Update packages
run: zypper --non-interactive --gpg-auto-import-keys ref
- name: Install openSUSE dependencies
run: >
zypper --non-interactive --gpg-auto-import-keys install
lsb-release
rpm-build
git
tar
make
cmake
gcc
gcc-c++
gettext-tools
glibc-devel
libboost_headers-devel
boost-devel
glib2-devel
glib2-tools
dbus-1-devel
alsa-devel
libnotify-devel
libgnutls-devel
protobuf-devel
sqlite3-devel
libpulse-devel
gstreamer-devel
gstreamer-plugins-base-devel
vlc-devel
taglib-devel
qt6-core-devel
qt6-gui-devel
qt6-widgets-devel
qt6-concurrent-devel
qt6-network-devel
qt6-sql-devel
qt6-dbus-devel
qt6-test-devel
qt6-base-common-devel
qt6-sql-sqlite
qt6-linguist-devel
libcdio-devel
libgpod-devel
libmtp-devel
libchromaprint-devel
desktop-file-utils
update-desktop-files
appstream-glib
hicolor-icon-theme
- name: Create Build Environment
shell: bash
run: cmake -E make_directory build
- name: Configure CMake
shell: bash
working-directory: build
run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_WERROR=ON -DBUILD_WITH_QT6=ON
- name: Create source tarball
working-directory: build
run: ../dist/scripts/maketarball.sh
- name: Create RPM build sources directories
run: mkdir -p ~/rpmbuild/SOURCES /usr/src/packages/SOURCES
- name: Copy source tarball
working-directory: build
run: cp strawberry-*.tar.xz /usr/src/packages/SOURCES/
- name: Build RPM
working-directory: build
run: rpmbuild -ba ../dist/unix/strawberry.spec
build_opensuse_tumbleweed_qt5:
name: Build openSUSE Tumbleweed Qt 5
runs-on: ubuntu-latest
container:
image: opensuse/tumbleweed
steps:
- uses: actions/checkout@v1.2.0
- name: Update packages
run: zypper --non-interactive --gpg-auto-import-keys ref
- name: Upgrade packages
run: zypper --non-interactive --gpg-auto-import-keys dup
- name: Install openSUSE dependencies
run: >
zypper --non-interactive --gpg-auto-import-keys install
lsb-release
rpm-build
git
tar
make
cmake
gcc
gcc-c++
gettext-tools
glibc-devel
libboost_headers-devel
boost-devel
glib2-devel
glib2-tools
dbus-1-devel
alsa-devel
libnotify-devel
libgnutls-devel
protobuf-devel
sqlite3-devel
libpulse-devel
gstreamer-devel
gstreamer-plugins-base-devel
vlc-devel
taglib-devel
libQt5Core-devel
libQt5Gui-devel
libQt5Widgets-devel
libQt5Concurrent-devel
libQt5Network-devel
libQt5Sql-devel
libQt5DBus-devel
libQt5Test-devel
libqt5-qtx11extras-devel
libqt5-qtbase-common-devel
libQt5Sql5-sqlite
libqt5-linguist-devel
libcdio-devel
libgpod-devel
libmtp-devel
libchromaprint-devel
desktop-file-utils
update-desktop-files
appstream-glib
hicolor-icon-theme
- name: Create Build Environment
shell: bash
run: cmake -E make_directory build
- name: Configure CMake
shell: bash
working-directory: build
run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_WERROR=ON -DBUILD_WITH_QT5=ON
- name: Create source tarball
working-directory: build
run: ../dist/scripts/maketarball.sh
- name: Create RPM build sources directories
run: mkdir -p ~/rpmbuild/SOURCES /usr/src/packages/SOURCES
- name: Copy source tarball
working-directory: build
run: cp strawberry-*.tar.xz /usr/src/packages/SOURCES/
- name: Build RPM
working-directory: build
run: rpmbuild -ba ../dist/unix/strawberry.spec
build_opensuse_tumbleweed_qt6:
name: Build openSUSE Tumbleweed Qt 6
runs-on: ubuntu-latest
container:
image: opensuse/tumbleweed
steps:
- uses: actions/checkout@v1.2.0
- name: Update packages
run: zypper --non-interactive --gpg-auto-import-keys ref
- name: Upgrade packages
run: zypper --non-interactive --gpg-auto-import-keys dup
- name: Install openSUSE dependencies
run: >
zypper --non-interactive --gpg-auto-import-keys install
lsb-release
rpm-build
git
tar
make
cmake
gcc
gcc-c++
gettext-tools
glibc-devel
libboost_headers-devel
boost-devel
glib2-devel
glib2-tools
dbus-1-devel
alsa-devel
libnotify-devel
libgnutls-devel
protobuf-devel
sqlite3-devel
libpulse-devel
gstreamer-devel
gstreamer-plugins-base-devel
vlc-devel
taglib-devel
qt6-core-devel
qt6-gui-devel
qt6-widgets-devel
qt6-concurrent-devel
qt6-network-devel
qt6-sql-devel
qt6-dbus-devel
qt6-test-devel
qt6-base-common-devel
qt6-sql-sqlite
qt6-linguist-devel
libcdio-devel
libgpod-devel
libmtp-devel
libchromaprint-devel
desktop-file-utils
update-desktop-files
appstream-glib
hicolor-icon-theme
- name: Create Build Environment
shell: bash
run: cmake -E make_directory build
- name: Configure CMake
shell: bash
working-directory: build
run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_WERROR=ON -DBUILD_WITH_QT6=ON
- name: Create source tarball
working-directory: build
run: ../dist/scripts/maketarball.sh
- name: Create RPM build sources directories
run: mkdir -p ~/rpmbuild/SOURCES /usr/src/packages/SOURCES
- name: Copy source tarball
working-directory: build
run: cp strawberry-*.tar.xz /usr/src/packages/SOURCES/
- name: Build RPM
working-directory: build
run: rpmbuild -ba ../dist/unix/strawberry.spec
build_fedora_32:
@@ -618,6 +694,83 @@ jobs:
run: rpmbuild -ba ../dist/unix/strawberry.spec
build_fedora_34:
name: Build Fedora 34
runs-on: ubuntu-latest
container:
image: fedora:34
env:
RPM_BUILD_NCPUS: "2"
steps:
- uses: actions/checkout@v1.2.0
- name: Update packages
run: yum update --assumeyes
- name: Upgrade packages
run: yum upgrade --assumeyes
- name: Install Fedora dependencies
run: >
dnf install --assumeyes
@development-tools
redhat-lsb-core
git
glibc
gcc-c++
rpmdevtools
make
cmake
pkgconfig
glib
man
tar
gettext
openssh
boost-devel
dbus-devel
protobuf-devel
protobuf-compiler
sqlite-devel
alsa-lib-devel
pulseaudio-libs-devel
libnotify-devel
gnutls-devel
qt5-qtbase-devel
qt5-qtx11extras-devel
qt5-qttools-devel
gstreamer1-devel
gstreamer1-plugins-base-devel
taglib-devel
libcdio-devel
libgpod-devel
libmtp-devel
libchromaprint-devel
fftw-devel
desktop-file-utils
libappstream-glib
hicolor-icon-theme
- name: Create Build Environment
shell: bash
run: cmake -E make_directory build
- name: Configure CMake
shell: bash
working-directory: build
run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_WERROR=ON
- name: Create source tarball
working-directory: build
run: ../dist/scripts/maketarball.sh
- name: Create RPM build sources directories
working-directory: build
run: mkdir -p ~/rpmbuild/SOURCES /usr/src/packages/SOURCES
- name: Copy source tarball
working-directory: build
run: cp strawberry-*.tar.xz ~/rpmbuild/SOURCES/
- name: Build RPM
working-directory: build
run: rpmbuild -ba ../dist/unix/strawberry.spec
build_centos_8:
name: Build CentOS 8
runs-on: ubuntu-latest
@@ -1055,8 +1208,7 @@ jobs:
- name: Link Sparkle
shell: bash
run: |
sudo ln -s /usr/local/Caskroom/sparkle/$(ls /usr/local/Caskroom/sparkle | head -n1)/Sparkle.framework /Library/Frameworks/Sparkle.framework
sudo ln -s /usr/local/Caskroom/sparkle/$(ls /usr/local/Caskroom/sparkle | head -n1)/Sparkle.framework.dSYM /Library/Frameworks/Sparkle.framework.dSYM
sudo ln -s /usr/local/Caskroom/sparkle/$(ls /usr/local/Caskroom/sparkle | head -n1) /usr/local/opt/sparkle
- name: Create Build Environment
shell: bash
@@ -1068,7 +1220,8 @@ jobs:
PKG_CONFIG_PATH: /usr/local/lib/pkgconfig
Qt6_DIR: /usr/local/opt/qt6/lib/cmake
Qt5LinguistTools_DIR: /usr/local/opt/qt6/lib/cmake/Qt6LinguistTools
GST_SCANNER_PATH: /usr/local/opt/gstreamer/libexec/gstreamer-1.0/gst-plugin-scanner
GIO_EXTRA_MODULES: /usr/local/lib/gio/modules
GST_PLUGIN_SCANNER: /usr/local/opt/gstreamer/libexec/gstreamer-1.0/gst-plugin-scanner
GST_PLUGIN_PATH: /usr/local/lib/gstreamer-1.0
working-directory: build
run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_WITH_QT6=ON -DBUILD_WERROR=ON -DUSE_BUNDLE=ON -DCMAKE_PREFIX_PATH=/usr/local/opt/qt6/lib/cmake
@@ -1082,9 +1235,6 @@ jobs:
working-directory: build
shell: bash
run: make install
- name: Hack to make macdeployqt find plugins
shell: bash
run: sudo ln -s /usr/local/Cellar/qt/$(ls /usr/local/Cellar/qt/ | tail -n1)/share/qt/plugins /usr/local/plugins
- name: Create DMG
working-directory: build
shell: bash
@@ -1131,8 +1281,7 @@ jobs:
- name: Link Sparkle
shell: bash
run: |
sudo ln -s /usr/local/Caskroom/sparkle/$(ls /usr/local/Caskroom/sparkle | head -n1)/Sparkle.framework /Library/Frameworks/Sparkle.framework
sudo ln -s /usr/local/Caskroom/sparkle/$(ls /usr/local/Caskroom/sparkle | head -n1)/Sparkle.framework.dSYM /Library/Frameworks/Sparkle.framework.dSYM
sudo ln -s /usr/local/Caskroom/sparkle/$(ls /usr/local/Caskroom/sparkle | head -n1) /usr/local/opt/sparkle
- name: Create Build Environment
shell: bash
@@ -1144,7 +1293,8 @@ jobs:
PKG_CONFIG_PATH: /usr/local/lib/pkgconfig
Qt5_DIR: /usr/local/opt/qt6/lib/cmake
Qt5LinguistTools_DIR: /usr/local/opt/qt6/lib/cmake/Qt6LinguistTools
GST_SCANNER_PATH: /usr/local/opt/gstreamer/libexec/gstreamer-1.0/gst-plugin-scanner
GIO_EXTRA_MODULES: /usr/local/lib/gio/modules
GST_PLUGIN_SCANNER: /usr/local/opt/gstreamer/libexec/gstreamer-1.0/gst-plugin-scanner
GST_PLUGIN_PATH: /usr/local/lib/gstreamer-1.0
working-directory: build
run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_WITH_QT6=ON -DBUILD_WERROR=ON -DUSE_BUNDLE=ON -DCMAKE_PREFIX_PATH=/usr/local/opt/qt6/lib/cmake
@@ -1158,9 +1308,6 @@ jobs:
working-directory: build
shell: bash
run: make install
- name: Hack to make macdeployqt find plugins
shell: bash
run: sudo ln -s /usr/local/Cellar/qt/$(ls /usr/local/Cellar/qt/ | tail -n1)/share/qt/plugins /usr/local/plugins
- name: Create DMG
working-directory: build
shell: bash

View File

@@ -19,8 +19,7 @@ before_install:
- brew install libcdio libmtp
- brew install create-dmg
- brew install --cask sparkle
- sudo ln -s /usr/local/Caskroom/sparkle/$(ls /usr/local/Caskroom/sparkle | head -n1)/Sparkle.framework /Library/Frameworks/Sparkle.framework
- sudo ln -s /usr/local/Caskroom/sparkle/$(ls /usr/local/Caskroom/sparkle | head -n1)/Sparkle.framework.dSYM /Library/Frameworks/Sparkle.framework.dSYM
- sudo ln -s /usr/local/Caskroom/sparkle/$(ls /usr/local/Caskroom/sparkle | head -n1) /usr/local/opt/sparkle
- export Qt6_DIR=/usr/local/opt/qt6/lib/cmake
- export Qt6LinguistTools_DIR=/usr/local/opt/qt6/lib/cmake/Qt6LinguistTools
- ls /usr/local/lib/gstreamer-1.0
@@ -31,7 +30,6 @@ before_script:
script:
- make -j8
- make install
- sudo ln -s /usr/local/Cellar/qt/$(ls /usr/local/Cellar/qt/ | tail -n1)/share/qt/plugins /usr/local/plugins
- make dmg2
after_success:
- ls -lh strawberry*.dmg

10
3rdparty/README.md vendored
View File

@@ -14,6 +14,12 @@ URL: https://github.com/itay-grudev/SingleApplication
SPMediaKeyTap
-------------
Used on macOS to exclusively enable strawberry to grab global media shortcuts.
Can safely be deleted on other platforms.
This is used for macOS only to enable strawberry to grab global shortcuts and can safely be deleted on other
platforms.
macdeployqt
-----------
A modified version of Qt's official macdeployqt utility that fixes some issues,
this version also deploys gstreamer plugins.
Can safely be deleted on other platforms.

7
3rdparty/macdeployqt/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,7 @@
add_executable(macdeployqt main.cpp shared.cpp)
target_link_libraries(macdeployqt PRIVATE
"-framework AppKit"
${QtCore_LIBRARIES}
)
#execute_process(COMMAND cp ${CMAKE_CURRENT_BINARY_DIR}/macdeployqt ${CMAKE_BINARY_DIR})

294
3rdparty/macdeployqt/main.cpp vendored Normal file
View File

@@ -0,0 +1,294 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#undef QT_NO_DEBUG_OUTPUT
#undef QT_NO_WARNING_OUTPUT
#undef QT_NO_INFO_OUTPUT
#include <QCoreApplication>
#include <QDir>
#include <QLibraryInfo>
#include "shared.h"
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
QString appBundlePath;
if (argc > 1)
appBundlePath = QString::fromLocal8Bit(argv[1]);
if (argc < 2 || appBundlePath.startsWith("-")) {
qDebug() << "Usage: macdeployqt app-bundle [options]";
qDebug() << "";
qDebug() << "Options:";
qDebug() << " -verbose=<0-3> : 0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug";
qDebug() << " -no-plugins : Skip plugin deployment";
qDebug() << " -dmg : Create a .dmg disk image";
qDebug() << " -no-strip : Don't run 'strip' on the binaries";
qDebug() << " -use-debug-libs : Deploy with debug versions of frameworks and plugins (implies -no-strip)";
qDebug() << " -executable=<path> : Let the given executable use the deployed frameworks too";
qDebug() << " -qmldir=<path> : Scan for QML imports in the given path";
qDebug() << " -qmlimport=<path> : Add the given path to the QML module search locations";
qDebug() << " -always-overwrite : Copy files even if the target file exists";
qDebug() << " -codesign=<ident> : Run codesign with the given identity on all executables";
qDebug() << " -hardened-runtime : Enable Hardened Runtime when code signing";
qDebug() << " -timestamp : Include a secure timestamp when code signing (requires internet connection)";
qDebug() << " -sign-for-notarization=<ident>: Activate the necessary options for notarization (requires internet connection)";
qDebug() << " -appstore-compliant : Skip deployment of components that use private API";
qDebug() << " -libpath=<path> : Add the given path to the library search path";
qDebug() << " -fs=<filesystem> : Set the filesystem used for the .dmg disk image (defaults to HFS+)";
qDebug() << " -plugins-dir=<path> : Set plugins directory";
qDebug() << "";
qDebug() << "macdeployqt takes an application bundle as input and makes it";
qDebug() << "self-contained by copying in the Qt frameworks and plugins that";
qDebug() << "the application uses.";
qDebug() << "";
qDebug() << "Plugins related to a framework are copied in with the";
qDebug() << "framework. The accessibility, image formats, and text codec";
qDebug() << "plugins are always copied, unless \"-no-plugins\" is specified.";
qDebug() << "";
qDebug() << "Qt plugins may use private API and will cause the app to be";
qDebug() << "rejected from the Mac App store. MacDeployQt will print a warning";
qDebug() << "when known incompatible plugins are deployed. Use -appstore-compliant ";
qDebug() << "to skip these plugins. Currently two SQL plugins are known to";
qDebug() << "be incompatible: qsqlodbc and qsqlpsql.";
qDebug() << "";
qDebug() << "See the \"Deploying Applications on OS X\" topic in the";
qDebug() << "documentation for more information about deployment on OS X.";
return 1;
}
appBundlePath = QDir::cleanPath(appBundlePath);
if (QDir().exists(appBundlePath) == false) {
qDebug() << "Error: Could not find app bundle" << appBundlePath;
return 1;
}
bool plugins = true;
bool dmg = false;
QByteArray filesystem("HFS+");
bool useDebugLibs = false;
extern bool runStripEnabled;
extern bool alwaysOwerwriteEnabled;
extern QStringList librarySearchPath;
QStringList additionalExecutables;
bool qmldirArgumentUsed = false;
QStringList qmlDirs;
QStringList qmlImportPaths;
extern bool runCodesign;
extern QString codesignIdentiy;
extern bool hardenedRuntime;
extern bool appstoreCompliant;
extern bool deployFramework;
extern bool secureTimestamp;
QString plugin_dir;
for (int i = 2; i < argc; ++i) {
QByteArray argument = QByteArray(argv[i]);
if (argument == QByteArray("-no-plugins")) {
LogDebug() << "Argument found:" << argument;
plugins = false;
} else if (argument == QByteArray("-dmg")) {
LogDebug() << "Argument found:" << argument;
dmg = true;
} else if (argument == QByteArray("-no-strip")) {
LogDebug() << "Argument found:" << argument;
runStripEnabled = false;
} else if (argument == QByteArray("-use-debug-libs")) {
LogDebug() << "Argument found:" << argument;
useDebugLibs = true;
runStripEnabled = false;
} else if (argument.startsWith(QByteArray("-verbose"))) {
LogDebug() << "Argument found:" << argument;
int index = argument.indexOf("=");
bool ok = false;
int number = argument.mid(index+1).toInt(&ok);
if (!ok)
LogError() << "Could not parse verbose level";
else
logLevel = number;
} else if (argument.startsWith(QByteArray("-executable"))) {
LogDebug() << "Argument found:" << argument;
int index = argument.indexOf('=');
if (index == -1)
LogError() << "Missing executable path";
else
additionalExecutables << argument.mid(index+1);
} else if (argument.startsWith(QByteArray("-qmldir"))) {
LogDebug() << "Argument found:" << argument;
qmldirArgumentUsed = true;
int index = argument.indexOf('=');
if (index == -1)
LogError() << "Missing qml directory path";
else
qmlDirs << argument.mid(index+1);
} else if (argument.startsWith(QByteArray("-qmlimport"))) {
LogDebug() << "Argument found:" << argument;
int index = argument.indexOf('=');
if (index == -1)
LogError() << "Missing qml import path";
else
qmlImportPaths << argument.mid(index+1);
} else if (argument.startsWith(QByteArray("-libpath"))) {
LogDebug() << "Argument found:" << argument;
int index = argument.indexOf('=');
if (index == -1)
LogError() << "Missing library search path";
else
librarySearchPath << argument.mid(index+1);
} else if (argument == QByteArray("-always-overwrite")) {
LogDebug() << "Argument found:" << argument;
alwaysOwerwriteEnabled = true;
} else if (argument.startsWith(QByteArray("-codesign"))) {
LogDebug() << "Argument found:" << argument;
int index = argument.indexOf("=");
if (index < 0 || index >= argument.size()) {
LogError() << "Missing code signing identity";
} else {
runCodesign = true;
codesignIdentiy = argument.mid(index+1);
}
} else if (argument.startsWith(QByteArray("-sign-for-notarization"))) {
LogDebug() << "Argument found:" << argument;
int index = argument.indexOf("=");
if (index < 0 || index >= argument.size()) {
LogError() << "Missing code signing identity";
} else {
runCodesign = true;
hardenedRuntime = true;
secureTimestamp = true;
codesignIdentiy = argument.mid(index+1);
}
} else if (argument.startsWith(QByteArray("-hardened-runtime"))) {
LogDebug() << "Argument found:" << argument;
hardenedRuntime = true;
} else if (argument.startsWith(QByteArray("-timestamp"))) {
LogDebug() << "Argument found:" << argument;
secureTimestamp = true;
} else if (argument == QByteArray("-appstore-compliant")) {
LogDebug() << "Argument found:" << argument;
appstoreCompliant = true;
// Undocumented option, may not work as intented
} else if (argument == QByteArray("-deploy-framework")) {
LogDebug() << "Argument found:" << argument;
deployFramework = true;
} else if (argument.startsWith(QByteArray("-fs"))) {
LogDebug() << "Argument found:" << argument;
int index = argument.indexOf('=');
if (index == -1)
LogError() << "Missing filesystem type";
else
filesystem = argument.mid(index+1);
} else if (argument.startsWith(QByteArray("-plugins-dir"))) {
LogDebug() << "Argument found:" << argument;
int index = argument.indexOf('=');
if (index == -1)
LogError() << "Missing filesystem type";
else
plugin_dir = argument.mid(index+1);
} else if (argument.startsWith("-")) {
LogError() << "Unknown argument" << argument << "\n";
return 1;
}
}
DeploymentInfo deploymentInfo = deployQtFrameworks(appBundlePath, additionalExecutables, useDebugLibs);
if (deploymentInfo.isDebug)
useDebugLibs = true;
if (deployFramework && deploymentInfo.isFramework)
fixupFramework(appBundlePath);
// Convenience: Look for .qml files in the current directoty if no -qmldir specified.
if (qmlDirs.isEmpty()) {
QDir dir;
if (!dir.entryList(QStringList() << QStringLiteral("*.qml")).isEmpty()) {
qmlDirs += QStringLiteral(".");
}
}
if (!qmlDirs.isEmpty()) {
bool ok = deployQmlImports(appBundlePath, deploymentInfo, qmlDirs, qmlImportPaths);
if (!ok && qmldirArgumentUsed)
return 1; // exit if the user explicitly asked for qml import deployment
// Update deploymentInfo.deployedFrameworks - the QML imports
// may have brought in extra frameworks as dependencies.
deploymentInfo.deployedFrameworks += findAppFrameworkNames(appBundlePath);
deploymentInfo.deployedFrameworks =
QSet<QString>(deploymentInfo.deployedFrameworks.begin(),
deploymentInfo.deployedFrameworks.end()).values();
}
if (plugins) {
if (plugin_dir.isEmpty()) {
deploymentInfo.pluginPath = QLibraryInfo::path(QLibraryInfo::PluginsPath);
}
else {
deploymentInfo.pluginPath = plugin_dir;
}
if (deploymentInfo.pluginPath.isEmpty()) {
LogError() << "Missing Qt plugins path\n";
return 1;
}
if (!QDir(deploymentInfo.pluginPath).exists()) {
LogError() << "Plugins path does not exist\n" << deploymentInfo.pluginPath;
return 1;
}
Q_ASSERT(!deploymentInfo.pluginPath.isEmpty());
if (!deploymentInfo.pluginPath.isEmpty()) {
LogNormal();
deployPlugins(appBundlePath, deploymentInfo, useDebugLibs);
createQtConf(appBundlePath);
}
}
if (runStripEnabled)
stripAppBinary(appBundlePath);
if (!FinalCheck(appBundlePath)) {
return 1;
}
if (runCodesign)
codesign(codesignIdentiy, appBundlePath);
if (dmg) {
LogNormal();
createDiskImage(appBundlePath, filesystem);
}
return 0;
}

1806
3rdparty/macdeployqt/shared.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

141
3rdparty/macdeployqt/shared.h vendored Normal file
View File

@@ -0,0 +1,141 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef MAC_DEPLOMYMENT_SHARED_H
#define MAC_DEPLOMYMENT_SHARED_H
#include <QString>
#include <QStringList>
#include <QDebug>
#include <QSet>
#include <QVersionNumber>
extern int logLevel;
#define LogError() if (logLevel < 0) {} else qDebug() << "ERROR:"
#define LogWarning() if (logLevel < 1) {} else qDebug() << "WARNING:"
#define LogNormal() if (logLevel < 2) {} else qDebug() << "Log:"
#define LogDebug() if (logLevel < 3) {} else qDebug() << "Log:"
extern bool runStripEnabled;
class FrameworkInfo
{
public:
bool isDylib;
QString frameworkDirectory;
QString frameworkName;
QString frameworkPath;
QString binaryDirectory;
QString binaryName;
QString binaryPath;
QString rpathUsed;
QString version;
QString installName;
QString deployedInstallName;
QString sourceFilePath;
QString frameworkDestinationDirectory;
QString binaryDestinationDirectory;
bool isDebugLibrary() const
{
return binaryName.contains(QLatin1String("_debug"));
}
};
class DylibInfo
{
public:
QString binaryPath;
QVersionNumber currentVersion;
QVersionNumber compatibilityVersion;
};
class OtoolInfo
{
public:
QString installName;
QString binaryPath;
QVersionNumber currentVersion;
QVersionNumber compatibilityVersion;
QList<DylibInfo> dependencies;
};
bool operator==(const FrameworkInfo &a, const FrameworkInfo &b);
QDebug operator<<(QDebug debug, const FrameworkInfo &info);
class ApplicationBundleInfo
{
public:
QString path;
QString binaryPath;
QStringList libraryPaths;
};
class DeploymentInfo
{
public:
QString qtPath;
QString pluginPath;
QStringList deployedFrameworks;
QSet<QString> rpathsUsed;
bool useLoaderPath;
bool isFramework;
bool isDebug;
bool containsModule(const QString &module, const QString &libInFix) const;
};
inline QDebug operator<<(QDebug debug, const ApplicationBundleInfo &info);
OtoolInfo findDependencyInfo(const QString &binaryPath);
FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs);
QString findAppBinary(const QString &appBundlePath);
QList<FrameworkInfo> getQtFrameworks(const QString &path, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs);
QList<FrameworkInfo> getQtFrameworks(const QStringList &otoolLines, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs);
QString copyFramework(const FrameworkInfo &framework, const QString path);
DeploymentInfo deployQtFrameworks(const QString &appBundlePath, const QStringList &additionalExecutables, bool useDebugLibs);
DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks,const QString &bundlePath, const QStringList &binaryPaths, bool useDebugLibs, bool useLoaderPath);
void createQtConf(const QString &appBundlePath);
void deployPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo, bool useDebugLibs);
bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInfo, QStringList &qmlDirs, QStringList &qmlImportPaths);
void changeIdentification(const QString &id, const QString &binaryPath);
void changeInstallName(const QString &oldName, const QString &newName, const QString &binaryPath);
void runStrip(const QString &binaryPath);
void stripAppBinary(const QString &bundlePath);
QString findAppBinary(const QString &appBundlePath);
QStringList findAppFrameworkNames(const QString &appBundlePath);
QStringList findAppFrameworkPaths(const QString &appBundlePath);
void codesignFile(const QString &identity, const QString &filePath);
QSet<QString> codesignBundle(const QString &identity,
const QString &appBundlePath,
QList<QString> additionalBinariesContainingRpaths);
void codesign(const QString &identity, const QString &appBundlePath);
void createDiskImage(const QString &appBundlePath, const QString &filesystemType);
void fixupFramework(const QString &appBundlePath);
bool FinalCheck(const QString &appBundlePath);
#endif

View File

@@ -220,7 +220,7 @@ void SingleApplicationPrivate::startSecondary() {
}
bool SingleApplicationPrivate::connectToPrimary(int timeout, ConnectionType connectionType) {
bool SingleApplicationPrivate::connectToPrimary(const int timeout, const ConnectionType connectionType) {
QElapsedTimer time;
time.start();
@@ -241,7 +241,7 @@ bool SingleApplicationPrivate::connectToPrimary(int timeout, ConnectionType conn
socket_->connectToServer(blockServerName_);
if (socket_->state() == QLocalSocket::ConnectingState) {
socket_->waitForConnected(timeout - time.elapsed());
socket_->waitForConnected(static_cast<int>(timeout - time.elapsed()));
}
// If connected break out of the loop
@@ -277,7 +277,7 @@ bool SingleApplicationPrivate::connectToPrimary(int timeout, ConnectionType conn
socket_->write(header);
socket_->write(initMsg);
bool result = socket_->waitForBytesWritten(timeout - time.elapsed());
bool result = socket_->waitForBytesWritten(static_cast<int>(timeout - time.elapsed()));
socket_->flush();
return result;
@@ -326,17 +326,17 @@ void SingleApplicationPrivate::slotConnectionEstablished() {
QLocalSocket *nextConnSocket = server_->nextPendingConnection();
connectionMap_.insert(nextConnSocket, ConnectionInfo());
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, [nextConnSocket, this]() {
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this, [nextConnSocket, this]() {
auto &info = connectionMap_[nextConnSocket];
Q_EMIT this->slotClientConnectionClosed(nextConnSocket, info.instanceId);
slotClientConnectionClosed(nextConnSocket, info.instanceId);
});
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, [nextConnSocket, this]() {
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, this, [nextConnSocket, this]() {
connectionMap_.remove(nextConnSocket);
nextConnSocket->deleteLater();
});
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, [nextConnSocket, this]() {
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this, [nextConnSocket, this]() {
auto &info = connectionMap_[nextConnSocket];
switch (info.stage) {
case StageHeader:
@@ -346,7 +346,7 @@ void SingleApplicationPrivate::slotConnectionEstablished() {
readInitMessageBody(nextConnSocket);
break;
case StageConnected:
Q_EMIT this->slotDataAvailable(nextConnSocket, info.instanceId);
slotDataAvailable(nextConnSocket, info.instanceId);
break;
default:
break;
@@ -438,7 +438,7 @@ void SingleApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
}
if (sock->bytesAvailable() > 0) {
Q_EMIT this->slotDataAvailable(sock, instanceId);
slotDataAvailable(sock, instanceId);
}
}
@@ -453,7 +453,7 @@ void SingleApplicationPrivate::slotDataAvailable(QLocalSocket *dataSocket, const
void SingleApplicationPrivate::slotClientConnectionClosed(QLocalSocket *closedSocket, const quint32 instanceId) {
if (closedSocket->bytesAvailable() > 0) {
Q_EMIT slotDataAvailable(closedSocket, instanceId);
slotDataAvailable(closedSocket, instanceId);
}
}

View File

@@ -85,7 +85,7 @@ class SingleApplicationPrivate : public QObject {
void initializeMemoryBlock();
void startPrimary();
void startSecondary();
bool connectToPrimary(const int msecs, const ConnectionType connectionType);
bool connectToPrimary(const int timeout, const ConnectionType connectionType);
quint16 blockChecksum();
qint64 primaryPid();
QString primaryUser();

View File

@@ -220,7 +220,7 @@ void SingleCoreApplicationPrivate::startSecondary() {
}
bool SingleCoreApplicationPrivate::connectToPrimary(int timeout, ConnectionType connectionType) {
bool SingleCoreApplicationPrivate::connectToPrimary(const int timeout, const ConnectionType connectionType) {
QElapsedTimer time;
time.start();
@@ -241,7 +241,7 @@ bool SingleCoreApplicationPrivate::connectToPrimary(int timeout, ConnectionType
socket_->connectToServer(blockServerName_);
if (socket_->state() == QLocalSocket::ConnectingState) {
socket_->waitForConnected(timeout - time.elapsed());
socket_->waitForConnected(static_cast<int>(timeout - time.elapsed()));
}
// If connected break out of the loop
@@ -277,7 +277,7 @@ bool SingleCoreApplicationPrivate::connectToPrimary(int timeout, ConnectionType
socket_->write(header);
socket_->write(initMsg);
bool result = socket_->waitForBytesWritten(timeout - time.elapsed());
bool result = socket_->waitForBytesWritten(timeout - static_cast<int>(time.elapsed()));
socket_->flush();
return result;
@@ -326,17 +326,17 @@ void SingleCoreApplicationPrivate::slotConnectionEstablished() {
QLocalSocket *nextConnSocket = server_->nextPendingConnection();
connectionMap_.insert(nextConnSocket, ConnectionInfo());
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, [nextConnSocket, this]() {
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this, [nextConnSocket, this]() {
auto &info = connectionMap_[nextConnSocket];
Q_EMIT this->slotClientConnectionClosed(nextConnSocket, info.instanceId);
slotClientConnectionClosed(nextConnSocket, info.instanceId);
});
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, [nextConnSocket, this]() {
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, this, [nextConnSocket, this]() {
connectionMap_.remove(nextConnSocket);
nextConnSocket->deleteLater();
});
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, [nextConnSocket, this]() {
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this, [nextConnSocket, this]() {
auto &info = connectionMap_[nextConnSocket];
switch (info.stage) {
case StageHeader:
@@ -346,7 +346,7 @@ void SingleCoreApplicationPrivate::slotConnectionEstablished() {
readInitMessageBody(nextConnSocket);
break;
case StageConnected:
Q_EMIT this->slotDataAvailable(nextConnSocket, info.instanceId);
slotDataAvailable(nextConnSocket, info.instanceId);
break;
default:
break;
@@ -438,7 +438,7 @@ void SingleCoreApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
}
if (sock->bytesAvailable() > 0) {
Q_EMIT this->slotDataAvailable(sock, instanceId);
slotDataAvailable(sock, instanceId);
}
}
@@ -453,7 +453,7 @@ void SingleCoreApplicationPrivate::slotDataAvailable(QLocalSocket *dataSocket, c
void SingleCoreApplicationPrivate::slotClientConnectionClosed(QLocalSocket *closedSocket, const quint32 instanceId) {
if (closedSocket->bytesAvailable() > 0) {
Q_EMIT slotDataAvailable(closedSocket, instanceId);
slotDataAvailable(closedSocket, instanceId);
}
}

View File

@@ -85,7 +85,7 @@ class SingleCoreApplicationPrivate : public QObject {
void initializeMemoryBlock();
void startPrimary();
void startSecondary();
bool connectToPrimary(const int msecs, const ConnectionType connectionType);
bool connectToPrimary(const int timeout, const ConnectionType connectionType);
quint16 blockChecksum();
qint64 primaryPid();
QString primaryUser();

View File

@@ -69,11 +69,6 @@ add_compile_options(${COMPILE_OPTIONS})
if(${CMAKE_BUILD_TYPE} MATCHES "Release")
add_definitions(-DNDEBUG)
add_definitions(-DQT_NO_DEBUG_OUTPUT)
#add_definitions(-DQT_NO_WARNING_OUTPUT)
endif()
if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
set(DEBUG ON)
endif()
if(APPLE)
@@ -256,7 +251,8 @@ set(SINGLEAPPLICATION_LIBRARIES singleapplication)
set(SINGLECOREAPPLICATION_LIBRARIES singlecoreapplication)
if(APPLE)
find_library(SPARKLE Sparkle)
find_library(SPARKLE Sparkle PATHS "/usr/local/opt/sparkle")
add_subdirectory(3rdparty/macdeployqt)
add_subdirectory(3rdparty/SPMediaKeyTap)
set(SPMEDIAKEYTAP_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/SPMediaKeyTap)
set(SPMEDIAKEYTAP_LIBRARIES SPMediaKeyTap)

View File

@@ -2,6 +2,17 @@ Strawberry Music Player
=======================
ChangeLog
0.9.2:
Bugfixes:
* Fix marking songs available.
* Fix crash when transcoding music, or copying music to devices with transcoding.
* Fix copying album covers to iPod.
* Fix playlist tabbar close and save right click actions.
* Fix slow opening of cover manager.
* (macOS) Fix crash when opening cover manager.
* (macOS) Fix broken Qt plugins resulting in album covers not showing.
0.9.1:
Bugfixes:
@@ -9,7 +20,7 @@ ChangeLog
* Fix overwriting existing newer last played when importing last played from last.fm.
* Fix memory leak on song change when moodbar is disabled.
* Fix playlist filter search for text with spaces with Qt 6.
* Fix 'Except between tracks on the same album' backend fade option always greyed out.
* Fix 'Except between tracks on the same album' backend fade option always grayed out.
* Fix read and save vorbis comment grouping tag.
* Fix QAtomicInteger compile error on armv.
* Fix compile error with protobuf 3.15.0 and newer.
@@ -31,6 +42,7 @@ ChangeLog
* Add right click actions to clear set cover, and option delete covers.
* Show artist and album underneath the albums in the cover manager when all Artists is selected.
* Disable unavailable right click cover actions.
* Remove 3rdparty TagLib now that TagLib 1.12 is available.
* (macOS) Update and improve build deployment/bundling for Qt 6.
New features:

View File

@@ -1,9 +1,11 @@
find_program(MACDEPLOYQT_EXECUTABLE NAMES macdeployqt PATHS /usr/local/opt/qt6/bin /usr/local/opt/qt5/bin /usr/local/bin REQUIRED)
if(MACDEPLOYQT_EXECUTABLE)
message(STATUS "Found macdeployqt: ${MACDEPLOYQT_EXECUTABLE}")
else()
message(WARNING "Missing macdeployqt executable.")
endif()
#find_program(MACDEPLOYQT_EXECUTABLE NAMES macdeployqt PATHS /usr/local/opt/qt6/bin /usr/local/opt/qt5/bin /usr/local/bin REQUIRED)
#if(MACDEPLOYQT_EXECUTABLE)
# message(STATUS "Found macdeployqt: ${MACDEPLOYQT_EXECUTABLE}")
#else()
# message(WARNING "Missing macdeployqt executable.")
#endif()
set(MACDEPLOYQT_EXECUTABLE "${CMAKE_BINARY_DIR}/3rdparty/macdeployqt/macdeployqt")
find_program(CREATEDMG_EXECUTABLE NAMES create-dmg REQUIRED)
if(CREATEDMG_EXECUTABLE)
@@ -19,14 +21,16 @@ endif()
if(MACDEPLOYQT_EXECUTABLE AND CREATEDMG_EXECUTABLE AND MACOS_VERSION_PACKAGE)
add_custom_target(dmg
COMMAND ${MACDEPLOYQT_EXECUTABLE} strawberry.app -executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/strawberry-tagreader
COMMAND ${CMAKE_SOURCE_DIR}/dist/macos/macdeploy.py strawberry.app
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/
COMMAND cp -r /usr/local/opt/sparkle/Sparkle.framework ${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/
COMMAND ${MACDEPLOYQT_EXECUTABLE} strawberry.app -verbose=3 -executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/strawberry-tagreader
COMMAND ${CREATEDMG_EXECUTABLE} --volname strawberry --background "${CMAKE_SOURCE_DIR}/dist/macos/dmg_background.png" --app-drop-link 450 218 --icon strawberry.app 150 218 --window-size 600 450 strawberry-${STRAWBERRY_VERSION_PACKAGE}-${MACOS_VERSION_PACKAGE}-${CMAKE_HOST_SYSTEM_PROCESSOR}.dmg strawberry.app
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
add_custom_target(dmg2
COMMAND ${MACDEPLOYQT_EXECUTABLE} strawberry.app -executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/strawberry-tagreader
COMMAND ${CMAKE_SOURCE_DIR}/dist/macos/macdeploy.py strawberry.app
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/
COMMAND cp -r /usr/local/opt/sparkle/Sparkle.framework ${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/
COMMAND ${MACDEPLOYQT_EXECUTABLE} strawberry.app -verbose=3 -executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/strawberry-tagreader
COMMAND ${CREATEDMG_EXECUTABLE} --skip-jenkins --volname strawberry --background "${CMAKE_SOURCE_DIR}/dist/macos/dmg_background.png" --app-drop-link 450 218 --icon strawberry.app 150 218 --window-size 600 450 strawberry-${STRAWBERRY_VERSION_PACKAGE}-${MACOS_VERSION_PACKAGE}-${CMAKE_HOST_SYSTEM_PROCESSOR}.dmg strawberry.app
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)

View File

@@ -1,6 +1,6 @@
set(STRAWBERRY_VERSION_MAJOR 0)
set(STRAWBERRY_VERSION_MINOR 9)
set(STRAWBERRY_VERSION_PATCH 1)
set(STRAWBERRY_VERSION_PATCH 2)
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
set(INCLUDE_GIT_REVISION OFF)

View File

@@ -1,514 +0,0 @@
#!/usr/bin/python
# Strawberry Music Player
# This file was part of Clementine.
#
# 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/>.
from distutils import spawn
import logging
import os
import re
import subprocess
import sys
import traceback
LOGGER = logging.getLogger('macdeploy')
LIBRARY_SEARCH_PATH = ['/usr/local/lib', '/usr/local/opt/icu4c/lib']
FRAMEWORK_SEARCH_PATH = [
'/Library/Frameworks',
os.path.join(os.environ['HOME'], 'Library/Frameworks'),
'/Library/Frameworks/Sparkle.framework/Versions'
]
QT_PLUGINS = [
'platforms/libqcocoa.dylib',
'platforminputcontexts/libqtvirtualkeyboardplugin.dylib',
'styles/libqmacstyle.dylib',
'sqldrivers/libqsqlite.dylib',
'bearer/libqgenericbearer.dylib',
'iconengines/libqsvgicon.dylib',
'imageformats/libqgif.dylib',
'imageformats/libqicns.dylib',
'imageformats/libqico.dylib',
'imageformats/libqjpeg.dylib',
'imageformats/libqsvg.dylib',
'imageformats/libqtiff.dylib',
'printsupport/libcocoaprintersupport.dylib',
'virtualkeyboard/libqtvirtualkeyboard_hangul.dylib',
'virtualkeyboard/libqtvirtualkeyboard_openwnn.dylib',
'virtualkeyboard/libqtvirtualkeyboard_pinyin.dylib',
'virtualkeyboard/libqtvirtualkeyboard_tcime.dylib',
'virtualkeyboard/libqtvirtualkeyboard_thai.dylib',
]
QT_PLUGINS_SEARCH_PATH = [
'/usr/local/opt/qt/plugins',
]
GSTREAMER_SEARCH_PATH = [
'/usr/local/lib/gstreamer-1.0',
'/usr/local/Cellar/gstreamer',
]
GSTREAMER_PLUGINS = [
'libgstapetag.dylib',
'libgstapp.dylib',
'libgstaudioconvert.dylib',
'libgstaudiofx.dylib',
'libgstaudiomixer.dylib',
'libgstaudioparsers.dylib',
'libgstaudiorate.dylib',
'libgstaudioresample.dylib',
'libgstaudiotestsrc.dylib',
'libgstaudiovisualizers.dylib',
'libgstauparse.dylib',
'libgstautoconvert.dylib',
'libgstautodetect.dylib',
'libgstcoreelements.dylib',
'libgstequalizer.dylib',
'libgstgio.dylib',
'libgsticydemux.dylib',
'libgstid3demux.dylib',
'libgstlevel.dylib',
'libgstosxaudio.dylib',
'libgstplayback.dylib',
'libgstrawparse.dylib',
'libgstreplaygain.dylib',
'libgstsoup.dylib',
'libgstspectrum.dylib',
'libgsttypefindfunctions.dylib',
'libgstvolume.dylib',
'libgstxingmux.dylib',
'libgsttcp.dylib',
'libgstudp.dylib',
'libgstpbtypes.dylib',
'libgstrtp.dylib',
'libgstrtsp.dylib',
'libgstflac.dylib',
'libgstwavparse.dylib',
'libgstfaac.dylib',
'libgstfaad.dylib',
'libgstogg.dylib',
'libgstopus.dylib',
'libgstopusparse.dylib',
'libgstasf.dylib',
'libgstspeex.dylib',
'libgsttaglib.dylib',
'libgstvorbis.dylib',
'libgstisomp4.dylib',
'libgstlibav.dylib',
'libgstaiff.dylib',
'libgstlame.dylib',
'libgstmusepack.dylib',
]
GIO_MODULES_SEARCH_PATH = ['/usr/local/lib/gio/modules',]
INSTALL_NAME_TOOL_APPLE = 'install_name_tool'
INSTALL_NAME_TOOL_CROSS = 'x86_64-apple-darwin-%s' % INSTALL_NAME_TOOL_APPLE
INSTALL_NAME_TOOL = INSTALL_NAME_TOOL_CROSS if spawn.find_executable(INSTALL_NAME_TOOL_CROSS) else INSTALL_NAME_TOOL_APPLE
OTOOL_APPLE = 'otool'
OTOOL_CROSS = 'x86_64-apple-darwin-%s' % OTOOL_APPLE
OTOOL = OTOOL_CROSS if spawn.find_executable(OTOOL_CROSS) else OTOOL_APPLE
class Error(Exception):
pass
class CouldNotFindFrameworkError(Error):
pass
class CouldNotFindGioModuleError(Error):
pass
class CouldNotFindQtPluginError(Error):
pass
class CouldNotParseFrameworkNameError(Error):
pass
class InstallNameToolError(Error):
pass
class CouldNotFindGstreamerPluginError(Error):
pass
if len(sys.argv) < 2:
print('Usage: %s <bundle.app>' % sys.argv[0])
bundle_dir = sys.argv[1]
bundle_name = os.path.basename(bundle_dir).split('.')[0]
commands = []
frameworks_dir = os.path.join(bundle_dir, 'Contents', 'Frameworks')
commands.append(['mkdir', '-p', frameworks_dir])
resources_dir = os.path.join(bundle_dir, 'Contents', 'Resources')
commands.append(['mkdir', '-p', resources_dir])
plugins_dir = os.path.join(bundle_dir, 'Contents', 'PlugIns')
binary = os.path.join(bundle_dir, 'Contents', 'MacOS', bundle_name)
tagreader_binary = os.path.join(plugins_dir, bundle_name + "-tagreader")
fixed_libraries = set()
fixed_frameworks = set()
def GetBrokenLibraries(binary):
#print("Checking libs for binary: %s" % binary)
output = subprocess.Popen([OTOOL, '-L', binary], stdout=subprocess.PIPE).communicate()[0].decode('utf-8')
broken_libs = {'frameworks': [], 'libs': []}
for line in [x.split(' ')[0].lstrip() for x in output.split('\n')[1:]]:
#print("Checking line: %s" % line)
if not line: # skip empty lines
continue
if os.path.basename(binary) == os.path.basename(line):
#print("mnope %s-%s" % (os.path.basename(binary), os.path.basename(line)))
continue
if re.match(r'^\s*/System/', line):
#print("system framework: %s" % line)
continue # System framework
elif re.match(r'^\s*/usr/lib/', line):
#print("unix style system lib: %s" % line)
continue # unix style system library
elif re.match(r'^\s*@executable_path', line) or re.match(r'^\s*@rpath', line) or re.match(r'^\s*@loader_path', line):
# Potentially already fixed library
if line.count('/') == 1:
relative_path = os.path.join(*line.split('/')[1:])
if not os.path.exists(os.path.join(frameworks_dir, relative_path)):
broken_libs['libs'].append(relative_path)
elif line.count('/') == 2:
relative_path = os.path.join(*line.split('/')[2:])
if not os.path.exists(os.path.join(frameworks_dir, relative_path)):
broken_libs['libs'].append(relative_path)
elif line.count('/') >= 3:
relative_path = os.path.join(*line.split('/')[3:])
if not os.path.exists(os.path.join(frameworks_dir, relative_path)):
broken_libs['frameworks'].append(relative_path)
else:
print("GetBrokenLibraries Error: %s" % line)
elif re.search(r'\w+\.framework', line):
#print("framework: %s" % line)
broken_libs['frameworks'].append(line)
else:
broken_libs['libs'].append(line)
return broken_libs
def FindFramework(path):
for search_path in FRAMEWORK_SEARCH_PATH:
abs_path = os.path.join(search_path, path)
if os.path.exists(abs_path):
LOGGER.debug("Found framework '%s' in '%s'", path, search_path)
return abs_path
raise CouldNotFindFrameworkError(path)
def FindLibrary(path):
if os.path.exists(path):
return path
for search_path in LIBRARY_SEARCH_PATH:
abs_path = os.path.join(search_path, path)
if os.path.exists(abs_path):
LOGGER.debug("Found library '%s' in '%s'", path, search_path)
return abs_path
else: # try harder---look for lib name in library folders
newpath = os.path.join(search_path,os.path.basename(path))
if os.path.exists(newpath):
return newpath
raise CouldNotFindFrameworkError(path)
def FixAllLibraries(broken_libs):
for framework in broken_libs['frameworks']:
FixFramework(framework)
for lib in broken_libs['libs']:
FixLibrary(lib)
def FixFramework(path):
if path in fixed_frameworks:
return
else:
fixed_frameworks.add(path)
abs_path = FindFramework(path)
broken_libs = GetBrokenLibraries(abs_path)
FixAllLibraries(broken_libs)
new_path = CopyFramework(abs_path)
id = os.sep.join(new_path.split(os.sep)[3:])
FixFrameworkId(new_path, id)
for framework in broken_libs['frameworks']:
FixFrameworkInstallPath(framework, new_path)
for library in broken_libs['libs']:
FixLibraryInstallPath(library, new_path)
def FixLibrary(path):
if path in fixed_libraries:
return
# Always bundle libraries provided by homebrew (/usr/local).
if not re.match(r'^\s*/usr/local', path) and FindSystemLibrary(os.path.basename(path)) is not None:
return
fixed_libraries.add(path)
abs_path = FindLibrary(path)
if abs_path == "":
print("Could not resolve %s, not fixing!" % path)
return
broken_libs = GetBrokenLibraries(abs_path)
FixAllLibraries(broken_libs)
new_path = CopyLibrary(abs_path)
FixLibraryId(new_path)
for framework in broken_libs['frameworks']:
FixFrameworkInstallPath(framework, new_path)
for library in broken_libs['libs']:
FixLibraryInstallPath(library, new_path)
def FixPlugin(abs_path, subdir):
broken_libs = GetBrokenLibraries(abs_path)
FixAllLibraries(broken_libs)
new_path = CopyPlugin(abs_path, subdir)
for framework in broken_libs['frameworks']:
FixFrameworkInstallPath(framework, new_path)
for library in broken_libs['libs']:
FixLibraryInstallPath(library, new_path)
def FixBinary(path):
broken_libs = GetBrokenLibraries(path)
FixAllLibraries(broken_libs)
for framework in broken_libs['frameworks']:
FixFrameworkInstallPath(framework, path)
for library in broken_libs['libs']:
FixLibraryInstallPath(library, path)
def CopyLibrary(path):
new_path = os.path.join(frameworks_dir, os.path.basename(path))
#args = ['cp', path, new_path]
args = ['ditto', '--arch=i386', '--arch=x86_64', path, new_path]
commands.append(args)
commands.append(['chmod', '+w', new_path])
LOGGER.info("Copying library '%s'", path)
return new_path
def CopyPlugin(path, subdir):
new_path = os.path.join(plugins_dir, subdir, os.path.basename(path))
args = ['mkdir', '-p', os.path.dirname(new_path)]
commands.append(args)
#args = ['cp', path, new_path]
args = ['ditto', '--arch=i386', '--arch=x86_64', path, new_path]
commands.append(args)
commands.append(['chmod', '+w', new_path])
LOGGER.info("Copying plugin '%s'", path)
return new_path
def CopyFramework(path):
parts = path.split(os.sep)
for i, part in enumerate(parts):
if re.match(r'\w+\.framework', part):
full_path = os.path.join(frameworks_dir, *parts[i:-1])
framework_name = part.split(".framework")[0]
break
def CopyFramework(src_binary):
while os.path.islink(src_binary):
src_binary = os.path.realpath(src_binary)
m = re.match(r'(.*/([^/]+)\.framework)/Versions/([^/]+)/.*', src_binary)
if not m:
raise CouldNotParseFrameworkNameError(src_binary)
src_base = m.group(1)
name = m.group(2)
version = m.group(3)
LOGGER.info('Copying framework %s version %s', name, version)
dest_base = os.path.join(frameworks_dir, '%s.framework' % name)
dest_dir = os.path.join(dest_base, 'Versions', version)
dest_binary = os.path.join(dest_dir, name)
commands.append(['mkdir', '-p', dest_dir])
commands.append(['cp', src_binary, dest_binary])
commands.append(['chmod', '+w', dest_binary])
# Copy special files from various places:
# QtCore has Resources/qt_menu.nib (copy to app's Resources)
# Sparkle has Resources/*
# Qt* have Resources/Info.plist
resources_src = os.path.join(src_base, 'Resources')
menu_nib = os.path.join(resources_src, 'qt_menu.nib')
if os.path.exists(menu_nib):
LOGGER.info("Copying qt_menu.nib '%s'", menu_nib)
commands.append(['cp', '-r', menu_nib, resources_dir])
elif os.path.exists(resources_src):
LOGGER.info("Copying resources dir '%s'", resources_src)
commands.append(['cp', '-r', resources_src, dest_dir])
info_plist = os.path.join(src_base, 'Contents', 'Info.plist')
if os.path.exists(info_plist):
LOGGER.info("Copying special file '%s'", info_plist)
resources_dest = os.path.join(dest_dir, 'Resources')
commands.append(['mkdir', resources_dest])
commands.append(['cp', '-r', info_plist, resources_dest])
# Create symlinks in the Framework to make it look like
# https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html
commands.append([
'ln', '-sf', 'Versions/Current/%s' % name, os.path.join(dest_base, name)
])
commands.append([
'ln', '-sf', 'Versions/Current/Resources',
os.path.join(dest_base, 'Resources')
])
commands.append(
['ln', '-sf', version, os.path.join(dest_base, 'Versions/Current')])
return dest_binary
def FixId(path, library_name):
id = '@executable_path/../Frameworks/%s' % library_name
args = [INSTALL_NAME_TOOL, '-id', id, path]
commands.append(args)
def FixLibraryId(path):
library_name = os.path.basename(path)
FixId(path, library_name)
def FixFrameworkId(path, id):
FixId(path, id)
def FixInstallPath(library_path, library, new_path):
args = [INSTALL_NAME_TOOL, '-change', library_path, new_path, library]
commands.append(args)
def FindSystemLibrary(library_name):
for path in ['/lib', '/usr/lib']:
full_path = os.path.join(path, library_name)
if os.path.exists(full_path):
return full_path
return None
def FixLibraryInstallPath(library_path, library):
system_library = FindSystemLibrary(os.path.basename(library_path))
if system_library is None or re.match(r'^\s*/usr/local', library_path):
new_path = '@executable_path/../Frameworks/%s' % os.path.basename(library_path)
FixInstallPath(library_path, library, new_path)
else:
FixInstallPath(library_path, library, system_library)
def FixFrameworkInstallPath(library_path, library):
parts = library_path.split(os.sep)
full_path = ""
for i, part in enumerate(parts):
if re.match(r'\w+\.framework', part):
full_path = os.path.join(*parts[i:])
break
if full_path:
new_path = '@executable_path/../Frameworks/%s' % full_path
FixInstallPath(library_path, library, new_path)
def FindQtPlugin(name):
for path in QT_PLUGINS_SEARCH_PATH:
if os.path.exists(path):
if os.path.exists(os.path.join(path, name)):
return os.path.join(path, name)
raise CouldNotFindQtPluginError(name)
def FindGstreamerPlugin(name):
for path in GSTREAMER_SEARCH_PATH:
if os.path.exists(path):
for dir, dirs, files in os.walk(path):
if name in files:
return os.path.join(dir, name)
raise CouldNotFindGstreamerPluginError(name)
def FindGioModule(name):
for path in GIO_MODULES_SEARCH_PATH:
if os.path.exists(path):
for dir, dirs, files in os.walk(path):
if name in files:
return os.path.join(dir, name)
raise CouldNotFindGioModuleError(name)
def main():
logging.basicConfig(filename='macdeploy.log', level=logging.DEBUG, format='%(asctime)s %(levelname)-8s %(message)s')
FixBinary(binary)
FixBinary(tagreader_binary)
# macdeployqt needs to handle strawberry-tagreader for Qt deployment, so we can't use FixPlugin() here.
#try:
# FixPlugin('strawberry-tagreader', '.')
#except:
# print('Failed to find blob: %s' % traceback.format_exc())
for plugin in GSTREAMER_PLUGINS:
FixPlugin(FindGstreamerPlugin(plugin), 'gstreamer')
FixPlugin(FindGstreamerPlugin('gst-plugin-scanner'), '.')
FixPlugin(FindGioModule('libgiognutls.so'), 'gio-modules')
#FixPlugin(FindGioModule('libgiognomeproxy.so'), 'gio-modules')
#for plugin in QT_PLUGINS:
#FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))
if len(sys.argv) <= 2:
print('Would run %d commands:' % len(commands))
for command in commands:
print(' '.join(command))
#print('OK?')
#raw_input()
for command in commands:
p = subprocess.Popen(command)
os.waitpid(p.pid, 0)
if __name__ == "__main__":
main()

View File

@@ -82,7 +82,7 @@ template <typename MT>
class AbstractMessageHandler : public _MessageHandlerBase {
public:
AbstractMessageHandler(QIODevice *device, QObject *parent);
~AbstractMessageHandler() override { AbortAll(); }
~AbstractMessageHandler() override { AbstractMessageHandler::AbortAll(); }
typedef MT MessageType;
typedef MessageReply<MT> ReplyType;

View File

@@ -191,10 +191,11 @@ void AnalyzerContainer::Load() {
}
// Framerate
QList<QAction*> actions = group_framerate_->actions();
for (int i = 0; i < framerate_list_.count(); ++i) {
if (current_framerate_ == framerate_list_[i]) {
ChangeFramerate(current_framerate_);
group_framerate_->actions()[i]->setChecked(true);
actions[i]->setChecked(true);
break;
}
}

View File

@@ -35,12 +35,12 @@
#include "analyzerbase.h"
#include "fht.h"
const uint BlockAnalyzer::kHeight = 2;
const uint BlockAnalyzer::kWidth = 4;
const uint BlockAnalyzer::kMinRows = 3; // arbituary
const uint BlockAnalyzer::kMinColumns = 32; // arbituary
const uint BlockAnalyzer::kMaxColumns = 256; // must be 2**n
const uint BlockAnalyzer::kFadeSize = 90;
const int BlockAnalyzer::kHeight = 2;
const int BlockAnalyzer::kWidth = 4;
const int BlockAnalyzer::kMinRows = 3; // arbituary
const int BlockAnalyzer::kMinColumns = 32; // arbituary
const int BlockAnalyzer::kMaxColumns = 256; // must be 2**n
const int BlockAnalyzer::kFadeSize = 90;
const char *BlockAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Block analyzer");
@@ -74,11 +74,11 @@ void BlockAnalyzer::resizeEvent(QResizeEvent *e) {
background_ = QPixmap(size());
canvas_ = QPixmap(size());
const uint oldRows = rows_;
const int oldRows = rows_;
// all is explained in analyze()..
// +1 to counter -1 in maxSizes, trust me we need this!
columns_ = qMin(static_cast<uint>(static_cast<double>(width() + 1) / (kWidth + 1)) + 1, kMaxColumns);
columns_ = qMin(static_cast<int>(static_cast<double>(width() + 1) / (kWidth + 1)) + 1, kMaxColumns);
rows_ = static_cast<uint>(static_cast<double>(height() + 1) / (kHeight + 1));
// this is the y-offset for drawing from the top of the widget
@@ -94,9 +94,9 @@ void BlockAnalyzer::resizeEvent(QResizeEvent *e) {
yscale_.resize(rows_ + 1);
const uint PRE = 1, PRO = 1; // PRE and PRO allow us to restrict the range somewhat
const int PRE = 1, PRO = 1; // PRE and PRO allow us to restrict the range somewhat
for (uint z = 0; z < rows_; ++z)
for (int z = 0; z < rows_; ++z)
yscale_[z] = 1 - (log10(PRE + z) / log10(PRE + rows_ + PRO));
yscale_[rows_] = 0;
@@ -115,7 +115,7 @@ void BlockAnalyzer::determineStep() {
// I calculated the value 30 based on some trial and error
// the fall time of 30 is too slow on framerates above 50fps
const double fallTime = timeout() < 20 ? 20 * rows_ : 30 * rows_;
const double fallTime = static_cast<double>(timeout() < 20 ? 20 * rows_ : 30 * rows_);
step_ = double(rows_ * timeout()) / fallTime;
@@ -164,12 +164,12 @@ void BlockAnalyzer::analyze(QPainter &p, const Analyzer::Scope &s, bool new_fram
// Paint the background
canvas_painter.drawPixmap(0, 0, background_);
for (uint y, x = 0; x < scope_.size(); ++x) {
for (int y, x = 0; x < static_cast<int>(scope_.size()); ++x) {
// determine y
for (y = 0; scope_[x] < yscale_[y]; ++y) continue;
// This is opposite to what you'd think, higher than y means the bar is lower than y (physically)
if (static_cast<float>(y) > store_[x])
if (static_cast<double>(y) > store_[x])
y = static_cast<int>(store_[x] += step_);
else
store_[x] = y;
@@ -182,8 +182,8 @@ void BlockAnalyzer::analyze(QPainter &p, const Analyzer::Scope &s, bool new_fram
}
if (fade_intensity_[x] > 0) {
const uint offset = --fade_intensity_[x];
const uint y2 = y_ + (fade_pos_[x] * (kHeight + 1));
const int offset = --fade_intensity_[x];
const int y2 = y_ + (fade_pos_[x] * (kHeight + 1));
canvas_painter.drawPixmap(x * (kWidth + 1), y2, fade_bars_[offset], 0, 0, kWidth, height() - y2);
}
@@ -200,7 +200,7 @@ void BlockAnalyzer::analyze(QPainter &p, const Analyzer::Scope &s, bool new_fram
}
static inline void adjustToLimits(int &b, int &f, uint &amount) {
static inline void adjustToLimits(int &b, int &f, int &amount) {
// with a range of 0-255 and maximum adjustment of amount, maximise the difference between f and b
@@ -235,8 +235,8 @@ static inline void adjustToLimits(int &b, int &f, uint &amount) {
* It won't modify the hue of fg unless absolutely necessary
* @return the adjusted form of fg
*/
QColor ensureContrast(const QColor &bg, const QColor &fg, uint amount = 150);
QColor ensureContrast(const QColor &bg, const QColor &fg, uint amount) {
QColor ensureContrast(const QColor &bg, const QColor &fg, int amount = 150);
QColor ensureContrast(const QColor &bg, const QColor &fg, int amount) {
class OutputOnExit {
public:
@@ -278,9 +278,9 @@ QColor ensureContrast(const QColor &bg, const QColor &fg, uint amount) {
// check the saturation for the two colours is sufficient that hue alone can
// provide sufficient contrast
if (ds > static_cast<int>(amount) / 2 && (bs > 125 && fs > 125))
if (ds > amount / 2 && (bs > 125 && fs > 125))
return fg;
else if (dv > static_cast<int>(amount) / 2 && (bv > 125 && fv > 125))
else if (dv > amount / 2 && (bv > 125 && fv > 125))
return fg;
}
@@ -295,11 +295,11 @@ QColor ensureContrast(const QColor &bg, const QColor &fg, uint amount) {
}
// test that there is available value to honor our contrast requirement
if (255 - dv < static_cast<int>(amount)) {
if (255 - dv < amount) {
// we have to modify the value and saturation of fg
// adjustToLimits( bv, fv, amount );
// see if we need to adjust the saturation
if (static_cast<int>(amount) > 0) adjustToLimits(bs, fs, amount);
if (amount > 0) adjustToLimits(bs, fs, amount);
// see if we need to adjust the hue
if (static_cast<int>(amount) > 0)
@@ -312,13 +312,13 @@ QColor ensureContrast(const QColor &bg, const QColor &fg, uint amount) {
return QColor::fromHsv(fh, fs, bv - static_cast<int>(amount));
if (fv < bv && fv > static_cast<int>(amount))
return QColor::fromHsv(fh, fs, fv - static_cast<int>(amount));
return QColor::fromHsv(fh, fs, fv - amount);
if (fv > bv && (255 - fv > static_cast<int>(amount)))
return QColor::fromHsv(fh, fs, fv + static_cast<int>(amount));
return QColor::fromHsv(fh, fs, fv + amount);
if (fv < bv && (255 - bv > static_cast<int>(amount)))
return QColor::fromHsv(fh, fs, bv + static_cast<int>(amount));
return QColor::fromHsv(fh, fs, bv + amount);
return Qt::blue;
}
@@ -338,7 +338,7 @@ void BlockAnalyzer::paletteChange(const QPalette&) {
bar()->fill(bg);
QPainter p(bar());
for (int y = 0; static_cast<uint>(y) < rows_; ++y)
for (int y = 0; y < rows_; ++y)
// graduate the fg color
p.fillRect(0, y * (kHeight + 1), kWidth, kHeight, QColor(r + static_cast<int>(dr * y), g + static_cast<int>(dg * y), b + static_cast<int>(db * y)));
@@ -360,7 +360,7 @@ void BlockAnalyzer::paletteChange(const QPalette&) {
for (uint y = 0; y < kFadeSize; ++y) {
fade_bars_[y].fill(palette().color(QPalette::Window));
QPainter f(&fade_bars_[y]);
for (int z = 0; static_cast<uint>(z) < rows_; ++z) {
for (int z = 0; z < rows_; ++z) {
const double Y = 1.0 - (log10(kFadeSize - y) / log10(kFadeSize));
f.fillRect(0, z * (kHeight + 1), kWidth, kHeight, QColor(r2 + static_cast<int>(dr2 * Y), g2 + static_cast<int>(dg2 * Y), b2 + static_cast<int>(db2 * Y)));
}
@@ -386,8 +386,8 @@ void BlockAnalyzer::drawBackground() {
if (!p.paintEngine()) return;
for (int x = 0; static_cast<uint>(x) < columns_; ++x)
for (int y = 0; static_cast<uint>(y) < rows_; ++y)
for (int x = 0; x < columns_; ++x)
for (int y = 0; y < rows_; ++y)
p.fillRect(x * (kWidth + 1), y * (kHeight + 1) + y_, kWidth, kHeight, bgdark);
}

View File

@@ -43,12 +43,12 @@ class BlockAnalyzer : public Analyzer::Base {
public:
Q_INVOKABLE explicit BlockAnalyzer(QWidget*);
static const uint kHeight;
static const uint kWidth;
static const uint kMinRows;
static const uint kMinColumns;
static const uint kMaxColumns;
static const uint kFadeSize;
static const int kHeight;
static const int kWidth;
static const int kMinRows;
static const int kMinColumns;
static const int kMaxColumns;
static const int kFadeSize;
static const char *kName;
@@ -65,21 +65,21 @@ class BlockAnalyzer : public Analyzer::Base {
private:
QPixmap *bar() { return &barpixmap_; }
uint columns_, rows_; // number of rows and columns of blocks
uint y_; // y-offset from top of widget
int columns_, rows_; // number of rows and columns of blocks
int y_; // y-offset from top of widget
QPixmap barpixmap_;
QPixmap topbarpixmap_;
QPixmap background_;
QPixmap canvas_;
Analyzer::Scope scope_; // so we don't create a vector every frame
QVector<float> store_; // current bar heights
QVector<float> yscale_;
QVector<double> store_; // current bar heights
QVector<double> yscale_;
QVector<QPixmap> fade_bars_;
QVector<uint> fade_pos_;
QVector<int> fade_pos_;
QVector<int> fade_intensity_;
float step_; // rows to fall per frame
double step_; // rows to fall per frame
};
#endif // BLOCKANALYZER_H

View File

@@ -39,9 +39,9 @@
using Analyzer::Scope;
const uint BoomAnalyzer::kColumnWidth = 4;
const uint BoomAnalyzer::kMaxBandCount = 256;
const uint BoomAnalyzer::kMinBandCount = 32;
const int BoomAnalyzer::kColumnWidth = 4;
const int BoomAnalyzer::kMaxBandCount = 256;
const int BoomAnalyzer::kMinBandCount = 32;
const char* BoomAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Boom analyzer");
@@ -80,10 +80,10 @@ void BoomAnalyzer::resizeEvent(QResizeEvent* e) {
const uint HEIGHT = height() - 2;
const double h = 1.2 / HEIGHT;
bands_ = qMin(static_cast<uint>(static_cast<double>(width() + 1) / (kColumnWidth + 1)) + 1, kMaxBandCount);
bands_ = qMin(static_cast<int>(static_cast<double>(width() + 1) / (kColumnWidth + 1)) + 1, kMaxBandCount);
scope_.resize(bands_);
F_ = static_cast<double>(HEIGHT) / (log10(256) * 1.1 /*<- max. amplitude*/);
F_ = double(HEIGHT) / (log10(256) * double(1.1) /*<- max. amplitude*/);
barPixmap_ = QPixmap(kColumnWidth - 2, HEIGHT);
canvas_ = QPixmap(size());
@@ -106,7 +106,7 @@ void BoomAnalyzer::transform(Scope& s) {
fht_->spectrum(s.data());
fht_->scale(s.data(), 1.0 / 50);
s.resize(scope_.size() <= kMaxBandCount / 2 ? kMaxBandCount / 2 : scope_.size());
s.resize(scope_.size() <= static_cast<quint64>(kMaxBandCount) / 2 ? kMaxBandCount / 2 : scope_.size());
}
@@ -116,7 +116,7 @@ void BoomAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) {
p.drawPixmap(0, 0, canvas_);
return;
}
float h;
double h;
const uint MAX_HEIGHT = height() - 1;
QPainter canvas_painter(&canvas_);
@@ -124,7 +124,7 @@ void BoomAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) {
Analyzer::interpolate(scope, scope_);
for (uint i = 0, x = 0, y; i < bands_; ++i, x += kColumnWidth + 1) {
for (int i = 0, x = 0, y; i < bands_; ++i, x += kColumnWidth + 1) {
h = log10(scope_[i] * 256.0) * F_;
if (h > MAX_HEIGHT) h = MAX_HEIGHT;
@@ -157,13 +157,13 @@ void BoomAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) {
}
}
y = height() - uint(bar_height_[i]);
y = height() - static_cast<int>(bar_height_[i]);
canvas_painter.drawPixmap(x + 1, y, barPixmap_, 0, y, -1, -1);
canvas_painter.setPen(fg_);
if (bar_height_[i] > 0)
canvas_painter.drawRect(x, y, kColumnWidth - 1, height() - y - 1);
y = height() - uint(peak_height_[i]);
y = height() - static_cast<int>(peak_height_[i]);
canvas_painter.setPen(palette().color(QPalette::Midlight));
canvas_painter.drawLine(x, y, x + kColumnWidth - 1, y);
}

View File

@@ -54,19 +54,19 @@ class BoomAnalyzer : public Analyzer::Base {
protected:
void resizeEvent(QResizeEvent *e) override;
static const uint kColumnWidth;
static const uint kMaxBandCount;
static const uint kMinBandCount;
static const int kColumnWidth;
static const int kMaxBandCount;
static const int kMinBandCount;
uint bands_;
int bands_;
Analyzer::Scope scope_;
QColor fg_;
double K_barHeight_, F_peakSpeed_, F_;
std::vector<float> bar_height_;
std::vector<float> peak_height_;
std::vector<float> peak_speed_;
std::vector<double> bar_height_;
std::vector<double> peak_height_;
std::vector<double> peak_speed_;
QPixmap barPixmap_;
QPixmap canvas_;

View File

@@ -112,7 +112,7 @@ void Rainbow::RainbowAnalyzer::resizeEvent(QResizeEvent* e) {
void Rainbow::RainbowAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, bool new_frame) {
// Discard the second half of the transform
const int scope_size = s.size() / 2;
const int scope_size = static_cast<int>(s.size() / 2);
if ((new_frame && is_playing_) || (buffer_[0].isNull() && buffer_[1].isNull())) {
// Transform the music into rainbows!

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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
@@ -597,7 +597,13 @@ void CollectionBackend::MarkSongsUnavailable(const SongList &songs, const bool u
}
transaction.Commit();
emit SongsDeleted(songs);
if (unavailable) {
emit SongsDeleted(songs);
}
else {
emit SongsDiscovered(songs);
}
UpdateTotalSongCountAsync();
UpdateTotalArtistCountAsync();
UpdateTotalAlbumCountAsync();
@@ -752,7 +758,7 @@ SongList CollectionBackend::GetSongsByForeignId(const QStringList &ids, const QS
QVector<Song> ret(ids.count());
while (q.next()) {
const QString foreign_id = q.value(Song::kColumns.count() + 1).toString();
const QString foreign_id = q.value(static_cast<int>(Song::kColumns.count()) + 1).toString();
const int index = ids.indexOf(foreign_id);
if (index == -1) continue;
@@ -1478,7 +1484,7 @@ void CollectionBackend::UpdatePlayCount(const QString &artist, const QString &ti
}
void CollectionBackend::UpdateSongRating(const int id, const float rating) {
void CollectionBackend::UpdateSongRating(const int id, const double rating) {
if (id == -1) return;
@@ -1488,7 +1494,7 @@ void CollectionBackend::UpdateSongRating(const int id, const float rating) {
}
void CollectionBackend::UpdateSongsRating(const QList<int> &id_list, const float rating) {
void CollectionBackend::UpdateSongsRating(const QList<int> &id_list, const double rating) {
if (id_list.isEmpty()) return;
@@ -1510,10 +1516,10 @@ void CollectionBackend::UpdateSongsRating(const QList<int> &id_list, const float
}
void CollectionBackend::UpdateSongRatingAsync(const int id, const float rating) {
metaObject()->invokeMethod(this, "UpdateSongRating", Qt::QueuedConnection, Q_ARG(int, id), Q_ARG(float, rating));
void CollectionBackend::UpdateSongRatingAsync(const int id, const double rating) {
metaObject()->invokeMethod(this, "UpdateSongRating", Qt::QueuedConnection, Q_ARG(int, id), Q_ARG(double, rating));
}
void CollectionBackend::UpdateSongsRatingAsync(const QList<int>& ids, const float rating) {
metaObject()->invokeMethod(this, "UpdateSongsRating", Qt::QueuedConnection, Q_ARG(QList<int>, ids), Q_ARG(float, rating));
void CollectionBackend::UpdateSongsRatingAsync(const QList<int>& ids, const double rating) {
metaObject()->invokeMethod(this, "UpdateSongsRating", Qt::QueuedConnection, Q_ARG(QList<int>, ids), Q_ARG(double, rating));
}

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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
@@ -193,8 +193,8 @@ class CollectionBackend : public CollectionBackendInterface {
void AddOrUpdateSongsAsync(const SongList &songs);
void UpdateSongRatingAsync(const int id, const float rating);
void UpdateSongsRatingAsync(const QList<int> &ids, const float rating);
void UpdateSongRatingAsync(const int id, const double rating);
void UpdateSongsRatingAsync(const QList<int> &ids, const double rating);
public slots:
void Exit();
@@ -220,8 +220,8 @@ class CollectionBackend : public CollectionBackendInterface {
void UpdateLastPlayed(const QString &artist, const QString &album, const QString &title, const qint64 lastplayed);
void UpdatePlayCount(const QString &artist, const QString &title, const int playcount);
void UpdateSongRating(const int id, const float rating);
void UpdateSongsRating(const QList<int> &id_list, const float rating);
void UpdateSongRating(const int id, const double rating);
void UpdateSongsRating(const QList<int> &id_list, const double rating);
signals:
void DirectoryDiscovered(Directory, SubdirectoryList);

View File

@@ -303,7 +303,8 @@ void CollectionFilterWidget::SetCollectionModel(CollectionModel *model) {
QObject::disconnect(model_, nullptr, this, nullptr);
QObject::disconnect(model_, nullptr, group_by_dialog_.get(), nullptr);
QObject::disconnect(group_by_dialog_.get(), nullptr, model_, nullptr);
for (QAction *action : filter_ages_.keys()) {
QList<QAction*> filter_ages = filter_ages_.keys();
for (QAction *action : filter_ages) {
QObject::disconnect(action, &QAction::triggered, model_, nullptr);
}
}
@@ -315,7 +316,8 @@ void CollectionFilterWidget::SetCollectionModel(CollectionModel *model) {
QObject::connect(model_, &CollectionModel::GroupingChanged, this, &CollectionFilterWidget::GroupingChanged);
QObject::connect(group_by_dialog_.get(), &GroupByDialog::Accepted, model_, &CollectionModel::SetGroupBy);
for (QAction *action : filter_ages_.keys()) {
QList<QAction*> filter_ages = filter_ages_.keys();
for (QAction *action : filter_ages) {
int age = filter_ages_[action];
QObject::connect(action, &QAction::triggered, [this, age]() { model_->SetFilterAge(age); } );
}
@@ -382,7 +384,9 @@ void CollectionFilterWidget::CheckCurrentGrouping(const CollectionModel::Groupin
}
// Check the advanced action
group_by_group_->actions().last()->setChecked(true);
QList<QAction*> actions = group_by_group_->actions();
QAction *action = actions.last();
action->setChecked(true);
}

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2020, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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
@@ -103,6 +103,7 @@ CollectionModel::CollectionModel(CollectionBackend *backend, Application *app, Q
group_by_[2] = GroupBy_None;
cover_loader_options_.get_image_data_ = false;
cover_loader_options_.get_image_ = true;
cover_loader_options_.scale_output_image_ = true;
cover_loader_options_.pad_output_image_ = true;
cover_loader_options_.desired_height_ = kPrettyCoverSize;
@@ -113,7 +114,8 @@ CollectionModel::CollectionModel(CollectionBackend *backend, Application *app, Q
QIcon nocover = IconLoader::Load("cdcase");
if (!nocover.isNull()) {
no_cover_icon_ = nocover.pixmap(nocover.availableSizes().last()).scaled(kPrettyCoverSize, kPrettyCoverSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QList<QSize> nocover_sizes = nocover.availableSizes();
no_cover_icon_ = nocover.pixmap(nocover_sizes.last()).scaled(kPrettyCoverSize, kPrettyCoverSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
if (app_ && !sIconCache) {
@@ -184,7 +186,7 @@ void CollectionModel::ReloadSettings() {
use_disk_cache_ = s.value(CollectionSettingsPage::kSettingsDiskCacheEnable, false).toBool();
QPixmapCache::setCacheLimit(MaximumCacheSize(&s, CollectionSettingsPage::kSettingsCacheSize, CollectionSettingsPage::kSettingsCacheSizeUnit, CollectionSettingsPage::kSettingsCacheSizeDefault) / 1024);
QPixmapCache::setCacheLimit(static_cast<int>(MaximumCacheSize(&s, CollectionSettingsPage::kSettingsCacheSize, CollectionSettingsPage::kSettingsCacheSizeUnit, CollectionSettingsPage::kSettingsCacheSizeDefault) / 1024));
if (sIconCache) {
sIconCache->setMaximumCacheSize(MaximumCacheSize(&s, CollectionSettingsPage::kSettingsDiskCacheSize, CollectionSettingsPage::kSettingsDiskCacheSizeUnit, CollectionSettingsPage::kSettingsDiskCacheSizeDefault));
@@ -381,10 +383,10 @@ QString CollectionModel::ContainerKey(const GroupBy type, const Song &song) cons
}
else {
if (song.bitdepth() <= 0) {
key = QString("%1 (%2)").arg(song.TextForFiletype()).arg(QString::number(song.samplerate() / 1000.0, 'G', 5));
key = QString("%1 (%2)").arg(song.TextForFiletype(), QString::number(song.samplerate() / 1000.0, 'G', 5));
}
else {
key = QString("%1 (%2/%3)").arg(song.TextForFiletype()).arg(QString::number(song.samplerate() / 1000.0, 'G', 5)).arg(song.bitdepth());
key = QString("%1 (%2/%3)").arg(song.TextForFiletype(), QString::number(song.samplerate() / 1000.0, 'G', 5)).arg(song.bitdepth());
}
}
break;
@@ -420,7 +422,8 @@ QString CollectionModel::DividerKey(const GroupBy type, CollectionItem *item) co
if (c.isDigit()) return "0";
if (c == ' ') return QString();
if (c.decompositionTag() != QChar::NoDecomposition) {
return QChar(c.decomposition()[0]);
QString decomposition = c.decomposition();
return QChar(decomposition[0]);
}
return c;
}
@@ -586,12 +589,13 @@ void CollectionModel::SongsDeleted(const SongList &songs) {
}
// Delete empty dividers
for (const QString &divider_key : divider_keys) {
for (const QString &divider_key : qAsConst(divider_keys)) {
if (!divider_nodes_.contains(divider_key)) continue;
// Look to see if there are any other items still under this divider
bool found = false;
for (CollectionItem *node : container_nodes_[0].values()) {
QList<CollectionItem*> container_nodes = container_nodes_[0].values();
for (CollectionItem *node : container_nodes) {
if (DividerKey(group_by_[0], node) == divider_key) {
found = true;
break;

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2020, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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
@@ -195,6 +195,9 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
void ExpandAll(CollectionItem *item = nullptr) const;
const CollectionModel::Grouping &GetGroupBy() const { return group_by_; }
void SetGroupBy(const CollectionModel::Grouping &g);
signals:
void TotalSongCountUpdated(int count);
void TotalArtistCountUpdated(int count);
@@ -206,8 +209,6 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
void SetFilterText(const QString &text);
void SetFilterQueryMode(QueryOptions::QueryMode query_mode);
void SetGroupBy(const CollectionModel::Grouping &g);
const CollectionModel::Grouping &GetGroupBy() const { return group_by_; }
void Init(const bool async = true);
void Reset();
void ResetAsync();

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2020, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2020, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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
@@ -91,7 +92,7 @@ CollectionQuery::CollectionQuery(const QueryOptions &options)
}
if (options.max_age() != -1) {
int cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - options.max_age();
qint64 cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - options.max_age();
where_clauses_ << "ctime > ?";
bound_values_ << cutoff;

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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
@@ -197,15 +198,15 @@ bool CollectionView::RestoreLevelFocus(const QModelIndex &parent) {
case CollectionItem::Type_Divider: {
QString text = model()->data(current, CollectionModel::Role_SortText).toString();
if (!last_selected_container_.isEmpty() && last_selected_container_ == text) {
emit expand(current);
expand(current);
setCurrentIndex(current);
return true;
}
else if (last_selected_path_.contains(text)) {
emit expand(current);
expand(current);
// If a selected container or song were not found, we've got into a wrong subtree (happens with "unknown" all the time)
if (!RestoreLevelFocus(current)) {
emit collapse(current);
collapse(current);
}
else {
return true;
@@ -462,7 +463,8 @@ void CollectionView::SetShowInVarious(const bool on) {
// If we have only one album and we are putting it into Various Artists, check to see
// if there are other Artists in this album and prompt the user if they'd like them moved, too
if (on && albums.keys().count() == 1) {
const QString album = albums.keys().first();
const QStringList albums_list = albums.keys();
const QString album = albums_list.first();
QList<Song> all_of_album = app_->collection_backend()->GetSongsByAlbum(album);
QSet<QString> other_artists;
for (const Song &s : all_of_album) {
@@ -480,10 +482,11 @@ void CollectionView::SetShowInVarious(const bool on) {
}
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
for (const QString &album : QSet<QString>(albums.keyBegin(), albums.keyEnd())) {
QSet<QString> albums_set = QSet<QString>(albums.keyBegin(), albums.keyEnd());
#else
for (const QString &album : QSet<QString>::fromList(albums.keys())) {
QSet<QString> albums_set = QSet<QString>::fromList(albums.keys());
#endif
for (const QString &album : albums_set) {
app_->collection_backend()->ForceCompilation(album, albums.values(album), on);
}

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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
@@ -110,6 +110,45 @@ void CollectionWatcher::Exit() {
}
void CollectionWatcher::ReloadSettingsAsync() {
QMetaObject::invokeMethod(this, "ReloadSettings", Qt::QueuedConnection);
}
void CollectionWatcher::ReloadSettings() {
const bool was_monitoring_before = monitor_;
QSettings s;
s.beginGroup(CollectionSettingsPage::kSettingsGroup);
scan_on_startup_ = s.value("startup_scan", true).toBool();
monitor_ = s.value("monitor", true).toBool();
mark_songs_unavailable_ = s.value("mark_songs_unavailable", false).toBool();
QStringList filters = s.value("cover_art_patterns", QStringList() << "front" << "cover").toStringList();
s.endGroup();
best_image_filters_.clear();
for (const QString &filter : filters) {
QString str = filter.trimmed();
if (!str.isEmpty()) best_image_filters_ << str;
}
if (!monitor_ && was_monitoring_before) {
fs_watcher_->Clear();
}
else if (monitor_ && !was_monitoring_before) {
// Add all directories to all QFileSystemWatchers again
QList<Directory> dirs = watched_dirs_.values();
for (const Directory &dir : dirs) {
SubdirectoryList subdirs = backend_->SubdirsInDirectory(dir.id);
for (const Subdirectory &subdir : subdirs) {
AddWatch(dir, subdir.path);
}
}
}
}
CollectionWatcher::ScanTransaction::ScanTransaction(CollectionWatcher *watcher, const int dir, const bool incremental, const bool ignores_mtime, const bool mark_songs_unavailable)
: progress_(0),
progress_max_(0),
@@ -119,15 +158,16 @@ CollectionWatcher::ScanTransaction::ScanTransaction(CollectionWatcher *watcher,
mark_songs_unavailable_(mark_songs_unavailable),
watcher_(watcher),
cached_songs_dirty_(true),
known_subdirs_dirty_(true)
{
known_subdirs_dirty_(true) {
QString description;
if (watcher_->device_name_.isEmpty())
if (watcher_->device_name_.isEmpty()) {
description = tr("Updating collection");
else
}
else {
description = tr("Updating %1").arg(watcher_->device_name_);
}
task_id_ = watcher_->task_manager_->StartTask(description);
emit watcher_->ScanStarted(task_id_);
@@ -310,7 +350,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
// Do not scan symlinked dirs that are already in collection
if (path_info.isSymLink()) {
QString real_path = path_info.symLinkTarget();
for (const Directory &dir : watched_dirs_) {
for (const Directory &dir : qAsConst(watched_dirs_)) {
if (real_path.startsWith(dir.path)) {
t->AddToProgress(1);
return;
@@ -347,6 +387,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
// First we "quickly" get a list of the files in the directory that we think might be music. While we're here, we also look for new subdirectories and possible album artwork.
QDirIterator it(path, QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot);
while (it.hasNext()) {
if (stop_requested_) return;
QString child(it.next());
@@ -384,7 +425,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
for (const QString &file : files_on_disk) {
if (stop_requested_) return;
// associated cue
// Associated cue
QString matching_cue = NoExtensionPart(file) + ".cue";
Song matching_song(source_);
@@ -401,14 +442,14 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
continue;
}
// cue sheet's path from collection (if any)
// CUE sheet's path from collection (if any)
QString song_cue = matching_song.cue_path();
qint64 song_cue_mtime = GetMtimeForCue(song_cue);
bool cue_deleted = song_cue_mtime == 0 && matching_song.has_cue();
bool cue_added = matching_cue_mtime != 0 && !matching_song.has_cue();
// watch out for cue songs which have their mtime equal to qMax(media_file_mtime, cue_sheet_mtime)
// Watch out for CUE songs which have their mtime equal to qMax(media_file_mtime, cue_sheet_mtime)
bool changed = (matching_song.mtime() != qMax(file_info.lastModified().toSecsSinceEpoch(), song_cue_mtime)) || cue_deleted || cue_added;
// Also want to look to see whether the album art has changed
@@ -417,16 +458,14 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
changed = true;
}
// the song's changed - reread the metadata from file
// The song's changed - reread the metadata from file
if (t->ignores_mtime() || changed) {
qLog(Debug) << file << "changed";
// if cue associated...
if (!cue_deleted && (matching_song.has_cue() || cue_added)) {
if (!cue_deleted && (matching_song.has_cue() || cue_added)) { // If CUE associated.
UpdateCueAssociatedSongs(file, path, matching_cue, image, t);
// if no cue or it's about to lose it...
}
else {
else { // If no CUE or it's about to lose it.
UpdateNonCueAssociatedSong(file, matching_song, image, cue_deleted, t);
}
}
@@ -444,7 +483,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
}
qLog(Debug) << file << "created";
// choose an image for the song(s)
// Choose an image for the song(s)
QUrl image = ImageForSong(file, album_art);
for (Song song : song_list) {
@@ -509,7 +548,7 @@ void CollectionWatcher::UpdateCueAssociatedSongs(const QString &file, const QStr
cue_song.set_directory_id(t->dir());
Song matching = sections_map[cue_song.beginning_nanosec()];
// a new section
// A new section
if (!matching.is_valid()) {
t->new_songs << cue_song;
// changed section
@@ -520,7 +559,7 @@ void CollectionWatcher::UpdateCueAssociatedSongs(const QString &file, const QStr
}
}
// sections that are now missing
// Sections that are now missing
for (const Song &matching : old_sections) {
if (!used_ids.contains(matching.id())) {
t->deleted_songs << matching;
@@ -531,7 +570,7 @@ void CollectionWatcher::UpdateCueAssociatedSongs(const QString &file, const QStr
void CollectionWatcher::UpdateNonCueAssociatedSong(const QString &file, const Song &matching_song, const QUrl &image, bool cue_deleted, ScanTransaction *t) {
// If a cue got deleted, we turn it's first section into the new 'raw' (cueless) song and we just remove the rest of the sections from the collection
// If a CUE got deleted, we turn it's first section into the new 'raw' (cueless) song and we just remove the rest of the sections from the collection
if (cue_deleted) {
for (const Song &song : backend_->GetSongsByUrl(QUrl::fromLocalFile(file))) {
if (!song.IsMetadataAndArtEqual(matching_song)) {
@@ -555,9 +594,8 @@ SongList CollectionWatcher::ScanNewFile(const QString &file, const QString &path
SongList song_list;
quint64 matching_cue_mtime = GetMtimeForCue(matching_cue);
// If it's a cue - create virtual tracks
if (matching_cue_mtime) {
// don't process the same cue many times
if (matching_cue_mtime) { // If it's a CUE - create virtual tracks
// Don't process the same cue many times
if (cues_processed->contains(matching_cue)) return song_list;
QFile cue(matching_cue);
@@ -580,9 +618,8 @@ SongList CollectionWatcher::ScanNewFile(const QString &file, const QString &path
*cues_processed << matching_cue;
}
// it's a normal media file
}
else {
else { // It's a normal media file
Song song(source_);
TagReaderClient::Instance()->ReadFileBlocking(file, &song);
if (song.is_valid()) {
@@ -653,7 +690,8 @@ void CollectionWatcher::AddWatch(const Directory &dir, const QString &path) {
void CollectionWatcher::RemoveWatch(const Directory &dir, const Subdirectory &subdir) {
for (const QString &subdir_path : subdir_mapping_.keys(dir)) {
QStringList subdir_paths = subdir_mapping_.keys(dir);
for (const QString &subdir_path : subdir_paths) {
if (subdir_path != subdir.path) continue;
fs_watcher_->RemovePath(subdir_path);
subdir_mapping_.remove(subdir_path);
@@ -668,7 +706,8 @@ void CollectionWatcher::RemoveDirectory(const Directory &dir) {
watched_dirs_.remove(dir.id);
// Stop watching the directory's subdirectories
for (const QString &subdir_path : subdir_mapping_.keys(dir)) {
QStringList subdir_paths = subdir_mapping_.keys(dir);
for (const QString &subdir_path : subdir_paths) {
fs_watcher_->RemovePath(subdir_path);
subdir_mapping_.remove(subdir_path);
}
@@ -708,7 +747,8 @@ void CollectionWatcher::DirectoryChanged(const QString &subdir) {
void CollectionWatcher::RescanPathsNow() {
for (int dir : rescan_queue_.keys()) {
QList<int> dirs = rescan_queue_.keys();
for (const int dir : dirs) {
if (stop_requested_) break;
ScanTransaction transaction(this, dir, false, false, mark_songs_unavailable_);
transaction.AddToProgressMax(rescan_queue_[dir].count());
@@ -793,44 +833,6 @@ QUrl CollectionWatcher::ImageForSong(const QString &path, QMap<QString, QStringL
}
void CollectionWatcher::ReloadSettingsAsync() {
QMetaObject::invokeMethod(this, "ReloadSettings", Qt::QueuedConnection);
}
void CollectionWatcher::ReloadSettings() {
const bool was_monitoring_before = monitor_;
QSettings s;
s.beginGroup(CollectionSettingsPage::kSettingsGroup);
scan_on_startup_ = s.value("startup_scan", true).toBool();
monitor_ = s.value("monitor", true).toBool();
mark_songs_unavailable_ = s.value("mark_songs_unavailable", false).toBool();
QStringList filters = s.value("cover_art_patterns", QStringList() << "front" << "cover").toStringList();
s.endGroup();
best_image_filters_.clear();
for (const QString &filter : filters) {
QString str = filter.trimmed();
if (!str.isEmpty()) best_image_filters_ << str;
}
if (!monitor_ && was_monitoring_before) {
fs_watcher_->Clear();
}
else if (monitor_ && !was_monitoring_before) {
// Add all directories to all QFileSystemWatchers again
for (const Directory &dir : watched_dirs_.values()) {
SubdirectoryList subdirs = backend_->SubdirsInDirectory(dir.id);
for (const Subdirectory &subdir : subdirs) {
AddWatch(dir, subdir.path);
}
}
}
}
void CollectionWatcher::SetRescanPausedAsync(bool pause) {
QMetaObject::invokeMethod(this, "SetRescanPaused", Qt::QueuedConnection, Q_ARG(bool, pause));
@@ -902,7 +904,8 @@ void CollectionWatcher::PerformScan(bool incremental, bool ignore_mtimes) {
stop_requested_ = false;
for (const Directory &dir : watched_dirs_.values()) {
QList<Directory> dirs = watched_dirs_.values();
for (const Directory &dir : dirs) {
if (stop_requested_) break;
ScanTransaction transaction(this, dir.id, incremental, ignore_mtimes, mark_songs_unavailable_);

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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
@@ -155,7 +155,7 @@ class CollectionWatcher : public QObject {
void FullScanNow();
void RescanTracksNow();
void RescanPathsNow();
void ScanSubdirectory(const QString &path, const Subdirectory &subdir, ScanTransaction *t, bool force_noincremental = false);
void ScanSubdirectory(const QString &path, const Subdirectory &subdir, CollectionWatcher::ScanTransaction *t, bool force_noincremental = false);
private:
static bool FindSongByPath(const SongList &list, const QString &path, Song *out);
@@ -228,4 +228,3 @@ inline QString CollectionWatcher::DirectoryPart(const QString& fileName) {
}
#endif // COLLECTIONWATCHER_H

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -1,7 +1,8 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2015, Nick Lanham <nick@afternight.org>
* Copyright 2019-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2015, Nick Lanham <nick@afternight.org>
* Copyright 2019-2021, 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

@@ -1,22 +1,3 @@
/*
* Strawberry Music Player
* Copyright 2013, Jonas Kvinge <jonas@strawbs.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 CONFIG_H_IN
#define CONFIG_H_IN
@@ -24,7 +5,6 @@
#define CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
#define CMAKE_EXECUTABLE_SUFFIX "${CMAKE_EXECUTABLE_SUFFIX}"
#cmakedefine DEBUG
#cmakedefine HAVE_BACKTRACE
#cmakedefine HAVE_GIO
#cmakedefine HAVE_DBUS

View File

@@ -1,6 +1,6 @@
/*
* Strawberry Music Player
* Copyright 2020, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2020-2021, 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

@@ -1,6 +1,6 @@
/*
* Strawberry Music Player
* Copyright 2020, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2020-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This code was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2013-2020, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2013-2021, 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
@@ -75,7 +75,8 @@ ContextAlbumsModel::ContextAlbumsModel(CollectionBackend *backend, Application *
QObject::connect(app_->album_cover_loader(), &AlbumCoverLoader::AlbumCoverLoaded, this, &ContextAlbumsModel::AlbumCoverLoaded);
QIcon nocover = IconLoader::Load("cdcase");
no_cover_icon_ = nocover.pixmap(nocover.availableSizes().last()).scaled(kPrettyCoverSize, kPrettyCoverSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QList<QSize> nocover_sizes = nocover.availableSizes();
no_cover_icon_ = nocover.pixmap(nocover_sizes.last()).scaled(kPrettyCoverSize, kPrettyCoverSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This code was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2013, Jonas Kvinge <jonas@strawbs.net>
* Copyright 2013-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This code was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2013-2020, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2013-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This code was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2013, Jonas Kvinge <jonas@strawbs.net>
* Copyright 2013-2021, 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

@@ -1,6 +1,6 @@
/*
* Strawberry Music Player
* Copyright 2013-2020, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2013-2021, 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

@@ -1,6 +1,6 @@
/*
* Strawberry Music Player
* Copyright 2013-2020, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2013-2021, 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

@@ -3,7 +3,7 @@
* This file was part of Clementine.
* Copyright 2012, David Sansome <me@davidsansome.com>
* Copyright 2012, 2014, John Maguire <john.maguire@gmail.com>
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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

@@ -3,7 +3,7 @@
* This file was part of Clementine.
* Copyright 2012, David Sansome <me@davidsansome.com>
* Copyright 2012, 2014, John Maguire <john.maguire@gmail.com>
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2012, David Sansome <me@davidsansome.com>
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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
@@ -184,7 +184,8 @@ QSqlDatabase Database::Connect() {
}
// Attach external databases
for (const QString &key : attached_databases_.keys()) {
QStringList keys = attached_databases_.keys();
for (const QString &key : keys) {
QString filename = attached_databases_[key].filename_;
if (!injected_database_name_.isNull()) filename = injected_database_name_;
@@ -204,7 +205,8 @@ QSqlDatabase Database::Connect() {
}
// We might have to initialize the schema in some attached databases now, if they were deleted and don't match up with the main schema version.
for (const QString &key : attached_databases_.keys()) {
keys = attached_databases_.keys();
for (const QString &key : keys) {
if (attached_databases_[key].is_temporary_ && attached_databases_[key].schema_.isEmpty())
continue;
// Find out if there are any tables in this database
@@ -453,7 +455,8 @@ QStringList Database::SongsTables(QSqlDatabase &db, int schema_version) const {
}
// look for the tables in attached dbs
for (const QString &key : attached_databases_.keys()) {
QStringList keys = attached_databases_.keys();
for (const QString &key : keys) {
QSqlQuery q(db);
q.prepare(QString("SELECT NAME FROM %1.sqlite_master WHERE type='table' AND name='songs' OR name LIKE '%songs'").arg(key));
if (q.exec()) {

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2012, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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

@@ -1,6 +1,6 @@
/*
* Strawberry Music Player
* Copyright 2013, 2017-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2013, 2017-2021, 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
@@ -75,7 +75,7 @@ QIcon IconLoader::Load(const QString &name, const int fixed_size, const int min_
if (icon_prop.allow_system_icon) {
ret = QIcon::fromTheme(name);
if (ret.isNull()) {
for (QString alt_name : icon_prop.names) {
for (const QString &alt_name : icon_prop.names) {
ret = QIcon::fromTheme(alt_name);
if (!ret.isNull()) break;
}

View File

@@ -1,6 +1,6 @@
/*
* Strawberry Music Player
* Copyright 2013, 2017-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2013, 2017-2021, 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

@@ -1,6 +1,6 @@
/*
* Strawberry Music Player
* Copyright 2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2019-2021, 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

@@ -1,6 +1,6 @@
/*
* Strawberry Music Player
* Copyright 2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2019-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2011, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -1,6 +1,6 @@
/*
* Strawberry Music Player
* Copyright 2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2019-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2012, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
*Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2013-2020, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2013-2021, 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
@@ -1599,11 +1599,11 @@ void MainWindow::FilePathChanged(const QString &path) {
settings_.setValue("file_path", path);
}
void MainWindow::Seeked(const qlonglong microseconds) {
void MainWindow::Seeked(const qint64 microseconds) {
const int position = microseconds / kUsecPerSec;
const int length = app_->player()->GetCurrentItem()->Metadata().length_nanosec() / kNsecPerSec;
if (tray_icon_) tray_icon_->SetProgress(double(position) / length * 100);
const qint64 position = microseconds / kUsecPerSec;
const qint64 length = app_->player()->GetCurrentItem()->Metadata().length_nanosec() / kNsecPerSec;
if (tray_icon_) tray_icon_->SetProgress(static_cast<int>(double(position) / length * 100));
}
@@ -1612,18 +1612,18 @@ void MainWindow::UpdateTrackPosition() {
PlaylistItemPtr item(app_->player()->GetCurrentItem());
if (!item) return;
const int length = (item->Metadata().length_nanosec() / kNsecPerSec);
const qint64 length = (item->Metadata().length_nanosec() / kNsecPerSec);
if (length <= 0) return;
const int position = std::floor(float(app_->player()->engine()->position_nanosec()) / kNsecPerSec + 0.5);
// Update the tray icon every 10 seconds
if (tray_icon_ && position % 10 == 0) tray_icon_->SetProgress(double(position) / length * 100);
if (tray_icon_ && position % 10 == 0) tray_icon_->SetProgress(static_cast<int>(double(position) / length * 100));
// Send Scrobble
if (app_->scrobbler()->IsEnabled() && item->Metadata().is_metadata_good()) {
Playlist *playlist = app_->playlist_manager()->active();
if (playlist && !playlist->scrobbled()) {
const int scrobble_point = (playlist->scrobble_point_nanosec() / kNsecPerSec);
const qint64 scrobble_point = (playlist->scrobble_point_nanosec() / kNsecPerSec);
if (position >= scrobble_point) {
app_->scrobbler()->Scrobble(item->Metadata(), scrobble_point);
playlist->set_scrobbled(true);
@@ -1637,8 +1637,8 @@ void MainWindow::UpdateTrackSliderPosition() {
PlaylistItemPtr item(app_->player()->GetCurrentItem());
const int slider_position = std::floor(float(app_->player()->engine()->position_nanosec()) / kNsecPerMsec);
const int slider_length = app_->player()->engine()->length_nanosec() / kNsecPerMsec;
const qint64 slider_position = std::floor(float(app_->player()->engine()->position_nanosec()) / kNsecPerMsec);
const qint64 slider_length = app_->player()->engine()->length_nanosec() / kNsecPerMsec;
// Update the slider
ui_->track_slider->SetValue(slider_position, slider_length);
@@ -1913,7 +1913,7 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
QString column_value = app_->playlist_manager()->current()->data(source_index).toString();
if (column_value.length() > 25) column_value = column_value.left(25) + "...";
ui_->action_selection_set_value->setText(tr("Set %1 to \"%2\"...").arg(column_name.toLower()).arg(column_value));
ui_->action_selection_set_value->setText(tr("Set %1 to \"%2\"...").arg(column_name.toLower(), column_value));
ui_->action_edit_value->setText(tr("Edit tag \"%1\"...").arg(column_name));
// Is it a collection item?

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2013-2020, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2013-2021, 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
@@ -200,7 +200,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
void ToggleShowHide();
void ToggleHide();
void Seeked(const qlonglong microseconds);
void Seeked(const qint64 microseconds);
void UpdateTrackPosition();
void UpdateTrackSliderPosition();

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2019-2021, 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
@@ -417,7 +418,8 @@ QStringList MergedProxyModel::mimeTypes() const {
QStringList ret;
ret << sourceModel()->mimeTypes();
for (const QAbstractItemModel *model : merge_points_.keys()) {
QList<QAbstractItemModel*> models = merge_points_.keys();
for (const QAbstractItemModel *model : models) {
ret << model->mimeTypes();
}
@@ -494,7 +496,8 @@ QAbstractItemModel *MergedProxyModel::GetModel(const QModelIndex &source_index)
// This is essentially const_cast<QAbstractItemModel*>(source_index.model()), but without the const_cast
const QAbstractItemModel *const_model = source_index.model();
if (const_model == sourceModel()) return sourceModel();
for (QAbstractItemModel *submodel : merge_points_.keys()) {
QList<QAbstractItemModel*> submodels = merge_points_.keys();
for (QAbstractItemModel *submodel : submodels) {
if (submodel == const_model) return submodel;
}
return nullptr;
@@ -508,19 +511,21 @@ void MergedProxyModel::DataChanged(const QModelIndex &top_left, const QModelInde
void MergedProxyModel::LayoutAboutToBeChanged() {
old_merge_points_.clear();
for (QAbstractItemModel *key : merge_points_.keys()) {
old_merge_points_[key] = merge_points_.value(key);
QList<QAbstractItemModel*> models = merge_points_.keys();
for (QAbstractItemModel *model : models) {
old_merge_points_[model] = merge_points_.value(model);
}
}
void MergedProxyModel::LayoutChanged() {
for (QAbstractItemModel *key : merge_points_.keys()) {
if (!old_merge_points_.contains(key)) continue;
QList<QAbstractItemModel*> models = merge_points_.keys();
for (QAbstractItemModel *model : models) {
if (!old_merge_points_.contains(model)) continue;
const int old_row = old_merge_points_[key].row();
const int new_row = merge_points_[key].row();
const int old_row = old_merge_points_[model].row();
const int new_row = merge_points_[model].row();
if (old_row != new_row) {
beginResetModel();

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2019-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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
@@ -411,9 +412,9 @@ void Mpris2::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &re
double Mpris2::Volume() const { return app_->player()->GetVolume() / 100.0; }
void Mpris2::SetVolume(double value) { app_->player()->SetVolume(value * 100); }
void Mpris2::SetVolume(double value) { app_->player()->SetVolume(static_cast<int>(value * 100)); }
qlonglong Mpris2::Position() const {
qint64 Mpris2::Position() const {
return app_->player()->engine()->position_nanosec() / kNsecPerUsec;
}
@@ -478,13 +479,16 @@ void Mpris2::Play() {
}
}
void Mpris2::Seek(qlonglong offset) {
void Mpris2::Seek(qint64 offset) {
if (CanSeek()) {
app_->player()->SeekTo(app_->player()->engine()->position_nanosec() / kNsecPerSec + offset / kUsecPerSec);
}
}
void Mpris2::SetPosition(const QDBusObjectPath &trackId, qlonglong offset) {
void Mpris2::SetPosition(const QDBusObjectPath &trackId, qint64 offset) {
if (CanSeek() && trackId.path() == current_track_id() && offset >= 0) {
offset *= kNsecPerUsec;
@@ -492,6 +496,7 @@ void Mpris2::SetPosition(const QDBusObjectPath &trackId, qlonglong offset) {
app_->player()->SeekTo(offset / kNsecPerSec);
}
}
}
void Mpris2::OpenUri(const QString &uri) {

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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
@@ -97,7 +98,7 @@ class Mpris2 : public QObject {
Q_PROPERTY(bool Shuffle READ Shuffle WRITE SetShuffle)
Q_PROPERTY(QVariantMap Metadata READ Metadata)
Q_PROPERTY(double Volume READ Volume WRITE SetVolume)
Q_PROPERTY(qlonglong Position READ Position)
Q_PROPERTY(qint64 Position READ Position)
Q_PROPERTY(double MinimumRate READ MinimumRate)
Q_PROPERTY(double MaximumRate READ MaximumRate)
Q_PROPERTY(bool CanGoNext READ CanGoNext)
@@ -145,7 +146,7 @@ class Mpris2 : public QObject {
QVariantMap Metadata() const;
double Volume() const;
void SetVolume(double value);
qlonglong Position() const;
qint64 Position() const;
double MaximumRate() const;
double MinimumRate() const;
bool CanGoNext() const;
@@ -162,8 +163,8 @@ class Mpris2 : public QObject {
void PlayPause();
void Stop();
void Play();
void Seek(qlonglong offset);
void SetPosition(const QDBusObjectPath &trackId, qlonglong offset);
void Seek(qint64 offset);
void SetPosition(const QDBusObjectPath &trackId, qint64 offset);
void OpenUri(const QString &uri);
// TrackList Properties
@@ -187,7 +188,7 @@ class Mpris2 : public QObject {
signals:
// Player
void Seeked(qlonglong position);
void Seeked(qint64 position);
// TrackList
void TrackListReplaced(Track_Ids Tracks, QDBusObjectPath CurrentTrack);

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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
@@ -633,7 +633,7 @@ void Player::CurrentMetadataChanged(const Song &metadata) {
}
void Player::SeekTo(const int seconds) {
void Player::SeekTo(const qint64 seconds) {
const qint64 length_nanosec = engine_->length_nanosec();

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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
@@ -87,7 +87,7 @@ class PlayerInterface : public QObject {
virtual void SetVolume(const int value) = 0;
virtual void VolumeUp() = 0;
virtual void VolumeDown() = 0;
virtual void SeekTo(const int seconds) = 0;
virtual void SeekTo(const qint64 seconds) = 0;
// Moves the position of the currently playing song five seconds forward.
virtual void SeekForward() = 0;
// Moves the position of the currently playing song five seconds backwards.
@@ -113,7 +113,7 @@ class PlayerInterface : public QObject {
void VolumeChanged(int volume);
void TrackSkipped(PlaylistItemPtr old_track);
// Emitted when there's a manual change to the current's track position.
void Seeked(qlonglong microseconds);
void Seeked(qint64 microseconds);
// Emitted when Player has processed a request to play another song.
// This contains the URL of the song and a flag saying whether it was able to play the song.
@@ -168,7 +168,7 @@ class Player : public PlayerInterface {
void SetVolume(const int value) override;
void VolumeUp() override { SetVolume(GetVolume() + 5); }
void VolumeDown() override { SetVolume(GetVolume() - 5); }
void SeekTo(const int seconds) override;
void SeekTo(const qint64 seconds) override;
void SeekForward() override;
void SeekBackward() override;

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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
@@ -60,7 +61,7 @@ QtSystemTrayIcon::QtSystemTrayIcon(QObject *parent)
}
tray_->setIcon(normal_icon_);
tray_->installEventFilter(this);
ClearNowPlaying();
QtSystemTrayIcon::ClearNowPlaying();
QObject::connect(tray_, &QSystemTrayIcon::activated, this, &QtSystemTrayIcon::Clicked);

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -41,7 +41,7 @@ gulong CheckedGConnect(gpointer source, const char *signal, GCallback callback,
GSignalQuery query;
g_signal_query(signal_id, &query);
// The signature for a signal callback is always: return_type callback(gpointer data1, params..., gpointer data2);
int signal_params = query.n_params + 2;
int signal_params = static_cast<int>(query.n_params) + 2;
if (signal_params != callback_param_count) {
qFatal("Connecting callback to signal with different parameters counts");
return 0;

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, 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

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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
@@ -152,6 +152,8 @@ const QString Song::kVariousArtists("various artists");
const QStringList Song::kArticles = QStringList() << "the " << "a " << "an ";
const QStringList Song::kAcceptedExtensions = QStringList() << "aac" << "ac3" << "dts";
struct Song::Private : public QSharedData {
explicit Private(Source source = Source_Unknown);
@@ -202,7 +204,7 @@ struct Song::Private : public QSharedData {
int playcount_;
int skipcount_;
int lastplayed_;
qint64 lastplayed_;
bool compilation_detected_; // From the collection scanner
bool compilation_on_; // Set by the user
@@ -214,7 +216,7 @@ struct Song::Private : public QSharedData {
QString cue_path_; // If the song has a CUE, this contains it's path.
float rating_; // Database rating, not read from tags.
double rating_; // Database rating, not read from tags.
QUrl stream_url_; // Temporary stream url set by url handler.
QImage image_; // Album Cover image set by album cover loader.
@@ -360,7 +362,7 @@ const QImage &Song::image() const { return d->image_; }
const QString &Song::cue_path() const { return d->cue_path_; }
bool Song::has_cue() const { return !d->cue_path_.isEmpty(); }
float Song::rating() const { return d->rating_; }
double Song::rating() const { return d->rating_; }
bool Song::is_collection_song() const { return d->source_ == Source_Collection; }
bool Song::is_metadata_good() const { return !d->url_.isEmpty() && !d->artist_.isEmpty() && !d->title_.isEmpty(); }
@@ -461,7 +463,7 @@ void Song::set_art_automatic(const QUrl &v) { d->art_automatic_ = v; }
void Song::set_art_manual(const QUrl &v) { d->art_manual_ = v; }
void Song::set_cue_path(const QString &v) { d->cue_path_ = v; }
void Song::set_rating(float v) { d->rating_ = v; }
void Song::set_rating(double v) { d->rating_ = v; }
void Song::set_stream_url(const QUrl &v) { d->stream_url_ = v; }
void Song::set_image(const QImage &i) { d->image_ = i; }
@@ -844,7 +846,7 @@ void Song::ToProtobuf(spb::tagreader::SongMetadata *pb) const {
#define tostr(n) (q.value(n).isNull() ? QString() : q.value(n).toString())
#define toint(n) (q.value(n).isNull() ? -1 : q.value(n).toInt())
#define tolonglong(n) (q.value(n).isNull() ? -1 : q.value(n).toLongLong())
#define tofloat(n) (q.value(n).isNull() ? -1 : q.value(n).toDouble())
#define todouble(n) (q.value(n).isNull() ? -1 : q.value(n).toDouble())
void Song::InitFromQuery(const SqlRow &q, bool reliable_metadata, int col) {
@@ -1013,7 +1015,7 @@ void Song::InitFromQuery(const SqlRow &q, bool reliable_metadata, int col) {
}
else if (Song::kColumns.value(i) == "rating") {
d->rating_ = tofloat(x);
d->rating_ = todouble(x);
}
else {
@@ -1029,7 +1031,7 @@ void Song::InitFromQuery(const SqlRow &q, bool reliable_metadata, int col) {
#undef tostr
#undef toint
#undef tolonglong
#undef tofloat
#undef todouble
}
@@ -1038,7 +1040,6 @@ void Song::InitFromFilePartial(const QString &filename) {
set_url(QUrl::fromLocalFile(filename));
QFileInfo info(filename);
d->basefilename_ = info.fileName();
QString suffix = info.suffix().toLower();
TagLib::FileRef fileref(filename.toUtf8().constData());
if (fileref.file()) {
@@ -1046,6 +1047,13 @@ void Song::InitFromFilePartial(const QString &filename) {
d->source_ = Source_LocalFile;
if (d->art_manual_.isEmpty()) InitArtManual();
}
else if (kAcceptedExtensions.contains(info.suffix(), Qt::CaseInsensitive)) {
d->valid_ = true;
d->source_ = Source_LocalFile;
d->filetype_ = FiletypeByExtension(info.suffix());
d->title_ = info.fileName();
if (d->art_manual_.isEmpty()) InitArtManual();
}
else {
d->valid_ = false;
d->error_ = QObject::tr("File %1 is not recognized as a valid audio file.").arg(filename);
@@ -1458,7 +1466,7 @@ QString Song::TitleWithCompilationArtist() const {
if (title.isEmpty()) title = d->basefilename_;
if (is_compilation() && !d->artist_.isEmpty() && !d->artist_.toLower().contains("various")) title = d->artist_ + " - " + title;
if (is_compilation() && !d->artist_.isEmpty() && !d->artist_.contains("various", Qt::CaseInsensitive)) title = d->artist_ + " - " + title;
return title;
@@ -1475,7 +1483,7 @@ QString Song::SampleRateBitDepthToText() const {
QString Song::PrettyRating() const {
float rating = d->rating_;
double rating = d->rating_;
if (rating == -1.0f) return "0";

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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
@@ -127,6 +127,8 @@ class Song {
static const QStringList kArticles;
static const QStringList kAcceptedExtensions;
static QString JoinSpec(const QString &table);
static Source SourceFromURL(const QUrl &url);
@@ -243,7 +245,7 @@ class Song {
const QString &cue_path() const;
bool has_cue() const;
float rating() const;
double rating() const;
const QString &effective_album() const;
int effective_originalyear() const;
@@ -356,7 +358,7 @@ class Song {
void set_cue_path(const QString &v);
void set_rating(const float v);
void set_rating(const double v);
void set_stream_url(const QUrl &v);
void set_image(const QImage &i);

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2021, 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

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