Compare commits
176 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47b5dea95c | ||
|
|
b0df63f1e8 | ||
|
|
3c4209b676 | ||
|
|
d51b9a8e0e | ||
|
|
3b56125bd2 | ||
|
|
6e69e39007 | ||
|
|
97208cb329 | ||
|
|
414a4a97fb | ||
|
|
2a809f96c4 | ||
|
|
17799b03f3 | ||
|
|
efc55fc648 | ||
|
|
22bd41211a | ||
|
|
4cb0171bd0 | ||
|
|
ce6c5af72c | ||
|
|
171575256c | ||
|
|
d3664dcf78 | ||
|
|
0788981783 | ||
|
|
aeee7c02d5 | ||
|
|
6e49a50461 | ||
|
|
fbc99827ab | ||
|
|
3b134320c4 | ||
|
|
c315e5016d | ||
|
|
7aebd6ed57 | ||
|
|
1a8ca06495 | ||
|
|
a27ae7e4a6 | ||
|
|
dd0ab897aa | ||
|
|
00ad92fb6d | ||
|
|
f84128ecbd | ||
|
|
ba89e0f4e3 | ||
|
|
832d36a4d4 | ||
|
|
0b437b3bfb | ||
|
|
7b50ec4630 | ||
|
|
4ddb13abac | ||
|
|
d2ac081177 | ||
|
|
9692fbf15b | ||
|
|
be966488e8 | ||
|
|
0ce613264f | ||
|
|
34634d776e | ||
|
|
673ded3819 | ||
|
|
b9a94ad3ae | ||
|
|
3f80b330cc | ||
|
|
01632d538c | ||
|
|
b0a9b1cd09 | ||
|
|
1f772081fd | ||
|
|
4ae54dbaad | ||
|
|
e47f4ff731 | ||
|
|
465369d79e | ||
|
|
15ddf6ff20 | ||
|
|
16a753bd95 | ||
|
|
c15103636c | ||
|
|
8a5f82ee7d | ||
|
|
5ec33ec821 | ||
|
|
ab7d383cf1 | ||
|
|
184e9a5c93 | ||
|
|
c4f5363cde | ||
|
|
002882cebf | ||
|
|
1cb3ec0c7b | ||
|
|
6bf325c6f6 | ||
|
|
09c7ff9e8b | ||
|
|
c2a94b61bf | ||
|
|
1db16232de | ||
|
|
3da681a6b1 | ||
|
|
a79b3e7852 | ||
|
|
b1099e6974 | ||
|
|
4f6e06131c | ||
|
|
19f69e9e6c | ||
|
|
01481da773 | ||
|
|
3e8f7e1cf1 | ||
|
|
5da69646f2 | ||
|
|
3cac01583b | ||
|
|
d16a26605e | ||
|
|
a4f692c788 | ||
|
|
9f01206c57 | ||
|
|
d34fc551ed | ||
|
|
7aa5f0d258 | ||
|
|
276a34bb66 | ||
|
|
0d820eda12 | ||
|
|
1991c1b677 | ||
|
|
459404e3f0 | ||
|
|
badc623a3c | ||
|
|
8e39f92cb7 | ||
|
|
3ff4885973 | ||
|
|
f9d45f7657 | ||
|
|
789ff9df5c | ||
|
|
a2064ed16b | ||
|
|
b3d06c0868 | ||
|
|
db1a6b3e38 | ||
|
|
8390237cc4 | ||
|
|
9967eae7bb | ||
|
|
b3be7d1c6f | ||
|
|
33ccb5dbb2 | ||
|
|
5b90c0d695 | ||
|
|
472a660239 | ||
|
|
ab67536d9a | ||
|
|
ee85fb3aec | ||
|
|
214b6f4358 | ||
|
|
af0d092054 | ||
|
|
b07903c3e9 | ||
|
|
ffa4c6bf09 | ||
|
|
b4125fa56c | ||
|
|
2c72302087 | ||
|
|
0fa52bc64f | ||
|
|
f55a80b15a | ||
|
|
0735483321 | ||
|
|
53fc2c7c21 | ||
|
|
f22133c3c5 | ||
|
|
2d5a6d6583 | ||
|
|
dc4adf2836 | ||
|
|
dd6e254e4f | ||
|
|
4c028c1659 | ||
|
|
d332a6777a | ||
|
|
378251f229 | ||
|
|
b6b9b903ed | ||
|
|
143d68cfd5 | ||
|
|
a31eac1426 | ||
|
|
797196f7fc | ||
|
|
c9d0bc81dd | ||
|
|
b5448ff607 | ||
|
|
5ebd363d5d | ||
|
|
1d439e673e | ||
|
|
0b7b7656b2 | ||
|
|
eb270df835 | ||
|
|
ff73dd2183 | ||
|
|
e043a03eb6 | ||
|
|
3cb4e8e373 | ||
|
|
7e6de528b4 | ||
|
|
df901c30ef | ||
|
|
13856b33ec | ||
|
|
a3a1c6f4c8 | ||
|
|
638998a861 | ||
|
|
6e2ec89a05 | ||
|
|
af67de8aa6 | ||
|
|
425dac478e | ||
|
|
b15c4ecd10 | ||
|
|
d7f88cf3a4 | ||
|
|
5b7fbcd9b8 | ||
|
|
7af64b0782 | ||
|
|
b84c70e811 | ||
|
|
f5b245c72d | ||
|
|
4307183817 | ||
|
|
aeb32783d6 | ||
|
|
3927b3bf27 | ||
|
|
da9d2f9417 | ||
|
|
1cec48e8f8 | ||
|
|
f1105393da | ||
|
|
dc7047e3c2 | ||
|
|
08b2945623 | ||
|
|
cbcc223150 | ||
|
|
9830f21e4a | ||
|
|
5f49567bf7 | ||
|
|
6154ae7342 | ||
|
|
978f3a3682 | ||
|
|
1f0961d574 | ||
|
|
a101252701 | ||
|
|
c96c29b1e3 | ||
|
|
3b0fc180ff | ||
|
|
9b8bfdf33c | ||
|
|
4328831fcd | ||
|
|
e5b3df41e9 | ||
|
|
cf5259e218 | ||
|
|
f24b6a520c | ||
|
|
4140163ab2 | ||
|
|
7afde0e93f | ||
|
|
d27a571882 | ||
|
|
1c70e3be25 | ||
|
|
1819f64467 | ||
|
|
9852e588c1 | ||
|
|
71a1ea481b | ||
|
|
9e32f0d778 | ||
|
|
4478174dc2 | ||
|
|
07553476d4 | ||
|
|
1773283456 | ||
|
|
221ab51d90 | ||
|
|
43e0dd922b | ||
|
|
b3262652c3 | ||
|
|
0cfa2b8c20 |
@@ -80,7 +80,6 @@ commands:
|
||||
libpulse-devel
|
||||
gstreamer-devel
|
||||
gstreamer-plugins-base-devel
|
||||
libxine-devel
|
||||
vlc-devel
|
||||
libQt5Core-devel
|
||||
libQt5Gui-devel
|
||||
@@ -96,9 +95,7 @@ commands:
|
||||
libqt5-linguist-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libmtp-devel
|
||||
libusbmuxd-devel
|
||||
libchromaprint-devel
|
||||
desktop-file-utils
|
||||
update-desktop-files
|
||||
@@ -150,8 +147,6 @@ commands:
|
||||
taglib-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libusbmuxd-devel
|
||||
libmtp-devel
|
||||
libchromaprint-devel
|
||||
fftw-devel
|
||||
@@ -214,8 +209,6 @@ commands:
|
||||
libchromaprint-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libusbmuxd-devel
|
||||
libmtp-devel
|
||||
libjpeg-devel
|
||||
cairo-devel
|
||||
@@ -238,14 +231,14 @@ commands:
|
||||
steps:
|
||||
- run:
|
||||
name: Update packages
|
||||
command: urpmi.update -a
|
||||
command: urpmi.update --auto -a
|
||||
- run:
|
||||
name: Configure auto update
|
||||
command: urpmi --auto-update
|
||||
command: urpmi --auto --auto-update
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: >
|
||||
urpmi --force
|
||||
urpmi --auto --force
|
||||
urpmi-debuginfo-install
|
||||
git
|
||||
tar
|
||||
@@ -281,8 +274,6 @@ commands:
|
||||
lib64gstreamer-plugins-base1.0-devel
|
||||
lib64cdio-devel
|
||||
lib64gpod-devel
|
||||
lib64plist-devel
|
||||
lib64usbmuxd-devel
|
||||
lib64mtp-devel
|
||||
lib64raw1394-devel
|
||||
lib64chromaprint-devel
|
||||
@@ -336,9 +327,6 @@ commands:
|
||||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
|
||||
|
||||
install_ubuntu_dependencies:
|
||||
@@ -390,9 +378,6 @@ commands:
|
||||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
|
||||
|
||||
jobs:
|
||||
@@ -501,15 +486,6 @@ jobs:
|
||||
- build_rpm
|
||||
|
||||
|
||||
build_debian_stretch:
|
||||
docker:
|
||||
- image: debian:stretch
|
||||
steps:
|
||||
- install_debian_dependencies
|
||||
- checkout
|
||||
- cmake
|
||||
- build_deb
|
||||
|
||||
build_debian_buster:
|
||||
docker:
|
||||
- image: debian:buster
|
||||
@@ -603,10 +579,6 @@ workflows:
|
||||
only: /.*/
|
||||
|
||||
|
||||
- build_debian_stretch:
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
- build_debian_buster:
|
||||
filters:
|
||||
tags:
|
||||
|
||||
176
.github/workflows/ccpp.yml
vendored
176
.github/workflows/ccpp.yml
vendored
@@ -38,7 +38,6 @@ jobs:
|
||||
libpulse-devel
|
||||
gstreamer-devel
|
||||
gstreamer-plugins-base-devel
|
||||
libxine-devel
|
||||
vlc-devel
|
||||
libQt5Core-devel
|
||||
libQt5Gui-devel
|
||||
@@ -54,9 +53,7 @@ jobs:
|
||||
libqt5-linguist-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libmtp-devel
|
||||
libusbmuxd-devel
|
||||
libchromaprint-devel
|
||||
desktop-file-utils
|
||||
update-desktop-files
|
||||
@@ -109,7 +106,6 @@ jobs:
|
||||
libpulse-devel
|
||||
gstreamer-devel
|
||||
gstreamer-plugins-base-devel
|
||||
libxine-devel
|
||||
vlc-devel
|
||||
libQt5Core-devel
|
||||
libQt5Gui-devel
|
||||
@@ -125,9 +121,7 @@ jobs:
|
||||
libqt5-linguist-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libmtp-devel
|
||||
libusbmuxd-devel
|
||||
libchromaprint-devel
|
||||
desktop-file-utils
|
||||
update-desktop-files
|
||||
@@ -188,7 +182,6 @@ jobs:
|
||||
libpulse-devel
|
||||
gstreamer-devel
|
||||
gstreamer-plugins-base-devel
|
||||
libxine-devel
|
||||
vlc-devel
|
||||
libQt5Core-devel
|
||||
libQt5Gui-devel
|
||||
@@ -204,9 +197,7 @@ jobs:
|
||||
libqt5-linguist-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libmtp-devel
|
||||
libusbmuxd-devel
|
||||
libchromaprint-devel
|
||||
desktop-file-utils
|
||||
update-desktop-files
|
||||
@@ -269,7 +260,6 @@ jobs:
|
||||
libpulse-devel
|
||||
gstreamer-devel
|
||||
gstreamer-plugins-base-devel
|
||||
libxine-devel
|
||||
vlc-devel
|
||||
libQt5Core-devel
|
||||
libQt5Gui-devel
|
||||
@@ -285,9 +275,7 @@ jobs:
|
||||
libqt5-linguist-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libmtp-devel
|
||||
libusbmuxd-devel
|
||||
libchromaprint-devel
|
||||
desktop-file-utils
|
||||
update-desktop-files
|
||||
@@ -313,6 +301,78 @@ jobs:
|
||||
run: rpmbuild -ba ../dist/unix/strawberry.spec
|
||||
|
||||
|
||||
build_opensuse_qt6:
|
||||
name: Build openSUSE Qt 6
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: opensuse/tumbleweed
|
||||
steps:
|
||||
- uses: actions/checkout@v1.2.0
|
||||
- name: Add Qt 6 repository
|
||||
run: zypper -n ar -c -f -n 'repo-qt6' https://download.opensuse.org/repositories/home:/jonaski:/qt6/openSUSE_Tumbleweed/ repo-qt6
|
||||
- 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
|
||||
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-x11extras-devel
|
||||
qt6-base-common-devel
|
||||
qt6-sql-sqlite
|
||||
qt6-qt5compat-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 -DWITH_QT6=ON
|
||||
- name: Build
|
||||
working-directory: build
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
|
||||
|
||||
build_fedora_32:
|
||||
name: Build Fedora 32
|
||||
runs-on: ubuntu-latest
|
||||
@@ -364,8 +424,6 @@ jobs:
|
||||
taglib-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libusbmuxd-devel
|
||||
libmtp-devel
|
||||
libchromaprint-devel
|
||||
fftw-devel
|
||||
@@ -448,8 +506,6 @@ jobs:
|
||||
libchromaprint-devel
|
||||
libcdio-devel
|
||||
libgpod-devel
|
||||
libplist-devel
|
||||
libusbmuxd-devel
|
||||
libmtp-devel
|
||||
libjpeg-devel
|
||||
cairo-devel
|
||||
@@ -494,14 +550,14 @@ jobs:
|
||||
- uses: actions/checkout@v1.2.0
|
||||
|
||||
- name: Update packages
|
||||
run: urpmi.update -a
|
||||
run: urpmi.update --auto -a
|
||||
|
||||
- name: Configure auto update
|
||||
run: urpmi --auto-update
|
||||
run: urpmi --auto --auto-update
|
||||
|
||||
- name: Install Mageia dependencies
|
||||
run: >
|
||||
urpmi --force
|
||||
urpmi --auto --force
|
||||
urpmi-debuginfo-install
|
||||
git
|
||||
tar
|
||||
@@ -537,8 +593,6 @@ jobs:
|
||||
lib64gstreamer-plugins-base1.0-devel
|
||||
lib64cdio-devel
|
||||
lib64gpod-devel
|
||||
lib64plist-devel
|
||||
lib64usbmuxd-devel
|
||||
lib64mtp-devel
|
||||
lib64raw1394-devel
|
||||
lib64chromaprint-devel
|
||||
@@ -570,65 +624,6 @@ jobs:
|
||||
run: rpmbuild -ba ../dist/unix/strawberry.spec
|
||||
|
||||
|
||||
build_debian_stretch:
|
||||
name: Build Debian Stretch
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: debian:stretch
|
||||
steps:
|
||||
- uses: actions/checkout@v1.2.0
|
||||
- name: Install Debian dependencies
|
||||
run: >
|
||||
apt-get update && apt-get install -y
|
||||
build-essential
|
||||
ssh
|
||||
git
|
||||
make
|
||||
cmake
|
||||
gcc
|
||||
pkg-config
|
||||
fakeroot
|
||||
gettext
|
||||
lsb-release
|
||||
libglib2.0-dev
|
||||
dpkg-dev
|
||||
libdbus-1-dev
|
||||
libboost-dev
|
||||
libprotobuf-dev
|
||||
protobuf-compiler
|
||||
libsqlite3-dev
|
||||
libgnutls28-dev
|
||||
libasound2-dev
|
||||
libpulse-dev
|
||||
qtbase5-dev
|
||||
qtbase5-dev-tools
|
||||
qtbase5-private-dev
|
||||
libqt5x11extras5-dev
|
||||
qttools5-dev
|
||||
libgstreamer1.0-dev
|
||||
libgstreamer-plugins-base1.0-dev
|
||||
gstreamer1.0-alsa
|
||||
gstreamer1.0-pulseaudio
|
||||
libchromaprint-dev
|
||||
libfftw3-dev
|
||||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
- 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
|
||||
- name: make deb
|
||||
shell: bash
|
||||
run: dpkg-buildpackage -b -d -uc -us -nc -j2
|
||||
|
||||
|
||||
build_debian_buster:
|
||||
name: Build Debian Buster
|
||||
runs-on: ubuntu-latest
|
||||
@@ -673,9 +668,6 @@ jobs:
|
||||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
- name: Create Build Environment
|
||||
shell: bash
|
||||
run: cmake -E make_directory build
|
||||
@@ -732,9 +724,6 @@ jobs:
|
||||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
- name: Create Build Environment
|
||||
shell: bash
|
||||
run: cmake -E make_directory build
|
||||
@@ -796,9 +785,6 @@ jobs:
|
||||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
- name: Create Build Environment
|
||||
shell: bash
|
||||
run: cmake -E make_directory build
|
||||
@@ -860,9 +846,6 @@ jobs:
|
||||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
- name: Create Build Environment
|
||||
shell: bash
|
||||
run: cmake -E make_directory build
|
||||
@@ -924,9 +907,6 @@ jobs:
|
||||
libcdio-dev
|
||||
libmtp-dev
|
||||
libgpod-dev
|
||||
libimobiledevice-dev
|
||||
libplist-dev
|
||||
libusbmuxd-dev
|
||||
- name: Create Build Environment
|
||||
shell: bash
|
||||
run: cmake -E make_directory build
|
||||
@@ -969,8 +949,6 @@ jobs:
|
||||
gst-libav
|
||||
libcdio
|
||||
libmtp
|
||||
libimobiledevice
|
||||
libplist
|
||||
create-dmg
|
||||
taglib
|
||||
|
||||
@@ -1034,9 +1012,7 @@ jobs:
|
||||
-DENABLE_WIN32_CONSOLE=OFF
|
||||
-DENABLE_DBUS=OFF
|
||||
-DENABLE_LIBGPOD=OFF
|
||||
-DENABLE_IMOBILEDEVICE=OFF
|
||||
-DENABLE_LIBMTP=OFF
|
||||
-DENABLE_XINE=OFF
|
||||
-DProtobuf_PROTOC_EXECUTABLE=/usr/src/strawberry-mxe/usr/x86_64-pc-linux-gnu/bin/protoc
|
||||
|
||||
- name: Run Make
|
||||
@@ -1049,7 +1025,7 @@ jobs:
|
||||
|
||||
- name: Create directories
|
||||
working-directory: build
|
||||
run: mkdir -p gio-modules platforms sqldrivers imageformats styles gstreamer-plugins xine-plugins nsisplugins
|
||||
run: mkdir -p gio-modules platforms sqldrivers imageformats styles gstreamer-plugins nsisplugins
|
||||
|
||||
- name: Copy GIO modules
|
||||
working-directory: build
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -104,7 +104,6 @@ Thumbs.db
|
||||
|
||||
# Stuff in dist
|
||||
maketarball.sh
|
||||
create-dmg.sh
|
||||
changelog
|
||||
PKGBUILD
|
||||
|
||||
|
||||
@@ -23,8 +23,11 @@ before_install:
|
||||
brew unlink python@2 || travis_terminate 1;
|
||||
brew install glib pkgconfig libffi protobuf protobuf-c qt gettext gnutls fftw sqlite chromaprint zlib taglib;
|
||||
brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav;
|
||||
brew install libcdio libmtp libimobiledevice libplist;
|
||||
brew install libcdio libmtp;
|
||||
brew install create-dmg;
|
||||
brew cask install 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;
|
||||
export Qt5_DIR=/usr/local/opt/qt5/lib/cmake;
|
||||
export Qt5LinguistTools_DIR=/usr/local/opt/qt5/lib/cmake/Qt5LinguistTools;
|
||||
export PATH="/usr/local/opt/gettext/bin:$PATH";
|
||||
|
||||
32
3rdparty/singleapplication/CMakeLists.txt
vendored
32
3rdparty/singleapplication/CMakeLists.txt
vendored
@@ -10,38 +10,46 @@ endif()
|
||||
|
||||
set(SINGLEAPP-SOURCES singleapplication.cpp singleapplication_p.cpp)
|
||||
set(SINGLEAPP-MOC-HEADERS singleapplication.h singleapplication_p.h)
|
||||
QT5_WRAP_CPP(SINGLEAPP-SOURCES-MOC ${SINGLEAPP-MOC-HEADERS})
|
||||
if(WITH_QT6)
|
||||
qt6_wrap_cpp(SINGLEAPP-SOURCES-MOC ${SINGLEAPP-MOC-HEADERS})
|
||||
else()
|
||||
qt5_wrap_cpp(SINGLEAPP-SOURCES-MOC ${SINGLEAPP-MOC-HEADERS})
|
||||
endif()
|
||||
add_library(singleapplication STATIC ${SINGLEAPP-SOURCES} ${SINGLEAPP-SOURCES-MOC})
|
||||
target_include_directories(singleapplication SYSTEM PRIVATE
|
||||
${Qt5Core_INCLUDE_DIRS}
|
||||
${Qt5Widgets_INCLUDE_DIRS}
|
||||
${Qt5Network_INCLUDE_DIRS}
|
||||
${QtCore_INCLUDE_DIRS}
|
||||
${QtWidgets_INCLUDE_DIRS}
|
||||
${QtNetwork_INCLUDE_DIRS}
|
||||
)
|
||||
target_include_directories(singleapplication PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
target_link_libraries(singleapplication PRIVATE
|
||||
${Qt5Core_LIBRARIES}
|
||||
${Qt5Widgets_LIBRARIES}
|
||||
${Qt5Network_LIBRARIES}
|
||||
${QtCore_LIBRARIES}
|
||||
${QtWidgets_LIBRARIES}
|
||||
${QtNetwork_LIBRARIES}
|
||||
)
|
||||
|
||||
set(SINGLECOREAPP-SOURCES singlecoreapplication.cpp singlecoreapplication_p.cpp)
|
||||
set(SINGLECOREAPP-MOC-HEADERS singlecoreapplication.h singlecoreapplication_p.h)
|
||||
QT5_WRAP_CPP(SINGLECOREAPP-SOURCES-MOC ${SINGLECOREAPP-MOC-HEADERS})
|
||||
if(WITH_QT6)
|
||||
qt6_wrap_cpp(SINGLECOREAPP-SOURCES-MOC ${SINGLECOREAPP-MOC-HEADERS})
|
||||
else()
|
||||
qt5_wrap_cpp(SINGLECOREAPP-SOURCES-MOC ${SINGLECOREAPP-MOC-HEADERS})
|
||||
endif()
|
||||
add_library(singlecoreapplication STATIC ${SINGLECOREAPP-SOURCES} ${SINGLECOREAPP-SOURCES-MOC})
|
||||
target_include_directories(singlecoreapplication SYSTEM PRIVATE
|
||||
${Qt5Core_INCLUDE_DIRS}
|
||||
${Qt5Network_INCLUDE_DIRS}
|
||||
${QtCore_INCLUDE_DIRS}
|
||||
${QtNetwork_INCLUDE_DIRS}
|
||||
)
|
||||
target_include_directories(singlecoreapplication PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
target_link_libraries(singlecoreapplication PRIVATE
|
||||
${Qt5Core_LIBRARIES}
|
||||
${Qt5Network_LIBRARIES}
|
||||
${QtCore_LIBRARIES}
|
||||
${QtNetwork_LIBRARIES}
|
||||
)
|
||||
|
||||
configure_file(config.h.in "${CMAKE_CURRENT_BINARY_DIR}/config.h")
|
||||
|
||||
14
3rdparty/taglib/ConfigureChecks.cmake
vendored
14
3rdparty/taglib/ConfigureChecks.cmake
vendored
@@ -6,32 +6,32 @@ include(CheckCXXSourceCompiles)
|
||||
# Check if the size of numeric types are suitable.
|
||||
|
||||
check_type_size("short" SIZEOF_SHORT)
|
||||
if(NOT ${SIZEOF_SHORT} EQUAL 2)
|
||||
if(NOT SIZEOF_SHORT EQUAL 2)
|
||||
message(FATAL_ERROR "TagLib requires that short is 16-bit wide.")
|
||||
endif()
|
||||
|
||||
check_type_size("int" SIZEOF_INT)
|
||||
if(NOT ${SIZEOF_INT} EQUAL 4)
|
||||
if(NOT SIZEOF_INT EQUAL 4)
|
||||
message(FATAL_ERROR "TagLib requires that int is 32-bit wide.")
|
||||
endif()
|
||||
|
||||
check_type_size("long long" SIZEOF_LONGLONG)
|
||||
if(NOT ${SIZEOF_LONGLONG} EQUAL 8)
|
||||
if(NOT SIZEOF_LONGLONG EQUAL 8)
|
||||
message(FATAL_ERROR "TagLib requires that long long is 64-bit wide.")
|
||||
endif()
|
||||
|
||||
check_type_size("wchar_t" SIZEOF_WCHAR_T)
|
||||
if(${SIZEOF_WCHAR_T} LESS 2)
|
||||
if(SIZEOF_WCHAR_T LESS 2)
|
||||
message(FATAL_ERROR "TagLib requires that wchar_t is sufficient to store a UTF-16 char.")
|
||||
endif()
|
||||
|
||||
check_type_size("float" SIZEOF_FLOAT)
|
||||
if(NOT ${SIZEOF_FLOAT} EQUAL 4)
|
||||
if(NOT SIZEOF_FLOAT EQUAL 4)
|
||||
message(FATAL_ERROR "TagLib requires that float is 32-bit wide.")
|
||||
endif()
|
||||
|
||||
check_type_size("double" SIZEOF_DOUBLE)
|
||||
if(NOT ${SIZEOF_DOUBLE} EQUAL 8)
|
||||
if(NOT SIZEOF_DOUBLE EQUAL 8)
|
||||
message(FATAL_ERROR "TagLib requires that double is 64-bit wide.")
|
||||
endif()
|
||||
|
||||
@@ -212,5 +212,5 @@ endif()
|
||||
|
||||
# Detect WinRT mode
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
|
||||
set(PLATFORM WINRT 1)
|
||||
set(PLATFORM WINRT 1)
|
||||
endif()
|
||||
|
||||
5
3rdparty/taglib/toolkit/tutils.h
vendored
5
3rdparty/taglib/toolkit/tutils.h
vendored
@@ -160,6 +160,9 @@ inline String formatString(const char *format, ...) {
|
||||
char buf[BufferSize];
|
||||
int length;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||
|
||||
# if defined(HAVE_VSNPRINTF)
|
||||
|
||||
length = vsnprintf(buf, BufferSize, format, args);
|
||||
@@ -180,6 +183,8 @@ inline String formatString(const char *format, ...) {
|
||||
|
||||
# endif
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
va_end(args);
|
||||
|
||||
if (length > 0)
|
||||
|
||||
178
CMakeLists.txt
178
CMakeLists.txt
@@ -50,16 +50,11 @@ list(APPEND COMPILE_OPTIONS
|
||||
-Wunused-parameter
|
||||
-Wformat=2
|
||||
-Wdisabled-optimization
|
||||
-Wno-sign-conversion
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-Woverloaded-virtual>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-Wno-old-style-cast>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fpermissive>
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
list(APPEND COMPILE_OPTIONS -Wno-unused-parameter)
|
||||
endif()
|
||||
|
||||
option(BUILD_WERROR "Build with -Werror" OFF)
|
||||
if(BUILD_WERROR)
|
||||
list(APPEND COMPILE_OPTIONS -Werror)
|
||||
@@ -77,6 +72,11 @@ if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
|
||||
set(DEBUG ON)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks")
|
||||
endif()
|
||||
|
||||
find_program(CCACHE_EXECUTABLE NAMES ccache)
|
||||
if (CCACHE_EXECUTABLE)
|
||||
message(STATUS "ccache found: will be used for compilation and linkage")
|
||||
@@ -93,7 +93,9 @@ if(Backtrace_FOUND)
|
||||
endif()
|
||||
find_package(GnuTLS REQUIRED)
|
||||
find_package(Protobuf REQUIRED)
|
||||
find_library(PROTOBUF_STATIC_LIBRARY libprotobuf.a libprotobuf)
|
||||
if (NOT Protobuf_PROTOC_EXECUTABLE)
|
||||
message(FATAL_ERROR "Missing protobuf compiler.")
|
||||
endif()
|
||||
if(LINUX)
|
||||
find_package(ALSA REQUIRED)
|
||||
pkg_check_modules(DBUS REQUIRED dbus-1)
|
||||
@@ -118,23 +120,17 @@ pkg_check_modules(GSTREAMER_AUDIO gstreamer-audio-1.0)
|
||||
pkg_check_modules(GSTREAMER_APP gstreamer-app-1.0)
|
||||
pkg_check_modules(GSTREAMER_TAG gstreamer-tag-1.0)
|
||||
pkg_check_modules(GSTREAMER_PBUTILS gstreamer-pbutils-1.0)
|
||||
pkg_check_modules(LIBXINE libxine)
|
||||
pkg_check_modules(LIBVLC libvlc)
|
||||
pkg_check_modules(SQLITE REQUIRED sqlite3>=3.9)
|
||||
pkg_check_modules(LIBPULSE libpulse)
|
||||
pkg_check_modules(CHROMAPRINT libchromaprint)
|
||||
pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92)
|
||||
pkg_check_modules(LIBMTP libmtp>=1.0)
|
||||
pkg_check_modules(LIBIMOBILEDEVICE libimobiledevice-1.0)
|
||||
pkg_search_module(LIBUSBMUXD libusbmuxd-2.0 libusbmuxd)
|
||||
pkg_search_module(LIBPLIST libplist-2.0 libplist)
|
||||
find_package(Gettext)
|
||||
find_package(FFTW3)
|
||||
|
||||
# QT
|
||||
set(QT_MIN_VERSION 5.6)
|
||||
option(WITH_QT6 "Use Qt 6" OFF)
|
||||
set(QT_COMPONENTS Core Concurrent Widgets Network Sql)
|
||||
|
||||
if(X11_FOUND)
|
||||
list(APPEND QT_COMPONENTS X11Extras)
|
||||
endif()
|
||||
@@ -148,32 +144,71 @@ if(WIN32)
|
||||
list(APPEND QT_COMPONENTS WinExtras)
|
||||
endif()
|
||||
|
||||
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS ${QT_COMPONENTS})
|
||||
|
||||
set(QT_LIBRARIES ${Qt5Core_LIBRARIES} ${Qt5Concurrent_LIBRARIES} ${Qt5Widgets_LIBRARIES} ${Qt5Network_LIBRARIES} ${Qt5Sql_LIBRARIES})
|
||||
set(QT_INCLUDE_DIRS ${Qt5Core_INCLUDE_DIRS} ${Qt5Concurrent_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5Sql_INCLUDE_DIRS})
|
||||
|
||||
if(Qt5DBus_FOUND)
|
||||
list(APPEND QT_LIBRARIES ${Qt5DBus_LIBRARIES})
|
||||
list(APPEND QT_INCLUDE_DIRS ${Qt5DBus_INCLUDE_DIRS})
|
||||
get_target_property(QT_DBUSXML2CPP_EXECUTABLE Qt5::qdbusxml2cpp LOCATION)
|
||||
endif()
|
||||
if(Qt5X11Extras_FOUND)
|
||||
list(APPEND QT_LIBRARIES ${Qt5X11Extras_LIBRARIES})
|
||||
list(APPEND QT_INCLUDE_DIRS ${Qt5X11Extras_INCLUDE_DIRS})
|
||||
endif()
|
||||
if(Qt5MacExtras_FOUND)
|
||||
list(APPEND QT_LIBRARIES ${Qt5MacExtras_LIBRARIES})
|
||||
list(APPEND QT_INCLUDE_DIRS ${Qt5MacExtras_INCLUDE_DIRS})
|
||||
endif()
|
||||
if(Qt5WinExtras_FOUND)
|
||||
list(APPEND QT_LIBRARIES ${Qt5WinExtras_LIBRARIES})
|
||||
list(APPEND QT_INCLUDE_DIRS ${Qt5WinExtras_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
find_package(Qt5 ${QT_MIN_VERSION} QUIET COMPONENTS LinguistTools CONFIG)
|
||||
if (Qt5LinguistTools_FOUND)
|
||||
set(QT_LCONVERT_EXECUTABLE Qt5::lconvert)
|
||||
if(WITH_QT6)
|
||||
list(APPEND QT_COMPONENTS Core5Compat)
|
||||
find_package(Qt6 REQUIRED COMPONENTS ${QT_COMPONENTS})
|
||||
set(QtCore_LIBRARIES Qt6::Core)
|
||||
set(QtConcurrent_LIBRARIES Qt6::Concurrent)
|
||||
set(QtWidgets_LIBRARIES Qt6::Widgets)
|
||||
set(QtNetwork_LIBRARIES Qt6::Network)
|
||||
set(QtSql_LIBRARIES Qt6::Sql)
|
||||
set(QT_LIBRARIES Qt6::Core Qt6::Concurrent Qt6::Widgets Qt6::Network Qt6::Sql Qt6::Core5Compat)
|
||||
if(Qt6DBus_FOUND)
|
||||
set(QtDBus_LIBRARIES Qt6::DBus)
|
||||
list(APPEND QT_LIBRARIES Qt6::DBus)
|
||||
get_target_property(QT_DBUSXML2CPP_EXECUTABLE Qt6::qdbusxml2cpp LOCATION)
|
||||
endif()
|
||||
if(Qt6X11Extras_FOUND)
|
||||
set(QtX11Extras_LIBRARIES Qt6::X11Extras)
|
||||
list(APPEND QT_LIBRARIES Qt6::X11Extras)
|
||||
endif()
|
||||
if(Qt6MacExtras_FOUND)
|
||||
set(QtMacExtras_LIBRARIES Qt6::MacExtras)
|
||||
list(APPEND QT_LIBRARIES Qt6::MacExtras)
|
||||
endif()
|
||||
if(Qt6WinExtras_FOUND)
|
||||
set(QtWinExtras_LIBRARIES Qt6::WinExtras)
|
||||
list(APPEND QT_LIBRARIES Qt6::WinExtras)
|
||||
endif()
|
||||
find_package(Qt6 QUIET COMPONENTS LinguistTools CONFIG)
|
||||
if (Qt6LinguistTools_FOUND)
|
||||
set(QT_LCONVERT_EXECUTABLE Qt6::lconvert)
|
||||
endif()
|
||||
else()
|
||||
set(QT_MIN_VERSION 5.8)
|
||||
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS ${QT_COMPONENTS})
|
||||
set(QtCore_LIBRARIES ${Qt5Core_LIBRARIES})
|
||||
set(QtConcurrent_LIBRARIES ${Qt5Concurrent_LIBRARIES})
|
||||
set(QtWidgets_LIBRARIES ${Qt5Widgets_LIBRARIES})
|
||||
set(QtNetwork_LIBRARIES ${Qt5Network_LIBRARIES})
|
||||
set(QtSql_LIBRARIES ${Qt5Sql_LIBRARIES})
|
||||
set(QT_LIBRARIES ${QtCore_LIBRARIES} ${QtConcurrent_LIBRARIES} ${QtWidgets_LIBRARIES} ${QtNetwork_LIBRARIES} ${QtSql_LIBRARIES})
|
||||
set(QT_INCLUDE_DIRS ${Qt5Core_INCLUDE_DIRS} ${Qt5Concurrent_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5Sql_INCLUDE_DIRS})
|
||||
if(Qt5DBus_FOUND)
|
||||
set(QtDBus_LIBRARIES ${Qt5DBus_LIBRARIES})
|
||||
list(APPEND QT_LIBRARIES ${Qt5DBus_LIBRARIES})
|
||||
list(APPEND QT_INCLUDE_DIRS ${Qt5DBus_INCLUDE_DIRS})
|
||||
get_target_property(QT_DBUSXML2CPP_EXECUTABLE Qt5::qdbusxml2cpp LOCATION)
|
||||
endif()
|
||||
if(Qt5X11Extras_FOUND)
|
||||
set(QtX11Extras_LIBRARIES ${Qt5X11Extras_LIBRARIES})
|
||||
list(APPEND QT_LIBRARIES ${Qt5X11Extras_LIBRARIES})
|
||||
list(APPEND QT_INCLUDE_DIRS ${Qt5X11Extras_INCLUDE_DIRS})
|
||||
endif()
|
||||
if(Qt5MacExtras_FOUND)
|
||||
set(QtMacExtras_LIBRARIES ${Qt5MacExtras_LIBRARIES})
|
||||
list(APPEND QT_LIBRARIES ${Qt5MacExtras_LIBRARIES})
|
||||
list(APPEND QT_INCLUDE_DIRS ${Qt5MacExtras_INCLUDE_DIRS})
|
||||
endif()
|
||||
if(Qt5WinExtras_FOUND)
|
||||
set(QtWinExtras_LIBRARIES ${Qt5WinExtras_LIBRARIES})
|
||||
list(APPEND QT_LIBRARIES ${Qt5WinExtras_LIBRARIES})
|
||||
list(APPEND QT_INCLUDE_DIRS ${Qt5WinExtras_INCLUDE_DIRS})
|
||||
endif()
|
||||
find_package(Qt5 ${QT_MIN_VERSION} QUIET COMPONENTS LinguistTools CONFIG)
|
||||
if (Qt5LinguistTools_FOUND)
|
||||
set(QT_LCONVERT_EXECUTABLE Qt5::lconvert)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(X11_FOUND)
|
||||
@@ -221,9 +256,20 @@ set(SINGLEAPPLICATION_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/singleap
|
||||
set(SINGLEAPPLICATION_LIBRARIES singleapplication)
|
||||
set(SINGLECOREAPPLICATION_LIBRARIES singlecoreapplication)
|
||||
|
||||
if (APPLE)
|
||||
if(APPLE)
|
||||
find_library(SPARKLE Sparkle)
|
||||
endif (APPLE)
|
||||
endif(APPLE)
|
||||
|
||||
if(NOT SPARKLE AND (APPLE OR WIN32))
|
||||
if(WITH_QT6)
|
||||
pkg_check_modules(QTSPARKLE qtsparkle-qt6)
|
||||
else()
|
||||
pkg_check_modules(QTSPARKLE qtsparkle-qt5)
|
||||
endif()
|
||||
if(QTSPARKLE_FOUND)
|
||||
set(HAVE_QTSPARKLE ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
# RC compiler
|
||||
@@ -258,10 +304,6 @@ optional_component(GSTREAMER ON "Engine: GStreamer backend"
|
||||
DEPENDS "gstreamer-pbutils-1.0" GSTREAMER_PBUTILS_FOUND
|
||||
)
|
||||
|
||||
optional_component(XINE ON "Engine: Xine backend"
|
||||
DEPENDS "libxine" LIBXINE_FOUND
|
||||
)
|
||||
|
||||
optional_component(VLC ON "Engine: VLC backend"
|
||||
DEPENDS "libvlc" LIBVLC_FOUND
|
||||
)
|
||||
@@ -299,22 +341,24 @@ optional_component(LIBMTP ON "Devices: MTP support"
|
||||
DEPENDS "libmtp" LIBMTP_FOUND
|
||||
)
|
||||
|
||||
optional_component(IMOBILEDEVICE ON "Devices: iPhone, iPod Touch, iPad and Apple TV support"
|
||||
DEPENDS "libimobiledevice" LIBIMOBILEDEVICE_FOUND
|
||||
DEPENDS "libplist" LIBPLIST_FOUND
|
||||
DEPENDS "libusbmuxd" LIBUSBMUXD_FOUND
|
||||
DEPENDS "libgpod" HAVE_LIBGPOD
|
||||
)
|
||||
|
||||
optional_component(SPARKLE ON "Sparkle integration"
|
||||
DEPENDS "macOS" APPLE
|
||||
DEPENDS "Sparkle" SPARKLE
|
||||
)
|
||||
|
||||
optional_component(TRANSLATIONS ON "Translations"
|
||||
DEPENDS "gettext" GETTEXT_FOUND
|
||||
DEPENDS "Qt5LinguistTools" Qt5LinguistTools_FOUND
|
||||
)
|
||||
if(WITH_QT6)
|
||||
optional_component(TRANSLATIONS ON "Translations"
|
||||
DEPENDS "gettext" GETTEXT_FOUND
|
||||
DEPENDS "Qt6LinguistTools" Qt6LinguistTools_FOUND
|
||||
)
|
||||
else()
|
||||
optional_component(TRANSLATIONS ON "Translations"
|
||||
DEPENDS "gettext" GETTEXT_FOUND
|
||||
DEPENDS "Qt5LinguistTools" Qt5LinguistTools_FOUND
|
||||
)
|
||||
endif()
|
||||
|
||||
option(INSTALL_TRANSLATIONS "Install translations" OFF)
|
||||
|
||||
optional_component(SUBSONIC ON "Subsonic support")
|
||||
optional_component(TIDAL ON "Tidal support")
|
||||
@@ -343,8 +387,8 @@ endif(USE_BUNDLE AND NOT USE_BUNDLE_DIR)
|
||||
|
||||
if(NOT CMAKE_CROSSCOMPILING)
|
||||
set(CMAKE_REQUIRED_FLAGS "--std=c++11")
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${Qt5Core_LIBRARIES} ${Qt5Sql_LIBRARIES})
|
||||
set(CMAKE_REQUIRED_INCLUDES ${Qt5Core_INCLUDE_DIRS} ${Qt5Sql_INCLUDE_DIRS})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${QtCore_LIBRARIES} ${QtSql_LIBRARIES})
|
||||
set(CMAKE_REQUIRED_INCLUDES ${QtCore_INCLUDE_DIRS} ${QtSql_INCLUDE_DIRS})
|
||||
check_cxx_source_runs("
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
@@ -361,20 +405,6 @@ if(NOT CMAKE_CROSSCOMPILING)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(HAVE_XINE)
|
||||
check_cxx_source_compiles("
|
||||
#define METRONOM_INTERNAL
|
||||
#include <iostream>
|
||||
#include <xine/metronom.h>
|
||||
int main() {
|
||||
metronom_t metronom;
|
||||
std::cout << metronom.pts_per_smpls;
|
||||
return 0;
|
||||
}
|
||||
"
|
||||
XINE_ANALYZER)
|
||||
endif()
|
||||
|
||||
# Set up definitions
|
||||
|
||||
add_definitions(-DBOOST_BIND_NO_PLACEHOLDERS)
|
||||
@@ -415,8 +445,8 @@ add_custom_target(uninstall
|
||||
|
||||
# Show a summary of what we have enabled
|
||||
summary_show()
|
||||
if(NOT HAVE_GSTREAMER AND NOT HAVE_XINE AND NOT HAVE_VLC)
|
||||
message(FATAL_ERROR "You need to have either GStreamer, Xine or VLC to compile!")
|
||||
if(NOT HAVE_GSTREAMER AND NOT HAVE_VLC)
|
||||
message(FATAL_ERROR "You need to have either GStreamer or VLC to compile!")
|
||||
elseif(NOT HAVE_GSTREAMER)
|
||||
message(WARNING "GStreamer is the only engine that is fully implemented. Using other engines is possible but not recommended.")
|
||||
endif()
|
||||
|
||||
46
Changelog
46
Changelog
@@ -2,6 +2,52 @@ Strawberry Music Player
|
||||
=======================
|
||||
ChangeLog
|
||||
|
||||
0.7.2:
|
||||
|
||||
BugFixes:
|
||||
* Fixed installation directory for translations.
|
||||
* Fixed collection sorting for non-ASCII characters.
|
||||
* Fixed closing connected devices on exit.
|
||||
|
||||
0.7.1:
|
||||
|
||||
Bugfixes:
|
||||
* Fixed incorrectly mapped global shortcuts keys "2" and "3".
|
||||
* Fixed Last.fm scrobbling to correctly start array notation for parameters at 0 and not 1.
|
||||
* Fixed sending trackNumber correctly for Last.fm and Libre.fm scrobbling.
|
||||
* Fixed collection search when using special characters in the search query.
|
||||
* Fixed reading and saving MP4 lyrics tag.
|
||||
* Fixed reading ASF comment tag.
|
||||
* Fixed adding playlist songs outside the collection when there are multiple files with the same URL.
|
||||
* Fixed the rescan songs option to work with local songs outside of the collection.
|
||||
* Fixed problems with editing song metadata in the playlists.
|
||||
* Fixed saving and restoring playlist scrollbar position when switching between playlists.
|
||||
* Fixed minor issue in cue parser with date and genre.
|
||||
* (macOS) Fixed gst-libav plugin issue resulting in MP3 not working.
|
||||
|
||||
Enhancements:
|
||||
* Simplified and improved startup behaviour code.
|
||||
* Adapted all source code to be compatible with Qt 6, and increased required Qt version to 5.8.
|
||||
* Added option to compile with Qt 6 (-DWITH_QT6=ON).
|
||||
* Base warning for show in file browser on unique directories to avoid unneeded warning about opening many files.
|
||||
* Use album artist instead of artist for album repeat mode when available.
|
||||
* Added extra safety for overwriting files for filesystem storages when organizing files.
|
||||
* Remove diacritics in FTS search.
|
||||
* Improved playlist context menu.
|
||||
* Added fatal CMake error for missing protobuf compiler.
|
||||
* Added support for parsing radio streams metadata with tilde in title.
|
||||
* Added CMake option to install translation files.
|
||||
* Increased maximum time step for seeking to 60.
|
||||
* (Unix) Added playback actions to desktop file.
|
||||
* (macOS) Hide behaviour settings that are unavailable on macOS.
|
||||
* (macOS) Fixed compile warnings.
|
||||
* (macOS) Added Sparkle integration to notify on new versions.
|
||||
* (Windows) Added QtSparkle support to notify on new versions.
|
||||
|
||||
Removed features:
|
||||
* Removed Xine engine support.
|
||||
* Removed broken imobiledevice (iPhone) support.
|
||||
|
||||
0.6.13:
|
||||
|
||||
Bugfixes:
|
||||
|
||||
17
README.md
17
README.md
@@ -2,7 +2,7 @@
|
||||
[](https://paypal.me/jonaskvinge)
|
||||
=======================
|
||||
|
||||
Strawberry is a music player and music collection organizer. It is a fork of Clementine released in 2018 aimed at music collectors and audiophiles. It's written in C++ using the Qt 5 framework.
|
||||
Strawberry is a music player and music collection organizer. It is a fork of Clementine released in 2018 aimed at music collectors and audiophiles. It's written in C++ using the Qt 5 or 6 toolkit.
|
||||
|
||||

|
||||
|
||||
@@ -44,7 +44,7 @@ You can also make a one-time payment through [paypal.me/jonaskvinge](https://pay
|
||||
* Support for multiple backends
|
||||
* Audio analyzer
|
||||
* Audio equalizer
|
||||
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
|
||||
* Transfer music to iPod, MTP or mass-storage USB player
|
||||
* Scrobbler with support for [Last.fm](https://www.last.fm/), [Libre.fm](https://libre.fm/) and [ListenBrainz](https://listenbrainz.org/)
|
||||
* Subsonic and Tidal streaming support
|
||||
|
||||
@@ -63,14 +63,14 @@ To build Strawberry from source you need the following installed on your system
|
||||
* [POSIX thread (pthread)](http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html)
|
||||
* [GLib](https://developer.gnome.org/glib/)
|
||||
* [Protobuf library and compiler](https://developers.google.com/protocol-buffers/)
|
||||
* [Qt 5.6 or higher with components Core, Gui, Widgets, Concurrent, Network and Sql](https://www.qt.io/)
|
||||
* [Qt 5 components X11Extras and DBus for Linux/BSD, MacExtras for macOS and WinExtras for Windows](https://www.qt.io/)
|
||||
* [Qt 5.8 or higher (or Qt 6) with components Core, Gui, Widgets, Concurrent, Network and Sql](https://www.qt.io/)
|
||||
* [Qt components X11Extras and DBus for Linux/BSD, MacExtras for macOS and WinExtras for Windows](https://www.qt.io/)
|
||||
* [SQLite 3.9 or newer with FTS5](https://www.sqlite.org)
|
||||
* [Chromaprint library](https://acoustid.org/chromaprint)
|
||||
* [ALSA library (linux)](https://www.alsa-project.org/)
|
||||
* [DBus (linux)](https://www.freedesktop.org/wiki/Software/dbus/)
|
||||
* [PulseAudio (linux optional)](https://www.freedesktop.org/wiki/Software/PulseAudio/?)
|
||||
* [GStreamer](https://gstreamer.freedesktop.org/), [Xine](https://www.xine-project.org) or [VLC](https://www.videolan.org)
|
||||
* [GStreamer](https://gstreamer.freedesktop.org/) or [VLC](https://www.videolan.org)
|
||||
* [GnuTLS](https://www.gnutls.org/)
|
||||
|
||||
Optional dependencies:
|
||||
@@ -78,12 +78,13 @@ Optional dependencies:
|
||||
* Audio CD: [libcdio](https://www.gnu.org/software/libcdio/)
|
||||
* MTP devices: [libmtp](http://libmtp.sourceforge.net/)
|
||||
* iPod Classic devices: [libgpod](http://www.gtkpod.org/libgpod/)
|
||||
* iPhone, iPod Touch, iPad and Apple TV devices: [libimobiledevice, libplist and libusbmuxd](https://www.libimobiledevice.org/)
|
||||
* Moodbar: [fftw3](http://www.fftw.org/)
|
||||
|
||||
Either GStreamer, Xine or VLC engine is required, but only GStreamer is fully implemented so far.
|
||||
Either GStreamer or VLC engine is required, but only GStreamer is fully implemented so far.
|
||||
You should also install the gstreamer plugins base and good, and optionally bad and ugly.
|
||||
|
||||
With Qt 6 we also depend on the Core5Compat module for QTextCodec.
|
||||
|
||||
### :wrench: Compiling from source
|
||||
|
||||
### Get the code:
|
||||
@@ -97,6 +98,8 @@ You should also install the gstreamer plugins base and good, and optionally bad
|
||||
cmake ..
|
||||
make -j4
|
||||
sudo make install
|
||||
|
||||
To compile with Qt 6 use: cmake .. -DWITH_QT6=ON
|
||||
|
||||
### :penguin: Packaging status
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
add_custom_target(dmg
|
||||
COMMAND /usr/local/opt/qt5/bin/macdeployqt strawberry.app
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/dist/macos/macdeploy.py strawberry.app
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/dist/macos/create-dmg.sh strawberry.app
|
||||
COMMAND create-dmg --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}.dmg strawberry.app
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
@@ -15,7 +15,11 @@ macro(optional_source TOGGLE)
|
||||
list(APPEND OTHER_SOURCES ${OPTIONAL_SOURCE_HEADERS})
|
||||
|
||||
set(_uic_sources)
|
||||
qt5_wrap_ui(_uic_sources ${OPTIONAL_SOURCE_UI})
|
||||
if(WITH_QT6)
|
||||
qt6_wrap_ui(_uic_sources ${OPTIONAL_SOURCE_UI})
|
||||
else()
|
||||
qt5_wrap_ui(_uic_sources ${OPTIONAL_SOURCE_UI})
|
||||
endif()
|
||||
list(APPEND OTHER_SOURCES ${_uic_sources})
|
||||
list(APPEND OTHER_UIC_SOURCES ${_uic_sources})
|
||||
endif(${TOGGLE})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
find_program(GETTEXT_XGETTEXT_EXECUTABLE xgettext)
|
||||
if(NOT GETTEXT_XGETTEXT_EXECUTABLE)
|
||||
@@ -19,6 +19,8 @@ set (XGETTEXT_OPTIONS
|
||||
--from-code=utf-8
|
||||
)
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/translations)
|
||||
|
||||
macro(add_pot outfiles header pot)
|
||||
# Make relative filenames for all source files
|
||||
set(add_pot_sources)
|
||||
@@ -64,14 +66,21 @@ macro(add_po outfiles po_prefix)
|
||||
)
|
||||
|
||||
list(APPEND ${outfiles} ${_qm_filepath})
|
||||
list(APPEND INSTALL_TRANSLATIONS_FILES ${_qm_filepath})
|
||||
endforeach (_lang)
|
||||
|
||||
# Generate a qrc file for the translations
|
||||
set(_qrc ${CMAKE_CURRENT_BINARY_DIR}/${ADD_PO_DIRECTORY}/translations.qrc)
|
||||
file(WRITE ${_qrc} "<RCC><qresource prefix=\"/${ADD_PO_DIRECTORY}\">")
|
||||
foreach(_lang ${ADD_PO_LANGUAGES})
|
||||
file(APPEND ${_qrc} "<file>${po_prefix}${_lang}.qm</file>")
|
||||
endforeach(_lang)
|
||||
file(APPEND ${_qrc} "</qresource></RCC>")
|
||||
qt5_add_resources(${outfiles} ${_qrc})
|
||||
if(NOT INSTALL_TRANSLATIONS)
|
||||
set(_qrc ${CMAKE_CURRENT_BINARY_DIR}/${ADD_PO_DIRECTORY}/translations.qrc)
|
||||
file(WRITE ${_qrc} "<RCC><qresource prefix=\"/${ADD_PO_DIRECTORY}\">")
|
||||
foreach(_lang ${ADD_PO_LANGUAGES})
|
||||
file(APPEND ${_qrc} "<file>${po_prefix}${_lang}.qm</file>")
|
||||
endforeach(_lang)
|
||||
file(APPEND ${_qrc} "</qresource></RCC>")
|
||||
if(WITH_QT6)
|
||||
qt6_add_resources(${outfiles} ${_qrc})
|
||||
else()
|
||||
qt5_add_resources(${outfiles} ${_qrc})
|
||||
endif()
|
||||
endif()
|
||||
endmacro(add_po)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
set(STRAWBERRY_VERSION_MAJOR 0)
|
||||
set(STRAWBERRY_VERSION_MINOR 6)
|
||||
set(STRAWBERRY_VERSION_PATCH 13)
|
||||
set(STRAWBERRY_VERSION_MINOR 7)
|
||||
set(STRAWBERRY_VERSION_PATCH 2)
|
||||
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
||||
|
||||
set(INCLUDE_GIT_REVISION OFF)
|
||||
|
||||
@@ -81,7 +81,6 @@
|
||||
<file>icons/128x128/view-refresh.png</file>
|
||||
<file>icons/128x128/library-music.png</file>
|
||||
<file>icons/128x128/vlc.png</file>
|
||||
<file>icons/128x128/xine.png</file>
|
||||
<file>icons/128x128/zoom-in.png</file>
|
||||
<file>icons/128x128/zoom-out.png</file>
|
||||
<file>icons/128x128/scrobble.png</file>
|
||||
@@ -172,7 +171,6 @@
|
||||
<file>icons/64x64/view-refresh.png</file>
|
||||
<file>icons/64x64/library-music.png</file>
|
||||
<file>icons/64x64/vlc.png</file>
|
||||
<file>icons/64x64/xine.png</file>
|
||||
<file>icons/64x64/zoom-in.png</file>
|
||||
<file>icons/64x64/zoom-out.png</file>
|
||||
<file>icons/64x64/scrobble.png</file>
|
||||
@@ -267,7 +265,6 @@
|
||||
<file>icons/48x48/view-refresh.png</file>
|
||||
<file>icons/48x48/library-music.png</file>
|
||||
<file>icons/48x48/vlc.png</file>
|
||||
<file>icons/48x48/xine.png</file>
|
||||
<file>icons/48x48/zoom-in.png</file>
|
||||
<file>icons/48x48/zoom-out.png</file>
|
||||
<file>icons/48x48/scrobble.png</file>
|
||||
@@ -362,7 +359,6 @@
|
||||
<file>icons/32x32/view-refresh.png</file>
|
||||
<file>icons/32x32/library-music.png</file>
|
||||
<file>icons/32x32/vlc.png</file>
|
||||
<file>icons/32x32/xine.png</file>
|
||||
<file>icons/32x32/zoom-in.png</file>
|
||||
<file>icons/32x32/zoom-out.png</file>
|
||||
<file>icons/32x32/scrobble.png</file>
|
||||
@@ -457,7 +453,6 @@
|
||||
<file>icons/22x22/view-refresh.png</file>
|
||||
<file>icons/22x22/library-music.png</file>
|
||||
<file>icons/22x22/vlc.png</file>
|
||||
<file>icons/22x22/xine.png</file>
|
||||
<file>icons/22x22/zoom-in.png</file>
|
||||
<file>icons/22x22/zoom-out.png</file>
|
||||
<file>icons/22x22/scrobble.png</file>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 8.3 KiB |
@@ -72,7 +72,7 @@ CREATE INDEX idx_device_%deviceid_songs_comp_artist ON device_%deviceid_songs (c
|
||||
|
||||
CREATE VIRTUAL TABLE device_%deviceid_fts USING fts5(
|
||||
ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 0"
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
);
|
||||
|
||||
UPDATE devices SET schema_version=1 WHERE ROWID=%deviceid;
|
||||
|
||||
@@ -180,7 +180,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS tidal_artists_songs_fts USING fts5(
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 0"
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
|
||||
);
|
||||
|
||||
@@ -195,7 +195,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS tidal_albums_songs_fts USING fts5(
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 0"
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
|
||||
);
|
||||
|
||||
@@ -210,7 +210,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS tidal_songs_fts USING fts5(
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 0"
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
|
||||
);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ CREATE VIRTUAL TABLE %allsongstables_fts USING fts5(
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 0"
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
|
||||
);
|
||||
|
||||
@@ -28,7 +28,7 @@ CREATE VIRTUAL TABLE playlist_items_fts_ USING fts5(
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 0"
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
|
||||
);
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ CREATE TABLE IF NOT EXISTS songs (
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||
genre TEXT,
|
||||
compilation INTEGER NOT NULL DEFAULT 0,
|
||||
composer TEXT,
|
||||
@@ -83,7 +83,7 @@ CREATE TABLE IF NOT EXISTS tidal_artists_songs (
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||
genre TEXT,
|
||||
compilation INTEGER NOT NULL DEFAULT 0,
|
||||
composer TEXT,
|
||||
@@ -140,7 +140,7 @@ CREATE TABLE IF NOT EXISTS tidal_albums_songs (
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||
genre TEXT,
|
||||
compilation INTEGER NOT NULL DEFAULT 0,
|
||||
composer TEXT,
|
||||
@@ -197,7 +197,7 @@ CREATE TABLE IF NOT EXISTS tidal_songs (
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||
genre TEXT,
|
||||
compilation INTEGER NOT NULL DEFAULT 0,
|
||||
composer TEXT,
|
||||
@@ -254,7 +254,7 @@ CREATE TABLE IF NOT EXISTS subsonic_songs (
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||
genre TEXT,
|
||||
compilation INTEGER NOT NULL DEFAULT 0,
|
||||
composer TEXT,
|
||||
@@ -410,7 +410,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS songs_fts USING fts5(
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 0"
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
|
||||
);
|
||||
|
||||
@@ -425,7 +425,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS tidal_artists_songs_fts USING fts5(
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 0"
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
|
||||
);
|
||||
|
||||
@@ -440,7 +440,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS tidal_albums_songs_fts USING fts5(
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 0"
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
|
||||
);
|
||||
|
||||
@@ -455,7 +455,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS tidal_songs_fts USING fts5(
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 0"
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
|
||||
);
|
||||
|
||||
@@ -470,7 +470,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS subsonic_songs_fts USING fts5(
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 0"
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
|
||||
);
|
||||
|
||||
@@ -485,7 +485,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS playlist_items_fts_ USING fts5(
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 0"
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
|
||||
);
|
||||
|
||||
@@ -500,6 +500,6 @@ CREATE VIRTUAL TABLE IF NOT EXISTS %allsongstables_fts USING fts5(
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 0"
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
|
||||
);
|
||||
|
||||
3
debian/control
vendored
3
debian/control
vendored
@@ -24,10 +24,7 @@ Build-Depends: debhelper (>= 11),
|
||||
libgstreamer-plugins-base1.0-dev,
|
||||
libcdio-dev,
|
||||
libgpod-dev,
|
||||
libimobiledevice-dev,
|
||||
libmtp-dev,
|
||||
libplist-dev,
|
||||
libusbmuxd-dev,
|
||||
libchromaprint-dev,
|
||||
libfftw3-dev
|
||||
Standards-Version: 4.2.1
|
||||
|
||||
37
debian/copyright
vendored
37
debian/copyright
vendored
@@ -122,8 +122,14 @@ Files: src/core/main.cpp
|
||||
src/context/contextalbumsview.h
|
||||
src/widgets/playingwidget.cpp
|
||||
src/widgets/playingwidget.h
|
||||
src/widgets/osdpretty.cpp
|
||||
src/widgets/osdpretty.h
|
||||
src/osd/osdbase.cpp
|
||||
src/osd/osdbase.h
|
||||
src/osd/osdpretty.cpp
|
||||
src/osd/osdpretty.h
|
||||
src/osd/osddbus.cpp
|
||||
src/osd/osddbus.h
|
||||
src/osd/osdmac.cpp
|
||||
src/osd/osdmac.h
|
||||
src/dialogs/about.cpp
|
||||
src/dialogs/about.h
|
||||
src/playlist/playlist.cpp
|
||||
@@ -171,12 +177,12 @@ Files: src/core/main.cpp
|
||||
src/settings/shortcutssettingspage.h
|
||||
src/settings/appearancesettingspage.cpp
|
||||
src/settings/appearancesettingspage.h
|
||||
src/organise/organise.cpp
|
||||
src/organise/organise.h
|
||||
src/organise/organisedialog.cpp
|
||||
src/organise/organisedialog.h
|
||||
src/organise/organiseerrordialog.cpp
|
||||
src/organise/organiseerrordialog.h
|
||||
src/organize/organize.cpp
|
||||
src/organize/organize.h
|
||||
src/organize/organizedialog.cpp
|
||||
src/organize/organizedialog.h
|
||||
src/organize/organizeerrordialog.cpp
|
||||
src/organize/organizeerrordialog.h
|
||||
src/transcoder/transcoder.cpp
|
||||
src/transcoder/transcoder.h
|
||||
src/musicbrainz/musicbrainzclient.cpp
|
||||
@@ -213,21 +219,6 @@ Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
2003-2005, Mark Kretschmann <markey@web.de>
|
||||
License: GPL-2+
|
||||
|
||||
Files: src/engine/xineengine.cpp
|
||||
src/engine/xineengine.h
|
||||
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
2005, Ian Monroe <ian@monroe.nu>
|
||||
2005, Christophe Thommeret <hftom@free.fr>
|
||||
2005, 2006, Mark Kretschmann <markey@web.de>
|
||||
2004, 2005, Max Howell <max.howell@methylblue.com>
|
||||
2003, 2004, J. Kofler <kaffeine@gmx.net>
|
||||
License: GPL-2+
|
||||
|
||||
Files: src/engine/xinescope.c
|
||||
src/engine/xinescope.h
|
||||
Copyright: 2004, Max Howell <max.howell@methylblue.com>
|
||||
License: GPL-2+
|
||||
|
||||
Files: src/widgets/fancytabwidget.cpp
|
||||
src/widgets/fancytabwidget.h
|
||||
Copyright: 2018, Vikram Ambrose <ambroseworks@gmail.com>
|
||||
|
||||
1
debian/rules
vendored
1
debian/rules
vendored
@@ -5,7 +5,6 @@
|
||||
|
||||
override_dh_auto_clean:
|
||||
rm -f dist/macos/Info.plist
|
||||
rm -f dist/macos/create-dmg.sh
|
||||
rm -f dist/unix/PKGBUILD
|
||||
rm -f dist/unix/strawberry.spec
|
||||
rm -f dist/scripts/maketarball.sh
|
||||
|
||||
1
dist/CMakeLists.txt
vendored
1
dist/CMakeLists.txt
vendored
@@ -3,7 +3,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unix/PKGBUILD.in ${CMAKE_CURRENT_SOUR
|
||||
|
||||
if (APPLE)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist.in ${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/create-dmg.sh.in ${CMAKE_CURRENT_SOURCE_DIR}/macos/create-dmg.sh)
|
||||
endif (APPLE)
|
||||
|
||||
if (WIN32)
|
||||
|
||||
4
dist/macos/Info.plist.in
vendored
4
dist/macos/Info.plist.in
vendored
@@ -34,6 +34,10 @@
|
||||
<string>public.app-category.music</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.13.4</string>
|
||||
<key>SUFeedURL</key>
|
||||
<string>https://www.strawberrymusicplayer.org/sparkle-macos</string>
|
||||
<key>SUPublicEDKey</key>
|
||||
<string>3IRScV8YtNVnx7zoeJAXvg28Kh1gN/Pyl2iPM467pG8=</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
|
||||
24
dist/macos/create-dmg.sh.in
vendored
24
dist/macos/create-dmg.sh.in
vendored
@@ -1,24 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
version="@STRAWBERRY_VERSION_PACKAGE@"
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <bundle.app> (append)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
name=$(basename "$1" | perl -pe 's/(.*).app/\1/')
|
||||
bundle_dir="$1"
|
||||
temp_dir="dmg/$name"
|
||||
if [ -z "$2" ]; then
|
||||
output_file="$name-$version.dmg"
|
||||
else
|
||||
output_file="$name-$2-$version.dmg"
|
||||
fi
|
||||
|
||||
rm -rf "$temp_dir"
|
||||
rm -f "$output_file"
|
||||
|
||||
mkdir -p "$temp_dir"
|
||||
|
||||
/usr/local/bin/create-dmg --volname "$name" --background "@CMAKE_SOURCE_DIR@/dist/macos/dmg_background.png" --app-drop-link 450 218 --icon $bundle_dir 150 218 --window-size 600 450 $output_file $bundle_dir
|
||||
60
dist/macos/macdeploy.py
vendored
60
dist/macos/macdeploy.py
vendored
@@ -27,11 +27,12 @@ import traceback
|
||||
|
||||
LOGGER = logging.getLogger('macdeploy')
|
||||
|
||||
LIBRARY_SEARCH_PATH = ['/usr/local/lib']
|
||||
LIBRARY_SEARCH_PATH = ['/usr/local/lib', '/usr/local/opt/icu4c/lib']
|
||||
|
||||
FRAMEWORK_SEARCH_PATH = [
|
||||
'/Library/Frameworks',
|
||||
os.path.join(os.environ['HOME'], 'Library/Frameworks')
|
||||
os.path.join(os.environ['HOME'], 'Library/Frameworks'),
|
||||
'/Library/Frameworks/Sparkle.framework/Versions'
|
||||
]
|
||||
|
||||
QT_PLUGINS = [
|
||||
@@ -154,12 +155,6 @@ class InstallNameToolError(Error):
|
||||
class CouldNotFindGstreamerPluginError(Error):
|
||||
pass
|
||||
|
||||
class CouldNotFindXinePluginError(Error):
|
||||
pass
|
||||
|
||||
class CouldNotFindVLCPluginError(Error):
|
||||
pass
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print 'Usage: %s <bundle.app>' % sys.argv[0]
|
||||
|
||||
@@ -196,11 +191,22 @@ def GetBrokenLibraries(binary):
|
||||
elif re.match(r'^\s*/usr/lib/', line):
|
||||
#print "unix style system lib"
|
||||
continue # unix style system library
|
||||
elif re.match(r'^\s*@executable_path', line) or re.match(r'^\s*@loader_path', line):
|
||||
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
|
||||
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)
|
||||
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):
|
||||
broken_libs['frameworks'].append(line)
|
||||
else:
|
||||
@@ -261,14 +267,21 @@ def FixFramework(path):
|
||||
|
||||
|
||||
def FixLibrary(path):
|
||||
if path in fixed_libraries or FindSystemLibrary(os.path.basename(path)) is not None:
|
||||
|
||||
if path in fixed_libraries:
|
||||
return
|
||||
else:
|
||||
fixed_libraries.add(path)
|
||||
|
||||
# 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)
|
||||
|
||||
@@ -416,7 +429,7 @@ def FindSystemLibrary(library_name):
|
||||
|
||||
def FixLibraryInstallPath(library_path, library):
|
||||
system_library = FindSystemLibrary(os.path.basename(library_path))
|
||||
if system_library is None:
|
||||
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:
|
||||
@@ -425,21 +438,14 @@ def FixLibraryInstallPath(library_path, 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
|
||||
new_path = '@executable_path/../Frameworks/%s' % full_path
|
||||
FixInstallPath(library_path, library, new_path)
|
||||
|
||||
|
||||
def FindXinePlugin(name):
|
||||
for path in XINEPLUGIN_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 CouldNotFindXinePluginError(name)
|
||||
if full_path:
|
||||
new_path = '@executable_path/../Frameworks/%s' % full_path
|
||||
FixInstallPath(library_path, library, new_path)
|
||||
|
||||
|
||||
def FindQtPlugin(name):
|
||||
|
||||
1
dist/scripts/maketarball.sh.in
vendored
1
dist/scripts/maketarball.sh.in
vendored
@@ -38,7 +38,6 @@ tar -cJf $name-$version.tar.xz \
|
||||
--exclude="$root/debian/changelog" \
|
||||
--exclude="$root/dist/scripts/maketarball.sh" \
|
||||
--exclude="$root/dist/unix/PKGBUILD" \
|
||||
--exclude="$root/dist/macos/create-dmg.sh" \
|
||||
--exclude="$root/dist/macos/Info.plist" \
|
||||
--exclude="$root/dist/windows/windres.rc" \
|
||||
--exclude="$root/src/translations/translations.pot" \
|
||||
|
||||
4
dist/unix/PKGBUILD.in
vendored
4
dist/unix/PKGBUILD.in
vendored
@@ -23,15 +23,11 @@ depends=(
|
||||
gstreamer
|
||||
gst-plugins-base
|
||||
gst-plugins-good
|
||||
xine-lib
|
||||
vlc
|
||||
chromaprint
|
||||
libgpod
|
||||
libcdio
|
||||
libmtp
|
||||
libusbmuxd
|
||||
libplist
|
||||
libimobiledevice
|
||||
fftw
|
||||
)
|
||||
optdepends=(
|
||||
|
||||
@@ -12,3 +12,28 @@ Categories=AudioVideo;Player;Qt;Audio;
|
||||
StartupNotify=false
|
||||
MimeType=x-content/audio-player;application/ogg;application/x-ogg;application/x-ogm-audio;audio/flac;audio/ogg;audio/vorbis;audio/aac;audio/mp4;audio/mpeg;audio/mpegurl;audio/vnd.rn-realaudio;audio/x-flac;audio/x-oggflac;audio/x-vorbis;audio/x-vorbis+ogg;audio/x-speex;audio/x-wav;audio/x-wavpack;audio/x-ape;audio/x-mp3;audio/x-mpeg;audio/x-mpegurl;audio/x-ms-wma;audio/x-musepack;audio/x-pn-realaudio;audio/x-scpls;video/x-ms-asf;x-scheme-handler/tidal;
|
||||
StartupWMClass=strawberry
|
||||
Actions=Play;Pause;Stop;StopAfterCurrent;Previous;Next;
|
||||
|
||||
[Desktop Action Play]
|
||||
Name=Play
|
||||
Exec=strawberry --play
|
||||
|
||||
[Desktop Action Pause]
|
||||
Name=Pause
|
||||
Exec=strawberry --pause
|
||||
|
||||
[Desktop Action Stop]
|
||||
Name=Stop
|
||||
Exec=strawberry --stop
|
||||
|
||||
[Desktop Action StopAfterCurrent]
|
||||
Name=Stop after this track
|
||||
Exec=strawberry --stop-after-current
|
||||
|
||||
[Desktop Action Previous]
|
||||
Name=Previous
|
||||
Exec=strawberry --previous
|
||||
|
||||
[Desktop Action Next]
|
||||
Name=Next
|
||||
Exec=strawberry --next
|
||||
|
||||
5
dist/unix/strawberry.spec.in
vendored
5
dist/unix/strawberry.spec.in
vendored
@@ -1,7 +1,7 @@
|
||||
Name: strawberry
|
||||
Version: @STRAWBERRY_VERSION_RPM_V@
|
||||
Release: @STRAWBERRY_VERSION_RPM_R@.@RPM_DISTRO@
|
||||
Summary: A music player and music collection organiser
|
||||
Summary: A music player and music collection organizer
|
||||
Group: Applications/Multimedia
|
||||
License: GPL-3.0+
|
||||
URL: https://www.strawberrymusicplayer.org/
|
||||
@@ -73,7 +73,6 @@ BuildRequires: pkgconfig(libmtp)
|
||||
BuildRequires: pkgconfig(libnotify)
|
||||
BuildRequires: pkgconfig(libudf)
|
||||
%if 0%{?suse_version} || 0%{?fedora_version}
|
||||
BuildRequires: pkgconfig(libxine)
|
||||
BuildRequires: pkgconfig(libvlc)
|
||||
%endif
|
||||
|
||||
@@ -107,7 +106,7 @@ Features:
|
||||
- Support for multiple backends
|
||||
- Audio analyzer
|
||||
- Audio equalizer
|
||||
- Transfer music to iPod, iPhone, MTP or mass-storage USB player
|
||||
- Transfer music to iPod, MTP or mass-storage USB player
|
||||
- Scrobbler with support for Last.fm, Libre.fm and ListenBrainz
|
||||
- Streaming support for Subsonic
|
||||
|
||||
|
||||
49
dist/windows/strawberry.nsi.in
vendored
49
dist/windows/strawberry.nsi.in
vendored
@@ -18,6 +18,10 @@
|
||||
!define debug
|
||||
!endif
|
||||
|
||||
!if "@WITH_QT6@" == "ON"
|
||||
!define with_qt6
|
||||
!endif
|
||||
|
||||
!ifdef debug
|
||||
!define PRODUCT_NAME "Strawberry Music Player Debug"
|
||||
!define PRODUCT_NAME_SHORT "Strawberry"
|
||||
@@ -91,17 +95,33 @@ SetCompressor /SOLID lzma
|
||||
Name "${PRODUCT_NAME}"
|
||||
!ifdef arch_x86
|
||||
!ifdef debug
|
||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-Debug-x86.exe"
|
||||
!ifdef with_qt6
|
||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-Qt6-Debug-x86.exe"
|
||||
!else
|
||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-Debug-x86.exe"
|
||||
!endif
|
||||
!else
|
||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-x86.exe"
|
||||
!ifdef with_qt6
|
||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-Qt6-x86.exe"
|
||||
!else
|
||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-x86.exe"
|
||||
!endif
|
||||
!endif
|
||||
!endif
|
||||
|
||||
!ifdef arch_x64
|
||||
!ifdef debug
|
||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-Debug-x64.exe"
|
||||
!ifdef with_qt6
|
||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-Qt6-Debug-x64.exe"
|
||||
!else
|
||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-Debug-x64.exe"
|
||||
!endif
|
||||
!else
|
||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-x64.exe"
|
||||
!ifdef with_qt6
|
||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-Qt6-x64.exe"
|
||||
!else
|
||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-x64.exe"
|
||||
!endif
|
||||
!endif
|
||||
!endif
|
||||
|
||||
@@ -209,6 +229,16 @@ Section "Strawberry" Strawberry
|
||||
File "libwavpack-1.dll"
|
||||
File "libwinpthread-1.dll"
|
||||
File "libxml2-2.dll"
|
||||
!ifdef with_qt6
|
||||
File "Qt6Concurrent.dll"
|
||||
File "Qt6Core.dll"
|
||||
File "Qt6Gui.dll"
|
||||
File "Qt6Network.dll"
|
||||
File "Qt6Sql.dll"
|
||||
File "Qt6Widgets.dll"
|
||||
File "Qt6WinExtras.dll"
|
||||
File "libqtsparkle-qt6.dll"
|
||||
!else
|
||||
File "Qt5Concurrent.dll"
|
||||
File "Qt5Core.dll"
|
||||
File "Qt5Gui.dll"
|
||||
@@ -216,6 +246,8 @@ Section "Strawberry" Strawberry
|
||||
File "Qt5Sql.dll"
|
||||
File "Qt5Widgets.dll"
|
||||
File "Qt5WinExtras.dll"
|
||||
File "libqtsparkle-qt5.dll"
|
||||
!endif
|
||||
File "zlib1.dll"
|
||||
File "libzstd.dll"
|
||||
File "libtasn1-6.dll"
|
||||
@@ -445,6 +477,15 @@ Section "Uninstall"
|
||||
Delete "$INSTDIR\Qt5Sql.dll"
|
||||
Delete "$INSTDIR\Qt5Widgets.dll"
|
||||
Delete "$INSTDIR\Qt5WinExtras.dll"
|
||||
Delete "$INSTDIR\libqtsparkle-qt5.dll"
|
||||
Delete "$INSTDIR\Qt6Concurrent.dll"
|
||||
Delete "$INSTDIR\Qt6Core.dll"
|
||||
Delete "$INSTDIR\Qt6Gui.dll"
|
||||
Delete "$INSTDIR\Qt6Network.dll"
|
||||
Delete "$INSTDIR\Qt6Sql.dll"
|
||||
Delete "$INSTDIR\Qt6Widgets.dll"
|
||||
Delete "$INSTDIR\Qt6WinExtras.dll"
|
||||
Delete "$INSTDIR\libqtsparkle-qt6.dll"
|
||||
Delete "$INSTDIR\zlib1.dll"
|
||||
Delete "$INSTDIR\libzstd.dll"
|
||||
Delete "$INSTDIR\libtasn1-6.dll"
|
||||
|
||||
@@ -9,7 +9,7 @@ link_directories(
|
||||
${GSTREAMER_BASE_LIBRARY_DIRS}
|
||||
${GSTREAMER_AUDIO_LIBRARY_DIRS}
|
||||
${FFTW3_LIBRARY_DIRS}
|
||||
${Qt5Core_LIBRARY_DIRS}
|
||||
${QtCore_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
add_library(gstmoodbar STATIC ${SOURCES})
|
||||
@@ -21,7 +21,7 @@ target_include_directories(gstmoodbar SYSTEM PRIVATE
|
||||
${GSTREAMER_BASE_INCLUDE_DIRS}
|
||||
${GSTREAMER_AUDIO_INCLUDE_DIRS}
|
||||
${FFTW3_INCLUDE_DIR}
|
||||
${Qt5Core_INCLUDE_DIRS}
|
||||
${QtCore_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_include_directories(gstmoodbar PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
@@ -33,5 +33,5 @@ target_link_libraries(gstmoodbar PRIVATE
|
||||
${GSTREAMER_BASE_LIBRARIES}
|
||||
${GSTREAMER_AUDIO_LIBRARIES}
|
||||
${FFTW3_FFTW_LIBRARY}
|
||||
${Qt5Core_LIBRARIES}
|
||||
${QtCore_LIBRARIES}
|
||||
)
|
||||
|
||||
@@ -179,7 +179,7 @@ static void gst_fastspectrum_reset_state (GstFastSpectrum * spectrum) {
|
||||
|
||||
static void gst_fastspectrum_finalize (GObject * object) {
|
||||
|
||||
GstFastSpectrum *spectrum = GST_FASTSPECTRUM (object);
|
||||
GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(object);
|
||||
|
||||
gst_fastspectrum_reset_state (spectrum);
|
||||
g_mutex_clear (&spectrum->lock);
|
||||
@@ -190,7 +190,7 @@ static void gst_fastspectrum_finalize (GObject * object) {
|
||||
|
||||
static void gst_fastspectrum_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) {
|
||||
|
||||
GstFastSpectrum *filter = GST_FASTSPECTRUM (object);
|
||||
GstFastSpectrum *filter = reinterpret_cast<GstFastSpectrum*>(object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_INTERVAL:{
|
||||
@@ -222,7 +222,7 @@ static void gst_fastspectrum_set_property (GObject * object, guint prop_id, cons
|
||||
|
||||
static void gst_fastspectrum_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) {
|
||||
|
||||
GstFastSpectrum *filter = GST_FASTSPECTRUM (object);
|
||||
GstFastSpectrum *filter = reinterpret_cast<GstFastSpectrum*>(object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_INTERVAL:
|
||||
@@ -240,7 +240,7 @@ static void gst_fastspectrum_get_property (GObject * object, guint prop_id, GVal
|
||||
|
||||
static gboolean gst_fastspectrum_start (GstBaseTransform * trans) {
|
||||
|
||||
GstFastSpectrum *spectrum = GST_FASTSPECTRUM (trans);
|
||||
GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(trans);
|
||||
|
||||
gst_fastspectrum_reset_state (spectrum);
|
||||
|
||||
@@ -250,7 +250,7 @@ static gboolean gst_fastspectrum_start (GstBaseTransform * trans) {
|
||||
|
||||
static gboolean gst_fastspectrum_stop (GstBaseTransform * trans) {
|
||||
|
||||
GstFastSpectrum *spectrum = GST_FASTSPECTRUM (trans);
|
||||
GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(trans);
|
||||
|
||||
gst_fastspectrum_reset_state (spectrum);
|
||||
|
||||
@@ -334,7 +334,7 @@ static void input_data_mixed_int16_max (const guint8 * _in, double * out, guint
|
||||
|
||||
static gboolean gst_fastspectrum_setup (GstAudioFilter * base, const GstAudioInfo * info) {
|
||||
|
||||
GstFastSpectrum *spectrum = GST_FASTSPECTRUM (base);
|
||||
GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(base);
|
||||
GstFastSpectrumInputData input_data = nullptr;
|
||||
|
||||
g_mutex_lock (&spectrum->lock);
|
||||
@@ -392,7 +392,7 @@ static void gst_fastspectrum_run_fft (GstFastSpectrum * spectrum, guint input_po
|
||||
|
||||
static GstFlowReturn gst_fastspectrum_transform_ip (GstBaseTransform *trans, GstBuffer *buffer) {
|
||||
|
||||
GstFastSpectrum *spectrum = GST_FASTSPECTRUM (trans);
|
||||
GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(trans);
|
||||
guint rate = GST_AUDIO_FILTER_RATE (spectrum);
|
||||
guint bps = GST_AUDIO_FILTER_BPS (spectrum);
|
||||
guint bpf = GST_AUDIO_FILTER_BPF (spectrum);
|
||||
|
||||
@@ -20,20 +20,24 @@ if(APPLE)
|
||||
list(APPEND SOURCES core/scoped_nsautorelease_pool.mm)
|
||||
endif(APPLE)
|
||||
|
||||
qt5_wrap_cpp(MOC ${HEADERS})
|
||||
if(WITH_QT6)
|
||||
qt6_wrap_cpp(MOC ${HEADERS})
|
||||
else()
|
||||
qt5_wrap_cpp(MOC ${HEADERS})
|
||||
endif()
|
||||
|
||||
link_directories(
|
||||
${GLIB_LIBRARY_DIRS}
|
||||
${Qt5Core_LIBRARY_DIRS}
|
||||
${Qt5Network_LIBRARY_DIRS}
|
||||
${QtCore_LIBRARY_DIRS}
|
||||
${QtNetwork_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
add_library(libstrawberry-common STATIC ${SOURCES} ${MOC})
|
||||
|
||||
target_include_directories(libstrawberry-common SYSTEM PRIVATE
|
||||
${GLIB_INCLUDE_DIRS}
|
||||
${Qt5Core_INCLUDE_DIRS}
|
||||
${Qt5Network_INCLUDE_DIRS}
|
||||
${QtCore_INCLUDE_DIRS}
|
||||
${QtNetwork_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_include_directories(libstrawberry-common PRIVATE
|
||||
@@ -46,8 +50,8 @@ target_include_directories(libstrawberry-common PRIVATE
|
||||
target_link_libraries(libstrawberry-common PRIVATE
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${GLIB_LIBRARIES}
|
||||
${Qt5Core_LIBRARIES}
|
||||
${Qt5Network_LIBRARIES}
|
||||
${QtCore_LIBRARIES}
|
||||
${QtNetwork_LIBRARIES}
|
||||
)
|
||||
|
||||
if(Backtrace_FOUND)
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatch>
|
||||
#include <QDateTime>
|
||||
#include <QIODevice>
|
||||
#include <QBuffer>
|
||||
@@ -306,11 +307,12 @@ QString LinuxDemangle(const QString &symbol);
|
||||
|
||||
QString LinuxDemangle(const QString &symbol) {
|
||||
|
||||
QRegExp regex("\\(([^+]+)");
|
||||
if (!symbol.contains(regex)) {
|
||||
QRegularExpression regex("\\(([^+]+)");
|
||||
QRegularExpressionMatch match = regex.match(symbol);
|
||||
if (!match.hasMatch()) {
|
||||
return symbol;
|
||||
}
|
||||
QString mangled_function = regex.cap(1);
|
||||
QString mangled_function = match.captured(1);
|
||||
return CXXDemangle(mangled_function);
|
||||
|
||||
}
|
||||
|
||||
@@ -102,10 +102,10 @@ void _MessageHandlerBase::WriteMessage(const QByteArray &data) {
|
||||
|
||||
// Sorry.
|
||||
if (flush_abstract_socket_) {
|
||||
((static_cast<QAbstractSocket*>(device_))->*(flush_abstract_socket_))();
|
||||
((qobject_cast<QAbstractSocket*>(device_))->*(flush_abstract_socket_))();
|
||||
}
|
||||
else if (flush_local_socket_) {
|
||||
((static_cast<QLocalSocket*>(device_))->*(flush_local_socket_))();
|
||||
((qobject_cast<QLocalSocket*>(device_))->*(flush_local_socket_))();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ template <typename HandlerType>
|
||||
WorkerPool<HandlerType>::~WorkerPool() {
|
||||
for (const Worker &worker : workers_) {
|
||||
if (worker.local_socket_ && worker.process_) {
|
||||
disconnect(worker.process_, SIGNAL(error(QProcess::ProcessError)), this, SLOT(ProcessError(QProcess::ProcessError)));
|
||||
disconnect(worker.process_, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(ProcessError(QProcess::ProcessError)));
|
||||
|
||||
// The worker is connected. Close his socket and wait for him to exit.
|
||||
qLog(Debug) << "Closing worker socket";
|
||||
@@ -263,7 +263,7 @@ void WorkerPool<HandlerType>::StartOneWorker(Worker *worker) {
|
||||
worker->process_ = new QProcess(this);
|
||||
|
||||
connect(worker->local_server_, SIGNAL(newConnection()), SLOT(NewConnection()));
|
||||
connect(worker->process_, SIGNAL(error(QProcess::ProcessError)), SLOT(ProcessError(QProcess::ProcessError)));
|
||||
connect(worker->process_, SIGNAL(errorOccurred(QProcess::ProcessError)), SLOT(ProcessError(QProcess::ProcessError)));
|
||||
|
||||
// Create a server, find an unused name and start listening
|
||||
forever {
|
||||
|
||||
@@ -17,8 +17,8 @@ add_library(libstrawberry-tagreader STATIC ${PROTO_SOURCES} ${SOURCES})
|
||||
target_include_directories(libstrawberry-tagreader SYSTEM PRIVATE
|
||||
${GLIB_INCLUDE_DIRS}
|
||||
${PROTOBUF_INCLUDE_DIRS}
|
||||
${Qt5Core_INCLUDE_DIRS}
|
||||
${Qt5Network_INCLUDE_DIRS}
|
||||
${QtCore_INCLUDE_DIRS}
|
||||
${QtNetwork_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_include_directories(libstrawberry-tagreader PRIVATE
|
||||
@@ -34,6 +34,11 @@ target_link_libraries(libstrawberry-tagreader PRIVATE
|
||||
${GLIB_LIBRARIES}
|
||||
${PROTOBUF_LIBRARY}
|
||||
${TAGLIB_LIBRARIES}
|
||||
${Qt5Core_LIBRARIES}
|
||||
${QtCore_LIBRARIES}
|
||||
${QtNetwork_LIBRARIES}
|
||||
libstrawberry-common
|
||||
)
|
||||
|
||||
if(WITH_QT6)
|
||||
target_link_libraries(libstrawberry-tagreader PRIVATE Qt6::Core5Compat)
|
||||
endif()
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QChar>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatch>
|
||||
|
||||
#include "fmpsparser.h"
|
||||
|
||||
@@ -89,20 +91,20 @@ bool FMPSParser::Parse(const QString &data) {
|
||||
|
||||
int FMPSParser::ParseValueRef(const QStringRef& data, QVariant* ret) const {
|
||||
// Try to match a float
|
||||
int pos = float_re_.indexIn(*data.string(), data.position());
|
||||
if (pos == data.position()) {
|
||||
*ret = float_re_.cap(1).toDouble();
|
||||
return float_re_.matchedLength();
|
||||
QRegularExpressionMatch re_match = float_re_.match(*data.string(), data.position());
|
||||
if (re_match.capturedStart() == data.position()) {
|
||||
*ret = re_match.captured(1).toDouble();
|
||||
return re_match.capturedLength();
|
||||
}
|
||||
|
||||
// Otherwise try to match a string
|
||||
pos = string_re_.indexIn(*data.string(), data.position());
|
||||
if (pos == data.position()) {
|
||||
re_match = string_re_.match(*data.string(), data.position());
|
||||
if (re_match.capturedStart() == data.position()) {
|
||||
// Replace escape sequences with their actual characters
|
||||
QString value = string_re_.cap(1);
|
||||
QString value = re_match.captured(1);
|
||||
value.replace(escape_re_, "\\1");
|
||||
*ret = value;
|
||||
return string_re_.matchedLength();
|
||||
return re_match.capturedLength();
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
#include <QList>
|
||||
#include <QMetaType>
|
||||
#include <QString>
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
|
||||
class QVariant;
|
||||
|
||||
class FMPSParser {
|
||||
public:
|
||||
public:
|
||||
FMPSParser();
|
||||
|
||||
// A FMPS result is a list of lists of values (where a value is a string or
|
||||
@@ -54,10 +54,10 @@ public:
|
||||
int ParseListList(const QString &data, Result *ret) const;
|
||||
int ParseListListRef(const QStringRef &data, Result *ret) const;
|
||||
|
||||
private:
|
||||
QRegExp float_re_;
|
||||
QRegExp string_re_;
|
||||
QRegExp escape_re_;
|
||||
private:
|
||||
QRegularExpression float_re_;
|
||||
QRegularExpression string_re_;
|
||||
QRegularExpression escape_re_;
|
||||
Result result_;
|
||||
};
|
||||
|
||||
|
||||
@@ -177,11 +177,11 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
|
||||
song->set_basefilename(DataCommaSizeFromQString(info.fileName()));
|
||||
song->set_url(url.constData(), url.size());
|
||||
song->set_filesize(info.size());
|
||||
song->set_mtime(info.lastModified().toTime_t());
|
||||
song->set_mtime(info.lastModified().toSecsSinceEpoch());
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||
song->set_ctime(info.birthTime().isValid() ? info.birthTime().toTime_t() : info.lastModified().toTime_t());
|
||||
song->set_ctime(info.birthTime().isValid() ? info.birthTime().toSecsSinceEpoch() : info.lastModified().toSecsSinceEpoch());
|
||||
#else
|
||||
song->set_ctime(info.created().toTime_t());
|
||||
song->set_ctime(info.created().toSecsSinceEpoch());
|
||||
#endif
|
||||
|
||||
std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename));
|
||||
@@ -342,6 +342,9 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
|
||||
if (mp4_tag->item("\251grp").isValid()) {
|
||||
Decode(mp4_tag->item("\251grp").toStringList().toString(" "), nullptr, song->mutable_grouping());
|
||||
}
|
||||
if (mp4_tag->item("\251lyr").isValid()) {
|
||||
Decode(mp4_tag->item("\251lyr").toStringList().toString(" "), nullptr, song->mutable_lyrics());
|
||||
}
|
||||
|
||||
if (mp4_tag->item(kMP4_OriginalYear_ID).isValid()) {
|
||||
song->set_originalyear(TStringToQString(mp4_tag->item(kMP4_OriginalYear_ID).toStringList().toString('\n')).left(4).toInt());
|
||||
@@ -355,6 +358,10 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
|
||||
|
||||
song->set_bitdepth(file_asf->audioProperties()->bitsPerSample());
|
||||
|
||||
if (file_asf->tag()) {
|
||||
Decode(file_asf->tag()->comment(), nullptr, song->mutable_comment());
|
||||
}
|
||||
|
||||
const TagLib::ASF::AttributeListMap &attributes_map = file_asf->tag()->attributeListMap();
|
||||
|
||||
if (attributes_map.contains(kASF_OriginalDate_ID)) {
|
||||
@@ -617,6 +624,7 @@ bool TagReader::SaveFile(const QString &filename, const pb::tagreader::SongMetad
|
||||
tag->setItem("disk", TagLib::MP4::Item(song.disc() <= 0 -1 ? 0 : song.disc(), 0));
|
||||
tag->setItem("\251wrt", TagLib::StringList(song.composer().c_str()));
|
||||
tag->setItem("\251grp", TagLib::StringList(song.grouping().c_str()));
|
||||
tag->setItem("\251lyr", TagLib::StringList(song.lyrics().c_str()));
|
||||
tag->setItem("aART", TagLib::StringList(song.albumartist().c_str()));
|
||||
tag->setItem("cpil", TagLib::StringList(song.compilation() ? "1" : "0"));
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
|
||||
class QTextCodec;
|
||||
|
||||
|
||||
#ifndef USE_SYSTEM_TAGLIB
|
||||
using namespace Strawberry_TagLib;
|
||||
#endif
|
||||
|
||||
@@ -55,8 +55,8 @@ message SongMetadata {
|
||||
optional string basefilename = 22;
|
||||
optional FileType filetype = 23;
|
||||
optional int32 filesize = 24;
|
||||
optional int32 mtime = 25;
|
||||
optional int32 ctime = 26;
|
||||
optional int64 mtime = 25;
|
||||
optional int64 ctime = 26;
|
||||
|
||||
optional int32 playcount = 27;
|
||||
optional int32 skipcount = 28;
|
||||
|
||||
@@ -4,14 +4,19 @@ set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
|
||||
|
||||
set(SOURCES main.cpp tagreaderworker.cpp)
|
||||
|
||||
qt5_wrap_cpp(MOC ${HEADERS})
|
||||
qt5_add_resources(QRC data/data.qrc)
|
||||
if(WITH_QT6)
|
||||
qt6_wrap_cpp(MOC ${HEADERS})
|
||||
qt6_add_resources(QRC data/data.qrc)
|
||||
else()
|
||||
qt5_wrap_cpp(MOC ${HEADERS})
|
||||
qt5_add_resources(QRC data/data.qrc)
|
||||
endif()
|
||||
|
||||
link_directories(
|
||||
${GLIB_LIBRARY_DIRS}
|
||||
${TAGLIB_LIBRARY_DIRS}
|
||||
${Qt5Core_LIBRARY_DIRS}
|
||||
${Qt5Network_LIBRARY_DIRS}
|
||||
${QtCore_LIBRARY_DIRS}
|
||||
${QtNetwork_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
add_executable(strawberry-tagreader ${SOURCES} ${MOC} ${QRC})
|
||||
@@ -19,8 +24,8 @@ add_executable(strawberry-tagreader ${SOURCES} ${MOC} ${QRC})
|
||||
target_include_directories(strawberry-tagreader SYSTEM PRIVATE
|
||||
${GLIB_INCLUDE_DIRS}
|
||||
${PROTOBUF_INCLUDE_DIRS}
|
||||
${Qt5Core_INCLUDE_DIRS}
|
||||
${Qt5Network_INCLUDE_DIRS}
|
||||
${QtCore_INCLUDE_DIRS}
|
||||
${QtNetwork_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_include_directories(strawberry-tagreader PRIVATE
|
||||
@@ -34,8 +39,8 @@ target_include_directories(strawberry-tagreader PRIVATE
|
||||
target_link_libraries(strawberry-tagreader PRIVATE
|
||||
${GLIB_LIBRARIES}
|
||||
${TAGLIB_LIBRARIES}
|
||||
${Qt5Core_LIBRARIES}
|
||||
${Qt5Network_LIBRARIES}
|
||||
${QtCore_LIBRARIES}
|
||||
${QtNetwork_LIBRARIES}
|
||||
libstrawberry-common
|
||||
libstrawberry-tagreader
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: strawberry
|
||||
version: '0.6.13+git'
|
||||
version: '0.7.2+git'
|
||||
summary: music player and collection organizer
|
||||
description: |
|
||||
Strawberry is a music player and collection organizer.
|
||||
@@ -99,14 +99,10 @@ parts:
|
||||
- libqt5x11extras5-dev
|
||||
- libgstreamer1.0-dev
|
||||
- libgstreamer-plugins-base1.0-dev
|
||||
- libxine2-dev
|
||||
- libvlc-dev
|
||||
- libcdio-dev
|
||||
- libgpod-dev
|
||||
- libimobiledevice-dev
|
||||
- libmtp-dev
|
||||
- libplist-dev
|
||||
- libusbmuxd-dev
|
||||
- libchromaprint-dev
|
||||
- libfftw3-dev
|
||||
|
||||
@@ -132,10 +128,6 @@ parts:
|
||||
- libcdio17
|
||||
- libgpod4
|
||||
- libmtp9
|
||||
- libimobiledevice6
|
||||
- libplist3
|
||||
- libusbmuxd4
|
||||
- libxine2
|
||||
- libvlc5
|
||||
- libvlccore9
|
||||
- libtag1v5
|
||||
@@ -144,7 +136,6 @@ parts:
|
||||
- libx11-6
|
||||
- libxcomposite1
|
||||
- libxcursor1
|
||||
- libxinerama1
|
||||
- libxrandr2
|
||||
- libdb5.3
|
||||
- libglu1
|
||||
|
||||
@@ -168,6 +168,7 @@ set(SOURCES
|
||||
dialogs/edittagdialog.cpp
|
||||
dialogs/trackselectiondialog.cpp
|
||||
dialogs/addstreamdialog.cpp
|
||||
dialogs/userpassdialog.cpp
|
||||
|
||||
widgets/autoexpandingtreeview.cpp
|
||||
widgets/busyindicator.cpp
|
||||
@@ -183,8 +184,6 @@ set(SOURCES
|
||||
widgets/linetextedit.cpp
|
||||
widgets/multiloadingindicator.cpp
|
||||
widgets/playingwidget.cpp
|
||||
widgets/osd.cpp
|
||||
widgets/osdpretty.cpp
|
||||
widgets/renametablineedit.cpp
|
||||
widgets/volumeslider.cpp
|
||||
widgets/stickyslider.cpp
|
||||
@@ -194,6 +193,9 @@ set(SOURCES
|
||||
widgets/tracksliderslider.cpp
|
||||
widgets/loginstatewidget.cpp
|
||||
|
||||
osd/osdbase.cpp
|
||||
osd/osdpretty.cpp
|
||||
|
||||
musicbrainz/acoustidclient.cpp
|
||||
musicbrainz/musicbrainzclient.cpp
|
||||
|
||||
@@ -221,10 +223,10 @@ set(SOURCES
|
||||
scrobbler/librefmscrobbler.cpp
|
||||
scrobbler/listenbrainzscrobbler.cpp
|
||||
|
||||
organise/organise.cpp
|
||||
organise/organiseformat.cpp
|
||||
organise/organisedialog.cpp
|
||||
organise/organiseerrordialog.cpp
|
||||
organize/organize.cpp
|
||||
organize/organizeformat.cpp
|
||||
organize/organizedialog.cpp
|
||||
organize/organizeerrordialog.cpp
|
||||
|
||||
)
|
||||
|
||||
@@ -364,6 +366,7 @@ set(HEADERS
|
||||
dialogs/edittagdialog.h
|
||||
dialogs/trackselectiondialog.h
|
||||
dialogs/addstreamdialog.h
|
||||
dialogs/userpassdialog.h
|
||||
|
||||
widgets/autoexpandingtreeview.h
|
||||
widgets/busyindicator.h
|
||||
@@ -378,8 +381,6 @@ set(HEADERS
|
||||
widgets/linetextedit.h
|
||||
widgets/multiloadingindicator.h
|
||||
widgets/playingwidget.h
|
||||
widgets/osd.h
|
||||
widgets/osdpretty.h
|
||||
widgets/renametablineedit.h
|
||||
widgets/volumeslider.h
|
||||
widgets/stickyslider.h
|
||||
@@ -390,6 +391,9 @@ set(HEADERS
|
||||
widgets/loginstatewidget.h
|
||||
widgets/qsearchfield.h
|
||||
|
||||
osd/osdbase.h
|
||||
osd/osdpretty.h
|
||||
|
||||
musicbrainz/acoustidclient.h
|
||||
musicbrainz/musicbrainzclient.h
|
||||
|
||||
@@ -415,9 +419,9 @@ set(HEADERS
|
||||
scrobbler/librefmscrobbler.h
|
||||
scrobbler/listenbrainzscrobbler.h
|
||||
|
||||
organise/organise.h
|
||||
organise/organisedialog.h
|
||||
organise/organiseerrordialog.h
|
||||
organize/organize.h
|
||||
organize/organizedialog.h
|
||||
organize/organizeerrordialog.h
|
||||
|
||||
)
|
||||
|
||||
@@ -465,18 +469,20 @@ set(UI
|
||||
dialogs/edittagdialog.ui
|
||||
dialogs/trackselectiondialog.ui
|
||||
dialogs/addstreamdialog.ui
|
||||
dialogs/userpassdialog.ui
|
||||
|
||||
widgets/trackslider.ui
|
||||
widgets/osdpretty.ui
|
||||
widgets/fileview.ui
|
||||
widgets/loginstatewidget.ui
|
||||
|
||||
osd/osdpretty.ui
|
||||
|
||||
internet/internettabsview.ui
|
||||
internet/internetcollectionviewcontainer.ui
|
||||
internet/internetsearchview.ui
|
||||
|
||||
organise/organisedialog.ui
|
||||
organise/organiseerrordialog.ui
|
||||
organize/organizedialog.ui
|
||||
organize/organizeerrordialog.ui
|
||||
|
||||
)
|
||||
|
||||
@@ -521,10 +527,12 @@ optional_source(HAVE_ALSA
|
||||
engine/alsadevicefinder.cpp
|
||||
)
|
||||
|
||||
# X11
|
||||
optional_source(X11_FOUND
|
||||
# DBUS
|
||||
optional_source(HAVE_DBUS
|
||||
SOURCES
|
||||
widgets/osd_x11.cpp
|
||||
osd/osddbus.cpp
|
||||
HEADERS
|
||||
osd/osddbus.h
|
||||
)
|
||||
|
||||
# GStreamer
|
||||
@@ -533,15 +541,6 @@ optional_source(HAVE_GSTREAMER
|
||||
HEADERS engine/gststartup.h engine/gstengine.h engine/gstenginepipeline.h engine/gstelementdeleter.h
|
||||
)
|
||||
|
||||
# Xine
|
||||
optional_source(HAVE_XINE
|
||||
SOURCES engine/xineengine.cpp
|
||||
HEADERS engine/xineengine.h
|
||||
)
|
||||
optional_source(XINE_ANALYZER
|
||||
SOURCES engine/xinescope.c
|
||||
)
|
||||
|
||||
# VLC
|
||||
optional_source(HAVE_VLC
|
||||
SOURCES engine/vlcengine.cpp
|
||||
@@ -561,31 +560,63 @@ if(UNIX AND HAVE_DBUS)
|
||||
HEADERS device/udisks2lister.h
|
||||
)
|
||||
|
||||
# MPRIS 2.0 DBUS interfaces
|
||||
qt5_add_dbus_adaptor(SOURCES
|
||||
dbus/org.mpris.MediaPlayer2.Player.xml
|
||||
core/mpris2.h mpris::Mpris2 core/mpris2_player Mpris2Player)
|
||||
qt5_add_dbus_adaptor(SOURCES
|
||||
dbus/org.mpris.MediaPlayer2.xml
|
||||
core/mpris2.h mpris::Mpris2 core/mpris2_root Mpris2Root)
|
||||
qt5_add_dbus_adaptor(SOURCES
|
||||
dbus/org.mpris.MediaPlayer2.TrackList.xml
|
||||
core/mpris2.h mpris::Mpris2 core/mpris2_tracklist Mpris2TrackList)
|
||||
if (WITH_QT6)
|
||||
|
||||
# MPRIS 2.1 DBUS interfaces
|
||||
qt5_add_dbus_adaptor(SOURCES
|
||||
dbus/org.mpris.MediaPlayer2.Playlists.xml
|
||||
core/mpris2.h mpris::Mpris2 core/mpris2_playlists Mpris2Playlists)
|
||||
# MPRIS 2.0 DBUS interfaces
|
||||
qt6_add_dbus_adaptor(SOURCES
|
||||
dbus/org.mpris.MediaPlayer2.Player.xml
|
||||
core/mpris2.h mpris::Mpris2 core/mpris2_player Mpris2Player)
|
||||
qt6_add_dbus_adaptor(SOURCES
|
||||
dbus/org.mpris.MediaPlayer2.xml
|
||||
core/mpris2.h mpris::Mpris2 core/mpris2_root Mpris2Root)
|
||||
qt6_add_dbus_adaptor(SOURCES
|
||||
dbus/org.mpris.MediaPlayer2.TrackList.xml
|
||||
core/mpris2.h mpris::Mpris2 core/mpris2_tracklist Mpris2TrackList)
|
||||
|
||||
# org.freedesktop.Notifications DBUS interface
|
||||
qt5_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.Notifications.xml
|
||||
dbus/notification)
|
||||
# MPRIS 2.1 DBUS interfaces
|
||||
qt6_add_dbus_adaptor(SOURCES
|
||||
dbus/org.mpris.MediaPlayer2.Playlists.xml
|
||||
core/mpris2.h mpris::Mpris2 core/mpris2_playlists Mpris2Playlists)
|
||||
|
||||
# org.gnome.SettingsDaemon interface
|
||||
qt5_add_dbus_interface(SOURCES
|
||||
dbus/org.gnome.SettingsDaemon.MediaKeys.xml
|
||||
dbus/gnomesettingsdaemon)
|
||||
# org.freedesktop.Notifications DBUS interface
|
||||
qt6_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.Notifications.xml
|
||||
dbus/notification)
|
||||
|
||||
# org.gnome.SettingsDaemon interface
|
||||
qt6_add_dbus_interface(SOURCES
|
||||
dbus/org.gnome.SettingsDaemon.MediaKeys.xml
|
||||
dbus/gnomesettingsdaemon)
|
||||
|
||||
else()
|
||||
|
||||
# MPRIS 2.0 DBUS interfaces
|
||||
qt5_add_dbus_adaptor(SOURCES
|
||||
dbus/org.mpris.MediaPlayer2.Player.xml
|
||||
core/mpris2.h mpris::Mpris2 core/mpris2_player Mpris2Player)
|
||||
qt5_add_dbus_adaptor(SOURCES
|
||||
dbus/org.mpris.MediaPlayer2.xml
|
||||
core/mpris2.h mpris::Mpris2 core/mpris2_root Mpris2Root)
|
||||
qt5_add_dbus_adaptor(SOURCES
|
||||
dbus/org.mpris.MediaPlayer2.TrackList.xml
|
||||
core/mpris2.h mpris::Mpris2 core/mpris2_tracklist Mpris2TrackList)
|
||||
|
||||
# MPRIS 2.1 DBUS interfaces
|
||||
qt5_add_dbus_adaptor(SOURCES
|
||||
dbus/org.mpris.MediaPlayer2.Playlists.xml
|
||||
core/mpris2.h mpris::Mpris2 core/mpris2_playlists Mpris2Playlists)
|
||||
|
||||
# org.freedesktop.Notifications DBUS interface
|
||||
qt5_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.Notifications.xml
|
||||
dbus/notification)
|
||||
|
||||
# org.gnome.SettingsDaemon interface
|
||||
qt5_add_dbus_interface(SOURCES
|
||||
dbus/org.gnome.SettingsDaemon.MediaKeys.xml
|
||||
dbus/gnomesettingsdaemon)
|
||||
|
||||
endif()
|
||||
|
||||
# org.freedesktop.Avahi.Server interface
|
||||
add_custom_command(
|
||||
@@ -626,21 +657,39 @@ if(UNIX AND HAVE_DBUS)
|
||||
PROPERTIES NO_NAMESPACE dbus/udisks2drive INCLUDE dbus/metatypes.h)
|
||||
set_source_files_properties(dbus/org.freedesktop.UDisks2.Job.xml
|
||||
PROPERTIES NO_NAMESPACE dbus/udisks2job INCLUDE dbus/metatypes.h)
|
||||
qt5_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.DBus.ObjectManager.xml
|
||||
dbus/objectmanager)
|
||||
qt5_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Filesystem.xml
|
||||
dbus/udisks2filesystem)
|
||||
qt5_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Block.xml
|
||||
dbus/udisks2block)
|
||||
qt5_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Drive.xml
|
||||
dbus/udisks2drive)
|
||||
qt5_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Job.xml
|
||||
dbus/udisks2job)
|
||||
if(WITH_QT6)
|
||||
qt6_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.DBus.ObjectManager.xml
|
||||
dbus/objectmanager)
|
||||
qt6_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Filesystem.xml
|
||||
dbus/udisks2filesystem)
|
||||
qt6_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Block.xml
|
||||
dbus/udisks2block)
|
||||
qt6_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Drive.xml
|
||||
dbus/udisks2drive)
|
||||
qt6_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Job.xml
|
||||
dbus/udisks2job)
|
||||
else()
|
||||
qt5_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.DBus.ObjectManager.xml
|
||||
dbus/objectmanager)
|
||||
qt5_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Filesystem.xml
|
||||
dbus/udisks2filesystem)
|
||||
qt5_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Block.xml
|
||||
dbus/udisks2block)
|
||||
qt5_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Drive.xml
|
||||
dbus/udisks2drive)
|
||||
qt5_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Job.xml
|
||||
dbus/udisks2job)
|
||||
endif()
|
||||
endif(HAVE_UDISKS2)
|
||||
|
||||
endif(UNIX AND HAVE_DBUS)
|
||||
@@ -688,21 +737,6 @@ optional_source(HAVE_GIO
|
||||
HEADERS device/giolister.h
|
||||
)
|
||||
|
||||
# imobiledevice backend and device
|
||||
optional_source(HAVE_IMOBILEDEVICE
|
||||
SOURCES
|
||||
device/afcdevice.cpp
|
||||
device/afcfile.cpp
|
||||
device/afctransfer.cpp
|
||||
device/ilister.cpp
|
||||
device/imobiledeviceconnection.cpp
|
||||
HEADERS
|
||||
device/afcdevice.h
|
||||
device/afcfile.h
|
||||
device/afctransfer.h
|
||||
device/ilister.h
|
||||
)
|
||||
|
||||
# mtp device
|
||||
optional_source(HAVE_LIBMTP
|
||||
SOURCES
|
||||
@@ -785,7 +819,7 @@ optional_source(APPLE
|
||||
core/macsystemtrayicon.mm
|
||||
core/macscreensaver.cpp
|
||||
core/macfslistener.mm
|
||||
widgets/osd_mac.mm
|
||||
osd/osdmac.mm
|
||||
widgets/qsearchfield_mac.mm
|
||||
engine/macosdevicefinder.cpp
|
||||
globalshortcuts/globalshortcutbackend-macos.mm
|
||||
@@ -793,6 +827,7 @@ optional_source(APPLE
|
||||
HEADERS
|
||||
core/macsystemtrayicon.h
|
||||
core/macfslistener.h
|
||||
osd/osdmac.h
|
||||
globalshortcuts/globalshortcutbackend-macos.h
|
||||
)
|
||||
|
||||
@@ -810,7 +845,6 @@ optional_source(WIN32
|
||||
SOURCES
|
||||
engine/directsounddevicefinder.cpp
|
||||
engine/mmdevicefinder.cpp
|
||||
widgets/osd_win.cpp
|
||||
core/windows7thumbbar.cpp
|
||||
HEADERS
|
||||
core/windows7thumbbar.h
|
||||
@@ -881,9 +915,15 @@ optional_source(HAVE_MOODBAR
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
|
||||
|
||||
qt5_wrap_cpp(MOC ${HEADERS})
|
||||
qt5_wrap_ui(UIC ${UI})
|
||||
qt5_add_resources(QRC ${RESOURCES})
|
||||
if(WITH_QT6)
|
||||
qt6_wrap_cpp(MOC ${HEADERS})
|
||||
qt6_wrap_ui(UIC ${UI})
|
||||
qt6_add_resources(QRC ${RESOURCES})
|
||||
else()
|
||||
qt5_wrap_cpp(MOC ${HEADERS})
|
||||
qt5_wrap_ui(UIC ${UI})
|
||||
qt5_add_resources(QRC ${RESOURCES})
|
||||
endif()
|
||||
|
||||
if(HAVE_TRANSLATIONS)
|
||||
|
||||
@@ -926,6 +966,7 @@ link_directories(
|
||||
${QT_LIBRARY_DIRS}
|
||||
${SINGLEAPPLICATION_LIBRARY_DIRS}
|
||||
${SINGLECOREAPPLICATION_LIBRARY_DIRS}
|
||||
${QTSPARKLE_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
if(HAVE_ALSA)
|
||||
@@ -947,10 +988,6 @@ if(HAVE_GSTREAMER)
|
||||
)
|
||||
endif(HAVE_GSTREAMER)
|
||||
|
||||
if(HAVE_XINE)
|
||||
link_directories(${LIBXINE_LIBRARY_DIRS})
|
||||
endif()
|
||||
|
||||
if(HAVE_VLC)
|
||||
link_directories(${LIBVLC_LIBRARY_DIRS})
|
||||
endif()
|
||||
@@ -983,14 +1020,6 @@ if(HAVE_LIBMTP)
|
||||
link_directories(${LIBMTP_LIBRARY_DIRS})
|
||||
endif(HAVE_LIBMTP)
|
||||
|
||||
if(HAVE_IMOBILEDEVICE)
|
||||
link_directories(
|
||||
${LIBUSBMUXD_LIBRARY_DIRS}
|
||||
${LIBPLIST_LIBRARY_DIRS}
|
||||
${LIBIMOBILEDEVICE_LIBRARY_DIRS}
|
||||
)
|
||||
endif(HAVE_IMOBILEDEVICE)
|
||||
|
||||
add_library(strawberry_lib STATIC
|
||||
${SOURCES}
|
||||
${MOC}
|
||||
@@ -1033,6 +1062,7 @@ target_link_libraries(strawberry_lib PUBLIC
|
||||
${QT_LIBRARIES}
|
||||
${SINGLEAPPLICATION_LIBRARIES}
|
||||
${SINGLECOREAPPLICATION_LIBRARIES}
|
||||
${QTSPARKLE_LIBRARIES}
|
||||
libstrawberry-common
|
||||
libstrawberry-tagreader
|
||||
)
|
||||
@@ -1070,11 +1100,6 @@ if(HAVE_MOODBAR)
|
||||
target_link_libraries(strawberry_lib PRIVATE gstmoodbar)
|
||||
endif()
|
||||
|
||||
if(HAVE_XINE)
|
||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBXINE_INCLUDE_DIRS})
|
||||
target_link_libraries(strawberry_lib PRIVATE ${LIBXINE_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_VLC)
|
||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBVLC_INCLUDE_DIRS})
|
||||
target_link_libraries(strawberry_lib PRIVATE ${LIBVLC_LIBRARIES})
|
||||
@@ -1115,19 +1140,6 @@ if(HAVE_LIBMTP)
|
||||
target_link_libraries(strawberry_lib PRIVATE ${LIBMTP_LIBRARIES})
|
||||
endif(HAVE_LIBMTP)
|
||||
|
||||
if(HAVE_IMOBILEDEVICE)
|
||||
target_include_directories(strawberry_lib SYSTEM PRIVATE
|
||||
${LIBUSBMUXD_INCLUDE_DIRS}
|
||||
${LIBPLIST_INCLUDE_DIRS}
|
||||
${LIBIMOBILEDEVICE_INCLUDE_DIRS}
|
||||
)
|
||||
target_link_libraries(strawberry_lib PRIVATE
|
||||
${LIBUSBMUXD_LIBRARIES}
|
||||
${LIBPLIST_LIBRARIES}
|
||||
${LIBIMOBILEDEVICE_LIBRARIES}
|
||||
)
|
||||
endif(HAVE_IMOBILEDEVICE)
|
||||
|
||||
|
||||
if(APPLE)
|
||||
target_link_libraries(strawberry_lib PRIVATE
|
||||
@@ -1149,11 +1161,10 @@ if(WIN32)
|
||||
target_link_libraries(strawberry_lib PRIVATE dsound)
|
||||
endif(WIN32)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
if(X11_FOUND)
|
||||
# Hack: the Gold linker pays attention to the order that libraries are specified on the link line.
|
||||
# -lX11 and -ldl are provided earlier in the link command but they're actually used by libraries that appear after them, so they end up getting ignored.
|
||||
# This appends them to the very end of the link line, ensuring they're always used.
|
||||
find_package(X11)
|
||||
if(FREEBSD)
|
||||
target_link_libraries(strawberry_lib PRIVATE ${X11_X11_LIB})
|
||||
else()
|
||||
@@ -1196,6 +1207,10 @@ if(NOT APPLE)
|
||||
install(TARGETS strawberry RUNTIME DESTINATION bin)
|
||||
endif()
|
||||
|
||||
if(HAVE_TRANSLATIONS AND INSTALL_TRANSLATIONS AND INSTALL_TRANSLATIONS_FILES)
|
||||
install(FILES ${INSTALL_TRANSLATIONS_FILES} DESTINATION share/strawberry/translations)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set_target_properties(strawberry PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/../dist/macos/Info.plist")
|
||||
endif (APPLE)
|
||||
|
||||
@@ -99,10 +99,14 @@ AnalyzerContainer::AnalyzerContainer(QWidget *parent)
|
||||
|
||||
void AnalyzerContainer::mouseReleaseEvent(QMouseEvent *e) {
|
||||
|
||||
if (engine_->type() != Engine::EngineType::GStreamer && engine_->type() != Engine::EngineType::Xine) return;
|
||||
if (engine_->type() != Engine::EngineType::GStreamer) return;
|
||||
|
||||
if (e->button() == Qt::RightButton) {
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
context_menu_->popup(e->globalPosition().toPoint());
|
||||
#else
|
||||
context_menu_->popup(e->globalPos());
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,11 +28,11 @@
|
||||
#include <QPoint>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QActionGroup>
|
||||
|
||||
#include "engine/engine_fwd.h"
|
||||
|
||||
class QTimer;
|
||||
class QActionGroup;
|
||||
class QMouseEvent;
|
||||
class QWheelEvent;
|
||||
|
||||
|
||||
@@ -325,7 +325,7 @@ QColor ensureContrast(const QColor &bg, const QColor &fg, uint amount) {
|
||||
|
||||
void BlockAnalyzer::paletteChange(const QPalette&) {
|
||||
|
||||
const QColor bg = palette().color(QPalette::Background);
|
||||
const QColor bg = palette().color(QPalette::Window);
|
||||
const QColor fg = ensureContrast(bg, palette().color(QPalette::Highlight));
|
||||
|
||||
topbarpixmap_.fill(fg);
|
||||
@@ -343,12 +343,12 @@ void BlockAnalyzer::paletteChange(const QPalette&) {
|
||||
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)));
|
||||
|
||||
{
|
||||
const QColor bg2 = palette().color(QPalette::Background).darker(112);
|
||||
const QColor bg2 = palette().color(QPalette::Window).darker(112);
|
||||
|
||||
// make a complimentary fadebar colour
|
||||
// TODO dark is not always correct, dumbo!
|
||||
int h, s, v;
|
||||
palette().color(QPalette::Background).darker(150).getHsv(&h, &s, &v);
|
||||
palette().color(QPalette::Window).darker(150).getHsv(&h, &s, &v);
|
||||
const QColor fg2(QColor::fromHsv(h + 120, s, v));
|
||||
|
||||
const double dr2 = fg2.red() - bg2.red();
|
||||
@@ -358,7 +358,7 @@ void BlockAnalyzer::paletteChange(const QPalette&) {
|
||||
|
||||
// Precalculate all fade-bar pixmaps
|
||||
for (uint y = 0; y < kFadeSize; ++y) {
|
||||
fade_bars_[y].fill(palette().color(QPalette::Background));
|
||||
fade_bars_[y].fill(palette().color(QPalette::Window));
|
||||
QPainter f(&fade_bars_[y]);
|
||||
for (int z = 0; static_cast<uint>(z) < rows_; ++z) {
|
||||
const double Y = 1.0 - (log10(kFadeSize - y) / log10(kFadeSize));
|
||||
@@ -377,7 +377,7 @@ void BlockAnalyzer::drawBackground() {
|
||||
return;
|
||||
}
|
||||
|
||||
const QColor bg = palette().color(QPalette::Background);
|
||||
const QColor bg = palette().color(QPalette::Window);
|
||||
const QColor bgdark = bg.darker(112);
|
||||
|
||||
background_.fill(bg);
|
||||
|
||||
@@ -87,7 +87,7 @@ void BoomAnalyzer::resizeEvent(QResizeEvent* e) {
|
||||
|
||||
barPixmap_ = QPixmap(kColumnWidth - 2, HEIGHT);
|
||||
canvas_ = QPixmap(size());
|
||||
canvas_.fill(palette().color(QPalette::Background));
|
||||
canvas_.fill(palette().color(QPalette::Window));
|
||||
|
||||
QPainter p(&barPixmap_);
|
||||
for (uint y = 0; y < HEIGHT; ++y) {
|
||||
@@ -120,7 +120,7 @@ void BoomAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) {
|
||||
const uint MAX_HEIGHT = height() - 1;
|
||||
|
||||
QPainter canvas_painter(&canvas_);
|
||||
canvas_.fill(palette().color(QPalette::Background));
|
||||
canvas_.fill(palette().color(QPalette::Window));
|
||||
|
||||
Analyzer::interpolate(scope, scope_);
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ void SCollection::Exit() {
|
||||
|
||||
void SCollection::ExitReceived() {
|
||||
|
||||
QObject *obj = static_cast<QObject*>(sender());
|
||||
QObject *obj = qobject_cast<QObject*>(sender());
|
||||
disconnect(obj, nullptr, this, nullptr);
|
||||
qLog(Debug) << obj << "successfully exited.";
|
||||
wait_for_exit_.removeAll(obj);
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include <QUrl>
|
||||
#include <QFileInfo>
|
||||
#include <QDateTime>
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
|
||||
@@ -222,7 +222,7 @@ SubdirectoryList CollectionBackend::SubdirsInDirectory(int id, QSqlDatabase &db)
|
||||
Subdirectory subdir;
|
||||
subdir.directory_id = id;
|
||||
subdir.path = q.value(0).toString();
|
||||
subdir.mtime = q.value(1).toUInt();
|
||||
subdir.mtime = q.value(1).toLongLong();
|
||||
subdirs << subdir;
|
||||
}
|
||||
|
||||
@@ -1031,7 +1031,7 @@ CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist,
|
||||
info.first_url = QUrl::fromEncoded(query.Value(7).toByteArray());
|
||||
|
||||
QString art_automatic = query.Value(5).toString();
|
||||
if (art_automatic.contains(QRegExp("..+:.*"))) {
|
||||
if (art_automatic.contains(QRegularExpression("..+:.*"))) {
|
||||
info.art_automatic = QUrl::fromEncoded(art_automatic.toUtf8());
|
||||
}
|
||||
else {
|
||||
@@ -1039,7 +1039,7 @@ CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist,
|
||||
}
|
||||
|
||||
QString art_manual = query.Value(6).toString();
|
||||
if (art_manual.contains(QRegExp("..+:.*"))) {
|
||||
if (art_manual.contains(QRegularExpression("..+:.*"))) {
|
||||
info.art_manual = QUrl::fromEncoded(art_manual.toUtf8());
|
||||
}
|
||||
else {
|
||||
@@ -1228,7 +1228,7 @@ void CollectionBackend::IncrementPlayCount(int id) {
|
||||
|
||||
QSqlQuery q(db);
|
||||
q.prepare(QString("UPDATE %1 SET playcount = playcount + 1, lastplayed = :now WHERE ROWID = :id").arg(songs_table_));
|
||||
q.bindValue(":now", QDateTime::currentDateTime().toTime_t());
|
||||
q.bindValue(":now", QDateTime::currentDateTime().toSecsSinceEpoch());
|
||||
q.bindValue(":id", id);
|
||||
q.exec();
|
||||
if (db_->CheckErrors(q)) return;
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
#include <QInputDialog>
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
@@ -63,27 +63,26 @@ CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
|
||||
|
||||
ui_->setupUi(this);
|
||||
|
||||
QString available_fields = Song::kFtsColumns.join(", ").replace(QRegExp("\\bfts"), "");
|
||||
QString available_fields = Song::kFtsColumns.join(", ").replace(QRegularExpression("\\bfts"), "");
|
||||
|
||||
ui_->filter->setToolTip(
|
||||
"<html><head/><body><p>" +
|
||||
QString("<html><head/><body><p>") +
|
||||
tr("Prefix a word with a field name to limit the search to that field, e.g.:") +
|
||||
" " +
|
||||
"<span style=\"font-weight:600;\">" +
|
||||
QString(" ") +
|
||||
QString("<span style=\"font-weight:600;\">") +
|
||||
tr("artist") +
|
||||
":" +
|
||||
"</span><span style=\"font-style:italic;\">Strawbs</span>" +
|
||||
" " +
|
||||
QString(":") +
|
||||
QString("</span><span style=\"font-style:italic;\">Strawbs</span>") +
|
||||
QString(" ") +
|
||||
tr("searches the collection for all artists that contain the word") +
|
||||
"Strawbs" +
|
||||
"." +
|
||||
"</p><p><span style=\"font-weight:600;\">" +
|
||||
QString(" Strawbs.") +
|
||||
QString("</p><p><span style=\"font-weight:600;\">") +
|
||||
tr("Available fields") +
|
||||
": " +
|
||||
QString(": ") +
|
||||
"</span><span style=\"font-style:italic;\">" +
|
||||
available_fields +
|
||||
"</span>." +
|
||||
"</p></body></html>"
|
||||
QString("</span>.") +
|
||||
QString("</p></body></html>")
|
||||
);
|
||||
|
||||
connect(ui_->filter, SIGNAL(returnPressed()), SIGNAL(ReturnPressed()));
|
||||
|
||||
@@ -33,7 +33,6 @@ class CollectionItem : public SimpleTreeItem<CollectionItem> {
|
||||
Type_Divider,
|
||||
Type_Container,
|
||||
Type_Song,
|
||||
Type_PlaylistContainer,
|
||||
Type_LoadingIndicator,
|
||||
};
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QtGlobal>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QtConcurrent>
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <QFuture>
|
||||
@@ -44,7 +44,7 @@
|
||||
#include <QUrl>
|
||||
#include <QImage>
|
||||
#include <QChar>
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
#include <QPixmapCache>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QSettings>
|
||||
@@ -97,8 +97,6 @@ CollectionModel::CollectionModel(CollectionBackend *backend, Application *app, Q
|
||||
total_album_count_(0),
|
||||
artist_icon_(IconLoader::Load("folder-sound")),
|
||||
album_icon_(IconLoader::Load("cdcase")),
|
||||
playlists_dir_icon_(IconLoader::Load("folder-sound")),
|
||||
playlist_icon_(IconLoader::Load("albums")),
|
||||
init_task_id_(-1),
|
||||
use_pretty_covers_(false),
|
||||
show_dividers_(true),
|
||||
@@ -695,8 +693,6 @@ QVariant CollectionModel::data(const CollectionItem *item, const int role) const
|
||||
|
||||
case Qt::DecorationRole:
|
||||
switch (item->type) {
|
||||
case CollectionItem::Type_PlaylistContainer:
|
||||
return playlists_dir_icon_;
|
||||
case CollectionItem::Type_Container:
|
||||
switch (container_type) {
|
||||
case GroupBy_Album:
|
||||
@@ -859,9 +855,8 @@ void CollectionModel::LazyPopulate(CollectionItem *parent, const bool signal) {
|
||||
}
|
||||
|
||||
void CollectionModel::ResetAsync() {
|
||||
QFuture<CollectionModel::QueryResult> future = QtConcurrent::run(this, &CollectionModel::RunQuery, root_);
|
||||
QFuture<CollectionModel::QueryResult> future = QtConcurrent::run(std::bind(&CollectionModel::RunQuery, this, root_));
|
||||
NewClosure(future, this, SLOT(ResetAsyncQueryFinished(QFuture<CollectionModel::QueryResult>)), future);
|
||||
|
||||
}
|
||||
|
||||
void CollectionModel::ResetAsyncQueryFinished(QFuture<CollectionModel::QueryResult> future) {
|
||||
@@ -1421,7 +1416,7 @@ QString CollectionModel::PrettyYearAlbum(const int year, const QString &album) {
|
||||
|
||||
QString CollectionModel::PrettyAlbumDisc(const QString &album, const int disc) {
|
||||
|
||||
if (disc <= 0 || album.contains(QRegExp(Song::kAlbumRemoveDisc))) return TextOrUnknown(album);
|
||||
if (disc <= 0 || album.contains(QRegularExpression(Song::kAlbumRemoveDisc))) return TextOrUnknown(album);
|
||||
else return TextOrUnknown(album) + " - (Disc " + QString::number(disc) + ")";
|
||||
|
||||
}
|
||||
@@ -1433,7 +1428,7 @@ QString CollectionModel::PrettyYearAlbumDisc(const int year, const QString &albu
|
||||
if (year <= 0) str = TextOrUnknown(album);
|
||||
else str = QString::number(year) + " - " + TextOrUnknown(album);
|
||||
|
||||
if (!album.contains(QRegExp(Song::kAlbumRemoveDisc)) && disc > 0) str += " - (Disc " + QString::number(disc) + ")";
|
||||
if (!album.contains(QRegularExpression(Song::kAlbumRemoveDisc)) && disc > 0) str += " - (Disc " + QString::number(disc) + ")";
|
||||
|
||||
return str;
|
||||
|
||||
@@ -1447,7 +1442,7 @@ QString CollectionModel::SortText(QString text) {
|
||||
else {
|
||||
text = text.toLower();
|
||||
}
|
||||
text = text.remove(QRegExp("[^\\w ]"));
|
||||
text = text.remove(QRegularExpression("[^\\w ]", QRegularExpression::UseUnicodePropertiesOption));
|
||||
|
||||
return text;
|
||||
|
||||
|
||||
@@ -280,8 +280,6 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
||||
QIcon album_icon_;
|
||||
// Used as a generic icon to show when no cover art is found, fixed to the same size as the artwork (32x32)
|
||||
QPixmap no_cover_icon_;
|
||||
QIcon playlists_dir_icon_;
|
||||
QIcon playlist_icon_;
|
||||
|
||||
static QNetworkDiskCache *sIconCache;
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ class CollectionPlaylistItem : public PlaylistItem {
|
||||
void Reload() override;
|
||||
|
||||
Song Metadata() const override;
|
||||
Song OriginalMetadata() const override { return song_; }
|
||||
void SetMetadata(const Song &song) { song_ = song; }
|
||||
|
||||
QUrl Url() const override;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringBuilder>
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
|
||||
@@ -46,9 +46,9 @@ CollectionQuery::CollectionQuery(const QueryOptions &options)
|
||||
|
||||
// Split on whitespace
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
QStringList tokens(options.filter().split(QRegExp("\\s+"), Qt::SkipEmptyParts));
|
||||
QStringList tokens(options.filter().split(QRegularExpression("\\s+"), Qt::SkipEmptyParts));
|
||||
#else
|
||||
QStringList tokens(options.filter().split(QRegExp("\\s+"), QString::SkipEmptyParts));
|
||||
QStringList tokens(options.filter().split(QRegularExpression("\\s+"), QString::SkipEmptyParts));
|
||||
#endif
|
||||
QString query;
|
||||
for (QString token : tokens) {
|
||||
@@ -65,17 +65,21 @@ CollectionQuery::CollectionQuery(const QueryOptions &options)
|
||||
QString subtoken = token.section(':', 1, -1);
|
||||
subtoken.replace(":", " ");
|
||||
subtoken = subtoken.trimmed();
|
||||
if (!subtoken.isEmpty())
|
||||
query += "fts" + columntoken + subtoken + "* ";
|
||||
if (!subtoken.isEmpty()) {
|
||||
if (!query.isEmpty()) query.append(" ");
|
||||
query += "fts" + columntoken + "\"" + subtoken + "\"*";
|
||||
}
|
||||
}
|
||||
else {
|
||||
token.replace(":", " ");
|
||||
token = token.trimmed();
|
||||
query += token + "* ";
|
||||
if (!query.isEmpty()) query.append(" ");
|
||||
query += "\"" + token + "\"*";
|
||||
}
|
||||
}
|
||||
else {
|
||||
query += token + "* ";
|
||||
if (!query.isEmpty()) query.append(" ");
|
||||
query += "\"" + token + "\"*";
|
||||
}
|
||||
}
|
||||
if (!query.isEmpty()) {
|
||||
@@ -86,7 +90,7 @@ CollectionQuery::CollectionQuery(const QueryOptions &options)
|
||||
}
|
||||
|
||||
if (options.max_age() != -1) {
|
||||
int cutoff = QDateTime::currentDateTime().toTime_t() - options.max_age();
|
||||
int cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - options.max_age();
|
||||
|
||||
where_clauses_ << "ctime > ?";
|
||||
bound_values_ << cutoff;
|
||||
@@ -202,7 +206,7 @@ QVariant CollectionQuery::Value(int column) const { return query_.value(column);
|
||||
bool QueryOptions::Matches(const Song &song) const {
|
||||
|
||||
if (max_age_ != -1) {
|
||||
const uint cutoff = QDateTime::currentDateTime().toTime_t() - max_age_;
|
||||
const uint cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - max_age_;
|
||||
if (song.ctime() <= cutoff) return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
# include "device/devicestatefiltermodel.h"
|
||||
#endif
|
||||
#include "dialogs/edittagdialog.h"
|
||||
#include "organise/organisedialog.h"
|
||||
#include "organize/organizedialog.h"
|
||||
#include "settings/collectionsettingspage.h"
|
||||
|
||||
CollectionView::CollectionView(QWidget *parent)
|
||||
@@ -325,7 +325,7 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
||||
add_to_playlist_enqueue_next_ = context_menu_->addAction(IconLoader::Load("go-next"), tr("Queue to play next"), this, SLOT(AddToPlaylistEnqueueNext()));
|
||||
|
||||
context_menu_->addSeparator();
|
||||
organise_ = context_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organise files..."), this, SLOT(Organise()));
|
||||
organize_ = context_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organize files..."), this, SLOT(Organize()));
|
||||
#ifndef Q_OS_WIN
|
||||
copy_to_device_ = context_menu_->addAction(IconLoader::Load("device"), tr("Copy to device..."), this, SLOT(CopyToDevice()));
|
||||
#endif
|
||||
@@ -366,39 +366,40 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
||||
int regular_editable = 0;
|
||||
|
||||
for (const QModelIndex &index : selected_indexes) {
|
||||
regular_elements++;
|
||||
++regular_elements;
|
||||
if(app_->collection_model()->data(index, CollectionModel::Role_Editable).toBool()) {
|
||||
regular_editable++;
|
||||
++regular_editable;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: check if custom plugin actions should be enabled / visible
|
||||
const int songs_selected = regular_elements;
|
||||
const bool regular_elements_only = songs_selected == regular_elements && regular_elements > 0;
|
||||
|
||||
// in all modes
|
||||
load_->setEnabled(songs_selected);
|
||||
add_to_playlist_->setEnabled(songs_selected);
|
||||
open_in_new_playlist_->setEnabled(songs_selected);
|
||||
add_to_playlist_enqueue_->setEnabled(songs_selected);
|
||||
load_->setEnabled(songs_selected > 0);
|
||||
add_to_playlist_->setEnabled(songs_selected > 0);
|
||||
open_in_new_playlist_->setEnabled(songs_selected > 0);
|
||||
add_to_playlist_enqueue_->setEnabled(songs_selected > 0);
|
||||
|
||||
// if neither edit_track not edit_tracks are available, we show disabled edit_track element
|
||||
edit_track_->setVisible(regular_editable <= 1);
|
||||
edit_track_->setVisible(regular_editable == 1);
|
||||
edit_track_->setEnabled(regular_editable == 1);
|
||||
edit_tracks_->setVisible(regular_editable > 1);
|
||||
edit_tracks_->setEnabled(regular_editable > 1);
|
||||
|
||||
rescan_songs_->setVisible(edit_track_->isVisible());
|
||||
rescan_songs_->setEnabled(true);
|
||||
rescan_songs_->setVisible(regular_editable > 0);
|
||||
rescan_songs_->setEnabled(regular_editable > 0);
|
||||
|
||||
organise_->setVisible(regular_elements_only);
|
||||
organize_->setVisible(regular_elements == regular_editable);
|
||||
#ifndef Q_OS_WIN
|
||||
copy_to_device_->setVisible(regular_elements_only);
|
||||
copy_to_device_->setVisible(regular_elements == regular_editable);
|
||||
#endif
|
||||
//delete_->setVisible(regular_elements_only);
|
||||
show_in_various_->setVisible(regular_elements_only);
|
||||
no_show_in_various_->setVisible(regular_elements_only);
|
||||
|
||||
// only when all selected items are editable
|
||||
organise_->setEnabled(regular_elements == regular_editable);
|
||||
organize_->setEnabled(regular_elements == regular_editable);
|
||||
#ifndef Q_OS_WIN
|
||||
copy_to_device_->setEnabled(regular_elements == regular_editable);
|
||||
#endif
|
||||
@@ -529,15 +530,15 @@ SongList CollectionView::GetSelectedSongs() const {
|
||||
|
||||
}
|
||||
|
||||
void CollectionView::Organise() {
|
||||
void CollectionView::Organize() {
|
||||
|
||||
if (!organise_dialog_)
|
||||
organise_dialog_.reset(new OrganiseDialog(app_->task_manager(), app_->collection_backend(), this));
|
||||
if (!organize_dialog_)
|
||||
organize_dialog_.reset(new OrganizeDialog(app_->task_manager(), app_->collection_backend(), this));
|
||||
|
||||
organise_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
||||
organise_dialog_->SetCopy(false);
|
||||
if (organise_dialog_->SetSongs(GetSelectedSongs()))
|
||||
organise_dialog_->show();
|
||||
organize_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
||||
organize_dialog_->SetCopy(false);
|
||||
if (organize_dialog_->SetSongs(GetSelectedSongs()))
|
||||
organize_dialog_->show();
|
||||
else {
|
||||
QMessageBox::warning(this, tr("Error"), tr("None of the selected songs were suitable for copying to a device"));
|
||||
}
|
||||
@@ -568,13 +569,13 @@ void CollectionView::RescanSongs() {
|
||||
void CollectionView::CopyToDevice() {
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
if (!organise_dialog_)
|
||||
organise_dialog_.reset(new OrganiseDialog(app_->task_manager(), nullptr, this));
|
||||
if (!organize_dialog_)
|
||||
organize_dialog_.reset(new OrganizeDialog(app_->task_manager(), nullptr, this));
|
||||
|
||||
organise_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
||||
organise_dialog_->SetCopy(true);
|
||||
organise_dialog_->SetSongs(GetSelectedSongs());
|
||||
organise_dialog_->show();
|
||||
organize_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
||||
organize_dialog_->SetCopy(true);
|
||||
organize_dialog_->SetSongs(GetSelectedSongs());
|
||||
organize_dialog_->show();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class QPaintEvent;
|
||||
class Application;
|
||||
class CollectionFilterWidget;
|
||||
class EditTagDialog;
|
||||
class OrganiseDialog;
|
||||
class OrganizeDialog;
|
||||
|
||||
class CollectionView : public AutoExpandingTreeView {
|
||||
Q_OBJECT
|
||||
@@ -102,7 +102,7 @@ class CollectionView : public AutoExpandingTreeView {
|
||||
void AddToPlaylistEnqueue();
|
||||
void AddToPlaylistEnqueueNext();
|
||||
void OpenInNewPlaylist();
|
||||
void Organise();
|
||||
void Organize();
|
||||
void CopyToDevice();
|
||||
void EditTracks();
|
||||
void RescanSongs();
|
||||
@@ -133,7 +133,7 @@ class CollectionView : public AutoExpandingTreeView {
|
||||
QAction *add_to_playlist_enqueue_;
|
||||
QAction *add_to_playlist_enqueue_next_;
|
||||
QAction *open_in_new_playlist_;
|
||||
QAction *organise_;
|
||||
QAction *organize_;
|
||||
#ifndef Q_OS_WIN
|
||||
QAction *copy_to_device_;
|
||||
#endif
|
||||
@@ -145,7 +145,7 @@ class CollectionView : public AutoExpandingTreeView {
|
||||
QAction *show_in_various_;
|
||||
QAction *no_show_in_various_;
|
||||
|
||||
std::unique_ptr<OrganiseDialog> organise_dialog_;
|
||||
std::unique_ptr<OrganizeDialog> organize_dialog_;
|
||||
std::unique_ptr<EditTagDialog> edit_tag_dialog_;
|
||||
|
||||
bool is_in_keyboard_search_;
|
||||
|
||||
@@ -328,7 +328,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
||||
return;
|
||||
}
|
||||
|
||||
if (!t->ignores_mtime() && !force_noincremental && t->is_incremental() && subdir.mtime == path_info.lastModified().toTime_t()) {
|
||||
if (!t->ignores_mtime() && !force_noincremental && t->is_incremental() && subdir.mtime == path_info.lastModified().toSecsSinceEpoch()) {
|
||||
// The directory hasn't changed since last time
|
||||
t->AddToProgress(1);
|
||||
return;
|
||||
@@ -362,7 +362,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
||||
Subdirectory new_subdir;
|
||||
new_subdir.directory_id = -1;
|
||||
new_subdir.path = child;
|
||||
new_subdir.mtime = child_info.lastModified().toTime_t();
|
||||
new_subdir.mtime = child_info.lastModified().toSecsSinceEpoch();
|
||||
my_new_subdirs << new_subdir;
|
||||
}
|
||||
}
|
||||
@@ -393,7 +393,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
||||
|
||||
Song matching_song(source_);
|
||||
if (FindSongByPath(songs_in_db, file, &matching_song)) {
|
||||
uint matching_cue_mtime = GetMtimeForCue(matching_cue);
|
||||
qint64 matching_cue_mtime = GetMtimeForCue(matching_cue);
|
||||
|
||||
// The song is in the database and still on disk.
|
||||
// Check the mtime to see if it's been changed since it was added.
|
||||
@@ -407,13 +407,13 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
||||
|
||||
// cue sheet's path from collection (if any)
|
||||
QString song_cue = matching_song.cue_path();
|
||||
uint song_cue_mtime = GetMtimeForCue(song_cue);
|
||||
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)
|
||||
bool changed = (matching_song.mtime() != qMax(file_info.lastModified().toTime_t(), song_cue_mtime)) || cue_deleted || cue_added;
|
||||
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
|
||||
QUrl image = ImageForSong(file, album_art);
|
||||
@@ -470,7 +470,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
||||
// Add this subdir to the new or touched list
|
||||
Subdirectory updated_subdir;
|
||||
updated_subdir.directory_id = t->dir();
|
||||
updated_subdir.mtime = path_info.exists() ? path_info.lastModified().toTime_t() : 0;
|
||||
updated_subdir.mtime = path_info.exists() ? path_info.lastModified().toSecsSinceEpoch() : 0;
|
||||
updated_subdir.path = path;
|
||||
|
||||
if (subdir.directory_id == -1)
|
||||
@@ -560,7 +560,7 @@ SongList CollectionWatcher::ScanNewFile(const QString &file, const QString &path
|
||||
|
||||
SongList song_list;
|
||||
|
||||
uint matching_cue_mtime = GetMtimeForCue(matching_cue);
|
||||
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
|
||||
@@ -629,7 +629,7 @@ void CollectionWatcher::PreserveUserSetData(const QString &file, const QUrl &ima
|
||||
|
||||
}
|
||||
|
||||
uint CollectionWatcher::GetMtimeForCue(const QString &cue_path) {
|
||||
quint64 CollectionWatcher::GetMtimeForCue(const QString &cue_path) {
|
||||
|
||||
// Slight optimisation
|
||||
if (cue_path.isEmpty()) {
|
||||
@@ -643,7 +643,7 @@ uint CollectionWatcher::GetMtimeForCue(const QString &cue_path) {
|
||||
|
||||
const QDateTime cue_last_modified = file_info.lastModified();
|
||||
|
||||
return cue_last_modified.isValid() ? cue_last_modified.toTime_t() : 0;
|
||||
return cue_last_modified.isValid() ? cue_last_modified.toSecsSinceEpoch() : 0;
|
||||
}
|
||||
|
||||
void CollectionWatcher::AddWatch(const Directory &dir, const QString &path) {
|
||||
|
||||
@@ -166,7 +166,7 @@ class CollectionWatcher : public QObject {
|
||||
QUrl ImageForSong(const QString &path, QMap<QString, QStringList> &album_art);
|
||||
void AddWatch(const Directory &dir, const QString &path);
|
||||
void RemoveWatch(const Directory &dir, const Subdirectory &subdir);
|
||||
uint GetMtimeForCue(const QString &cue_path);
|
||||
quint64 GetMtimeForCue(const QString &cue_path);
|
||||
void PerformScan(bool incremental, bool ignore_mtimes);
|
||||
|
||||
// Updates the sections of a cue associated and altered (according to mtime) media file during a scan.
|
||||
|
||||
@@ -49,7 +49,7 @@ struct Subdirectory {
|
||||
|
||||
int directory_id;
|
||||
QString path;
|
||||
uint mtime;
|
||||
qint64 mtime;
|
||||
};
|
||||
Q_DECLARE_METATYPE(Subdirectory)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>You can change the way the songs in the collection are organised.</string>
|
||||
<string>You can change the way the songs in the collection are organized.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
|
||||
@@ -31,20 +31,18 @@
|
||||
#cmakedefine HAVE_X11
|
||||
#cmakedefine HAVE_UDISKS2
|
||||
#cmakedefine HAVE_ALSA
|
||||
#cmakedefine HAVE_IMOBILEDEVICE
|
||||
#cmakedefine HAVE_AUDIOCD
|
||||
#cmakedefine HAVE_LIBGPOD
|
||||
#cmakedefine HAVE_LIBMTP
|
||||
#cmakedefine HAVE_LIBPULSE
|
||||
#cmakedefine HAVE_SPARKLE
|
||||
#cmakedefine HAVE_QTSPARKLE
|
||||
#cmakedefine HAVE_CHROMAPRINT
|
||||
#cmakedefine HAVE_GLOBALSHORTCUTS
|
||||
#cmakedefine USE_INSTALL_PREFIX
|
||||
|
||||
#cmakedefine HAVE_GSTREAMER
|
||||
#cmakedefine HAVE_VLC
|
||||
#cmakedefine HAVE_XINE
|
||||
#cmakedefine XINE_ANALYZER
|
||||
|
||||
#cmakedefine HAVE_SUBSONIC
|
||||
#cmakedefine HAVE_TIDAL
|
||||
@@ -59,9 +57,10 @@
|
||||
#cmakedefine HAVE_TAGLIB_DSDIFFFILE
|
||||
|
||||
#cmakedefine USE_BUNDLE
|
||||
|
||||
#define USE_BUNDLE_DIR "${USE_BUNDLE_DIR}"
|
||||
|
||||
#cmakedefine HAVE_TRANSLATIONS
|
||||
#cmakedefine INSTALL_TRANSLATIONS
|
||||
#define TRANSLATIONS_DIR "${CMAKE_INSTALL_PREFIX}/share/strawberry/translations"
|
||||
|
||||
#endif // CONFIG_H_IN
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include <QVariant>
|
||||
#include <QList>
|
||||
#include <QSet>
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
@@ -62,8 +62,7 @@ ContextAlbumsModel::ContextAlbumsModel(CollectionBackend *backend, Application *
|
||||
SimpleTreeModel<CollectionItem>(new CollectionItem(this), parent),
|
||||
backend_(backend),
|
||||
app_(app),
|
||||
album_icon_(IconLoader::Load("cdcase")),
|
||||
playlists_dir_icon_(IconLoader::Load("folder-sound")) {
|
||||
album_icon_(IconLoader::Load("cdcase")) {
|
||||
|
||||
root_->lazy_loaded = true;
|
||||
|
||||
@@ -195,8 +194,6 @@ QVariant ContextAlbumsModel::data(const CollectionItem *item, int role) const {
|
||||
|
||||
case Qt::DecorationRole:
|
||||
switch (item->type) {
|
||||
case CollectionItem::Type_PlaylistContainer:
|
||||
return playlists_dir_icon_;
|
||||
case CollectionItem::Type_Container:
|
||||
if (item->type == CollectionItem::Type_Container && item->container_level == 0) { return album_icon_; }
|
||||
break;
|
||||
@@ -370,7 +367,7 @@ QString ContextAlbumsModel::SortText(QString text) {
|
||||
else {
|
||||
text = text.toLower();
|
||||
}
|
||||
text = text.remove(QRegExp("[^\\w ]"));
|
||||
text = text.remove(QRegularExpression("[^\\w ]", QRegularExpression::UseUnicodePropertiesOption));
|
||||
|
||||
return text;
|
||||
|
||||
|
||||
@@ -120,7 +120,6 @@ class ContextAlbumsModel : public SimpleTreeModel<CollectionItem> {
|
||||
QMap<int, CollectionItem*> song_nodes_;
|
||||
QIcon album_icon_;
|
||||
QPixmap no_cover_icon_;
|
||||
QIcon playlists_dir_icon_;
|
||||
AlbumCoverLoaderOptions cover_loader_options_;
|
||||
typedef QPair<CollectionItem*, QString> ItemAndCacheKey;
|
||||
QMap<quint64, ItemAndCacheKey> pending_art_;
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
# include "device/devicestatefiltermodel.h"
|
||||
#endif
|
||||
#include "dialogs/edittagdialog.h"
|
||||
#include "organise/organisedialog.h"
|
||||
#include "organize/organizedialog.h"
|
||||
|
||||
#include "contextalbumsmodel.h"
|
||||
#include "contextalbumsview.h"
|
||||
@@ -257,7 +257,7 @@ void ContextAlbumsView::contextMenuEvent(QContextMenuEvent *e) {
|
||||
add_to_playlist_enqueue_ = context_menu_->addAction(IconLoader::Load("go-next"), tr("Queue track"), this, SLOT(AddToPlaylistEnqueue()));
|
||||
|
||||
context_menu_->addSeparator();
|
||||
organise_ = context_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organise files..."), this, SLOT(Organise()));
|
||||
organize_ = context_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organize files..."), this, SLOT(Organize()));
|
||||
#ifndef Q_OS_WIN
|
||||
copy_to_device_ = context_menu_->addAction(IconLoader::Load("device"), tr("Copy to device..."), this, SLOT(CopyToDevice()));
|
||||
#endif
|
||||
@@ -304,13 +304,13 @@ void ContextAlbumsView::contextMenuEvent(QContextMenuEvent *e) {
|
||||
edit_track_->setVisible(regular_editable <= 1);
|
||||
edit_track_->setEnabled(regular_editable == 1);
|
||||
|
||||
organise_->setVisible(regular_elements_only);
|
||||
organize_->setVisible(regular_elements_only);
|
||||
#ifndef Q_OS_WIN
|
||||
copy_to_device_->setVisible(regular_elements_only);
|
||||
#endif
|
||||
|
||||
// only when all selected items are editable
|
||||
organise_->setEnabled(regular_elements == regular_editable);
|
||||
organize_->setEnabled(regular_elements == regular_editable);
|
||||
#ifndef Q_OS_WIN
|
||||
copy_to_device_->setEnabled(regular_elements == regular_editable);
|
||||
#endif
|
||||
@@ -369,15 +369,15 @@ SongList ContextAlbumsView::GetSelectedSongs() const {
|
||||
return model_->GetChildSongs(selected_indexes);
|
||||
}
|
||||
|
||||
void ContextAlbumsView::Organise() {
|
||||
void ContextAlbumsView::Organize() {
|
||||
|
||||
if (!organise_dialog_)
|
||||
organise_dialog_.reset(new OrganiseDialog(app_->task_manager(), app_->collection_backend(), this));
|
||||
if (!organize_dialog_)
|
||||
organize_dialog_.reset(new OrganizeDialog(app_->task_manager(), app_->collection_backend(), this));
|
||||
|
||||
organise_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
||||
organise_dialog_->SetCopy(false);
|
||||
if (organise_dialog_->SetSongs(GetSelectedSongs()))
|
||||
organise_dialog_->show();
|
||||
organize_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
||||
organize_dialog_->SetCopy(false);
|
||||
if (organize_dialog_->SetSongs(GetSelectedSongs()))
|
||||
organize_dialog_->show();
|
||||
else {
|
||||
QMessageBox::warning(this, tr("Error"), tr("None of the selected songs were suitable for copying to a device"));
|
||||
}
|
||||
@@ -396,13 +396,13 @@ void ContextAlbumsView::EditTracks() {
|
||||
|
||||
void ContextAlbumsView::CopyToDevice() {
|
||||
#ifndef Q_OS_WIN
|
||||
if (!organise_dialog_)
|
||||
organise_dialog_.reset(new OrganiseDialog(app_->task_manager()));
|
||||
if (!organize_dialog_)
|
||||
organize_dialog_.reset(new OrganizeDialog(app_->task_manager()));
|
||||
|
||||
organise_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
||||
organise_dialog_->SetCopy(true);
|
||||
organise_dialog_->SetSongs(GetSelectedSongs());
|
||||
organise_dialog_->show();
|
||||
organize_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
||||
organize_dialog_->SetCopy(true);
|
||||
organize_dialog_->SetSongs(GetSelectedSongs());
|
||||
organize_dialog_->show();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class QPaintEvent;
|
||||
class Application;
|
||||
class ContextAlbumsModel;
|
||||
class EditTagDialog;
|
||||
class OrganiseDialog;
|
||||
class OrganizeDialog;
|
||||
|
||||
class ContextItemDelegate : public QStyledItemDelegate {
|
||||
Q_OBJECT
|
||||
@@ -93,7 +93,7 @@ class ContextAlbumsView : public AutoExpandingTreeView {
|
||||
void AddToPlaylist();
|
||||
void AddToPlaylistEnqueue();
|
||||
void OpenInNewPlaylist();
|
||||
void Organise();
|
||||
void Organize();
|
||||
void CopyToDevice();
|
||||
void EditTracks();
|
||||
void ShowInBrowser();
|
||||
@@ -112,7 +112,7 @@ class ContextAlbumsView : public AutoExpandingTreeView {
|
||||
QAction *add_to_playlist_;
|
||||
QAction *add_to_playlist_enqueue_;
|
||||
QAction *open_in_new_playlist_;
|
||||
QAction *organise_;
|
||||
QAction *organize_;
|
||||
#ifndef Q_OS_WIN
|
||||
QAction *copy_to_device_;
|
||||
#endif
|
||||
@@ -120,7 +120,7 @@ class ContextAlbumsView : public AutoExpandingTreeView {
|
||||
QAction *edit_tracks_;
|
||||
QAction *show_in_browser_;
|
||||
|
||||
std::unique_ptr<OrganiseDialog> organise_dialog_;
|
||||
std::unique_ptr<OrganizeDialog> organize_dialog_;
|
||||
std::unique_ptr<EditTagDialog> edit_tag_dialog_;
|
||||
|
||||
bool is_in_keyboard_search_;
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
SBSystemPreferencesWindow, SBSystemPreferencesPane,
|
||||
SBSystemPreferencesAnchor;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmultichar"
|
||||
#pragma GCC diagnostic ignored "-Wfour-char-constants"
|
||||
|
||||
enum SBSystemPreferencesSaveOptions {
|
||||
SBSystemPreferencesSaveOptionsYes = 'yes ' /* Save the file. */,
|
||||
SBSystemPreferencesSaveOptionsNo = 'no ' /* Do not save the file. */,
|
||||
@@ -27,6 +31,9 @@ enum SBSystemPreferencesPrintingErrorHandling {
|
||||
SBSystemPreferencesPrintingErrorHandlingDetailed =
|
||||
'lwdt' /* print a detailed report of PostScript errors */
|
||||
};
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
typedef enum SBSystemPreferencesPrintingErrorHandling
|
||||
SBSystemPreferencesPrintingErrorHandling;
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include <QString>
|
||||
#include <QStringBuilder>
|
||||
#include <QStringList>
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
#include <QUrl>
|
||||
#include <QSqlDriver>
|
||||
#include <QSqlDatabase>
|
||||
@@ -392,7 +392,7 @@ void Database::ExecSchemaCommandsFromFile(QSqlDatabase &db, const QString &filen
|
||||
void Database::ExecSchemaCommands(QSqlDatabase &db, const QString &schema, int schema_version, bool in_transaction) {
|
||||
|
||||
// Run each command
|
||||
const QStringList commands(schema.split(QRegExp("; *\n\n")));
|
||||
const QStringList commands(schema.split(QRegularExpression("; *\n\n")));
|
||||
|
||||
// We don't want this list to reflect possible DB schema changes so we initialize it before executing any statements.
|
||||
// If no outer transaction is provided the song tables need to be queried before beginning an inner transaction! Otherwise
|
||||
|
||||
@@ -69,8 +69,13 @@ bool FilesystemMusicStorage::CopyToStorage(const CopyJob &job) {
|
||||
// Copy or move
|
||||
bool result(true);
|
||||
if (job.remove_original_) {
|
||||
result = QFile::rename(src.absoluteFilePath(), dest.absoluteFilePath());
|
||||
if (!cover_src.filePath().isEmpty() && !cover_dest.filePath().isEmpty()) {
|
||||
if (dest.exists() && !job.overwrite_) {
|
||||
result = false;
|
||||
}
|
||||
else {
|
||||
result = QFile::rename(src.absoluteFilePath(), dest.absoluteFilePath());
|
||||
}
|
||||
if ((!cover_dest.exists() || job.overwrite_) && !cover_src.filePath().isEmpty() && !cover_dest.filePath().isEmpty()) {
|
||||
QFile::rename(cover_src.absoluteFilePath(), cover_dest.absoluteFilePath());
|
||||
}
|
||||
// Remove empty directories.
|
||||
@@ -83,10 +88,13 @@ bool FilesystemMusicStorage::CopyToStorage(const CopyJob &job) {
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if (!dest.exists()) {
|
||||
if (dest.exists() && !job.overwrite_) {
|
||||
result = false;
|
||||
}
|
||||
else {
|
||||
result = QFile::copy(src.absoluteFilePath(), dest.absoluteFilePath());
|
||||
}
|
||||
if (!cover_src.filePath().isEmpty() && !cover_dest.filePath().isEmpty() && !cover_dest.exists()) {
|
||||
if ((!cover_dest.exists() || job.overwrite_) && !cover_src.filePath().isEmpty() && !cover_dest.filePath().isEmpty()) {
|
||||
QFile::copy(cover_src.absoluteFilePath(), cover_dest.absoluteFilePath());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,6 @@ static const QMap<QString, IconProperties> iconmapper_ = {
|
||||
{ "view-refresh", { {}} },
|
||||
{ "library-music", { {"vinyl"}} },
|
||||
{ "vlc", { {}} },
|
||||
{ "xine", { {}} },
|
||||
{ "zoom-in", { {}} },
|
||||
{ "zoom-out", { {}, 0, 0 } }
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
#include "globalshortcuts/globalshortcutbackend-macos.h"
|
||||
|
||||
#ifdef HAVE_SPARKLE
|
||||
# import <Sparkle/SUUpdater.h>
|
||||
# import <SUUpdater.h>
|
||||
#endif
|
||||
|
||||
#include <QApplication>
|
||||
@@ -117,6 +117,9 @@ QDebug operator<<(QDebug dbg, NSObject* object) {
|
||||
|
||||
- (BOOL) applicationShouldHandleReopen: (NSApplication*)app hasVisibleWindows:(BOOL)flag {
|
||||
|
||||
Q_UNUSED(app);
|
||||
Q_UNUSED(flag);
|
||||
|
||||
if (application_handler_) {
|
||||
application_handler_->Activate();
|
||||
}
|
||||
@@ -129,6 +132,7 @@ QDebug operator<<(QDebug dbg, NSObject* object) {
|
||||
}
|
||||
|
||||
- (NSMenu*)applicationDockMenu:(NSApplication*)sender {
|
||||
Q_UNUSED(sender);
|
||||
return dock_menu_;
|
||||
}
|
||||
|
||||
@@ -141,11 +145,13 @@ QDebug operator<<(QDebug dbg, NSObject* object) {
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification {
|
||||
|
||||
Q_UNUSED(aNotification);
|
||||
}
|
||||
|
||||
- (BOOL)application:(NSApplication*)app openFile:(NSString*)filename {
|
||||
|
||||
Q_UNUSED(app);
|
||||
|
||||
qLog(Debug) << "Wants to open:" << [filename UTF8String];
|
||||
|
||||
if (application_handler_->LoadUrl(QString::fromUtf8([filename UTF8String]))) {
|
||||
@@ -159,17 +165,20 @@ QDebug operator<<(QDebug dbg, NSObject* object) {
|
||||
- (void)application:(NSApplication*)app openFiles:(NSArray*)filenames {
|
||||
|
||||
qLog(Debug) << "Wants to open:" << filenames;
|
||||
[filenames enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL* stop) {
|
||||
[filenames enumerateObjectsUsingBlock:^(id object, NSUInteger, BOOL*) {
|
||||
[self application:app openFile:(NSString*)object];
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*) sender {
|
||||
Q_UNUSED(sender);
|
||||
return NSTerminateNow;
|
||||
}
|
||||
|
||||
- (BOOL) userNotificationCenter: (id)center shouldPresentNotification: (id)notification {
|
||||
Q_UNUSED(center);
|
||||
Q_UNUSED(notification);
|
||||
// Always show notifications, even if Strawberry is in the foreground.
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,10 @@ void MacFSListener::Init() { run_loop_ = CFRunLoopGetCurrent(); }
|
||||
|
||||
void MacFSListener::EventStreamCallback(ConstFSEventStreamRef stream, void* user_data, size_t num_events, void* event_paths, const FSEventStreamEventFlags event_flags[], const FSEventStreamEventId event_ids[]) {
|
||||
|
||||
Q_UNUSED(stream);
|
||||
Q_UNUSED(event_flags);
|
||||
Q_UNUSED(event_ids);
|
||||
|
||||
MacFSListener* me = reinterpret_cast<MacFSListener*>(user_data);
|
||||
char** paths = reinterpret_cast<char**>(event_paths);
|
||||
for (size_t i = 0; i < num_events; ++i) {
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
}
|
||||
|
||||
- (BOOL) validateMenuItem: (NSMenuItem*)menuItem {
|
||||
Q_UNUSED(menuItem);
|
||||
// This is called when the menu is shown.
|
||||
return action_->isEnabled();
|
||||
}
|
||||
@@ -206,5 +207,6 @@ void MacSystemTrayIcon::ClearNowPlaying() {
|
||||
}
|
||||
|
||||
void MacSystemTrayIcon::SetNowPlaying(const Song& song, const QUrl& cover_url) {
|
||||
Q_UNUSED(cover_url);
|
||||
p_->ShowNowPlaying(song.artist(), song.PrettyTitle());
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
@@ -67,9 +68,11 @@
|
||||
#include <QStackedWidget>
|
||||
#include <QTabBar>
|
||||
#include <QToolButton>
|
||||
#include <QClipboard>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "core/closure.h"
|
||||
#include "core/network.h"
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
@@ -97,14 +100,14 @@
|
||||
#include "dialogs/trackselectiondialog.h"
|
||||
#include "dialogs/edittagdialog.h"
|
||||
#include "dialogs/addstreamdialog.h"
|
||||
#include "organise/organisedialog.h"
|
||||
#include "organize/organizedialog.h"
|
||||
#include "widgets/fancytabwidget.h"
|
||||
#include "widgets/playingwidget.h"
|
||||
#include "widgets/volumeslider.h"
|
||||
#include "widgets/fileview.h"
|
||||
#include "widgets/multiloadingindicator.h"
|
||||
#include "widgets/osd.h"
|
||||
#include "widgets/trackslider.h"
|
||||
#include "osd/osdbase.h"
|
||||
#include "context/contextview.h"
|
||||
#include "context/contextalbumsview.h"
|
||||
#include "collection/collection.h"
|
||||
@@ -181,6 +184,14 @@
|
||||
# include "windows7thumbbar.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_QTSPARKLE
|
||||
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
# include <qtsparkle-qt6/Updater>
|
||||
# else
|
||||
# include <qtsparkle-qt5/Updater>
|
||||
# endif
|
||||
#endif // HAVE_QTSPARKLE
|
||||
|
||||
const char *MainWindow::kSettingsGroup = "MainWindow";
|
||||
const char *MainWindow::kAllFilesFilterSpec = QT_TR_NOOP("All Files (*)");
|
||||
|
||||
@@ -189,7 +200,7 @@ const int kTrackSliderUpdateTimeMs = 200;
|
||||
const int kTrackPositionUpdateTimeMs = 1000;
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, const CommandlineOptions &options, QWidget *parent) :
|
||||
MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSDBase *osd, const CommandlineOptions &options, QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui_(new Ui_MainWindow),
|
||||
#ifdef Q_OS_WIN
|
||||
@@ -221,8 +232,8 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
return cover_manager;
|
||||
}),
|
||||
equalizer_(new Equalizer),
|
||||
organise_dialog_([=]() {
|
||||
OrganiseDialog *dialog = new OrganiseDialog(app->task_manager(), app->collection_backend(), this);
|
||||
organize_dialog_([=]() {
|
||||
OrganizeDialog *dialog = new OrganizeDialog(app->task_manager(), app->collection_backend(), this);
|
||||
dialog->SetDestinationModel(app->collection()->model()->directory_model());
|
||||
return dialog;
|
||||
}),
|
||||
@@ -243,9 +254,28 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
#ifdef HAVE_TIDAL
|
||||
tidal_view_(new InternetTabsView(app_, app->internet_services()->ServiceBySource(Song::Source_Tidal), TidalSettingsPage::kSettingsGroup, SettingsDialog::Page_Tidal, this)),
|
||||
#endif
|
||||
collection_show_all_(nullptr),
|
||||
collection_show_duplicates_(nullptr),
|
||||
collection_show_untagged_(nullptr),
|
||||
playlist_menu_(new QMenu(this)),
|
||||
playlist_play_pause_(nullptr),
|
||||
playlist_stop_after_(nullptr),
|
||||
playlist_undoredo_(nullptr),
|
||||
playlist_organize_(nullptr),
|
||||
playlist_show_in_collection_(nullptr),
|
||||
playlist_copy_to_collection_(nullptr),
|
||||
playlist_move_to_collection_(nullptr),
|
||||
#ifndef Q_OS_WIN
|
||||
playlist_copy_to_device_(nullptr),
|
||||
#endif
|
||||
playlist_open_in_browser_(nullptr),
|
||||
playlist_copy_url_(nullptr),
|
||||
playlist_queue_(nullptr),
|
||||
playlist_queue_play_next_(nullptr),
|
||||
playlist_skip_(nullptr),
|
||||
playlist_add_to_another_(nullptr),
|
||||
playlistitem_actions_separator_(nullptr),
|
||||
playlist_rescan_songs_(nullptr),
|
||||
collection_sort_model_(new QSortFilterProxyModel(this)),
|
||||
track_position_timer_(new QTimer(this)),
|
||||
track_slider_timer_(new QTimer(this)),
|
||||
@@ -335,7 +365,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
#endif
|
||||
playlist_list_->SetApplication(app_);
|
||||
|
||||
organise_dialog_->SetDestinationModel(app_->collection()->model()->directory_model());
|
||||
organize_dialog_->SetDestinationModel(app_->collection()->model()->directory_model());
|
||||
|
||||
// Icons
|
||||
qLog(Debug) << "Creating UI";
|
||||
@@ -371,8 +401,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
ui_->action_shuffle->setIcon(IconLoader::Load("media-playlist-shuffle"));
|
||||
ui_->action_remove_duplicates->setIcon(IconLoader::Load("list-remove"));
|
||||
ui_->action_remove_unavailable->setIcon(IconLoader::Load("list-remove"));
|
||||
|
||||
//ui_->action_remove_from_playlist->setIcon(IconLoader::Load("list-remove"));
|
||||
ui_->action_remove_from_playlist->setIcon(IconLoader::Load("list-remove"));
|
||||
|
||||
// Configure
|
||||
|
||||
@@ -416,7 +445,6 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
connect(ui_->action_remove_unavailable, SIGNAL(triggered()), app_->playlist_manager(), SLOT(RemoveUnavailableCurrent()));
|
||||
connect(ui_->action_remove_from_playlist, SIGNAL(triggered()), SLOT(PlaylistRemoveCurrent()));
|
||||
connect(ui_->action_edit_track, SIGNAL(triggered()), SLOT(EditTracks()));
|
||||
connect(ui_->action_rescan_songs, SIGNAL(triggered()), SLOT(RescanSongs()));
|
||||
connect(ui_->action_renumber_tracks, SIGNAL(triggered()), SLOT(RenumberTracks()));
|
||||
connect(ui_->action_selection_set_value, SIGNAL(triggered()), SLOT(SelectionSetValue()));
|
||||
connect(ui_->action_edit_value, SIGNAL(triggered()), SLOT(EditValue()));
|
||||
@@ -446,6 +474,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
connect(ui_->action_abort_collection_scan, SIGNAL(triggered()), app_->collection(), SLOT(AbortScan()));
|
||||
#if defined(HAVE_GSTREAMER)
|
||||
connect(ui_->action_add_files_to_transcoder, SIGNAL(triggered()), SLOT(AddFilesToTranscoder()));
|
||||
ui_->action_add_files_to_transcoder->setIcon(IconLoader::Load("tools-wizard"));
|
||||
#else
|
||||
ui_->action_add_files_to_transcoder->setDisabled(true);
|
||||
#endif
|
||||
@@ -621,8 +650,11 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
playlist_menu_->addAction(ui_->action_edit_value);
|
||||
playlist_menu_->addAction(ui_->action_renumber_tracks);
|
||||
playlist_menu_->addAction(ui_->action_selection_set_value);
|
||||
#if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
|
||||
playlist_menu_->addAction(ui_->action_auto_complete_tags);
|
||||
playlist_menu_->addAction(ui_->action_rescan_songs);
|
||||
#endif
|
||||
playlist_rescan_songs_ = playlist_menu_->addAction(IconLoader::Load("view-refresh"), tr("Rescan song(s)..."), this, SLOT(RescanSongs()));
|
||||
playlist_menu_->addAction(playlist_rescan_songs_);
|
||||
#ifdef HAVE_GSTREAMER
|
||||
playlist_menu_->addAction(ui_->action_add_files_to_transcoder);
|
||||
#endif
|
||||
@@ -632,10 +664,11 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
#endif
|
||||
playlist_copy_to_collection_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Copy to collection..."), this, SLOT(PlaylistCopyToCollection()));
|
||||
playlist_move_to_collection_ = playlist_menu_->addAction(IconLoader::Load("go-jump"), tr("Move to collection..."), this, SLOT(PlaylistMoveToCollection()));
|
||||
playlist_organise_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organise files..."), this, SLOT(PlaylistMoveToCollection()));
|
||||
playlist_organize_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organize files..."), this, SLOT(PlaylistMoveToCollection()));
|
||||
playlist_open_in_browser_ = playlist_menu_->addAction(IconLoader::Load("document-open-folder"), tr("Show in file browser..."), this, SLOT(PlaylistOpenInBrowser()));
|
||||
playlist_open_in_browser_->setVisible(false);
|
||||
playlist_show_in_collection_ = playlist_menu_->addAction(IconLoader::Load("edit-find"), tr("Show in collection..."), this, SLOT(ShowInCollection()));
|
||||
playlist_copy_url_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Copy URL(s)..."), this, SLOT(PlaylistCopyUrl()));
|
||||
playlist_menu_->addSeparator();
|
||||
playlistitem_actions_separator_ = playlist_menu_->addSeparator();
|
||||
playlist_menu_->addAction(ui_->action_clear_playlist);
|
||||
@@ -681,8 +714,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
thumbbar_->SetActions(QList<QAction*>() << ui_->action_previous_track << ui_->action_play_pause << ui_->action_stop << ui_->action_next_track << nullptr << ui_->action_love);
|
||||
#endif
|
||||
|
||||
#if (defined(Q_OS_MACOS) && defined(HAVE_SPARKLE))
|
||||
// Add check for updates item to application menu.
|
||||
#if defined(HAVE_SPARKLE) || defined(HAVE_QTSPARKLE)
|
||||
QAction *check_updates = ui_->menu_tools->addAction(tr("Check for updates..."));
|
||||
check_updates->setMenuRole(QAction::ApplicationSpecificRole);
|
||||
connect(check_updates, SIGNAL(triggered(bool)), SLOT(CheckForUpdates()));
|
||||
@@ -822,42 +854,48 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
// Reload playlist settings, for BG and glowing
|
||||
ui_->playlist->view()->ReloadSettings();
|
||||
|
||||
#ifdef Q_OS_MACOS // Always show mainwindow on startup if on macos
|
||||
#ifdef Q_OS_MACOS // Always show the mainwindow on startup for macOS
|
||||
show();
|
||||
#else
|
||||
QSettings s;
|
||||
s.beginGroup(BehaviourSettingsPage::kSettingsGroup);
|
||||
BehaviourSettingsPage::StartupBehaviour behaviour = BehaviourSettingsPage::StartupBehaviour(s.value("startupbehaviour", BehaviourSettingsPage::Startup_Remember).toInt());
|
||||
s.endGroup();
|
||||
bool hidden = settings_.value("hidden", false).toBool();
|
||||
if (hidden && (!QSystemTrayIcon::isSystemTrayAvailable() || !tray_icon_ || !tray_icon_->IsVisible())) {
|
||||
hidden = false;
|
||||
settings_.setValue("hidden", false);
|
||||
show();
|
||||
}
|
||||
else {
|
||||
switch (behaviour) {
|
||||
case BehaviourSettingsPage::Startup_Remember:
|
||||
was_maximized_ = settings_.value("maximized", true).toBool();
|
||||
if (was_maximized_) setWindowState(windowState() | Qt::WindowMaximized);
|
||||
was_minimized_ = settings_.value("minimized", false).toBool();
|
||||
if (was_minimized_) setWindowState(windowState() | Qt::WindowMinimized);
|
||||
setVisible(!hidden);
|
||||
break;
|
||||
case BehaviourSettingsPage::Startup_Show:
|
||||
show();
|
||||
break;
|
||||
case BehaviourSettingsPage::Startup_Hide:
|
||||
switch (behaviour) {
|
||||
case BehaviourSettingsPage::Startup_Show:
|
||||
show();
|
||||
break;
|
||||
case BehaviourSettingsPage::Startup_ShowMaximized:
|
||||
setWindowState(windowState() | Qt::WindowMaximized);
|
||||
show();
|
||||
break;
|
||||
case BehaviourSettingsPage::Startup_ShowMinimized:
|
||||
setWindowState(windowState() | Qt::WindowMinimized);
|
||||
show();
|
||||
break;
|
||||
case BehaviourSettingsPage::Startup_Hide:
|
||||
if (QSystemTrayIcon::isSystemTrayAvailable() && tray_icon_ && tray_icon_->IsVisible()) {
|
||||
hide();
|
||||
break;
|
||||
case BehaviourSettingsPage::Startup_ShowMaximized:
|
||||
setWindowState(windowState() | Qt::WindowMaximized);
|
||||
}
|
||||
// fallthrough
|
||||
case BehaviourSettingsPage::Startup_Remember:
|
||||
default: {
|
||||
|
||||
was_maximized_ = settings_.value("maximized", true).toBool();
|
||||
if (was_maximized_) setWindowState(windowState() | Qt::WindowMaximized);
|
||||
|
||||
was_minimized_ = settings_.value("minimized", false).toBool();
|
||||
if (was_minimized_) setWindowState(windowState() | Qt::WindowMinimized);
|
||||
|
||||
if (!QSystemTrayIcon::isSystemTrayAvailable() || !tray_icon_ || !tray_icon_->IsVisible()) {
|
||||
settings_.setValue("hidden", false);
|
||||
show();
|
||||
break;
|
||||
case BehaviourSettingsPage::Startup_ShowMinimized:
|
||||
setWindowState(windowState() | Qt::WindowMinimized);
|
||||
show();
|
||||
break;
|
||||
}
|
||||
else {
|
||||
setVisible(!settings_.value("hidden", false).toBool());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -881,6 +919,22 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
app_->scrobbler()->Submit();
|
||||
}
|
||||
|
||||
#ifdef HAVE_QTSPARKLE
|
||||
QUrl sparkle_url;
|
||||
#if defined(Q_OS_MACOS)
|
||||
sparkle_url.setUrl("https://www.strawberrymusicplayer.org/sparkle-macos");
|
||||
#elif defined(Q_OS_WIN)
|
||||
sparkle_url.setUrl("https://www.strawberrymusicplayer.org/sparkle-windows");
|
||||
#endif
|
||||
if (!sparkle_url.isEmpty()) {
|
||||
qLog(Debug) << "Creating Qt Sparkle updater";
|
||||
qtsparkle::Updater *updater = new qtsparkle::Updater(sparkle_url, this);
|
||||
updater->SetNetworkAccessManager(new NetworkAccessManager(this));
|
||||
updater->SetVersion(STRAWBERRY_VERSION_PACKAGE);
|
||||
connect(check_updates, SIGNAL(triggered()), updater, SLOT(CheckNow()));
|
||||
}
|
||||
#endif
|
||||
|
||||
qLog(Debug) << "Started" << QThread::currentThread();
|
||||
initialized_ = true;
|
||||
|
||||
@@ -936,6 +990,8 @@ void MainWindow::ReloadSettings() {
|
||||
}
|
||||
}
|
||||
|
||||
osd_->ReloadSettings();
|
||||
|
||||
album_cover_choice_controller_->search_cover_auto_action()->setChecked(settings_.value("search_for_cover_auto", true).toBool());
|
||||
|
||||
#ifdef HAVE_SUBSONIC
|
||||
@@ -970,7 +1026,6 @@ void MainWindow::ReloadAllSettings() {
|
||||
app_->ReloadSettings();
|
||||
app_->collection()->ReloadSettings();
|
||||
app_->player()->ReloadSettings();
|
||||
osd_->ReloadSettings();
|
||||
collection_view_->ReloadSettings();
|
||||
ui_->playlist->view()->ReloadSettings();
|
||||
app_->playlist_manager()->playlist_container()->ReloadSettings();
|
||||
@@ -1052,7 +1107,7 @@ void MainWindow::ExitFinished() {
|
||||
|
||||
void MainWindow::EngineChanged(Engine::EngineType enginetype) {
|
||||
|
||||
ui_->action_equalizer->setEnabled(enginetype == Engine::EngineType::GStreamer || enginetype == Engine::EngineType::Xine);
|
||||
ui_->action_equalizer->setEnabled(enginetype == Engine::EngineType::GStreamer);
|
||||
#ifdef Q_OS_WIN
|
||||
ui_->action_open_cd->setEnabled(false);
|
||||
ui_->action_open_cd->setVisible(false);
|
||||
@@ -1191,7 +1246,7 @@ void MainWindow::TrackSkipped(PlaylistItemPtr item) {
|
||||
|
||||
void MainWindow::TabSwitched() {
|
||||
|
||||
if (playing_widget_ && ui_->action_toggle_show_sidebar->isChecked() && (ui_->tabs->tabBar()->tabData(ui_->tabs->currentIndex()).toString().toLower() != "context" || !context_view_->album_enabled())) {
|
||||
if (playing_widget_ && ui_->action_toggle_show_sidebar->isChecked() && (ui_->tabs->currentIndex() != ui_->tabs->IndexOfTab(context_view_) || !context_view_->album_enabled())) {
|
||||
ui_->widget_playing->SetEnabled();
|
||||
}
|
||||
else {
|
||||
@@ -1596,14 +1651,14 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
||||
}
|
||||
|
||||
// Are we allowed to pause?
|
||||
if (index.isValid()) {
|
||||
if (source_index.isValid()) {
|
||||
playlist_play_pause_->setEnabled(app_->playlist_manager()->current()->current_row() != source_index.row() || !(app_->playlist_manager()->current()->item_at(source_index.row())->options() & PlaylistItem::PauseDisabled));
|
||||
}
|
||||
else {
|
||||
playlist_play_pause_->setEnabled(false);
|
||||
}
|
||||
|
||||
playlist_stop_after_->setEnabled(index.isValid());
|
||||
playlist_stop_after_->setEnabled(source_index.isValid());
|
||||
|
||||
// Are any of the selected songs editable or queued?
|
||||
QModelIndexList selection = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||
@@ -1615,6 +1670,7 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
||||
int in_skipped = 0;
|
||||
int not_in_skipped = 0;
|
||||
int local_songs = 0;
|
||||
int collection_songs = 0;
|
||||
|
||||
for (const QModelIndex &idx : selection) {
|
||||
|
||||
@@ -1625,6 +1681,7 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
||||
if (!item) continue;
|
||||
|
||||
if (item->Metadata().url().isLocalFile()) ++local_songs;
|
||||
if (item->Metadata().source() == Song::Source_Collection) ++collection_songs;
|
||||
|
||||
if (item->Metadata().has_cue()) {
|
||||
cue_selected = true;
|
||||
@@ -1642,29 +1699,32 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
||||
}
|
||||
|
||||
// this is available when we have one or many files and at least one of those is not CUE related
|
||||
ui_->action_edit_track->setEnabled(editable);
|
||||
ui_->action_edit_track->setVisible(editable);
|
||||
ui_->action_edit_track->setEnabled(editable > 0);
|
||||
ui_->action_edit_track->setVisible(editable > 0);
|
||||
#if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
|
||||
ui_->action_auto_complete_tags->setEnabled(editable);
|
||||
ui_->action_auto_complete_tags->setVisible(editable);
|
||||
#else
|
||||
ui_->action_auto_complete_tags->setEnabled(false);
|
||||
ui_->action_auto_complete_tags->setVisible(false);
|
||||
ui_->action_auto_complete_tags->setEnabled(editable > 0);
|
||||
ui_->action_auto_complete_tags->setVisible(editable > 0);
|
||||
#endif
|
||||
|
||||
ui_->action_rescan_songs->setEnabled(editable);
|
||||
ui_->action_rescan_songs->setVisible(editable);
|
||||
playlist_rescan_songs_->setEnabled(editable > 0);
|
||||
playlist_rescan_songs_->setVisible(editable > 0);
|
||||
|
||||
#ifdef HAVE_GSTREAMER
|
||||
ui_->action_add_files_to_transcoder->setEnabled(editable);
|
||||
ui_->action_add_files_to_transcoder->setVisible(editable);
|
||||
#endif
|
||||
|
||||
// the rest of the read / write actions work only when there are no CUEs involved
|
||||
if (cue_selected) editable = 0;
|
||||
|
||||
playlist_open_in_browser_->setVisible(local_songs == selected);
|
||||
playlist_open_in_browser_->setVisible(selected > 0 && local_songs == selected);
|
||||
|
||||
bool track_column = (index.column() == Playlist::Column_Track);
|
||||
ui_->action_renumber_tracks->setVisible(editable >= 2 && track_column);
|
||||
ui_->action_selection_set_value->setVisible(editable >= 2 && !track_column);
|
||||
ui_->action_edit_value->setVisible(editable);
|
||||
ui_->action_remove_from_playlist->setEnabled(!selection.isEmpty());
|
||||
ui_->action_edit_value->setVisible(editable > 0);
|
||||
ui_->action_remove_from_playlist->setEnabled(selected > 0);
|
||||
ui_->action_remove_from_playlist->setVisible(selected > 0);
|
||||
|
||||
playlist_show_in_collection_->setVisible(false);
|
||||
playlist_copy_to_collection_->setVisible(false);
|
||||
@@ -1672,7 +1732,9 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
||||
#if defined(HAVE_GSTREAMER) && !defined(Q_OS_WIN)
|
||||
playlist_copy_to_device_->setVisible(false);
|
||||
#endif
|
||||
playlist_organise_->setVisible(false);
|
||||
playlist_organize_->setVisible(false);
|
||||
|
||||
playlist_copy_url_->setVisible(selected > 0);
|
||||
|
||||
if (selected < 1) {
|
||||
playlist_queue_->setVisible(false);
|
||||
@@ -1715,7 +1777,7 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
||||
else {
|
||||
|
||||
Playlist::Column column = static_cast<Playlist::Column>(index.column());
|
||||
bool column_is_editable = Playlist::column_is_editable(column) && editable;
|
||||
bool column_is_editable = Playlist::column_is_editable(column) && editable > 0;
|
||||
|
||||
ui_->action_selection_set_value->setVisible(ui_->action_selection_set_value->isVisible() && column_is_editable);
|
||||
ui_->action_edit_value->setVisible(ui_->action_edit_value->isVisible() && column_is_editable);
|
||||
@@ -1730,17 +1792,17 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
||||
// Is it a collection item?
|
||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
||||
if (item && item->IsLocalCollectionItem() && item->Metadata().id() != -1) {
|
||||
playlist_organise_->setVisible(editable);
|
||||
playlist_show_in_collection_->setVisible(editable);
|
||||
playlist_organize_->setVisible(editable > 0);
|
||||
playlist_show_in_collection_->setVisible(editable > 0);
|
||||
playlist_open_in_browser_->setVisible(true);
|
||||
}
|
||||
else {
|
||||
playlist_copy_to_collection_->setVisible(editable);
|
||||
playlist_move_to_collection_->setVisible(editable);
|
||||
playlist_copy_to_collection_->setVisible(editable > 0);
|
||||
playlist_move_to_collection_->setVisible(editable > 0);
|
||||
}
|
||||
|
||||
#if defined(HAVE_GSTREAMER) && !defined(Q_OS_WIN)
|
||||
playlist_copy_to_device_->setVisible(editable);
|
||||
playlist_copy_to_device_->setVisible(editable > 0);
|
||||
#endif
|
||||
|
||||
// Remove old item actions, if any.
|
||||
@@ -1758,32 +1820,36 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
||||
if (playlist_add_to_another_ != nullptr) {
|
||||
playlist_menu_->removeAction(playlist_add_to_another_);
|
||||
delete playlist_add_to_another_;
|
||||
playlist_add_to_another_ = nullptr;
|
||||
}
|
||||
|
||||
// create the playlist submenu
|
||||
QMenu *add_to_another_menu = new QMenu(tr("Add to another playlist"), this);
|
||||
add_to_another_menu->setIcon(IconLoader::Load("list-add"));
|
||||
// Create the playlist submenu if songs are selected.
|
||||
if (selected > 0) {
|
||||
QMenu *add_to_another_menu = new QMenu(tr("Add to another playlist"), this);
|
||||
add_to_another_menu->setIcon(IconLoader::Load("list-add"));
|
||||
|
||||
for (const PlaylistBackend::Playlist &playlist : app_->playlist_backend()->GetAllOpenPlaylists()) {
|
||||
// don't add the current playlist
|
||||
if (playlist.id != app_->playlist_manager()->current()->id()) {
|
||||
QAction *existing_playlist = new QAction(this);
|
||||
existing_playlist->setText(playlist.name);
|
||||
existing_playlist->setData(playlist.id);
|
||||
add_to_another_menu->addAction(existing_playlist);
|
||||
for (const PlaylistBackend::Playlist &playlist : app_->playlist_backend()->GetAllOpenPlaylists()) {
|
||||
// don't add the current playlist
|
||||
if (playlist.id != app_->playlist_manager()->current()->id()) {
|
||||
QAction *existing_playlist = new QAction(this);
|
||||
existing_playlist->setText(playlist.name);
|
||||
existing_playlist->setData(playlist.id);
|
||||
add_to_another_menu->addAction(existing_playlist);
|
||||
}
|
||||
}
|
||||
|
||||
add_to_another_menu->addSeparator();
|
||||
// add to a new playlist
|
||||
QAction *new_playlist = new QAction(this);
|
||||
new_playlist->setText(tr("New playlist"));
|
||||
new_playlist->setData(-1); // fake id
|
||||
add_to_another_menu->addAction(new_playlist);
|
||||
playlist_add_to_another_ = playlist_menu_->insertMenu(ui_->action_remove_from_playlist, add_to_another_menu);
|
||||
|
||||
connect(add_to_another_menu, SIGNAL(triggered(QAction*)), SLOT(AddToPlaylist(QAction*)));
|
||||
|
||||
}
|
||||
|
||||
add_to_another_menu->addSeparator();
|
||||
// add to a new playlist
|
||||
QAction *new_playlist = new QAction(this);
|
||||
new_playlist->setText(tr("New playlist"));
|
||||
new_playlist->setData(-1); // fake id
|
||||
add_to_another_menu->addAction(new_playlist);
|
||||
playlist_add_to_another_ = playlist_menu_->insertMenu(ui_->action_remove_from_playlist, add_to_another_menu);
|
||||
|
||||
connect(add_to_another_menu, SIGNAL(triggered(QAction*)), SLOT(AddToPlaylist(QAction*)));
|
||||
|
||||
playlist_menu_->popup(global_pos);
|
||||
|
||||
}
|
||||
@@ -1811,8 +1877,13 @@ void MainWindow::RescanSongs() {
|
||||
const QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
|
||||
if (!source_index.isValid()) continue;
|
||||
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
|
||||
if (!item || !item->IsLocalCollectionItem()) continue;
|
||||
songs << item->Metadata();
|
||||
if (!item) continue;
|
||||
if (item->IsLocalCollectionItem()) {
|
||||
songs << item->Metadata();
|
||||
}
|
||||
else if (item->Metadata().source() == Song::Source_LocalFile) {
|
||||
item->Reload();
|
||||
}
|
||||
}
|
||||
|
||||
if (songs.isEmpty()) return;
|
||||
@@ -1831,7 +1902,7 @@ void MainWindow::EditTracks() {
|
||||
if (!source_index.isValid()) continue;
|
||||
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
|
||||
if (!item) continue;
|
||||
Song song = item->Metadata();
|
||||
Song song = item->OriginalMetadata();
|
||||
if (song.IsEditable()) {
|
||||
songs << song;
|
||||
items << item;
|
||||
@@ -1868,7 +1939,7 @@ void MainWindow::RenumberTracks() {
|
||||
|
||||
// if first selected song has a track number set, start from that offset
|
||||
if (!indexes.isEmpty()) {
|
||||
const Song first_song = app_->playlist_manager()->current()->item_at(indexes[0].row())->Metadata();
|
||||
const Song first_song = app_->playlist_manager()->current()->item_at(indexes[0].row())->OriginalMetadata();
|
||||
if (first_song.track() > 0) track = first_song.track();
|
||||
}
|
||||
|
||||
@@ -1877,7 +1948,7 @@ void MainWindow::RenumberTracks() {
|
||||
if (!source_index.isValid()) continue;
|
||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
||||
if (!item) continue;
|
||||
Song song = item->Metadata();
|
||||
Song song = item->OriginalMetadata();
|
||||
if (song.IsEditable()) {
|
||||
song.set_track(track);
|
||||
TagReaderReply *reply = TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
|
||||
@@ -1907,7 +1978,7 @@ void MainWindow::SelectionSetValue() {
|
||||
if (!source_index.isValid()) continue;
|
||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
||||
if (!item) continue;
|
||||
Song song = item->Metadata();
|
||||
Song song = item->OriginalMetadata();
|
||||
if (!song.is_valid() || !song.url().isLocalFile()) continue;
|
||||
if (Playlist::set_column_value(song, column, column_value)) {
|
||||
TagReaderReply *reply = TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
|
||||
@@ -2013,13 +2084,13 @@ void MainWindow::ShowInCollection() {
|
||||
if (!source_index.isValid()) continue;
|
||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
||||
if (item && item->IsLocalCollectionItem()) {
|
||||
songs << item->Metadata();
|
||||
songs << item->OriginalMetadata();
|
||||
break;
|
||||
}
|
||||
}
|
||||
QString search;
|
||||
if (!songs.isEmpty()) {
|
||||
search ="artist:" + songs.first().artist() + " album:" + songs.first().album();
|
||||
search = "artist:" + songs.first().artist() + " album:" + songs.first().album();
|
||||
}
|
||||
collection_view_->filter()->ShowInCollection(search);
|
||||
|
||||
@@ -2210,7 +2281,7 @@ void MainWindow::AddFilesToTranscoder() {
|
||||
if (!source_index.isValid()) continue;
|
||||
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
|
||||
if (!item) continue;
|
||||
Song song = item->Metadata();
|
||||
Song song = item->OriginalMetadata();
|
||||
if (!song.is_valid() || !song.url().isLocalFile()) continue;
|
||||
filenames << song.url().toLocalFile();
|
||||
}
|
||||
@@ -2252,29 +2323,29 @@ void MainWindow::PlayingWidgetPositionChanged(const bool above_status_bar) {
|
||||
|
||||
void MainWindow::CopyFilesToCollection(const QList<QUrl> &urls) {
|
||||
|
||||
organise_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
||||
organise_dialog_->SetUrls(urls);
|
||||
organise_dialog_->SetCopy(true);
|
||||
organise_dialog_->show();
|
||||
organize_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
||||
organize_dialog_->SetUrls(urls);
|
||||
organize_dialog_->SetCopy(true);
|
||||
organize_dialog_->show();
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::MoveFilesToCollection(const QList<QUrl> &urls) {
|
||||
|
||||
organise_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
||||
organise_dialog_->SetUrls(urls);
|
||||
organise_dialog_->SetCopy(false);
|
||||
organise_dialog_->show();
|
||||
organize_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
||||
organize_dialog_->SetUrls(urls);
|
||||
organize_dialog_->SetCopy(false);
|
||||
organize_dialog_->show();
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::CopyFilesToDevice(const QList<QUrl> &urls) {
|
||||
|
||||
#if defined(HAVE_GSTREAMER) && !defined(Q_OS_WIN)
|
||||
organise_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
||||
organise_dialog_->SetCopy(true);
|
||||
if (organise_dialog_->SetUrls(urls))
|
||||
organise_dialog_->show();
|
||||
organize_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
||||
organize_dialog_->SetCopy(true);
|
||||
if (organize_dialog_->SetUrls(urls))
|
||||
organize_dialog_->show();
|
||||
else {
|
||||
QMessageBox::warning(this, tr("Error"), tr("None of the selected songs were suitable for copying to a device"));
|
||||
}
|
||||
@@ -2301,14 +2372,14 @@ void MainWindow::EditFileTags(const QList<QUrl> &urls) {
|
||||
}
|
||||
|
||||
void MainWindow::PlaylistCopyToCollection() {
|
||||
PlaylistOrganiseSelected(true);
|
||||
PlaylistOrganizeSelected(true);
|
||||
}
|
||||
|
||||
void MainWindow::PlaylistMoveToCollection() {
|
||||
PlaylistOrganiseSelected(false);
|
||||
PlaylistOrganizeSelected(false);
|
||||
}
|
||||
|
||||
void MainWindow::PlaylistOrganiseSelected(const bool copy) {
|
||||
void MainWindow::PlaylistOrganizeSelected(const bool copy) {
|
||||
|
||||
SongList songs;
|
||||
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
||||
@@ -2316,16 +2387,16 @@ void MainWindow::PlaylistOrganiseSelected(const bool copy) {
|
||||
if (!source_index.isValid()) continue;
|
||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
||||
if (!item) continue;
|
||||
Song song = item->Metadata();
|
||||
Song song = item->OriginalMetadata();
|
||||
if (!song.is_valid() || !song.url().isLocalFile()) continue;
|
||||
songs << song;
|
||||
}
|
||||
if (songs.isEmpty()) return;
|
||||
|
||||
organise_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
||||
organise_dialog_->SetSongs(songs);
|
||||
organise_dialog_->SetCopy(copy);
|
||||
organise_dialog_->show();
|
||||
organize_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
||||
organize_dialog_->SetSongs(songs);
|
||||
organize_dialog_->SetCopy(copy);
|
||||
organize_dialog_->show();
|
||||
|
||||
}
|
||||
|
||||
@@ -2342,6 +2413,25 @@ void MainWindow::PlaylistOpenInBrowser() {
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::PlaylistCopyUrl() {
|
||||
|
||||
QList<QUrl> urls;
|
||||
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
||||
const QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
|
||||
if (!source_index.isValid()) continue;
|
||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
||||
if (!item) continue;
|
||||
urls << item->StreamUrl();
|
||||
}
|
||||
|
||||
if (urls.count() > 0) {
|
||||
QMimeData *mime_data = new QMimeData;
|
||||
mime_data->setUrls(urls);
|
||||
QApplication::clipboard()->setMimeData(mime_data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::PlaylistQueue() {
|
||||
|
||||
QModelIndexList indexes;
|
||||
@@ -2387,16 +2477,16 @@ void MainWindow::PlaylistCopyToDevice() {
|
||||
if (!source_index.isValid()) continue;
|
||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
||||
if (!item) continue;
|
||||
Song song = item->Metadata();
|
||||
Song song = item->OriginalMetadata();
|
||||
if (!song.is_valid() || !song.url().isLocalFile()) continue;
|
||||
songs << song;
|
||||
}
|
||||
if (songs.isEmpty()) return;
|
||||
|
||||
organise_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
||||
organise_dialog_->SetCopy(true);
|
||||
if (organise_dialog_->SetSongs(songs))
|
||||
organise_dialog_->show();
|
||||
organize_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
||||
organize_dialog_->SetCopy(true);
|
||||
if (organize_dialog_->SetSongs(songs))
|
||||
organize_dialog_->show();
|
||||
else {
|
||||
QMessageBox::warning(this, tr("Error"), tr("None of the selected songs were suitable for copying to a device"));
|
||||
}
|
||||
@@ -2427,7 +2517,7 @@ void MainWindow::ShowCoverManager() {
|
||||
|
||||
SettingsDialog *MainWindow::CreateSettingsDialog() {
|
||||
|
||||
SettingsDialog *settings_dialog = new SettingsDialog(app_, this);
|
||||
SettingsDialog *settings_dialog = new SettingsDialog(app_, osd_, this);
|
||||
#ifdef HAVE_GLOBALSHORTCUTS
|
||||
settings_dialog->SetGlobalShortcutManager(global_shortcuts_);
|
||||
#endif
|
||||
@@ -2436,7 +2526,7 @@ SettingsDialog *MainWindow::CreateSettingsDialog() {
|
||||
connect(settings_dialog, SIGNAL(ReloadSettings()), SLOT(ReloadAllSettings()));
|
||||
|
||||
// Allows custom notification preview
|
||||
connect(settings_dialog, SIGNAL(NotificationPreview(OSD::Behaviour, QString, QString)), SLOT(HandleNotificationPreview(OSD::Behaviour, QString, QString)));
|
||||
connect(settings_dialog, SIGNAL(NotificationPreview(OSDBase::Behaviour, QString, QString)), SLOT(HandleNotificationPreview(OSDBase::Behaviour, QString, QString)));
|
||||
return settings_dialog;
|
||||
|
||||
}
|
||||
@@ -2531,7 +2621,11 @@ void MainWindow::Raise() {
|
||||
activateWindow();
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) {
|
||||
#else
|
||||
bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) {
|
||||
#endif
|
||||
|
||||
Q_UNUSED(eventType);
|
||||
Q_UNUSED(result);
|
||||
@@ -2573,7 +2667,7 @@ void MainWindow::AutoCompleteTags() {
|
||||
if (!source_index.isValid()) continue;
|
||||
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
|
||||
if (!item) continue;
|
||||
Song song = item->Metadata();
|
||||
Song song = item->OriginalMetadata();
|
||||
if (song.IsEditable()) {
|
||||
songs << song;
|
||||
autocomplete_tag_items_ << item;
|
||||
@@ -2602,7 +2696,7 @@ void MainWindow::AutoCompleteTagsAccepted() {
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::HandleNotificationPreview(OSD::Behaviour type, QString line1, QString line2) {
|
||||
void MainWindow::HandleNotificationPreview(OSDBase::Behaviour type, QString line1, QString line2) {
|
||||
|
||||
if (!app_->playlist_manager()->current()->GetAllSongs().isEmpty()) {
|
||||
// Show a preview notification for the first song in the current playlist
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
#include "engine/enginetype.h"
|
||||
#include "engine/engine_fwd.h"
|
||||
#include "mac_startup.h"
|
||||
#include "widgets/osd.h"
|
||||
#include "osd/osdbase.h"
|
||||
#include "collection/collectionmodel.h"
|
||||
#include "playlist/playlistitem.h"
|
||||
#include "settings/settingsdialog.h"
|
||||
@@ -77,7 +77,7 @@ class ErrorDialog;
|
||||
class FileView;
|
||||
class GlobalShortcuts;
|
||||
class MimeData;
|
||||
class OrganiseDialog;
|
||||
class OrganizeDialog;
|
||||
class PlaylistListContainer;
|
||||
class QueueView;
|
||||
class SystemTrayIcon;
|
||||
@@ -100,7 +100,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, const CommandlineOptions& options, QWidget *parent = nullptr);
|
||||
explicit MainWindow(Application *app, SystemTrayIcon *tray_icon, OSDBase *osd, const CommandlineOptions& options, QWidget *parent = nullptr);
|
||||
~MainWindow() override;
|
||||
|
||||
static const char *kSettingsGroup;
|
||||
@@ -112,7 +112,11 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result) override;
|
||||
#else
|
||||
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
|
||||
#endif
|
||||
|
||||
// PlatformInterface
|
||||
void Activate() override;
|
||||
@@ -164,8 +168,9 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
void PlaylistCopyToCollection();
|
||||
void PlaylistMoveToCollection();
|
||||
void PlaylistCopyToDevice();
|
||||
void PlaylistOrganiseSelected(const bool copy);
|
||||
void PlaylistOrganizeSelected(const bool copy);
|
||||
void PlaylistOpenInBrowser();
|
||||
void PlaylistCopyUrl();
|
||||
void ShowInCollection();
|
||||
|
||||
void ChangeCollectionQueryMode(QAction *action);
|
||||
@@ -238,7 +243,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
void Exit();
|
||||
void DoExit();
|
||||
|
||||
void HandleNotificationPreview(const OSD::Behaviour type, QString line1, QString line2);
|
||||
void HandleNotificationPreview(const OSDBase::Behaviour type, QString line1, QString line2);
|
||||
|
||||
void ShowConsole();
|
||||
|
||||
@@ -283,7 +288,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
|
||||
Application *app_;
|
||||
SystemTrayIcon *tray_icon_;
|
||||
OSD *osd_;
|
||||
OSDBase *osd_;
|
||||
Lazy<About> about_dialog_;
|
||||
Lazy<EditTagDialog> edit_tag_dialog_;
|
||||
AlbumCoverChoiceController *album_cover_choice_controller_;
|
||||
@@ -303,7 +308,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
Lazy<SettingsDialog> settings_dialog_;
|
||||
Lazy<AlbumCoverManager> cover_manager_;
|
||||
std::unique_ptr<Equalizer> equalizer_;
|
||||
Lazy<OrganiseDialog> organise_dialog_;
|
||||
Lazy<OrganizeDialog> organize_dialog_;
|
||||
#ifdef HAVE_GSTREAMER
|
||||
Lazy<TranscodeDialog> transcode_dialog_;
|
||||
#endif
|
||||
@@ -326,7 +331,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
QAction *playlist_play_pause_;
|
||||
QAction *playlist_stop_after_;
|
||||
QAction *playlist_undoredo_;
|
||||
QAction *playlist_organise_;
|
||||
QAction *playlist_organize_;
|
||||
QAction *playlist_show_in_collection_;
|
||||
QAction *playlist_copy_to_collection_;
|
||||
QAction *playlist_move_to_collection_;
|
||||
@@ -334,14 +339,14 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
QAction *playlist_copy_to_device_;
|
||||
#endif
|
||||
QAction *playlist_open_in_browser_;
|
||||
QAction *playlist_copy_url_;
|
||||
QAction *playlist_queue_;
|
||||
QAction* playlist_queue_play_next_;
|
||||
QAction *playlist_skip_;
|
||||
QAction *playlist_add_to_another_;
|
||||
QList<QAction*> playlistitem_actions_;
|
||||
QAction *playlistitem_actions_separator_;
|
||||
QAction *search_for_artist_;
|
||||
QAction *search_for_album_;
|
||||
QAction *playlist_rescan_songs_;
|
||||
|
||||
QModelIndex playlist_menu_index_;
|
||||
|
||||
|
||||
@@ -831,11 +831,6 @@
|
||||
<string notr="true">Ctrl+Shift+T</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_rescan_songs">
|
||||
<property name="text">
|
||||
<string>Rescan songs(s)</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_add_stream">
|
||||
<property name="text">
|
||||
<string>Add stream...</string>
|
||||
|
||||
@@ -193,7 +193,7 @@ void MergedProxyModel::SourceModelReset() {
|
||||
|
||||
void MergedProxyModel::SubModelReset() {
|
||||
|
||||
QAbstractItemModel *submodel = static_cast<QAbstractItemModel*>(sender());
|
||||
QAbstractItemModel *submodel = qobject_cast<QAbstractItemModel*>(sender());
|
||||
|
||||
// TODO: When we require Qt 4.6, use beginResetModel() and endResetModel() in CollectionModel and catch those here
|
||||
// that will let us do away with this std::numeric_limits<int>::max() hack.
|
||||
@@ -241,7 +241,7 @@ QModelIndex MergedProxyModel::GetActualSourceParent(const QModelIndex &source_pa
|
||||
}
|
||||
|
||||
void MergedProxyModel::RowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end) {
|
||||
beginInsertRows(mapFromSource(GetActualSourceParent(source_parent, static_cast<QAbstractItemModel*>(sender()))), start, end);
|
||||
beginInsertRows(mapFromSource(GetActualSourceParent(source_parent, qobject_cast<QAbstractItemModel*>(sender()))), start, end);
|
||||
}
|
||||
|
||||
void MergedProxyModel::RowsInserted(const QModelIndex&, int, int) {
|
||||
@@ -249,7 +249,7 @@ void MergedProxyModel::RowsInserted(const QModelIndex&, int, int) {
|
||||
}
|
||||
|
||||
void MergedProxyModel::RowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end) {
|
||||
beginRemoveRows(mapFromSource(GetActualSourceParent(source_parent, static_cast<QAbstractItemModel*>(sender()))), start, end);
|
||||
beginRemoveRows(mapFromSource(GetActualSourceParent(source_parent, qobject_cast<QAbstractItemModel*>(sender()))), start, end);
|
||||
}
|
||||
|
||||
void MergedProxyModel::RowsRemoved(const QModelIndex&, int, int) {
|
||||
|
||||
@@ -32,12 +32,14 @@
|
||||
#include <QMetaType>
|
||||
#include <QFileInfo>
|
||||
#include <QList>
|
||||
#include <QVector>
|
||||
#include <QMap>
|
||||
#include <QByteArray>
|
||||
#include <QUrl>
|
||||
#include <QImage>
|
||||
#include <QNetworkCookie>
|
||||
#include <QNetworkReply>
|
||||
#include <QItemSelection>
|
||||
#ifdef HAVE_DBUS
|
||||
# include <QDBusMetaType>
|
||||
#endif
|
||||
@@ -55,6 +57,7 @@
|
||||
#include "playlist/playlistsequence.h"
|
||||
#include "covermanager/albumcoverloaderresult.h"
|
||||
#include "covermanager/albumcoverfetcher.h"
|
||||
#include "covermanager/coversearchstatistics.h"
|
||||
#include "equalizer/equalizer.h"
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
@@ -69,6 +72,7 @@ void RegisterMetaTypes() {
|
||||
qRegisterMetaType<const char*>("const char*");
|
||||
qRegisterMetaType<QList<int>>("QList<int>");
|
||||
qRegisterMetaType<QList<QUrl>>("QList<QUrl>");
|
||||
qRegisterMetaType<QVector<int>>("QVector<int>");
|
||||
qRegisterMetaType<QFileInfo>("QFileInfo");
|
||||
qRegisterMetaType<QAbstractSocket::SocketState>();
|
||||
qRegisterMetaType<QAbstractSocket::SocketState>("QAbstractSocket::SocketState");
|
||||
@@ -76,7 +80,9 @@ void RegisterMetaTypes() {
|
||||
qRegisterMetaType<QList<QNetworkCookie> >("QList<QNetworkCookie>");
|
||||
qRegisterMetaType<QNetworkReply*>("QNetworkReply*");
|
||||
qRegisterMetaType<QNetworkReply**>("QNetworkReply**");
|
||||
qRegisterMetaTypeStreamOperators<QMap<int, int> >("ColumnAlignmentMap");
|
||||
qRegisterMetaType<QItemSelection>("QItemSelection");
|
||||
qRegisterMetaTypeStreamOperators<QMap<int, Qt::Alignment>>("ColumnAlignmentMap");
|
||||
qRegisterMetaTypeStreamOperators<QMap<int, int>>("ColumnAlignmentIntMap");
|
||||
qRegisterMetaType<Directory>("Directory");
|
||||
qRegisterMetaType<DirectoryList>("DirectoryList");
|
||||
qRegisterMetaType<Subdirectory>("Subdirectory");
|
||||
@@ -102,6 +108,7 @@ void RegisterMetaTypes() {
|
||||
qRegisterMetaType<AlbumCoverLoaderResult>("AlbumCoverLoaderResult");
|
||||
qRegisterMetaType<AlbumCoverLoaderResult::Type>("AlbumCoverLoaderResult::Type");
|
||||
qRegisterMetaType<CoverSearchResult>("CoverSearchResult");
|
||||
qRegisterMetaType<CoverSearchStatistics>("CoverSearchStatistics");
|
||||
qRegisterMetaType<QList<CoverSearchResult> >("QList<CoverSearchResult>");
|
||||
qRegisterMetaType<CoverSearchResults>("CoverSearchResults");
|
||||
qRegisterMetaType<Equalizer::Params>("Equalizer::Params");
|
||||
|
||||
@@ -134,10 +134,9 @@ Mpris2::Mpris2(Application *app, QObject *parent)
|
||||
|
||||
app_name_[0] = app_name_[0].toUpper();
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0))
|
||||
if (!QGuiApplication::desktopFileName().isEmpty())
|
||||
desktop_files_ << QGuiApplication::desktopFileName();
|
||||
#endif
|
||||
|
||||
QStringList domain_split = QCoreApplication::organizationDomain().split(".");
|
||||
std::reverse(domain_split.begin(), domain_split.end());
|
||||
desktop_files_ << QStringList() << domain_split.join(".") + "." + QCoreApplication::applicationName().toLower();
|
||||
|
||||
@@ -56,7 +56,7 @@ inline void AddMetadata(const QString &key, const QDateTime &metadata, QVariantM
|
||||
}
|
||||
|
||||
inline QString AsMPRISDateTimeType(const int time) {
|
||||
return time != -1 ? QDateTime::fromTime_t(time).toString(Qt::ISODate) : "";
|
||||
return time != -1 ? QDateTime::fromSecsSinceEpoch(time).toString(Qt::ISODate) : "";
|
||||
}
|
||||
|
||||
} // namespace mpris
|
||||
|
||||
@@ -127,7 +127,11 @@ QNetworkReply *NetworkAccessManager::createRequest(Operation op, const QNetworkR
|
||||
}
|
||||
|
||||
QNetworkRequest new_request(request);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
|
||||
new_request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
#else
|
||||
new_request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
#endif
|
||||
new_request.setRawHeader("User-Agent", user_agent);
|
||||
|
||||
if (op == QNetworkAccessManager::PostOperation && !new_request.header(QNetworkRequest::ContentTypeHeader).isValid()) {
|
||||
|
||||
@@ -51,9 +51,6 @@
|
||||
# include "engine/gstengine.h"
|
||||
# include "engine/gststartup.h"
|
||||
#endif
|
||||
#ifdef HAVE_XINE
|
||||
# include "engine/xineengine.h"
|
||||
#endif
|
||||
#ifdef HAVE_VLC
|
||||
# include "engine/vlcengine.h"
|
||||
#endif
|
||||
@@ -125,12 +122,6 @@ Engine::EngineType Player::CreateEngine(Engine::EngineType enginetype) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_XINE
|
||||
case Engine::Xine:
|
||||
use_enginetype=Engine::Xine;
|
||||
engine_.reset(new XineEngine(app_->task_manager()));
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_VLC
|
||||
case Engine::VLC:
|
||||
use_enginetype=Engine::VLC;
|
||||
@@ -267,8 +258,7 @@ void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
|
||||
switch (result.type_) {
|
||||
case UrlHandler::LoadResult::Error:
|
||||
if (is_current) {
|
||||
EngineStateChanged(Engine::Error);
|
||||
FatalError();
|
||||
InvalidSongRequested(result.original_url_);
|
||||
}
|
||||
emit Error(result.error_);
|
||||
break;
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
#include <QUrl>
|
||||
#include <QImage>
|
||||
#include <QIcon>
|
||||
@@ -148,9 +148,9 @@ const QString Song::kFtsUpdateSpec = Utilities::Updateify(Song::kFtsColumns).joi
|
||||
const QString Song::kManuallyUnsetCover = "(unset)";
|
||||
const QString Song::kEmbeddedCover = "(embedded)";
|
||||
|
||||
const QRegExp Song::kAlbumRemoveDisc(" ?-? ((\\(|\\[)?)(Disc|CD) ?([0-9]{1,2})((\\)|\\])?)$");
|
||||
const QRegExp Song::kAlbumRemoveMisc(" ?-? ((\\(|\\[)?)(Remastered|([0-9]{1,4}) *Remaster) ?((\\)|\\])?)$");
|
||||
const QRegExp Song::kTitleRemoveMisc(" ?-? ((\\(|\\[)?)(Remastered|Live|Remastered Version|([0-9]{1,4}) *Remaster) ?((\\)|\\])?)$");
|
||||
const QRegularExpression Song::kAlbumRemoveDisc(" ?-? ((\\(|\\[)?)(Disc|CD) ?([0-9]{1,2})((\\)|\\])?)$");
|
||||
const QRegularExpression Song::kAlbumRemoveMisc(" ?-? ((\\(|\\[)?)(Remastered|([0-9]{1,4}) *Remaster) ?((\\)|\\])?)$");
|
||||
const QRegularExpression Song::kTitleRemoveMisc(" ?-? ((\\(|\\[)?)(Remastered|Live|Remastered Version|([0-9]{1,4}) *Remaster) ?((\\)|\\])?)$");
|
||||
const QString Song::kVariousArtists("various artists");
|
||||
|
||||
const QStringList Song::kArticles = QStringList() << "the " << "a " << "an ";
|
||||
@@ -199,8 +199,8 @@ struct Song::Private : public QSharedData {
|
||||
QUrl url_;
|
||||
FileType filetype_;
|
||||
int filesize_;
|
||||
int mtime_;
|
||||
int ctime_;
|
||||
qint64 mtime_;
|
||||
qint64 ctime_;
|
||||
bool unavailable_;
|
||||
|
||||
int playcount_;
|
||||
@@ -322,8 +322,8 @@ const QUrl &Song::url() const { return d->url_; }
|
||||
const QString &Song::basefilename() const { return d->basefilename_; }
|
||||
Song::FileType Song::filetype() const { return d->filetype_; }
|
||||
int Song::filesize() const { return d->filesize_; }
|
||||
uint Song::mtime() const { return d->mtime_; }
|
||||
uint Song::ctime() const { return d->ctime_; }
|
||||
qint64 Song::mtime() const { return d->mtime_; }
|
||||
qint64 Song::ctime() const { return d->ctime_; }
|
||||
|
||||
int Song::playcount() const { return d->playcount_; }
|
||||
int Song::skipcount() const { return d->skipcount_; }
|
||||
@@ -428,8 +428,8 @@ void Song::set_url(const QUrl &v) { d->url_ = v; }
|
||||
void Song::set_basefilename(const QString &v) { d->basefilename_ = v; }
|
||||
void Song::set_filetype(FileType v) { d->filetype_ = v; }
|
||||
void Song::set_filesize(int v) { d->filesize_ = v; }
|
||||
void Song::set_mtime(int v) { d->mtime_ = v; }
|
||||
void Song::set_ctime(int v) { d->ctime_ = v; }
|
||||
void Song::set_mtime(qint64 v) { d->mtime_ = v; }
|
||||
void Song::set_ctime(qint64 v) { d->ctime_ = v; }
|
||||
void Song::set_unavailable(bool v) { d->unavailable_ = v; }
|
||||
|
||||
void Song::set_playcount(int v) { d->playcount_ = v; }
|
||||
@@ -925,10 +925,10 @@ void Song::InitFromQuery(const SqlRow &q, bool reliable_metadata, int col) {
|
||||
d->filesize_ = toint(x);
|
||||
}
|
||||
else if (Song::kColumns.value(i) == "mtime") {
|
||||
d->mtime_ = toint(x);
|
||||
d->mtime_ = tolonglong(x);
|
||||
}
|
||||
else if (Song::kColumns.value(i) == "ctime") {
|
||||
d->ctime_ = toint(x);
|
||||
d->ctime_ = tolonglong(x);
|
||||
}
|
||||
else if (Song::kColumns.value(i) == "unavailable") {
|
||||
d->unavailable_ = q.value(x).toBool();
|
||||
@@ -958,7 +958,7 @@ void Song::InitFromQuery(const SqlRow &q, bool reliable_metadata, int col) {
|
||||
|
||||
else if (Song::kColumns.value(i) == "art_automatic") {
|
||||
QString art_automatic = tostr(x);
|
||||
if (art_automatic.contains(QRegExp("..+:.*"))) {
|
||||
if (art_automatic.contains(QRegularExpression("..+:.*"))) {
|
||||
set_art_automatic(QUrl::fromEncoded(art_automatic.toUtf8()));
|
||||
}
|
||||
else {
|
||||
@@ -967,7 +967,7 @@ void Song::InitFromQuery(const SqlRow &q, bool reliable_metadata, int col) {
|
||||
}
|
||||
else if (Song::kColumns.value(i) == "art_manual") {
|
||||
QString art_manual = tostr(x);
|
||||
if (art_manual.contains(QRegExp("..+:.*"))) {
|
||||
if (art_manual.contains(QRegularExpression("..+:.*"))) {
|
||||
set_art_manual(QUrl::fromEncoded(art_manual.toUtf8()));
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
#include <QUrl>
|
||||
#include <QImage>
|
||||
#include <QIcon>
|
||||
@@ -120,10 +120,9 @@ class Song {
|
||||
static const QString kManuallyUnsetCover;
|
||||
static const QString kEmbeddedCover;
|
||||
|
||||
static const QRegExp kAlbumRemoveDisc;
|
||||
static const QRegExp kAlbumRemoveMisc;
|
||||
static const QRegExp kTitleRemoveMisc;
|
||||
static const QRegExp kFilenameRemoveNonFatChars;
|
||||
static const QRegularExpression kAlbumRemoveDisc;
|
||||
static const QRegularExpression kAlbumRemoveMisc;
|
||||
static const QRegularExpression kTitleRemoveMisc;
|
||||
|
||||
static const QString kVariousArtists;
|
||||
|
||||
@@ -228,8 +227,8 @@ class Song {
|
||||
const QString &basefilename() const;
|
||||
FileType filetype() const;
|
||||
int filesize() const;
|
||||
uint mtime() const;
|
||||
uint ctime() const;
|
||||
qint64 mtime() const;
|
||||
qint64 ctime() const;
|
||||
|
||||
int playcount() const;
|
||||
int skipcount() const;
|
||||
@@ -329,8 +328,8 @@ class Song {
|
||||
void set_basefilename(const QString &v);
|
||||
void set_filetype(FileType v);
|
||||
void set_filesize(int v);
|
||||
void set_mtime(int v);
|
||||
void set_ctime(int v);
|
||||
void set_mtime(qint64 v);
|
||||
void set_ctime(qint64 v);
|
||||
void set_unavailable(bool v);
|
||||
|
||||
void set_playcount(int v);
|
||||
|
||||
@@ -90,9 +90,8 @@ void StyleSheetLoader::UpdateStyleSheet(QWidget *widget, StyleSheetData styledat
|
||||
.arg(alt.alpha()));
|
||||
|
||||
ReplaceColor(&stylesheet, "Window", p, QPalette::Window);
|
||||
ReplaceColor(&stylesheet, "Background", p, QPalette::Background);
|
||||
ReplaceColor(&stylesheet, "Background", p, QPalette::Window);
|
||||
ReplaceColor(&stylesheet, "WindowText", p, QPalette::WindowText);
|
||||
ReplaceColor(&stylesheet, "Foreground", p, QPalette::Foreground);
|
||||
ReplaceColor(&stylesheet, "Base", p, QPalette::Base);
|
||||
ReplaceColor(&stylesheet, "AlternateBase", p, QPalette::AlternateBase);
|
||||
ReplaceColor(&stylesheet, "ToolTipBase", p, QPalette::ToolTipBase);
|
||||
|
||||
@@ -50,7 +50,8 @@
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatch>
|
||||
#include <QTcpServer>
|
||||
#include <QTemporaryFile>
|
||||
#include <QPoint>
|
||||
@@ -157,7 +158,7 @@ QString WordyTimeNanosec(qint64 nanoseconds) {
|
||||
QString Ago(int seconds_since_epoch, const QLocale &locale) {
|
||||
|
||||
const QDateTime now = QDateTime::currentDateTime();
|
||||
const QDateTime then = QDateTime::fromTime_t(seconds_since_epoch);
|
||||
const QDateTime then = QDateTime::fromSecsSinceEpoch(seconds_since_epoch);
|
||||
const int days_ago = then.date().daysTo(now.date());
|
||||
const QString time = then.time().toString(locale.timeFormat(QLocale::ShortFormat));
|
||||
|
||||
@@ -336,8 +337,10 @@ QString ColorToRgba(const QColor &c) {
|
||||
}
|
||||
|
||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
|
||||
void OpenInFileManager(const QString &path);
|
||||
void OpenInFileManager(const QString &path) {
|
||||
void OpenInFileManager(const QString path, const QUrl &url);
|
||||
void OpenInFileManager(const QString path, const QUrl &url) {
|
||||
|
||||
if (!url.isLocalFile()) return;
|
||||
|
||||
QProcess proc;
|
||||
proc.start("xdg-mime", QStringList() << "query" << "default" << "inode/directory");
|
||||
@@ -375,29 +378,22 @@ void OpenInFileManager(const QString &path) {
|
||||
}
|
||||
|
||||
if (command.isEmpty() || command == "exo-open") {
|
||||
QFileInfo info(path);
|
||||
if (!info.exists()) return;
|
||||
QString directory = info.dir().path();
|
||||
if (directory.isEmpty()) return;
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(directory));
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
||||
}
|
||||
else if (command.startsWith("nautilus")) {
|
||||
proc.startDetached(command, QStringList() << command_params << "--select" << path);
|
||||
proc.startDetached(command, QStringList() << command_params << "--select" << url.toLocalFile());
|
||||
}
|
||||
else if (command.startsWith("dolphin") || command.startsWith("konqueror") || command.startsWith("kfmclient")) {
|
||||
proc.startDetached(command, QStringList() << command_params << "--select" << "--new-window" << path);
|
||||
proc.startDetached(command, QStringList() << command_params << "--select" << "--new-window" << url.toLocalFile());
|
||||
}
|
||||
else if (command.startsWith("caja")) {
|
||||
QFileInfo info(path);
|
||||
if (!info.exists()) return;
|
||||
QString directory = info.dir().path();
|
||||
proc.startDetached(command, QStringList() << command_params << "--no-desktop" << directory);
|
||||
proc.startDetached(command, QStringList() << command_params << "--no-desktop" << path);
|
||||
}
|
||||
else if (command.startsWith("pcmanfm")) {
|
||||
proc.startDetached(command, QStringList() << command_params << QFileInfo(path).dir().path());
|
||||
proc.startDetached(command, QStringList() << command_params << path);
|
||||
}
|
||||
else {
|
||||
proc.startDetached(command, QStringList() << command_params << path);
|
||||
proc.startDetached(command, QStringList() << command_params << url.toLocalFile());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -405,28 +401,42 @@ void OpenInFileManager(const QString &path) {
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
// Better than openUrl(dirname(path)) - also highlights file at path
|
||||
void RevealFileInFinder(QString const &path) {
|
||||
void RevealFileInFinder(const QString &path) {
|
||||
QProcess::execute("/usr/bin/open", QStringList() << "-R" << path);
|
||||
}
|
||||
#endif // Q_OS_MACOS
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void ShowFileInExplorer(QString const &path);
|
||||
void ShowFileInExplorer(QString const &path) {
|
||||
void ShowFileInExplorer(const QString &path);
|
||||
void ShowFileInExplorer(const QString &path) {
|
||||
QProcess::execute("explorer.exe", QStringList() << "/select," << QDir::toNativeSeparators(path));
|
||||
}
|
||||
#endif
|
||||
|
||||
void OpenInFileBrowser(const QList<QUrl> &urls) {
|
||||
|
||||
if (urls.count() > 50) {
|
||||
QMap<QString, QUrl> dirs;
|
||||
|
||||
for (const QUrl &url : urls) {
|
||||
if (!url.isLocalFile()) {
|
||||
continue;
|
||||
}
|
||||
QString path = url.toLocalFile();
|
||||
if (!QFile::exists(path)) continue;
|
||||
|
||||
const QString directory = QFileInfo(path).dir().path();
|
||||
if (dirs.contains(directory)) continue;
|
||||
dirs.insert(directory, url);
|
||||
}
|
||||
|
||||
if (dirs.count() > 50) {
|
||||
QMessageBox messagebox(QMessageBox::Critical, tr("Show in file browser"), tr("Too many songs selected."));
|
||||
messagebox.exec();
|
||||
return;
|
||||
}
|
||||
|
||||
if (urls.count() > 5) {
|
||||
QMessageBox messagebox(QMessageBox::Information, tr("Show in file browser"), tr("%1 songs selected, are you sure you want to open them all?").arg(urls.count()), QMessageBox::Open|QMessageBox::Cancel);
|
||||
if (dirs.count() > 5) {
|
||||
QMessageBox messagebox(QMessageBox::Information, tr("Show in file browser"), tr("%1 songs in %2 different directories selected, are you sure you want to open them all?").arg(urls.count()).arg(dirs.count()), QMessageBox::Open|QMessageBox::Cancel);
|
||||
messagebox.setTextFormat(Qt::RichText);
|
||||
int result = messagebox.exec();
|
||||
switch (result) {
|
||||
@@ -438,27 +448,15 @@ void OpenInFileBrowser(const QList<QUrl> &urls) {
|
||||
}
|
||||
}
|
||||
|
||||
QSet<QString> dirs;
|
||||
|
||||
for (const QUrl &url : urls) {
|
||||
if (!url.isLocalFile()) {
|
||||
continue;
|
||||
}
|
||||
QString path = url.toLocalFile();
|
||||
|
||||
if (!QFile::exists(path)) continue;
|
||||
|
||||
const QString directory = QFileInfo(path).dir().path();
|
||||
if (dirs.contains(directory)) continue;
|
||||
dirs.insert(directory);
|
||||
|
||||
QMap<QString, QUrl>::iterator i;
|
||||
for (i = dirs.begin(); i != dirs.end(); ++i) {
|
||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
|
||||
OpenInFileManager(path);
|
||||
OpenInFileManager(i.key(), i.value());
|
||||
#elif defined(Q_OS_MACOS)
|
||||
// Revealing multiple files in the finder only opens one window, so it also makes sense to reveal at most one per directory
|
||||
RevealFileInFinder(path);
|
||||
RevealFileInFinder(i.value().toLocalFile());
|
||||
#elif defined(Q_OS_WIN32)
|
||||
ShowFileInExplorer(path);
|
||||
ShowFileInExplorer(i.value().toLocalFile());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -533,16 +531,6 @@ QString PrettySize(const QSize &size) {
|
||||
return QString::number(size.width()) + "x" + QString::number(size.height());
|
||||
}
|
||||
|
||||
void ForwardMouseEvent(const QMouseEvent *e, QWidget *target) {
|
||||
QMouseEvent c(e->type(), target->mapFromGlobal(e->globalPos()), e->globalPos(), e->button(), e->buttons(), e->modifiers());
|
||||
|
||||
QApplication::sendEvent(target, &c);
|
||||
}
|
||||
|
||||
bool IsMouseEventInWidget(const QMouseEvent *e, const QWidget *widget) {
|
||||
return widget->rect().contains(widget->mapFromGlobal(e->globalPos()));
|
||||
}
|
||||
|
||||
quint16 PickUnusedPort() {
|
||||
|
||||
forever {
|
||||
@@ -613,8 +601,9 @@ bool ParseUntilElementCI(QXmlStreamReader *reader, const QString &name) {
|
||||
|
||||
QDateTime ParseRFC822DateTime(const QString &text) {
|
||||
|
||||
QRegExp regexp("(\\d{1,2}) (\\w{3,12}) (\\d+) (\\d{1,2}):(\\d{1,2}):(\\d{1,2})");
|
||||
if (regexp.indexIn(text) == -1) {
|
||||
QRegularExpression regexp("(\\d{1,2}) (\\w{3,12}) (\\d+) (\\d{1,2}):(\\d{1,2}):(\\d{1,2})");
|
||||
QRegularExpressionMatch re_match = regexp.match(text);
|
||||
if (!re_match.hasMatch()) {
|
||||
return QDateTime();
|
||||
}
|
||||
|
||||
@@ -646,9 +635,9 @@ QDateTime ParseRFC822DateTime(const QString &text) {
|
||||
monthmap["November"] = 11;
|
||||
monthmap["December"] = 12;
|
||||
|
||||
const QDate date(regexp.cap(static_cast<int>(MatchNames::YEARS)).toInt(), monthmap[regexp.cap(static_cast<int>(MatchNames::MONTHS))], regexp.cap(static_cast<int>(MatchNames::DAYS)).toInt());
|
||||
const QDate date(re_match.captured(static_cast<int>(MatchNames::YEARS)).toInt(), monthmap[re_match.captured(static_cast<int>(MatchNames::MONTHS))], re_match.captured(static_cast<int>(MatchNames::DAYS)).toInt());
|
||||
|
||||
const QTime time(regexp.cap(static_cast<int>(MatchNames::HOURS)).toInt(), regexp.cap(static_cast<int>(MatchNames::MINUTES)).toInt(), regexp.cap(static_cast<int>(MatchNames::SECONDS)).toInt());
|
||||
const QTime time(re_match.captured(static_cast<int>(MatchNames::HOURS)).toInt(), re_match.captured(static_cast<int>(MatchNames::MINUTES)).toInt(), re_match.captured(static_cast<int>(MatchNames::SECONDS)).toInt());
|
||||
|
||||
return QDateTime(date, time);
|
||||
|
||||
@@ -932,19 +921,20 @@ QString MacAddress() {
|
||||
|
||||
QString ReplaceMessage(const QString &message, const Song &song, const QString &newline) {
|
||||
|
||||
QRegExp variable_replacer("[%][a-z]+[%]");
|
||||
QRegularExpression variable_replacer("[%][a-z]+[%]");
|
||||
QString copy(message);
|
||||
|
||||
// Replace the first line
|
||||
int pos = 0;
|
||||
variable_replacer.indexIn(message);
|
||||
while ((pos = variable_replacer.indexIn(message, pos)) != -1) {
|
||||
QStringList captured = variable_replacer.capturedTexts();
|
||||
QRegularExpressionMatch match;
|
||||
for (match = variable_replacer.match(message, pos) ; match.hasMatch() ; match = variable_replacer.match(message, pos)) {
|
||||
pos = match.capturedStart();
|
||||
QStringList captured = match.capturedTexts();
|
||||
copy.replace(captured[0], ReplaceVariable(captured[0], song, newline));
|
||||
pos += variable_replacer.matchedLength();
|
||||
pos += match.capturedLength();
|
||||
}
|
||||
|
||||
int index_of = copy.indexOf(QRegExp(" - (>|$)"));
|
||||
int index_of = copy.indexOf(QRegularExpression(" - (>|$)"));
|
||||
if (index_of >= 0) copy = copy.remove(index_of, 3);
|
||||
|
||||
return copy;
|
||||
|
||||
@@ -85,12 +85,6 @@ QByteArray Sha1CoverHash(const QString &artist, const QString &album);
|
||||
// Picks an unused ephemeral port number. Doesn't hold the port open so there's the obvious race condition
|
||||
quint16 PickUnusedPort();
|
||||
|
||||
// Forwards a mouse event to a different widget, remapping the event's widget coordinates relative to those of the target widget.
|
||||
void ForwardMouseEvent(const QMouseEvent *e, QWidget *target);
|
||||
|
||||
// Checks if the mouse event was inside the widget's rectangle.
|
||||
bool IsMouseEventInWidget(const QMouseEvent *e, const QWidget *widget);
|
||||
|
||||
// Reads all children of the current element,
|
||||
// and returns with the stream reader either on the EndElement for the current element, or the end of the file - whichever came first.
|
||||
void ConsumeCurrentElement(QXmlStreamReader *reader);
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
#include <QUrl>
|
||||
#include <QImage>
|
||||
#include <QImageWriter>
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
#include "collection/collectionbackend.h"
|
||||
#include "settings/collectionsettingspage.h"
|
||||
#include "organise/organiseformat.h"
|
||||
#include "organize/organizeformat.h"
|
||||
#include "internet/internetservices.h"
|
||||
#include "internet/internetservice.h"
|
||||
#include "albumcoverchoicecontroller.h"
|
||||
@@ -163,8 +163,8 @@ void AlbumCoverChoiceController::SaveCoverToFileManual(const Song &song, const Q
|
||||
}
|
||||
initial_file_name = initial_file_name + "-" + (song.effective_album().isEmpty() ? tr("unknown") : song.effective_album()) + ".jpg";
|
||||
initial_file_name = initial_file_name.toLower();
|
||||
initial_file_name.replace(QRegExp("\\s"), "-");
|
||||
initial_file_name.remove(OrganiseFormat::kInvalidFatCharacters);
|
||||
initial_file_name.replace(QRegularExpression("\\s"), "-");
|
||||
initial_file_name.remove(OrganizeFormat::kInvalidFatCharacters);
|
||||
|
||||
QString save_filename = QFileDialog::getSaveFileName(this, tr("Save album cover"), GetInitialPathForFileDialog(song, initial_file_name), tr(kSaveImageFileFilter) + ";;" + tr(kAllFilesFilter));
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ struct CoverSearchRequest {
|
||||
|
||||
// This structure represents a single result of some album's cover search request.
|
||||
struct CoverSearchResult {
|
||||
explicit CoverSearchResult() : score(0.0) {}
|
||||
explicit CoverSearchResult() : score_provider(0.0), score_match(0.0), score_quality(0.0), number(0) {}
|
||||
|
||||
// Used for grouping in the user interface.
|
||||
QString provider;
|
||||
@@ -73,8 +73,23 @@ struct CoverSearchResult {
|
||||
// An URL of a cover image
|
||||
QUrl image_url;
|
||||
|
||||
// Image size
|
||||
QSize image_size;
|
||||
|
||||
// Score for this provider
|
||||
float score_provider;
|
||||
|
||||
// Score for match
|
||||
float score_match;
|
||||
|
||||
// Score for image quality
|
||||
float score_quality;
|
||||
|
||||
// The result number
|
||||
int number;
|
||||
|
||||
// Total score for this result
|
||||
float score;
|
||||
float score() const { return score_provider + score_match + score_quality; }
|
||||
|
||||
};
|
||||
Q_DECLARE_METATYPE(CoverSearchResult)
|
||||
|
||||
@@ -98,8 +98,8 @@ void AlbumCoverFetcherSearch::Start(CoverProviders *cover_providers) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If album is missing, check if we can still use this provider by searching using artist + title.
|
||||
if (!provider->allow_missing_album() && request_.album.isEmpty()) {
|
||||
// If artist and album is missing, check if we can still use this provider by searching using title.
|
||||
if (!provider->allow_missing_album() && request_.album.isEmpty() && !request_.title.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -133,17 +133,81 @@ void AlbumCoverFetcherSearch::ProviderSearchResults(CoverProvider *provider, con
|
||||
|
||||
CoverSearchResults results_copy(results);
|
||||
for (int i = 0 ; i < results_copy.count() ; ++i) {
|
||||
|
||||
results_copy[i].provider = provider->name();
|
||||
results_copy[i].score = provider->quality();
|
||||
if (results_copy[i].artist.toLower() == request_.artist.toLower()) {
|
||||
results_copy[i].score += 0.5;
|
||||
results_copy[i].score_provider = provider->quality();
|
||||
|
||||
QString request_artist = request_.artist.toLower();
|
||||
QString request_album = request_.album.toLower();
|
||||
QString result_artist = results_copy[i].artist.toLower();
|
||||
QString result_album = results_copy[i].album.toLower();
|
||||
|
||||
if (result_artist == request_artist) {
|
||||
results_copy[i].score_match += 0.5;
|
||||
}
|
||||
if (results_copy[i].album.toLower() == request_.album.toLower()) {
|
||||
results_copy[i].score += 0.5;
|
||||
if (result_album == request_album) {
|
||||
results_copy[i].score_match += 0.5;
|
||||
}
|
||||
if (results_copy[i].artist.toLower() != request_.artist.toLower() && results_copy[i].album.toLower() != request_.album.toLower()) {
|
||||
results_copy[i].score -= 1.5;
|
||||
if (result_artist != request_artist && result_album != request_album) {
|
||||
results_copy[i].score_match -= 1.5;
|
||||
}
|
||||
|
||||
if (request_album.isEmpty() && result_artist != request_artist) {
|
||||
results_copy[i].score_match -= 1;
|
||||
}
|
||||
|
||||
// Decrease score if the search was based on artist and song title, and the resulting album is a compilation or live album.
|
||||
// This is done since we can't match the album titles, and we want to prevent compilation or live albums from being picked before studio albums for streams.
|
||||
// TODO: Make these regular expressions.
|
||||
if (request_album.isEmpty() && (
|
||||
result_album.contains("hits") ||
|
||||
result_album.contains("greatest") ||
|
||||
result_album.contains("best") ||
|
||||
result_album.contains("collection") ||
|
||||
result_album.contains("classics") ||
|
||||
result_album.contains("singles") ||
|
||||
result_album.contains("bootleg") ||
|
||||
result_album.contains("live") ||
|
||||
result_album.contains("concert") ||
|
||||
result_album.contains("essential") ||
|
||||
result_album.contains("ultimate") ||
|
||||
result_album.contains("karaoke") ||
|
||||
result_album.contains("mixtape") ||
|
||||
result_album.contains("country rock") ||
|
||||
result_album.contains("indie folk") ||
|
||||
result_album.contains("soft rock") ||
|
||||
result_album.contains("folk music") ||
|
||||
result_album.contains("60's rock") ||
|
||||
result_album.contains("60's romance") ||
|
||||
result_album.contains("60s music") ||
|
||||
result_album.contains("late 60s") ||
|
||||
result_album.contains("the 60s") ||
|
||||
result_album.contains("folk and blues") ||
|
||||
result_album.contains("60 from the 60's") ||
|
||||
result_album.contains("classic psychedelic") ||
|
||||
result_album.contains("playlist: acoustic") ||
|
||||
result_album.contains("90's rnb playlist") ||
|
||||
result_album.contains("rock 80s") ||
|
||||
result_album.contains("classic 80s") ||
|
||||
result_album.contains("rock anthems") ||
|
||||
result_album.contains("rock songs") ||
|
||||
result_album.contains("rock 2019") ||
|
||||
result_album.contains("guitar anthems") ||
|
||||
result_album.contains("driving anthems") ||
|
||||
result_album.contains("traffic jam jams") ||
|
||||
result_album.contains("perfect background music") ||
|
||||
result_album.contains("70's gold") ||
|
||||
result_album.contains("rockfluence") ||
|
||||
result_album.contains("acoustic dinner accompaniment") ||
|
||||
result_album.contains("complete studio albums") ||
|
||||
result_album.contains("mellow rock")
|
||||
)) {
|
||||
results_copy[i].score_match -= 1;
|
||||
}
|
||||
|
||||
// Set the initial image quality score besed on the size returned by the API, this is recalculated when the image is received.
|
||||
results_copy[i].score_quality += ScoreImage(results_copy[i].image_size);
|
||||
|
||||
}
|
||||
|
||||
// Add results from the current provider to our pool
|
||||
@@ -204,10 +268,14 @@ void AlbumCoverFetcherSearch::FetchMoreImages() {
|
||||
++i;
|
||||
CoverSearchResult result = results_.takeFirst();
|
||||
|
||||
qLog(Debug) << "Loading" << result.image_url << "from" << result.provider << "with current score" << result.score;
|
||||
qLog(Debug) << "Loading" << result.artist << result.album << result.image_url << "from" << result.provider << "with current score" << result.score();
|
||||
|
||||
QNetworkRequest req(result.image_url);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
|
||||
req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
#else
|
||||
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
#endif
|
||||
QNetworkReply *image_reply = network_->get(req);
|
||||
connect(image_reply, &QNetworkReply::finished, [=] { ProviderCoverFetchFinished(image_reply); });
|
||||
pending_image_loads_[image_reply] = result;
|
||||
@@ -251,9 +319,13 @@ void AlbumCoverFetcherSearch::ProviderCoverFetchFinished(QNetworkReply *reply) {
|
||||
if (QImageReader::supportedMimeTypes().contains(mimetype.toUtf8())) {
|
||||
QImage image;
|
||||
if (image.loadFromData(reply->readAll())) {
|
||||
result.score += ScoreImage(image);
|
||||
candidate_images_.insert(result.score, CandidateImage(result, image));
|
||||
qLog(Debug) << reply->url() << "from" << result.provider << "scored" << result.score;
|
||||
if (result.image_size != QSize(0,0) && result.image_size != image.size()) {
|
||||
qLog(Debug) << "API size for image" << result.image_size << "for" << reply->url() << "from" << result.provider << "did not match retrieved size" << image.size();
|
||||
}
|
||||
result.image_size = image.size();
|
||||
result.score_quality = ScoreImage(image.size());
|
||||
candidate_images_.insert(result.score(), CandidateImage(result, image));
|
||||
qLog(Debug) << reply->url() << "from" << result.provider << "scored" << result.score();
|
||||
}
|
||||
else {
|
||||
qLog(Error) << "Error decoding image data from" << reply->url();
|
||||
@@ -283,18 +355,15 @@ void AlbumCoverFetcherSearch::ProviderCoverFetchFinished(QNetworkReply *reply) {
|
||||
|
||||
}
|
||||
|
||||
float AlbumCoverFetcherSearch::ScoreImage(const QImage &image) const {
|
||||
float AlbumCoverFetcherSearch::ScoreImage(const QSize size) const {
|
||||
|
||||
// Invalid images score nothing
|
||||
if (image.isNull()) {
|
||||
return 0.0;
|
||||
}
|
||||
if (size.width() == 0 || size.height() == 0) return 0.0;
|
||||
|
||||
// A 500x500px image scores 1.0, bigger scores higher
|
||||
const float size_score = std::sqrt(float(image.width() * image.height())) / kTargetSize;
|
||||
const float size_score = std::sqrt(float(size.width() * size.height())) / kTargetSize;
|
||||
|
||||
// A 1:1 image scores 1.0, anything else scores less
|
||||
const float aspect_score = 1.0 - float(std::max(image.width(), image.height()) - std::min(image.width(), image.height())) / std::max(image.height(), image.width());
|
||||
const float aspect_score = 1.0 - float(std::max(size.width(), size.height()) - std::min(size.width(), size.height())) / std::max(size.height(), size.width());
|
||||
|
||||
return size_score + aspect_score;
|
||||
|
||||
@@ -310,7 +379,7 @@ void AlbumCoverFetcherSearch::SendBestImage() {
|
||||
cover_url = best_image.first.image_url;
|
||||
image = best_image.second;
|
||||
|
||||
qLog(Info) << "Using" << best_image.first.image_url << "from" << best_image.first.provider << "with score" << best_image.first.score;
|
||||
qLog(Info) << "Using" << best_image.first.image_url << "from" << best_image.first.provider << "with score" << best_image.first.score();
|
||||
|
||||
statistics_.chosen_images_by_provider_[best_image.first.provider]++;
|
||||
statistics_.chosen_images_++;
|
||||
@@ -348,5 +417,9 @@ bool AlbumCoverFetcherSearch::ProviderCompareOrder(CoverProvider *a, CoverProvid
|
||||
}
|
||||
|
||||
bool AlbumCoverFetcherSearch::CoverSearchResultCompareScore(const CoverSearchResult &a, const CoverSearchResult &b) {
|
||||
return a.score > b.score;
|
||||
return a.score() > b.score();
|
||||
}
|
||||
|
||||
bool AlbumCoverFetcherSearch::CoverSearchResultCompareNumber(const CoverSearchResult &a, const CoverSearchResult &b) {
|
||||
return a.number < b.number;
|
||||
}
|
||||
|
||||
@@ -59,6 +59,8 @@ class AlbumCoverFetcherSearch : public QObject {
|
||||
|
||||
CoverSearchStatistics statistics() const { return statistics_; }
|
||||
|
||||
static bool CoverSearchResultCompareNumber(const CoverSearchResult &a, const CoverSearchResult &b);
|
||||
|
||||
signals:
|
||||
// It's the end of search (when there was no fetch-me-a-cover request).
|
||||
void SearchFinished(const quint64, const CoverSearchResults &results);
|
||||
@@ -77,7 +79,7 @@ class AlbumCoverFetcherSearch : public QObject {
|
||||
void AllProvidersFinished();
|
||||
|
||||
void FetchMoreImages();
|
||||
float ScoreImage(const QImage &image) const;
|
||||
float ScoreImage(const QSize size) const;
|
||||
void SendBestImage();
|
||||
|
||||
static bool ProviderCompareOrder(CoverProvider *a, CoverProvider *b);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user