Compare commits
167 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4683db900 | ||
|
|
5a90643ba8 | ||
|
|
4a1ab2f004 | ||
|
|
36be755a78 | ||
|
|
ffd8c88b1f | ||
|
|
84ff163b34 | ||
|
|
811e625618 | ||
|
|
037b0d7dea | ||
|
|
d578d3c66d | ||
|
|
2644dbd5ab | ||
|
|
245103dc30 | ||
|
|
eb30c654c5 | ||
|
|
3b925c24ad | ||
|
|
beefdabc64 | ||
|
|
91e06cadf3 | ||
|
|
4ea5eb8292 | ||
|
|
af06f8e70a | ||
|
|
3238e295ba | ||
|
|
26fbd5c144 | ||
|
|
e64a2b98c4 | ||
|
|
42417e5554 | ||
|
|
82e613206e | ||
|
|
f1038152e9 | ||
|
|
2597a8faed | ||
|
|
8008ec895a | ||
|
|
d85d25b931 | ||
|
|
de62552ad1 | ||
|
|
155485173b | ||
|
|
82079fcf70 | ||
|
|
3b2eea5292 | ||
|
|
1f2ad9c177 | ||
|
|
cc6e5a6c69 | ||
|
|
c77c7a247a | ||
|
|
552440f50e | ||
|
|
2a9ccd7480 | ||
|
|
f265c055a5 | ||
|
|
837e5388ea | ||
|
|
9883dc6925 | ||
|
|
e3ad00e930 | ||
|
|
6428ae8b3a | ||
|
|
07c182d5b8 | ||
|
|
64aa15842c | ||
|
|
19c8da06e6 | ||
|
|
7dd959f4a1 | ||
|
|
148ae530d8 | ||
|
|
e75698ee9a | ||
|
|
80bea31b98 | ||
|
|
4ea57d1181 | ||
|
|
854847ca8a | ||
|
|
bd39e7cb0d | ||
|
|
20ef621a20 | ||
|
|
145c276c97 | ||
|
|
1c5d0dceb1 | ||
|
|
359f320b06 | ||
|
|
108d522dcf | ||
|
|
96e746c508 | ||
|
|
b2c862e7d5 | ||
|
|
9334fe9f24 | ||
|
|
b964385024 | ||
|
|
3f3059c98b | ||
|
|
8da616491d | ||
|
|
cb0db8750f | ||
|
|
08224443e3 | ||
|
|
5c2989196f | ||
|
|
4c4c84e104 | ||
|
|
232399ea28 | ||
|
|
9d22e4ec07 | ||
|
|
ee5bc16e47 | ||
|
|
74f0f885b9 | ||
|
|
b914d9aaba | ||
|
|
136f150d67 | ||
|
|
5b50cbb61b | ||
|
|
cb3a9bf195 | ||
|
|
cb847951e6 | ||
|
|
11228f0634 | ||
|
|
a0889d60f1 | ||
|
|
0055ebe8a7 | ||
|
|
58c7a9b9cc | ||
|
|
6afc081ff0 | ||
|
|
2c0ad2fc88 | ||
|
|
77e934beab | ||
|
|
368022ec43 | ||
|
|
69f8ca95bc | ||
|
|
dde8661e93 | ||
|
|
2604e1a0ff | ||
|
|
e8471bcc66 | ||
|
|
d230dd7365 | ||
|
|
74dce24e91 | ||
|
|
bc667a6474 | ||
|
|
a2cae06582 | ||
|
|
5212587055 | ||
|
|
efd42bc68f | ||
|
|
ebaa2e7918 | ||
|
|
7ebcc73a49 | ||
|
|
be09011bb7 | ||
|
|
2778a55e8e | ||
|
|
9b5fe3bfd6 | ||
|
|
91eef0d695 | ||
|
|
88704efad8 | ||
|
|
f4e4483392 | ||
|
|
63102bce23 | ||
|
|
8890a3dd0f | ||
|
|
3d9dec2c27 | ||
|
|
c96ad61c80 | ||
|
|
acd74d5b54 | ||
|
|
4808188964 | ||
|
|
1bb045b3b0 | ||
|
|
bdca60c0ad | ||
|
|
8d9c135498 | ||
|
|
0f76482916 | ||
|
|
38eb86bdee | ||
|
|
cbce9892d5 | ||
|
|
f624b7a331 | ||
|
|
1ebcd61a75 | ||
|
|
358da72ffe | ||
|
|
9666feca37 | ||
|
|
03eb52eac8 | ||
|
|
6562cc710c | ||
|
|
222001bc13 | ||
|
|
e93f14248a | ||
|
|
7119f1bc81 | ||
|
|
548fa3f6ee | ||
|
|
8ddd309d5d | ||
|
|
8c8acbb546 | ||
|
|
fe30f27af3 | ||
|
|
d5d2eaba8a | ||
|
|
e8f64bfe8f | ||
|
|
79b03993b0 | ||
|
|
e3b8f9cb8c | ||
|
|
819463a865 | ||
|
|
c69777ca39 | ||
|
|
40f3e828aa | ||
|
|
dc8520ebec | ||
|
|
7ffbedf0dd | ||
|
|
826fad1ad4 | ||
|
|
1c4d3aebad | ||
|
|
ff6e93fc15 | ||
|
|
17e88bb97d | ||
|
|
d3dd26c596 | ||
|
|
c2a7509e0e | ||
|
|
079040b721 | ||
|
|
b80d239820 | ||
|
|
c3ff43dac2 | ||
|
|
4ac51afd8f | ||
|
|
26eab51698 | ||
|
|
388dcf2a1f | ||
|
|
9bfd14d067 | ||
|
|
061e0562d1 | ||
|
|
2ba20b013d | ||
|
|
dc36f87a6e | ||
|
|
e82ecb48b8 | ||
|
|
c56a134179 | ||
|
|
11028456ad | ||
|
|
81fcb02974 | ||
|
|
5ef4976c53 | ||
|
|
160356072f | ||
|
|
c10df5b634 | ||
|
|
70fdd5b0b3 | ||
|
|
6c1ec51fab | ||
|
|
66b1c22174 | ||
|
|
97138fd6b9 | ||
|
|
03c69be421 | ||
|
|
3a9a952cb0 | ||
|
|
3bd0331aa3 | ||
|
|
3ecf224d91 | ||
|
|
37743606a2 | ||
|
|
58587f4a9a |
57
.github/workflows/build.yml
vendored
57
.github/workflows/build.yml
vendored
@@ -628,7 +628,7 @@ jobs:
|
|||||||
|
|
||||||
upload-ubuntu-ppa:
|
upload-ubuntu-ppa:
|
||||||
name: Upload Ubuntu PPA
|
name: Upload Ubuntu PPA
|
||||||
if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false && (github.event_name == 'release' || (github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/ci')))
|
if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false && (github.event_name == 'release' || (github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/ci' || github.ref == 'refs/heads/1.1')))
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -730,13 +730,27 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
runner: [ 'macos-12' ]
|
runner: [ 'macos-13', 'macos-14' ]
|
||||||
buildtype: [ 'release' ]
|
buildtype: [ 'release' ]
|
||||||
|
|
||||||
runs-on: ${{ matrix.runner }}
|
runs-on: ${{ matrix.runner }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
|
- name: Set MACOSX_DEPLOYMENT_TARGET
|
||||||
|
run: |
|
||||||
|
for i in 12 13 14 15; do
|
||||||
|
if [ -d "/Library/Developer/CommandLineTools/SDKs/MacOSX${i}.sdk" ]; then
|
||||||
|
echo "Using macOS SDK ${i}"
|
||||||
|
echo "MACOSX_DEPLOYMENT_TARGET=${i}.0" >> $GITHUB_ENV
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Verify MACOSX_DEPLOYMENT_TARGET
|
||||||
|
run: |
|
||||||
|
test "${MACOSX_DEPLOYMENT_TARGET}" = "" && false || echo "MACOSX_DEPLOYMENT_TARGET: ${MACOSX_DEPLOYMENT_TARGET}"
|
||||||
|
|
||||||
- name: Set arch
|
- name: Set arch
|
||||||
shell: bash
|
shell: bash
|
||||||
run: echo "arch=$(uname -m)" >> $GITHUB_ENV
|
run: echo "arch=$(uname -m)" >> $GITHUB_ENV
|
||||||
@@ -784,7 +798,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Configure CMake
|
- name: Configure CMake
|
||||||
env:
|
env:
|
||||||
MACOSX_DEPLOYMENT_TARGET: 12.0
|
|
||||||
PKG_CONFIG_PATH: ${{env.prefix_path}}/lib/pkgconfig
|
PKG_CONFIG_PATH: ${{env.prefix_path}}/lib/pkgconfig
|
||||||
LDFLAGS: -L${{env.prefix_path}}/lib -Wl,-rpath,${{env.prefix_path}}/lib
|
LDFLAGS: -L${{env.prefix_path}}/lib -Wl,-rpath,${{env.prefix_path}}/lib
|
||||||
run: >
|
run: >
|
||||||
@@ -801,7 +814,7 @@ jobs:
|
|||||||
-DICU_ROOT="${{env.prefix_path}}"
|
-DICU_ROOT="${{env.prefix_path}}"
|
||||||
-DFFTW3_DIR="${{env.prefix_path}}"
|
-DFFTW3_DIR="${{env.prefix_path}}"
|
||||||
-DAPPLE_DEVELOPER_ID=$(test '${{github.repository}}' = 'strawberrymusicplayer/strawberry' && test '${{github.event.pull_request.base.repo.full_name}}' = '${{github.event.pull_request.head.repo.full_name}}' && echo "383J84DVB6" || echo "")
|
-DAPPLE_DEVELOPER_ID=$(test '${{github.repository}}' = 'strawberrymusicplayer/strawberry' && test '${{github.event.pull_request.base.repo.full_name}}' = '${{github.event.pull_request.head.repo.full_name}}' && echo "383J84DVB6" || echo "")
|
||||||
-DENABLE_SPOTIFY=OFF
|
-DENABLE_SPOTIFY=$(test -f "${{env.prefix_path}}/lib/gstreamer-1.0/libgstspotify.dylib" && echo "ON" || echo "OFF")
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build build --config Release --parallel 4
|
run: cmake --build build --config Release --parallel 4
|
||||||
@@ -820,9 +833,14 @@ jobs:
|
|||||||
run: make deploy
|
run: make deploy
|
||||||
|
|
||||||
- name: Manually Codesign
|
- name: Manually Codesign
|
||||||
if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false
|
if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false && matrix.runner == 'macos-13'
|
||||||
working-directory: build
|
working-directory: build
|
||||||
run: codesign -s 383J84DVB6 -f strawberry.app/Contents/Frameworks/{libsoup-3.0.0.dylib,libnghttp2.14.dylib,libpsl.5.dylib,libpcre2-8.0.dylib,libpcre2-16.0.dylib,libpng16.16.dylib,libzstd.1.dylib,libfreetype.6.dylib} strawberry.app/Contents/Frameworks/png.framework/png strawberry.app
|
run: codesign -s 383J84DVB6 -f strawberry.app/Contents/Frameworks/{libpcre2-8.0.dylib,libpcre2-16.0.dylib,libpng16.16.dylib,libfreetype.6.dylib,libzstd.1.dylib,libutf8_validity.dylib} strawberry.app/Contents/Frameworks/png.framework/png strawberry.app
|
||||||
|
|
||||||
|
- name: Manually Codesign
|
||||||
|
if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false && matrix.runner == 'macos-14'
|
||||||
|
working-directory: build
|
||||||
|
run: codesign -s 383J84DVB6 -f strawberry.app/Contents/Frameworks/png.framework/png strawberry.app
|
||||||
|
|
||||||
- name: Deploy check
|
- name: Deploy check
|
||||||
working-directory: build
|
working-directory: build
|
||||||
@@ -877,6 +895,20 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
|
- name: Set MACOSX_DEPLOYMENT_TARGET
|
||||||
|
run: |
|
||||||
|
for i in 12 13 14 15; do
|
||||||
|
if [ -d "/Library/Developer/CommandLineTools/SDKs/MacOSX${i}.sdk" ]; then
|
||||||
|
echo "Using macOS SDK ${i}"
|
||||||
|
echo "MACOSX_DEPLOYMENT_TARGET=${i}.0" >> $GITHUB_ENV
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Verify MACOSX_DEPLOYMENT_TARGET
|
||||||
|
run: |
|
||||||
|
test "${MACOSX_DEPLOYMENT_TARGET}" = "" && false || echo "MACOSX_DEPLOYMENT_TARGET: ${MACOSX_DEPLOYMENT_TARGET}"
|
||||||
|
|
||||||
- name: Set arch
|
- name: Set arch
|
||||||
shell: bash
|
shell: bash
|
||||||
run: echo "arch=$(uname -m)" >> $GITHUB_ENV
|
run: echo "arch=$(uname -m)" >> $GITHUB_ENV
|
||||||
@@ -907,7 +939,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Configure CMake
|
- name: Configure CMake
|
||||||
env:
|
env:
|
||||||
MACOSX_DEPLOYMENT_TARGET: 11.0
|
|
||||||
PKG_CONFIG_PATH: ${{env.prefix_path}}/lib/pkgconfig
|
PKG_CONFIG_PATH: ${{env.prefix_path}}/lib/pkgconfig
|
||||||
LDFLAGS: -L${{env.prefix_path}}/lib -Wl,-rpath,${{env.prefix_path}}/lib
|
LDFLAGS: -L${{env.prefix_path}}/lib -Wl,-rpath,${{env.prefix_path}}/lib
|
||||||
run: >
|
run: >
|
||||||
@@ -924,7 +955,7 @@ jobs:
|
|||||||
-DICU_ROOT="${{env.prefix_path}}"
|
-DICU_ROOT="${{env.prefix_path}}"
|
||||||
-DFFTW3_DIR="${{env.prefix_path}}"
|
-DFFTW3_DIR="${{env.prefix_path}}"
|
||||||
-DAPPLE_DEVELOPER_ID="383J84DVB6"
|
-DAPPLE_DEVELOPER_ID="383J84DVB6"
|
||||||
-DENABLE_SPOTIFY=OFF
|
-DENABLE_SPOTIFY=$(test -f "${{env.prefix_path}}/lib/gstreamer-1.0/libgstspotify.dylib" && echo "ON" || echo "OFF")
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build build --config Release --parallel 4
|
run: cmake --build build --config Release --parallel 4
|
||||||
@@ -967,11 +998,11 @@ jobs:
|
|||||||
echo "upload_path=${{secrets.DOWNLOADS_PATH}}/development_releases/macos" >> $GITHUB_OUTPUT
|
echo "upload_path=${{secrets.DOWNLOADS_PATH}}/development_releases/macos" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Create server path
|
#- name: Create server path
|
||||||
run: ssh -p ${{secrets.SSH_PORT}} -o StrictHostKeyChecking=no ${{secrets.SSH_USER}}@${{secrets.SSH_HOST}} mkdir -p ${{steps.set-upload-path.outputs.upload_path}}
|
#run: ssh -p ${{secrets.SSH_PORT}} -o StrictHostKeyChecking=no ${{secrets.SSH_USER}}@${{secrets.SSH_HOST}} mkdir -p ${{steps.set-upload-path.outputs.upload_path}}
|
||||||
|
|
||||||
- name: rsync
|
#- name: rsync
|
||||||
run: rsync -e "ssh -p ${{secrets.SSH_PORT}} -o StrictHostKeyChecking=no" -var build/*.dmg ${{secrets.SSH_USER}}@${{secrets.SSH_HOST}}:${{steps.set-upload-path.outputs.upload_path}}/
|
#run: rsync -e "ssh -p ${{secrets.SSH_PORT}} -o StrictHostKeyChecking=no" -var build/*.dmg ${{secrets.SSH_USER}}@${{secrets.SSH_HOST}}:${{steps.set-upload-path.outputs.upload_path}}/
|
||||||
|
|
||||||
|
|
||||||
build-windows-mingw:
|
build-windows-mingw:
|
||||||
@@ -1517,7 +1548,7 @@ jobs:
|
|||||||
upload_path="${{secrets.RELEASES_PATH}}/"
|
upload_path="${{secrets.RELEASES_PATH}}/"
|
||||||
else
|
else
|
||||||
distro=$(echo "$i" | cut -d '/' -f 2)
|
distro=$(echo "$i" | cut -d '/' -f 2)
|
||||||
if [ "$(echo "$i" | grep '-' || true)" = "" ]; then
|
if [ -z "$(echo "${distro}" | grep '-' || true)" ]; then
|
||||||
upload_path="${{secrets.BUILDS_PATH}}/${distro}/"
|
upload_path="${{secrets.BUILDS_PATH}}/${distro}/"
|
||||||
else
|
else
|
||||||
distro_name=$(echo "${distro}" | cut -d '-' -f 1)
|
distro_name=$(echo "${distro}" | cut -d '-' -f 1)
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -13,4 +13,6 @@
|
|||||||
/dist/scripts/maketarball.sh
|
/dist/scripts/maketarball.sh
|
||||||
/dist/unix/strawberry.spec
|
/dist/unix/strawberry.spec
|
||||||
/dist/windows/strawberry.nsi
|
/dist/windows/strawberry.nsi
|
||||||
src/translations/translations.pot
|
/debian/control
|
||||||
|
/debian/changelog
|
||||||
|
/dist/macos/Info.plist
|
||||||
|
|||||||
17
3rdparty/README.md
vendored
17
3rdparty/README.md
vendored
@@ -2,20 +2,27 @@
|
|||||||
============================================
|
============================================
|
||||||
|
|
||||||
KDSingleApplication
|
KDSingleApplication
|
||||||
-----------------
|
-------------------
|
||||||
This is a small static library used by Strawberry to prevent it from starting twice per user session.
|
A small library used by Strawberry to prevent it from starting twice per user session.
|
||||||
If the user tries to start strawberry twice, the main window will maximize instead of starting another instance.
|
If the user tries to start strawberry twice, the main window will maximize instead of starting another instance.
|
||||||
It is also used to pass command-line options through to the first instance.
|
It is also used to pass command-line options through to the first instance.
|
||||||
|
This 3rdparty copy is used only if KDSingleApplication 1.1 or higher is not found on the system.
|
||||||
|
|
||||||
URL: https://github.com/KDAB/KDSingleApplication/
|
URL: https://github.com/KDAB/KDSingleApplication/
|
||||||
|
|
||||||
|
|
||||||
SPMediaKeyTap
|
SPMediaKeyTap
|
||||||
-------------
|
-------------
|
||||||
Used on macOS to exclusively enable strawberry to grab global media shortcuts.
|
A library used on macOS to exclusively grab global media shortcuts.
|
||||||
Can safely be deleted on other platforms.
|
|
||||||
|
|
||||||
|
The library is no longer maintained by the original author.
|
||||||
|
|
||||||
|
The directory can safely be deleted on other platforms.
|
||||||
|
|
||||||
getopt
|
getopt
|
||||||
------
|
------
|
||||||
getopt included only when compiling on Windows.
|
getopt included on Windows for command line options parsing with Unicode support .
|
||||||
|
|
||||||
|
The directory can safely be deleted on other platforms.
|
||||||
|
|
||||||
|
URL: https://github.com/ludvikjerabek/getopt-win
|
||||||
|
|||||||
2
3rdparty/kdsingleapplication/CMakeLists.txt
vendored
2
3rdparty/kdsingleapplication/CMakeLists.txt
vendored
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.7)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
set(SOURCES KDSingleApplication/src/kdsingleapplication.cpp KDSingleApplication/src/kdsingleapplication_localsocket.cpp)
|
set(SOURCES KDSingleApplication/src/kdsingleapplication.cpp KDSingleApplication/src/kdsingleapplication_localsocket.cpp)
|
||||||
set(HEADERS KDSingleApplication/src/kdsingleapplication.h KDSingleApplication/src/kdsingleapplication_localsocket_p.h)
|
set(HEADERS KDSingleApplication/src/kdsingleapplication.h KDSingleApplication/src/kdsingleapplication_localsocket_p.h)
|
||||||
qt_wrap_cpp(MOC ${HEADERS})
|
qt_wrap_cpp(MOC ${HEADERS})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.7)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
project(strawberry)
|
project(strawberry)
|
||||||
|
|
||||||
@@ -84,6 +84,13 @@ add_compile_options(${COMPILE_OPTIONS})
|
|||||||
|
|
||||||
if(CMAKE_BUILD_TYPE MATCHES "Release")
|
if(CMAKE_BUILD_TYPE MATCHES "Release")
|
||||||
add_definitions(-DNDEBUG)
|
add_definitions(-DNDEBUG)
|
||||||
|
set(ENABLE_DEBUG_OUTPUT_DEFAULT OFF)
|
||||||
|
else()
|
||||||
|
set(ENABLE_DEBUG_OUTPUT_DEFAULT ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(ENABLE_DEBUG_OUTPUT "Enable debug output" ${ENABLE_DEBUG_OUTPUT_DEFAULT})
|
||||||
|
if(NOT ENABLE_DEBUG_OUTPUT)
|
||||||
add_definitions(-DQT_NO_DEBUG_OUTPUT)
|
add_definitions(-DQT_NO_DEBUG_OUTPUT)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -92,6 +99,8 @@ if(USE_RPATH)
|
|||||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(QT_NO_SHOW_OLD_QT_WRAP_CPP_WARNING ON)
|
||||||
|
|
||||||
find_program(CCACHE_EXECUTABLE NAMES ccache)
|
find_program(CCACHE_EXECUTABLE NAMES ccache)
|
||||||
if(CCACHE_EXECUTABLE)
|
if(CCACHE_EXECUTABLE)
|
||||||
message(STATUS "ccache found: will be used for compilation and linkage")
|
message(STATUS "ccache found: will be used for compilation and linkage")
|
||||||
@@ -494,6 +503,8 @@ add_definitions(
|
|||||||
-DQT_NO_FOREACH
|
-DQT_NO_FOREACH
|
||||||
-DQT_ASCII_CAST_WARNINGS
|
-DQT_ASCII_CAST_WARNINGS
|
||||||
-DQT_NO_CAST_FROM_ASCII
|
-DQT_NO_CAST_FROM_ASCII
|
||||||
|
-DQT_NO_KEYWORDS
|
||||||
|
-DQT_NO_SIGNALS_SLOTS_KEYWORDS
|
||||||
)
|
)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
|||||||
39
Changelog
39
Changelog
@@ -2,6 +2,45 @@ Strawberry Music Player
|
|||||||
=======================
|
=======================
|
||||||
ChangeLog
|
ChangeLog
|
||||||
|
|
||||||
|
Version 1.1.3 (2024.09.21):
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed gstreamer registry lookup leak in Spotify settings.
|
||||||
|
* Fixed all songs in a CUE sheet starting playback at the zero position (#1549).
|
||||||
|
* Fixed playback going to pause and back to play on song change.
|
||||||
|
* Fixed Genius Lyrics login not working (#1554).
|
||||||
|
* Fixed slow collection filter search.
|
||||||
|
|
||||||
|
Version 1.1.2 (2024.09.12):
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed Tidal Open API cover provider to only login when needed instead of on startup.
|
||||||
|
* Fixed KDE added keyboard accelerator characters (ampersands) appearing in sidebar (#1400, #1389, #1476).
|
||||||
|
* Fixed KDE added keyboard accelerator characters (ampersands) appearing when editing playlist name (#1499).
|
||||||
|
* Fixed collection "Search for this" adding prefix without value (#1510).
|
||||||
|
* Fixed play (-p) command line option not working on startup (#1465).
|
||||||
|
* Fixed scan transaction being started when "Update the collection when Strawberry starts" option is unchecked (#1469)
|
||||||
|
* Fixed Spotify bitrate being limited 128kbit/s.
|
||||||
|
* Fixed Spotify returning too many artists and albums.
|
||||||
|
* Fixed manually switching Spotify songs blocking UI.
|
||||||
|
* Fixed analyzer not being set.
|
||||||
|
* Fixed context top text being updated causing selected text to be unselected.
|
||||||
|
* Fixed filter search to use filename for songs with empty title.
|
||||||
|
* Fixed missing developer in Appstream appdata file.
|
||||||
|
* Fixed MPRIS2 DesktopEntry to return desktop file entry without ".desktop" (#1516)
|
||||||
|
* Fixed WavPack .wvc accepted as valid audio files (#1525).
|
||||||
|
* Fixed dynamic playlist controls not following system colors (#1483).
|
||||||
|
* Fixed freeze on playlist right click (#1478).
|
||||||
|
* Fixed copying songs to a iPod device keeping too many files open (#1527).
|
||||||
|
* Fixed MBIDs from MP4 being parsed incorrectly causing ListenBrainz errors (#1531).
|
||||||
|
* Fixed playlist sorting after filename (#1538).
|
||||||
|
|
||||||
|
Enhancements:
|
||||||
|
* Improved volume adjustment and track seeking using touchpad (#1498).
|
||||||
|
* Use own thread for lyrics parsing.
|
||||||
|
* Added url and filename columns to collection and playlist filter search.
|
||||||
|
* (macOS) Added Spotify.
|
||||||
|
|
||||||
Version 1.1.1 (2024.07.22):
|
Version 1.1.1 (2024.07.22):
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ Resources:
|
|||||||
* Wiki: https://wiki.strawberrymusicplayer.org/
|
* Wiki: https://wiki.strawberrymusicplayer.org/
|
||||||
* Forum: https://forum.strawberrymusicplayer.org/
|
* Forum: https://forum.strawberrymusicplayer.org/
|
||||||
* Github: https://github.com/strawberrymusicplayer/strawberry
|
* Github: https://github.com/strawberrymusicplayer/strawberry
|
||||||
* Buildbot: https://buildbot.strawberrymusicplayer.org/
|
|
||||||
* Latest builds: https://builds.strawberrymusicplayer.org/
|
* Latest builds: https://builds.strawberrymusicplayer.org/
|
||||||
* openSUSE buildservice: https://build.opensuse.org/package/show/home:jonaski:audio/strawberry
|
* openSUSE buildservice: https://build.opensuse.org/package/show/home:jonaski:audio/strawberry
|
||||||
* Ubuntu PPA: https://launchpad.net/~jonaski/+archive/ubuntu/strawberry
|
* Ubuntu PPA: https://launchpad.net/~jonaski/+archive/ubuntu/strawberry
|
||||||
* Ubuntu Unstable PPA: https://launchpad.net/~jonaski/+archive/ubuntu/strawberry-unstable
|
* Ubuntu Unstable PPA: https://launchpad.net/~jonaski/+archive/ubuntu/strawberry-unstable
|
||||||
|
* Translations: https://crowdin.com/project/strawberrymusicplayer/
|
||||||
|
|
||||||
### :bangbang: Opening an issue
|
### :bangbang: Opening an issue
|
||||||
|
|
||||||
@@ -119,4 +119,4 @@ To compile on Windows with Visual Studio 2019 or 2022, see https://github.com/st
|
|||||||
|
|
||||||
### :penguin: Packaging status
|
### :penguin: Packaging status
|
||||||
|
|
||||||
[](https://repology.org/metapackage/strawberry/versions)
|
[](https://repology.org/metapackage/strawberry/versions)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ macro(add_pot outfiles header pot)
|
|||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${pot}
|
OUTPUT ${pot}
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
COMMAND ${GETTEXT_XGETTEXT_EXECUTABLE} ${XGETTEXT_OPTIONS} -s -C --omit-header --output="${CMAKE_CURRENT_BINARY_DIR}/pot.temp" ${add_pot_sources}
|
COMMAND ${GETTEXT_XGETTEXT_EXECUTABLE} ${XGETTEXT_OPTIONS} -C --omit-header --no-location --output="${CMAKE_CURRENT_BINARY_DIR}/pot.temp" ${add_pot_sources}
|
||||||
COMMAND cat ${header} ${CMAKE_CURRENT_BINARY_DIR}/pot.temp > ${pot}
|
COMMAND cat ${header} ${CMAKE_CURRENT_BINARY_DIR}/pot.temp > ${pot}
|
||||||
DEPENDS ${add_pot_sources} ${header}
|
DEPENDS ${add_pot_sources} ${header}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
set(STRAWBERRY_VERSION_MAJOR 1)
|
set(STRAWBERRY_VERSION_MAJOR 1)
|
||||||
set(STRAWBERRY_VERSION_MINOR 1)
|
set(STRAWBERRY_VERSION_MINOR 1)
|
||||||
set(STRAWBERRY_VERSION_PATCH 1)
|
set(STRAWBERRY_VERSION_PATCH 3)
|
||||||
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
||||||
|
|
||||||
set(INCLUDE_GIT_REVISION OFF)
|
set(INCLUDE_GIT_REVISION ON)
|
||||||
|
|
||||||
set(majorminorpatch "${STRAWBERRY_VERSION_MAJOR}.${STRAWBERRY_VERSION_MINOR}.${STRAWBERRY_VERSION_PATCH}")
|
set(majorminorpatch "${STRAWBERRY_VERSION_MAJOR}.${STRAWBERRY_VERSION_MINOR}.${STRAWBERRY_VERSION_PATCH}")
|
||||||
|
|
||||||
|
|||||||
3
crowdin.yml
Normal file
3
crowdin.yml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
files:
|
||||||
|
- source: /src/translations/translations.pot
|
||||||
|
translation: /src/translations/%locale_with_underscore%.po
|
||||||
@@ -45,5 +45,6 @@
|
|||||||
<file>mood/sample.mood</file>
|
<file>mood/sample.mood</file>
|
||||||
<file>text/ghosts.txt</file>
|
<file>text/ghosts.txt</file>
|
||||||
<file>pictures/sidebar-background.png</file>
|
<file>pictures/sidebar-background.png</file>
|
||||||
|
<file>style/dynamicplaylistcontrols.css</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
13
data/style/dynamicplaylistcontrols.css
Normal file
13
data/style/dynamicplaylistcontrols.css
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#container {
|
||||||
|
background: %background;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid rgba(200, 200, 200, 75%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#label1 {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#label2 {
|
||||||
|
font-size: 7.5pt;
|
||||||
|
}
|
||||||
1
dist/macos/macgstcopy.sh
vendored
1
dist/macos/macgstcopy.sh
vendored
@@ -111,6 +111,7 @@ libgstrtsp
|
|||||||
libgstsoup
|
libgstsoup
|
||||||
libgstspectrum
|
libgstspectrum
|
||||||
libgstspeex
|
libgstspeex
|
||||||
|
libgstspotify
|
||||||
libgsttaglib
|
libgsttaglib
|
||||||
libgsttcp
|
libgsttcp
|
||||||
libgsttwolame
|
libgsttwolame
|
||||||
|
|||||||
@@ -12,11 +12,14 @@
|
|||||||
<summary>A music player and collection organizer</summary>
|
<summary>A music player and collection organizer</summary>
|
||||||
<url type="homepage">https://www.strawberrymusicplayer.org/</url>
|
<url type="homepage">https://www.strawberrymusicplayer.org/</url>
|
||||||
<url type="bugtracker">https://github.com/strawberrymusicplayer/strawberry/</url>
|
<url type="bugtracker">https://github.com/strawberrymusicplayer/strawberry/</url>
|
||||||
<translation type="qt">strawberry</translation>
|
<developer id="net.jkvinge.jonas">
|
||||||
|
<name>Jonas Kvinge</name>
|
||||||
|
</developer>
|
||||||
|
<translation type="gettext">strawberry</translation>
|
||||||
<content_rating type="oars-1.1" />
|
<content_rating type="oars-1.1" />
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>
|
||||||
Strawberry is a music player and music collection organizer. It is aimed at music collectors and audiophiles. With Strawberry you can play and manage your digital music collection, or stream your favorite radios. It also has unofficial streaming support for Tidal and Qobuz. Strawberry is free software released under GPL. The source code is available on GitHub. It's written in C++ using the Qt toolkit and GStreamer. Strawberry is compatible with both Qt version 5 and 6.
|
Strawberry is a music player and music collection organizer. It is aimed at music collectors and audiophiles. Strawberry is free software released under GPL. It's written in C++ using the Qt framework and GStreamer.
|
||||||
</p>
|
</p>
|
||||||
<p>Features:</p>
|
<p>Features:</p>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -30,12 +33,11 @@
|
|||||||
<li>Automatically retrieve tags from MusicBrainz</li>
|
<li>Automatically retrieve tags from MusicBrainz</li>
|
||||||
<li>Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify</li>
|
<li>Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify</li>
|
||||||
<li>Song lyrics from Genius, Musixmatch, ChartLyrics, lyrics.ovh, lololyrics.com, songlyrics.com, azlyrics.com and elyrics.net</li>
|
<li>Song lyrics from Genius, Musixmatch, ChartLyrics, lyrics.ovh, lololyrics.com, songlyrics.com, azlyrics.com and elyrics.net</li>
|
||||||
<li>Support for multiple backends</li>
|
|
||||||
<li>Audio analyzer and equalizer</li>
|
<li>Audio analyzer and equalizer</li>
|
||||||
<li>Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic</li>
|
<li>Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic</li>
|
||||||
<li>Scrobbler with support for Last.fm, Libre.fm and ListenBrainz</li>
|
<li>Scrobbler with support for Last.fm, Libre.fm and ListenBrainz</li>
|
||||||
<li>Streaming support for Subsonic-compatible servers</li>
|
<li>Streaming support for Subsonic-compatible servers</li>
|
||||||
<li>Unofficial streaming support for Tidal and Qobuz</li>
|
<li>Unofficial streaming support for Tidal, Spotify and Qobuz</li>
|
||||||
</ul>
|
</ul>
|
||||||
</description>
|
</description>
|
||||||
<screenshots>
|
<screenshots>
|
||||||
@@ -50,6 +52,8 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
<update_contact>eclipseo@fedoraproject.org</update_contact>
|
<update_contact>eclipseo@fedoraproject.org</update_contact>
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="1.1.3" date="2024-09-21"/>
|
||||||
|
<release version="1.1.2" date="2024-09-12"/>
|
||||||
<release version="1.1.1" date="2024-07-22"/>
|
<release version="1.1.1" date="2024-07-22"/>
|
||||||
<release version="1.1.0" date="2024-07-14"/>
|
<release version="1.1.0" date="2024-07-14"/>
|
||||||
<release version="1.0.23" date="2024-01-11"/>
|
<release version="1.0.23" date="2024-01-11"/>
|
||||||
|
|||||||
34
dist/windows/strawberry.nsi.in
vendored
34
dist/windows/strawberry.nsi.in
vendored
@@ -261,6 +261,7 @@ Section "Strawberry" Strawberry
|
|||||||
File "libFLAC-12.dll"
|
File "libFLAC-12.dll"
|
||||||
File "libbrotlicommon.dll"
|
File "libbrotlicommon.dll"
|
||||||
File "libbrotlidec.dll"
|
File "libbrotlidec.dll"
|
||||||
|
File "libbrotlienc.dll"
|
||||||
File "libbs2b-0.dll"
|
File "libbs2b-0.dll"
|
||||||
File "libbz2.dll"
|
File "libbz2.dll"
|
||||||
File "libchromaprint.dll"
|
File "libchromaprint.dll"
|
||||||
@@ -328,6 +329,7 @@ Section "Strawberry" Strawberry
|
|||||||
File "libtasn1-6.dll"
|
File "libtasn1-6.dll"
|
||||||
File "libtwolame-0.dll"
|
File "libtwolame-0.dll"
|
||||||
File "libunistring-5.dll"
|
File "libunistring-5.dll"
|
||||||
|
File "libutf8_validity.dll"
|
||||||
File "libvorbis-0.dll"
|
File "libvorbis-0.dll"
|
||||||
File "libvorbisenc-2.dll"
|
File "libvorbisenc-2.dll"
|
||||||
File "libvorbisfile-3.dll"
|
File "libvorbisfile-3.dll"
|
||||||
@@ -450,6 +452,7 @@ Section "Strawberry" Strawberry
|
|||||||
File "liblzma.dll"
|
File "liblzma.dll"
|
||||||
File "libmp3lame.dll"
|
File "libmp3lame.dll"
|
||||||
File "libopenmpt.dll"
|
File "libopenmpt.dll"
|
||||||
|
File "utf8_validity.dll"
|
||||||
File "mpcdec.dll"
|
File "mpcdec.dll"
|
||||||
File "mpg123.dll"
|
File "mpg123.dll"
|
||||||
File "nghttp2.dll"
|
File "nghttp2.dll"
|
||||||
@@ -526,13 +529,13 @@ Section "Strawberry" Strawberry
|
|||||||
File "Qt6Widgets.dll"
|
File "Qt6Widgets.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
File "avcodec-60.dll"
|
File "avcodec-61.dll"
|
||||||
File "avfilter-9.dll"
|
File "avfilter-10.dll"
|
||||||
File "avformat-60.dll"
|
File "avformat-61.dll"
|
||||||
File "avutil-58.dll"
|
File "avutil-59.dll"
|
||||||
File "postproc-57.dll"
|
File "postproc-58.dll"
|
||||||
File "swresample-4.dll"
|
File "swresample-5.dll"
|
||||||
File "swscale-7.dll"
|
File "swscale-8.dll"
|
||||||
|
|
||||||
; Register Strawberry with Default Programs
|
; Register Strawberry with Default Programs
|
||||||
Var /GLOBAL AppIcon
|
Var /GLOBAL AppIcon
|
||||||
@@ -831,6 +834,7 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libFLAC-12.dll"
|
Delete "$INSTDIR\libFLAC-12.dll"
|
||||||
Delete "$INSTDIR\libbrotlicommon.dll"
|
Delete "$INSTDIR\libbrotlicommon.dll"
|
||||||
Delete "$INSTDIR\libbrotlidec.dll"
|
Delete "$INSTDIR\libbrotlidec.dll"
|
||||||
|
Delete "$INSTDIR\libbrotlienc.dll"
|
||||||
Delete "$INSTDIR\libbs2b-0.dll"
|
Delete "$INSTDIR\libbs2b-0.dll"
|
||||||
Delete "$INSTDIR\libbz2.dll"
|
Delete "$INSTDIR\libbz2.dll"
|
||||||
Delete "$INSTDIR\libchromaprint.dll"
|
Delete "$INSTDIR\libchromaprint.dll"
|
||||||
@@ -898,6 +902,7 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libtasn1-6.dll"
|
Delete "$INSTDIR\libtasn1-6.dll"
|
||||||
Delete "$INSTDIR\libtwolame-0.dll"
|
Delete "$INSTDIR\libtwolame-0.dll"
|
||||||
Delete "$INSTDIR\libunistring-5.dll"
|
Delete "$INSTDIR\libunistring-5.dll"
|
||||||
|
Delete "$INSTDIR\libutf8_validity.dll"
|
||||||
Delete "$INSTDIR\libvorbis-0.dll"
|
Delete "$INSTDIR\libvorbis-0.dll"
|
||||||
Delete "$INSTDIR\libvorbisenc-2.dll"
|
Delete "$INSTDIR\libvorbisenc-2.dll"
|
||||||
Delete "$INSTDIR\libvorbisfile-3.dll"
|
Delete "$INSTDIR\libvorbisfile-3.dll"
|
||||||
@@ -1020,6 +1025,7 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\liblzma.dll"
|
Delete "$INSTDIR\liblzma.dll"
|
||||||
Delete "$INSTDIR\libmp3lame.dll"
|
Delete "$INSTDIR\libmp3lame.dll"
|
||||||
Delete "$INSTDIR\libopenmpt.dll"
|
Delete "$INSTDIR\libopenmpt.dll"
|
||||||
|
Delete "$INSTDIR\utf8_validity.dll"
|
||||||
Delete "$INSTDIR\mpcdec.dll"
|
Delete "$INSTDIR\mpcdec.dll"
|
||||||
Delete "$INSTDIR\mpg123.dll"
|
Delete "$INSTDIR\mpg123.dll"
|
||||||
Delete "$INSTDIR\nghttp2.dll"
|
Delete "$INSTDIR\nghttp2.dll"
|
||||||
@@ -1095,13 +1101,13 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\Qt6Widgets.dll"
|
Delete "$INSTDIR\Qt6Widgets.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
Delete "$INSTDIR\avcodec-60.dll"
|
Delete "$INSTDIR\avcodec-61.dll"
|
||||||
Delete "$INSTDIR\avfilter-9.dll"
|
Delete "$INSTDIR\avfilter-10.dll"
|
||||||
Delete "$INSTDIR\avformat-60.dll"
|
Delete "$INSTDIR\avformat-61.dll"
|
||||||
Delete "$INSTDIR\avutil-58.dll"
|
Delete "$INSTDIR\avutil-59.dll"
|
||||||
Delete "$INSTDIR\postproc-57.dll"
|
Delete "$INSTDIR\postproc-58.dll"
|
||||||
Delete "$INSTDIR\swresample-4.dll"
|
Delete "$INSTDIR\swresample-5.dll"
|
||||||
Delete "$INSTDIR\swscale-7.dll"
|
Delete "$INSTDIR\swscale-8.dll"
|
||||||
|
|
||||||
!ifdef mingw
|
!ifdef mingw
|
||||||
Delete "$INSTDIR\gio-modules\libgiognutls.dll"
|
Delete "$INSTDIR\gio-modules\libgiognutls.dll"
|
||||||
|
|||||||
@@ -1,16 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.7)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
set(SOURCES gstfastspectrum.cpp gstmoodbarplugin.cpp)
|
set(SOURCES gstfastspectrum.cpp gstmoodbarplugin.cpp)
|
||||||
|
|
||||||
link_directories(
|
|
||||||
${GLIB_LIBRARY_DIRS}
|
|
||||||
${GOBJECT_LIBRARY_DIRS}
|
|
||||||
${GSTREAMER_LIBRARY_DIRS}
|
|
||||||
${GSTREAMER_BASE_LIBRARY_DIRS}
|
|
||||||
${GSTREAMER_AUDIO_LIBRARY_DIRS}
|
|
||||||
${FFTW3_LIBRARY_DIRS}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library(gstmoodbar STATIC ${SOURCES})
|
add_library(gstmoodbar STATIC ${SOURCES})
|
||||||
|
|
||||||
target_include_directories(gstmoodbar SYSTEM PRIVATE
|
target_include_directories(gstmoodbar SYSTEM PRIVATE
|
||||||
@@ -24,6 +15,15 @@ target_include_directories(gstmoodbar SYSTEM PRIVATE
|
|||||||
|
|
||||||
target_include_directories(gstmoodbar PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(gstmoodbar PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
target_link_directories(gstmoodbar PRIVATE
|
||||||
|
${GLIB_LIBRARY_DIRS}
|
||||||
|
${GOBJECT_LIBRARY_DIRS}
|
||||||
|
${GSTREAMER_LIBRARY_DIRS}
|
||||||
|
${GSTREAMER_BASE_LIBRARY_DIRS}
|
||||||
|
${GSTREAMER_AUDIO_LIBRARY_DIRS}
|
||||||
|
${FFTW3_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
target_link_libraries(gstmoodbar PRIVATE
|
target_link_libraries(gstmoodbar PRIVATE
|
||||||
${GLIB_LIBRARIES}
|
${GLIB_LIBRARIES}
|
||||||
${GOBJECT_LIBRARIES}
|
${GOBJECT_LIBRARIES}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.7)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
core/logging.cpp
|
core/logging.cpp
|
||||||
@@ -16,8 +16,6 @@ set(HEADERS
|
|||||||
|
|
||||||
qt_wrap_cpp(MOC ${HEADERS})
|
qt_wrap_cpp(MOC ${HEADERS})
|
||||||
|
|
||||||
link_directories(${GLIB_LIBRARY_DIRS})
|
|
||||||
|
|
||||||
add_library(libstrawberry-common STATIC ${SOURCES} ${MOC})
|
add_library(libstrawberry-common STATIC ${SOURCES} ${MOC})
|
||||||
|
|
||||||
target_include_directories(libstrawberry-common SYSTEM PRIVATE ${GLIB_INCLUDE_DIRS})
|
target_include_directories(libstrawberry-common SYSTEM PRIVATE ${GLIB_INCLUDE_DIRS})
|
||||||
@@ -31,6 +29,8 @@ if(Backtrace_FOUND)
|
|||||||
target_include_directories(libstrawberry-common SYSTEM PRIVATE ${Backtrace_INCLUDE_DIRS})
|
target_include_directories(libstrawberry-common SYSTEM PRIVATE ${Backtrace_INCLUDE_DIRS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
target_link_directories(libstrawberry-common PRIVATE ${GLIB_LIBRARY_DIRS})
|
||||||
|
|
||||||
target_link_libraries(libstrawberry-common PRIVATE
|
target_link_libraries(libstrawberry-common PRIVATE
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
${CMAKE_THREAD_LIBS_INIT}
|
||||||
${GLIB_LIBRARIES}
|
${GLIB_LIBRARIES}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <utility>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
# include <cxxabi.h>
|
# include <cxxabi.h>
|
||||||
@@ -157,12 +159,13 @@ static void MessageHandler(QtMsgType type, const QMessageLogContext&, const QStr
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QString &line : message.split(QLatin1Char('\n'))) {
|
const QStringList lines = message.split(QLatin1Char('\n'));
|
||||||
|
for (const QString &line : lines) {
|
||||||
BufferedDebug d = CreateLogger<BufferedDebug>(level, QStringLiteral("unknown"), -1, nullptr);
|
BufferedDebug d = CreateLogger<BufferedDebug>(level, QStringLiteral("unknown"), -1, nullptr);
|
||||||
d << line.toLocal8Bit().constData();
|
d << line.toLocal8Bit().constData();
|
||||||
if (d.buf_) {
|
if (d.buf_) {
|
||||||
d.buf_->close();
|
d.buf_->close();
|
||||||
fprintf(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout, "%s\n", d.buf_->buffer().data());
|
fprintf(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout, "%s\n", d.buf_->buffer().constData());
|
||||||
fflush(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout);
|
fflush(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,7 +196,8 @@ void SetLevels(const QString &levels) {
|
|||||||
|
|
||||||
if (!sClassLevels) return;
|
if (!sClassLevels) return;
|
||||||
|
|
||||||
for (const QString &item : levels.split(QLatin1Char(','))) {
|
const QStringList items = levels.split(QLatin1Char(','));
|
||||||
|
for (const QString &item : items) {
|
||||||
const QStringList class_level = item.split(QLatin1Char(':'));
|
const QStringList class_level = item.split(QLatin1Char(':'));
|
||||||
|
|
||||||
QString class_name;
|
QString class_name;
|
||||||
@@ -310,8 +314,8 @@ QString CXXDemangle(const QString &mangled_function) {
|
|||||||
QString LinuxDemangle(const QString &symbol);
|
QString LinuxDemangle(const QString &symbol);
|
||||||
QString LinuxDemangle(const QString &symbol) {
|
QString LinuxDemangle(const QString &symbol) {
|
||||||
|
|
||||||
QRegularExpression regex(QStringLiteral("\\(([^+]+)"));
|
static const QRegularExpression regex_symbol(QStringLiteral("\\(([^+]+)"));
|
||||||
QRegularExpressionMatch match = regex.match(symbol);
|
QRegularExpressionMatch match = regex_symbol.match(symbol);
|
||||||
if (!match.hasMatch()) {
|
if (!match.hasMatch()) {
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
@@ -370,20 +374,49 @@ void DumpStackTrace() {
|
|||||||
// It's okay that the LoggedDebug instance is copied to a QDebug in these. It doesn't override any behavior that should be needed after return.
|
// It's okay that the LoggedDebug instance is copied to a QDebug in these. It doesn't override any behavior that should be needed after return.
|
||||||
#define qCreateLogger(line, pretty_function, category, level) logging::CreateLogger<LoggedDebug>(logging::Level_##level, logging::ParsePrettyFunction(pretty_function), line, category)
|
#define qCreateLogger(line, pretty_function, category, level) logging::CreateLogger<LoggedDebug>(logging::Level_##level, logging::ParsePrettyFunction(pretty_function), line, category)
|
||||||
|
|
||||||
QDebug CreateLoggerInfo(int line, const char *pretty_function, const char *category) { return qCreateLogger(line, pretty_function, category, Info); }
|
QDebug CreateLoggerFatal(const int line, const char *pretty_function, const char *category) { return qCreateLogger(line, pretty_function, category, Fatal); }
|
||||||
QDebug CreateLoggerFatal(int line, const char *pretty_function, const char *category) { return qCreateLogger(line, pretty_function, category, Fatal); }
|
QDebug CreateLoggerError(const int line, const char *pretty_function, const char *category) { return qCreateLogger(line, pretty_function, category, Error); }
|
||||||
QDebug CreateLoggerError(int line, const char *pretty_function, const char *category) { return qCreateLogger(line, pretty_function, category, Error); }
|
|
||||||
|
#ifdef QT_NO_INFO_OUTPUT
|
||||||
|
QNoDebug CreateLoggerInfo(const int line, const char *pretty_function, const char *category) {
|
||||||
|
|
||||||
|
Q_UNUSED(line)
|
||||||
|
Q_UNUSED(pretty_function)
|
||||||
|
Q_UNUSED(category)
|
||||||
|
|
||||||
|
return QNoDebug();
|
||||||
|
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
QDebug CreateLoggerInfo(const int line, const char *pretty_function, const char *category) { return qCreateLogger(line, pretty_function, category, Info); }
|
||||||
|
#endif // QT_NO_INFO_OUTPUT
|
||||||
|
|
||||||
#ifdef QT_NO_WARNING_OUTPUT
|
#ifdef QT_NO_WARNING_OUTPUT
|
||||||
QNoDebug CreateLoggerWarning(int, const char*, const char*) { return QNoDebug(); }
|
QNoDebug CreateLoggerWarning(const int line, const char *pretty_function, const char *category) {
|
||||||
|
|
||||||
|
Q_UNUSED(line)
|
||||||
|
Q_UNUSED(pretty_function)
|
||||||
|
Q_UNUSED(category)
|
||||||
|
|
||||||
|
return QNoDebug();
|
||||||
|
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
QDebug CreateLoggerWarning(int line, const char *pretty_function, const char *category) { return qCreateLogger(line, pretty_function, category, Warning); }
|
QDebug CreateLoggerWarning(const int line, const char *pretty_function, const char *category) { return qCreateLogger(line, pretty_function, category, Warning); }
|
||||||
#endif // QT_NO_WARNING_OUTPUT
|
#endif // QT_NO_WARNING_OUTPUT
|
||||||
|
|
||||||
#ifdef QT_NO_DEBUG_OUTPUT
|
#ifdef QT_NO_DEBUG_OUTPUT
|
||||||
QNoDebug CreateLoggerDebug(int, const char*, const char*) { return QNoDebug(); }
|
QNoDebug CreateLoggerDebug(const int line, const char *pretty_function, const char *category) {
|
||||||
|
|
||||||
|
Q_UNUSED(line)
|
||||||
|
Q_UNUSED(pretty_function)
|
||||||
|
Q_UNUSED(category)
|
||||||
|
|
||||||
|
return QNoDebug();
|
||||||
|
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
QDebug CreateLoggerDebug(int line, const char *pretty_function, const char *category) { return qCreateLogger(line, pretty_function, category, Debug); }
|
QDebug CreateLoggerDebug(const int line, const char *pretty_function, const char *category) { return qCreateLogger(line, pretty_function, category, Debug); }
|
||||||
#endif // QT_NO_DEBUG_OUTPUT
|
#endif // QT_NO_DEBUG_OUTPUT
|
||||||
|
|
||||||
} // namespace logging
|
} // namespace logging
|
||||||
|
|||||||
@@ -72,20 +72,25 @@ enum Level {
|
|||||||
|
|
||||||
void DumpStackTrace();
|
void DumpStackTrace();
|
||||||
|
|
||||||
QDebug CreateLoggerInfo(int line, const char *pretty_function, const char *category);
|
QDebug CreateLoggerFatal(const int line, const char *pretty_function, const char *category);
|
||||||
QDebug CreateLoggerFatal(int line, const char *pretty_function, const char *category);
|
QDebug CreateLoggerError(const int line, const char *pretty_function, const char *category);
|
||||||
QDebug CreateLoggerError(int line, const char *pretty_function, const char *category);
|
|
||||||
|
#ifdef QT_NO_INFO_OUTPUT
|
||||||
|
QNoDebug CreateLoggerInfo(const int line, const char *pretty_function, const char *category);
|
||||||
|
#else
|
||||||
|
QDebug CreateLoggerInfo(const int line, const char *pretty_function, const char *category);
|
||||||
|
#endif // QT_NO_INFO_OUTPUT
|
||||||
|
|
||||||
#ifdef QT_NO_WARNING_OUTPUT
|
#ifdef QT_NO_WARNING_OUTPUT
|
||||||
QNoDebug CreateLoggerWarning(int, const char*, const char*);
|
QNoDebug CreateLoggerWarning(const int line, const char *pretty_function, const char *category);
|
||||||
#else
|
#else
|
||||||
QDebug CreateLoggerWarning(int line, const char *pretty_function, const char *category);
|
QDebug CreateLoggerWarning(const int line, const char *pretty_function, const char *category);
|
||||||
#endif // QT_NO_WARNING_OUTPUT
|
#endif // QT_NO_WARNING_OUTPUT
|
||||||
|
|
||||||
#ifdef QT_NO_DEBUG_OUTPUT
|
#ifdef QT_NO_DEBUG_OUTPUT
|
||||||
QNoDebug CreateLoggerDebug(int, const char*, const char*);
|
QNoDebug CreateLoggerDebug(const int line, const char *pretty_function, const char *category);
|
||||||
#else
|
#else
|
||||||
QDebug CreateLoggerDebug(int line, const char *pretty_function, const char *category);
|
QDebug CreateLoggerDebug(const int line, const char *pretty_function, const char *category);
|
||||||
#endif // QT_NO_DEBUG_OUTPUT
|
#endif // QT_NO_DEBUG_OUTPUT
|
||||||
|
|
||||||
void GLog(const char *domain, int level, const char *message, void *user_data);
|
void GLog(const char *domain, int level, const char *message, void *user_data);
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class _MessageHandlerBase : public QObject {
|
|||||||
// After this is true, messages cannot be sent to the handler any more.
|
// After this is true, messages cannot be sent to the handler any more.
|
||||||
bool is_device_closed() const { return is_device_closed_; }
|
bool is_device_closed() const { return is_device_closed_; }
|
||||||
|
|
||||||
protected slots:
|
protected Q_SLOTS:
|
||||||
void WriteMessage(const QByteArray &data);
|
void WriteMessage(const QByteArray &data);
|
||||||
void DeviceReadyRead();
|
void DeviceReadyRead();
|
||||||
virtual void DeviceClosed();
|
virtual void DeviceClosed();
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ void _MessageReplyBase::Abort() {
|
|||||||
finished_ = true;
|
finished_ = true;
|
||||||
success_ = false;
|
success_ = false;
|
||||||
|
|
||||||
emit Finished();
|
Q_EMIT Finished();
|
||||||
qLog(Debug) << "Releasing ID" << id() << "(aborted)";
|
qLog(Debug) << "Releasing ID" << id() << "(aborted)";
|
||||||
semaphore_.release();
|
semaphore_.release();
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class _MessageReplyBase : public QObject {
|
|||||||
|
|
||||||
void Abort();
|
void Abort();
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void Finished();
|
void Finished();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -52,11 +52,11 @@ class _WorkerPoolBase : public QObject {
|
|||||||
public:
|
public:
|
||||||
explicit _WorkerPoolBase(QObject *parent = nullptr);
|
explicit _WorkerPoolBase(QObject *parent = nullptr);
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
// Emitted when a worker failed to start. This usually happens when the worker wasn't found, or couldn't be executed.
|
// Emitted when a worker failed to start. This usually happens when the worker wasn't found, or couldn't be executed.
|
||||||
void WorkerFailedToStart();
|
void WorkerFailedToStart();
|
||||||
|
|
||||||
protected slots:
|
protected Q_SLOTS:
|
||||||
virtual void DoStart() {}
|
virtual void DoStart() {}
|
||||||
virtual void NewConnection() {}
|
virtual void NewConnection() {}
|
||||||
virtual void ProcessReadyReadStandardOutput() {}
|
virtual void ProcessReadyReadStandardOutput() {}
|
||||||
@@ -293,7 +293,7 @@ void WorkerPool<HandlerType>::StartOneWorker(Worker *worker) {
|
|||||||
QObject::connect(worker->process_, &QProcess::readyReadStandardError, this, &WorkerPool::ProcessReadyReadStandardError);
|
QObject::connect(worker->process_, &QProcess::readyReadStandardError, this, &WorkerPool::ProcessReadyReadStandardError);
|
||||||
|
|
||||||
// Create a server, find an unused name and start listening
|
// Create a server, find an unused name and start listening
|
||||||
forever {
|
Q_FOREVER {
|
||||||
const quint32 unique_number = QRandomGenerator::global()->bounded(static_cast<quint32>(quint64(this) & 0xFFFFFFFF));
|
const quint32 unique_number = QRandomGenerator::global()->bounded(static_cast<quint32>(quint64(this) & 0xFFFFFFFF));
|
||||||
const QString name = QStringLiteral("%1_%2").arg(local_server_name_).arg(unique_number);
|
const QString name = QStringLiteral("%1_%2").arg(local_server_name_).arg(unique_number);
|
||||||
|
|
||||||
@@ -357,7 +357,7 @@ void WorkerPool<HandlerType>::ProcessError(QProcess::ProcessError error) {
|
|||||||
// Failed to start errors are bad - it usually means the worker isn't installed.
|
// Failed to start errors are bad - it usually means the worker isn't installed.
|
||||||
// Don't restart the process, but tell our owner, who will probably want to do something fatal.
|
// Don't restart the process, but tell our owner, who will probably want to do something fatal.
|
||||||
qLog(Error) << "Worker failed to start";
|
qLog(Error) << "Worker failed to start";
|
||||||
emit WorkerFailedToStart();
|
Q_EMIT WorkerFailedToStart();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.7)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
# Workaround a bug in protobuf-generate.cmake (https://github.com/protocolbuffers/protobuf/issues/12450)
|
# Workaround a bug in protobuf-generate.cmake (https://github.com/protocolbuffers/protobuf/issues/12450)
|
||||||
if(NOT protobuf_PROTOC_EXE)
|
if(NOT protobuf_PROTOC_EXE)
|
||||||
@@ -19,19 +19,6 @@ if(HAVE_TAGPARSER)
|
|||||||
list(APPEND SOURCES tagreadertagparser.cpp)
|
list(APPEND SOURCES tagreadertagparser.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
link_directories(
|
|
||||||
${GLIB_LIBRARY_DIRS}
|
|
||||||
${PROTOBUF_LIBRARY_DIRS}
|
|
||||||
)
|
|
||||||
|
|
||||||
if(HAVE_TAGLIB)
|
|
||||||
link_directories(${TAGLIB_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_TAGPARSER)
|
|
||||||
link_directories(${TAGPARSER_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(libstrawberry-tagreader STATIC ${PROTO_SOURCES} ${SOURCES})
|
add_library(libstrawberry-tagreader STATIC ${PROTO_SOURCES} ${SOURCES})
|
||||||
|
|
||||||
target_include_directories(libstrawberry-tagreader SYSTEM PRIVATE
|
target_include_directories(libstrawberry-tagreader SYSTEM PRIVATE
|
||||||
@@ -47,6 +34,11 @@ target_include_directories(libstrawberry-tagreader PRIVATE
|
|||||||
${CMAKE_BINARY_DIR}/src
|
${CMAKE_BINARY_DIR}/src
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_link_directories(libstrawberry-tagreader PRIVATE
|
||||||
|
${GLIB_LIBRARY_DIRS}
|
||||||
|
${PROTOBUF_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
target_link_libraries(libstrawberry-tagreader PRIVATE
|
target_link_libraries(libstrawberry-tagreader PRIVATE
|
||||||
${GLIB_LIBRARIES}
|
${GLIB_LIBRARIES}
|
||||||
${Protobuf_LIBRARIES}
|
${Protobuf_LIBRARIES}
|
||||||
@@ -58,11 +50,13 @@ target_link_libraries(libstrawberry-tagreader PRIVATE
|
|||||||
|
|
||||||
if(HAVE_TAGLIB)
|
if(HAVE_TAGLIB)
|
||||||
target_include_directories(libstrawberry-tagreader SYSTEM PRIVATE ${TAGLIB_INCLUDE_DIRS})
|
target_include_directories(libstrawberry-tagreader SYSTEM PRIVATE ${TAGLIB_INCLUDE_DIRS})
|
||||||
|
target_link_directories(libstrawberry-tagreader PRIVATE ${TAGLIB_LIBRARY_DIRS})
|
||||||
target_link_libraries(libstrawberry-tagreader PRIVATE ${TAGLIB_LIBRARIES})
|
target_link_libraries(libstrawberry-tagreader PRIVATE ${TAGLIB_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_TAGPARSER)
|
if(HAVE_TAGPARSER)
|
||||||
target_include_directories(libstrawberry-tagreader SYSTEM PRIVATE ${TAGPARSER_INCLUDE_DIRS})
|
target_include_directories(libstrawberry-tagreader SYSTEM PRIVATE ${TAGPARSER_INCLUDE_DIRS})
|
||||||
|
target_link_directories(libstrawberry-tagreader PRIVATE ${TAGPARSER_LIBRARY_DIRS})
|
||||||
target_link_libraries(libstrawberry-tagreader PRIVATE ${TAGPARSER_LIBRARIES})
|
target_link_libraries(libstrawberry-tagreader PRIVATE ${TAGPARSER_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "tagreaderbase.h"
|
#include "tagreaderbase.h"
|
||||||
|
|
||||||
TagReaderBase::TagReaderBase() = default;
|
TagReaderBase::TagReaderBase() = default;
|
||||||
|
TagReaderBase::~TagReaderBase() = default;
|
||||||
|
|
||||||
QString TagReaderBase::ErrorString(const Result &result) {
|
QString TagReaderBase::ErrorString(const Result &result) {
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
class TagReaderBase {
|
class TagReaderBase {
|
||||||
public:
|
public:
|
||||||
explicit TagReaderBase();
|
explicit TagReaderBase();
|
||||||
~TagReaderBase() = default;
|
virtual ~TagReaderBase();
|
||||||
|
|
||||||
class Result {
|
class Result {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -229,6 +229,7 @@ TagReaderBase::Result GME::VGM::Read(const QFileInfo &fileinfo, spb::tagreader::
|
|||||||
|
|
||||||
file.seek(static_cast<qint64>(GD3_TAG_PTR + pt));
|
file.seek(static_cast<qint64>(GD3_TAG_PTR + pt));
|
||||||
QByteArray gd3_version = file.read(4);
|
QByteArray gd3_version = file.read(4);
|
||||||
|
Q_UNUSED(gd3_version)
|
||||||
|
|
||||||
file.seek(file.pos() + 4);
|
file.seek(file.pos() + 4);
|
||||||
QByteArray gd3_length_bytes = file.read(4);
|
QByteArray gd3_length_bytes = file.read(4);
|
||||||
|
|||||||
@@ -99,7 +99,6 @@ class TagReaderGME : public TagReaderBase {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TagReaderGME();
|
explicit TagReaderGME();
|
||||||
~TagReaderGME() = default;
|
|
||||||
|
|
||||||
bool IsMediaFile(const QString &filename) const override;
|
bool IsMediaFile(const QString &filename) const override;
|
||||||
|
|
||||||
|
|||||||
@@ -798,13 +798,13 @@ void TagReaderTagLib::ParseMP4Tags(TagLib::MP4::Tag *tag, QString *disc, QString
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tag->contains(kMP4_MusicBrainz_AlbumArtistId)) {
|
if (tag->contains(kMP4_MusicBrainz_AlbumArtistId)) {
|
||||||
AssignTagLibStringToStdString(tag->item(kMP4_MusicBrainz_AlbumArtistId).toStringList().toString(), song->mutable_musicbrainz_album_artist_id());
|
AssignTagLibStringToStdString(TagLibStringListToSlashSeparatedString(tag->item(kMP4_MusicBrainz_AlbumArtistId).toStringList()), song->mutable_musicbrainz_album_artist_id());
|
||||||
}
|
}
|
||||||
if (tag->contains(kMP4_MusicBrainz_ArtistId)) {
|
if (tag->contains(kMP4_MusicBrainz_ArtistId)) {
|
||||||
AssignTagLibStringToStdString(tag->item(kMP4_MusicBrainz_ArtistId).toStringList().toString(), song->mutable_musicbrainz_artist_id());
|
AssignTagLibStringToStdString(TagLibStringListToSlashSeparatedString(tag->item(kMP4_MusicBrainz_ArtistId).toStringList()), song->mutable_musicbrainz_artist_id());
|
||||||
}
|
}
|
||||||
if (tag->contains(kMP4_MusicBrainz_OriginalArtistId)) {
|
if (tag->contains(kMP4_MusicBrainz_OriginalArtistId)) {
|
||||||
AssignTagLibStringToStdString(tag->item(kMP4_MusicBrainz_OriginalArtistId).toStringList().toString(), song->mutable_musicbrainz_original_artist_id());
|
AssignTagLibStringToStdString(TagLibStringListToSlashSeparatedString(tag->item(kMP4_MusicBrainz_OriginalArtistId).toStringList()), song->mutable_musicbrainz_original_artist_id());
|
||||||
}
|
}
|
||||||
if (tag->contains(kMP4_MusicBrainz_AlbumId)) {
|
if (tag->contains(kMP4_MusicBrainz_AlbumId)) {
|
||||||
AssignTagLibStringToStdString(tag->item(kMP4_MusicBrainz_AlbumId).toStringList().toString(), song->mutable_musicbrainz_album_id());
|
AssignTagLibStringToStdString(tag->item(kMP4_MusicBrainz_AlbumId).toStringList().toString(), song->mutable_musicbrainz_album_id());
|
||||||
@@ -825,7 +825,7 @@ void TagReaderTagLib::ParseMP4Tags(TagLib::MP4::Tag *tag, QString *disc, QString
|
|||||||
AssignTagLibStringToStdString(tag->item(kMP4_MusicBrainz_ReleaseGroupId).toStringList().toString(), song->mutable_musicbrainz_release_group_id());
|
AssignTagLibStringToStdString(tag->item(kMP4_MusicBrainz_ReleaseGroupId).toStringList().toString(), song->mutable_musicbrainz_release_group_id());
|
||||||
}
|
}
|
||||||
if (tag->contains(kMP4_MusicBrainz_WorkId)) {
|
if (tag->contains(kMP4_MusicBrainz_WorkId)) {
|
||||||
AssignTagLibStringToStdString(tag->item(kMP4_MusicBrainz_WorkId).toStringList().toString(), song->mutable_musicbrainz_work_id());
|
AssignTagLibStringToStdString(TagLibStringListToSlashSeparatedString(tag->item(kMP4_MusicBrainz_WorkId).toStringList()), song->mutable_musicbrainz_work_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1211,7 +1211,7 @@ void TagReaderTagLib::SetUnsyncLyricsFrame(const std::string &value, TagLib::ID3
|
|||||||
// If no frames stored create empty frame
|
// If no frames stored create empty frame
|
||||||
if (frames_buffer.isEmpty()) {
|
if (frames_buffer.isEmpty()) {
|
||||||
TagLib::ID3v2::UnsynchronizedLyricsFrame frame(TagLib::String::UTF8);
|
TagLib::ID3v2::UnsynchronizedLyricsFrame frame(TagLib::String::UTF8);
|
||||||
frame.setDescription("Clementine editor");
|
frame.setDescription("Strawberry editor");
|
||||||
frames_buffer.push_back(frame.render());
|
frames_buffer.push_back(frame.render());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1870,3 +1870,17 @@ TagReaderBase::Result TagReaderTagLib::SaveSongRatingToFile(const QString &filen
|
|||||||
return success ? Result::ErrorCode::Success : Result::ErrorCode::FileSaveError;
|
return success ? Result::ErrorCode::Success : Result::ErrorCode::FileSaveError;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TagLib::String TagReaderTagLib::TagLibStringListToSlashSeparatedString(const TagLib::StringList &taglib_string_list) {
|
||||||
|
|
||||||
|
TagLib::String result_string;
|
||||||
|
for (const TagLib::String &taglib_string : taglib_string_list) {
|
||||||
|
if (!result_string.isEmpty()) {
|
||||||
|
result_string += '/';
|
||||||
|
}
|
||||||
|
result_string += taglib_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result_string;
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class FileRefFactory;
|
|||||||
class TagReaderTagLib : public TagReaderBase {
|
class TagReaderTagLib : public TagReaderBase {
|
||||||
public:
|
public:
|
||||||
explicit TagReaderTagLib();
|
explicit TagReaderTagLib();
|
||||||
~TagReaderTagLib();
|
~TagReaderTagLib() override;
|
||||||
|
|
||||||
static inline TagLib::String StdStringToTagLibString(const std::string &s) {
|
static inline TagLib::String StdStringToTagLibString(const std::string &s) {
|
||||||
return TagLib::String(s.c_str(), TagLib::String::UTF8);
|
return TagLib::String(s.c_str(), TagLib::String::UTF8);
|
||||||
@@ -86,7 +86,7 @@ class TagReaderTagLib : public TagReaderBase {
|
|||||||
Result ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override;
|
Result ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override;
|
||||||
Result WriteFile(const QString &filename, const spb::tagreader::WriteFileRequest &request) const override;
|
Result WriteFile(const QString &filename, const spb::tagreader::WriteFileRequest &request) const override;
|
||||||
|
|
||||||
Result LoadEmbeddedArt(const QString &filename, QByteArray &data) const;
|
Result LoadEmbeddedArt(const QString &filename, QByteArray &data) const override;
|
||||||
Result SaveEmbeddedArt(const QString &filename, const spb::tagreader::SaveEmbeddedArtRequest &request) const override;
|
Result SaveEmbeddedArt(const QString &filename, const spb::tagreader::SaveEmbeddedArtRequest &request) const override;
|
||||||
|
|
||||||
Result SaveSongPlaycountToFile(const QString &filename, const uint playcount) const override;
|
Result SaveSongPlaycountToFile(const QString &filename, const uint playcount) const override;
|
||||||
@@ -136,6 +136,8 @@ class TagReaderTagLib : public TagReaderBase {
|
|||||||
void SetEmbeddedArt(TagLib::ID3v2::Tag *tag, const QByteArray &data, const QString &mime_type) const;
|
void SetEmbeddedArt(TagLib::ID3v2::Tag *tag, const QByteArray &data, const QString &mime_type) const;
|
||||||
void SetEmbeddedArt(TagLib::MP4::File *aac_file, TagLib::MP4::Tag *tag, const QByteArray &data, const QString &mime_type) const;
|
void SetEmbeddedArt(TagLib::MP4::File *aac_file, TagLib::MP4::Tag *tag, const QByteArray &data, const QString &mime_type) const;
|
||||||
|
|
||||||
|
static TagLib::String TagLibStringListToSlashSeparatedString(const TagLib::StringList &taglib_string_list);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileRefFactory *factory_;
|
FileRefFactory *factory_;
|
||||||
|
|
||||||
|
|||||||
@@ -46,8 +46,6 @@
|
|||||||
|
|
||||||
TagReaderTagParser::TagReaderTagParser() = default;
|
TagReaderTagParser::TagReaderTagParser() = default;
|
||||||
|
|
||||||
TagReaderTagParser::~TagReaderTagParser() = default;
|
|
||||||
|
|
||||||
bool TagReaderTagParser::IsMediaFile(const QString &filename) const {
|
bool TagReaderTagParser::IsMediaFile(const QString &filename) const {
|
||||||
|
|
||||||
qLog(Debug) << "Checking for valid file" << filename;
|
qLog(Debug) << "Checking for valid file" << filename;
|
||||||
|
|||||||
@@ -37,7 +37,6 @@
|
|||||||
class TagReaderTagParser : public TagReaderBase {
|
class TagReaderTagParser : public TagReaderBase {
|
||||||
public:
|
public:
|
||||||
explicit TagReaderTagParser();
|
explicit TagReaderTagParser();
|
||||||
~TagReaderTagParser();
|
|
||||||
|
|
||||||
bool IsMediaFile(const QString &filename) const override;
|
bool IsMediaFile(const QString &filename) const override;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
qt_wrap_cpp(MACDEPLOYCHECK_MOC ${CMAKE_SOURCE_DIR}/ext/libstrawberry-common/core/logging.h)
|
qt_wrap_cpp(MACDEPLOYCHECK_MOC ${CMAKE_SOURCE_DIR}/ext/libstrawberry-common/core/logging.h)
|
||||||
link_directories(${GLIB_LIBRARY_DIRS})
|
|
||||||
add_executable(macdeploycheck macdeploycheck.cpp ${CMAKE_SOURCE_DIR}/ext/libstrawberry-common/core/logging.cpp ${MACDEPLOYCHECK_MOC})
|
add_executable(macdeploycheck macdeploycheck.cpp ${CMAKE_SOURCE_DIR}/ext/libstrawberry-common/core/logging.cpp ${MACDEPLOYCHECK_MOC})
|
||||||
target_include_directories(macdeploycheck PUBLIC SYSTEM
|
target_include_directories(macdeploycheck PUBLIC SYSTEM
|
||||||
${GLIB_INCLUDE_DIRS}
|
${GLIB_INCLUDE_DIRS}
|
||||||
@@ -8,6 +10,7 @@ target_include_directories(macdeploycheck PUBLIC
|
|||||||
${CMAKE_SOURCE_DIR}/ext/libstrawberry-common
|
${CMAKE_SOURCE_DIR}/ext/libstrawberry-common
|
||||||
${CMAKE_BINARY_DIR}/src
|
${CMAKE_BINARY_DIR}/src
|
||||||
)
|
)
|
||||||
|
target_link_directories(macdeploycheck PUBLIC ${GLIB_LIBRARY_DIRS})
|
||||||
target_link_libraries(macdeploycheck PUBLIC
|
target_link_libraries(macdeploycheck PUBLIC
|
||||||
"-framework AppKit"
|
"-framework AppKit"
|
||||||
${GLIB_LIBRARIES}
|
${GLIB_LIBRARIES}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.7)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
|
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
@@ -7,16 +7,6 @@ set(HEADERS tagreaderworker.h)
|
|||||||
|
|
||||||
qt_wrap_cpp(MOC ${HEADERS})
|
qt_wrap_cpp(MOC ${HEADERS})
|
||||||
|
|
||||||
link_directories(${GLIB_LIBRARY_DIRS})
|
|
||||||
|
|
||||||
if(HAVE_TAGLIB)
|
|
||||||
link_directories(${TAGLIB_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_TAGPARSER)
|
|
||||||
link_directories(${TAGPARSER_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_executable(strawberry-tagreader ${SOURCES} ${MOC} ${QRC})
|
add_executable(strawberry-tagreader ${SOURCES} ${MOC} ${QRC})
|
||||||
|
|
||||||
target_include_directories(strawberry-tagreader SYSTEM PRIVATE
|
target_include_directories(strawberry-tagreader SYSTEM PRIVATE
|
||||||
@@ -31,6 +21,8 @@ target_include_directories(strawberry-tagreader PRIVATE
|
|||||||
${CMAKE_BINARY_DIR}/src
|
${CMAKE_BINARY_DIR}/src
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_link_directories(strawberry-tagreader PRIVATE ${GLIB_LIBRARY_DIRS})
|
||||||
|
|
||||||
target_link_libraries(strawberry-tagreader PRIVATE
|
target_link_libraries(strawberry-tagreader PRIVATE
|
||||||
${GLIB_LIBRARIES}
|
${GLIB_LIBRARIES}
|
||||||
Qt${QT_VERSION_MAJOR}::Core
|
Qt${QT_VERSION_MAJOR}::Core
|
||||||
@@ -41,11 +33,13 @@ target_link_libraries(strawberry-tagreader PRIVATE
|
|||||||
|
|
||||||
if(HAVE_TAGLIB)
|
if(HAVE_TAGLIB)
|
||||||
target_include_directories(strawberry-tagreader SYSTEM PRIVATE ${TAGLIB_INCLUDE_DIRS})
|
target_include_directories(strawberry-tagreader SYSTEM PRIVATE ${TAGLIB_INCLUDE_DIRS})
|
||||||
|
target_link_directories(strawberry-tagreader PRIVATE ${TAGLIB_LIBRARY_DIRS})
|
||||||
target_link_libraries(strawberry-tagreader PRIVATE ${TAGLIB_LIBRARIES})
|
target_link_libraries(strawberry-tagreader PRIVATE ${TAGLIB_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_TAGPARSER)
|
if(HAVE_TAGPARSER)
|
||||||
target_include_directories(strawberry-tagreader SYSTEM PRIVATE ${TAGPARSER_INCLUDE_DIRS})
|
target_include_directories(strawberry-tagreader SYSTEM PRIVATE ${TAGPARSER_INCLUDE_DIRS})
|
||||||
|
target_link_directories(strawberry-tagreader PRIVATE ${TAGPARSER_LIBRARY_DIRS})
|
||||||
target_link_libraries(strawberry-tagreader PRIVATE ${TAGPARSER_LIBRARIES})
|
target_link_libraries(strawberry-tagreader PRIVATE ${TAGPARSER_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -73,7 +74,7 @@ void TagReaderWorker::DeviceClosed() {
|
|||||||
|
|
||||||
void TagReaderWorker::HandleMessage(const spb::tagreader::Message &message, spb::tagreader::Message &reply) {
|
void TagReaderWorker::HandleMessage(const spb::tagreader::Message &message, spb::tagreader::Message &reply) {
|
||||||
|
|
||||||
for (shared_ptr<TagReaderBase> reader : tagreaders_) {
|
for (shared_ptr<TagReaderBase> reader : std::as_const(tagreaders_)) {
|
||||||
|
|
||||||
if (message.has_is_media_file_request()) {
|
if (message.has_is_media_file_request()) {
|
||||||
const QString filename = QString::fromStdString(message.is_media_file_request().filename());
|
const QString filename = QString::fromStdString(message.is_media_file_request().filename());
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.7)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
if(HAVE_TRANSLATIONS)
|
if(HAVE_TRANSLATIONS)
|
||||||
include(../cmake/Translations.cmake)
|
include(../cmake/Translations.cmake)
|
||||||
@@ -41,6 +41,9 @@ set(SOURCES
|
|||||||
core/translations.cpp
|
core/translations.cpp
|
||||||
core/systemtrayicon.cpp
|
core/systemtrayicon.cpp
|
||||||
core/localredirectserver.cpp
|
core/localredirectserver.cpp
|
||||||
|
core/mimedata.cpp
|
||||||
|
core/potranslator.cpp
|
||||||
|
core/temporaryfile.cpp
|
||||||
utilities/strutils.cpp
|
utilities/strutils.cpp
|
||||||
utilities/envutils.cpp
|
utilities/envutils.cpp
|
||||||
utilities/colorutils.cpp
|
utilities/colorutils.cpp
|
||||||
@@ -110,8 +113,10 @@ set(SOURCES
|
|||||||
playlist/playlistfilter.cpp
|
playlist/playlistfilter.cpp
|
||||||
playlist/playlistheader.cpp
|
playlist/playlistheader.cpp
|
||||||
playlist/playlistitem.cpp
|
playlist/playlistitem.cpp
|
||||||
|
playlist/playlistitemmimedata.cpp
|
||||||
playlist/playlistlistcontainer.cpp
|
playlist/playlistlistcontainer.cpp
|
||||||
playlist/playlistlistmodel.cpp
|
playlist/playlistlistmodel.cpp
|
||||||
|
playlist/playlistlistsortfiltermodel.cpp
|
||||||
playlist/playlistlistview.cpp
|
playlist/playlistlistview.cpp
|
||||||
playlist/playlistmanager.cpp
|
playlist/playlistmanager.cpp
|
||||||
playlist/playlistsaveoptionsdialog.cpp
|
playlist/playlistsaveoptionsdialog.cpp
|
||||||
@@ -120,6 +125,7 @@ set(SOURCES
|
|||||||
playlist/playlistundocommands.cpp
|
playlist/playlistundocommands.cpp
|
||||||
playlist/playlistview.cpp
|
playlist/playlistview.cpp
|
||||||
playlist/playlistproxystyle.cpp
|
playlist/playlistproxystyle.cpp
|
||||||
|
playlist/songmimedata.cpp
|
||||||
playlist/songloaderinserter.cpp
|
playlist/songloaderinserter.cpp
|
||||||
playlist/songplaylistitem.cpp
|
playlist/songplaylistitem.cpp
|
||||||
playlist/dynamicplaylistcontrols.cpp
|
playlist/dynamicplaylistcontrols.cpp
|
||||||
@@ -140,17 +146,23 @@ set(SOURCES
|
|||||||
|
|
||||||
smartplaylists/playlistgenerator.cpp
|
smartplaylists/playlistgenerator.cpp
|
||||||
smartplaylists/playlistgeneratorinserter.cpp
|
smartplaylists/playlistgeneratorinserter.cpp
|
||||||
|
smartplaylists/playlistgeneratormimedata.cpp
|
||||||
smartplaylists/playlistquerygenerator.cpp
|
smartplaylists/playlistquerygenerator.cpp
|
||||||
smartplaylists/smartplaylistquerywizardplugin.cpp
|
smartplaylists/smartplaylistquerywizardplugin.cpp
|
||||||
|
smartplaylists/smartplaylistquerywizardpluginsortpage.cpp
|
||||||
|
smartplaylists/smartplaylistquerywizardpluginsearchpage.cpp
|
||||||
smartplaylists/smartplaylistsearch.cpp
|
smartplaylists/smartplaylistsearch.cpp
|
||||||
smartplaylists/smartplaylistsearchpreview.cpp
|
smartplaylists/smartplaylistsearchpreview.cpp
|
||||||
smartplaylists/smartplaylistsearchterm.cpp
|
smartplaylists/smartplaylistsearchterm.cpp
|
||||||
smartplaylists/smartplaylistsearchtermwidget.cpp
|
smartplaylists/smartplaylistsearchtermwidget.cpp
|
||||||
|
smartplaylists/smartplaylistsearchtermwidgetoverlay.cpp
|
||||||
smartplaylists/smartplaylistsmodel.cpp
|
smartplaylists/smartplaylistsmodel.cpp
|
||||||
smartplaylists/smartplaylistsviewcontainer.cpp
|
smartplaylists/smartplaylistsviewcontainer.cpp
|
||||||
smartplaylists/smartplaylistsview.cpp
|
smartplaylists/smartplaylistsview.cpp
|
||||||
smartplaylists/smartplaylistwizard.cpp
|
smartplaylists/smartplaylistwizard.cpp
|
||||||
smartplaylists/smartplaylistwizardplugin.cpp
|
smartplaylists/smartplaylistwizardplugin.cpp
|
||||||
|
smartplaylists/smartplaylistwizardtypepage.cpp
|
||||||
|
smartplaylists/smartplaylistwizardfinishpage.cpp
|
||||||
|
|
||||||
covermanager/albumcovermanager.cpp
|
covermanager/albumcovermanager.cpp
|
||||||
covermanager/albumcovermanagerlist.cpp
|
covermanager/albumcovermanagerlist.cpp
|
||||||
@@ -195,6 +207,7 @@ set(SOURCES
|
|||||||
lyrics/azlyricscomlyricsprovider.cpp
|
lyrics/azlyricscomlyricsprovider.cpp
|
||||||
lyrics/elyricsnetlyricsprovider.cpp
|
lyrics/elyricsnetlyricsprovider.cpp
|
||||||
lyrics/letraslyricsprovider.cpp
|
lyrics/letraslyricsprovider.cpp
|
||||||
|
lyrics/lyricfindlyricsprovider.cpp
|
||||||
|
|
||||||
providers/musixmatchprovider.cpp
|
providers/musixmatchprovider.cpp
|
||||||
|
|
||||||
@@ -230,6 +243,8 @@ set(SOURCES
|
|||||||
widgets/busyindicator.cpp
|
widgets/busyindicator.cpp
|
||||||
widgets/clickablelabel.cpp
|
widgets/clickablelabel.cpp
|
||||||
widgets/fancytabwidget.cpp
|
widgets/fancytabwidget.cpp
|
||||||
|
widgets/fancytabbar.cpp
|
||||||
|
widgets/fancytabdata.cpp
|
||||||
widgets/favoritewidget.cpp
|
widgets/favoritewidget.cpp
|
||||||
widgets/fileview.cpp
|
widgets/fileview.cpp
|
||||||
widgets/fileviewlist.cpp
|
widgets/fileviewlist.cpp
|
||||||
@@ -268,6 +283,7 @@ set(SOURCES
|
|||||||
streaming/streamingcollectionview.cpp
|
streaming/streamingcollectionview.cpp
|
||||||
streaming/streamingcollectionviewcontainer.cpp
|
streaming/streamingcollectionviewcontainer.cpp
|
||||||
streaming/streamingsearchview.cpp
|
streaming/streamingsearchview.cpp
|
||||||
|
streaming/streamsongmimedata.cpp
|
||||||
|
|
||||||
radios/radioservices.cpp
|
radios/radioservices.cpp
|
||||||
radios/radiobackend.cpp
|
radios/radiobackend.cpp
|
||||||
@@ -279,6 +295,7 @@ set(SOURCES
|
|||||||
radios/radiochannel.cpp
|
radios/radiochannel.cpp
|
||||||
radios/somafmservice.cpp
|
radios/somafmservice.cpp
|
||||||
radios/radioparadiseservice.cpp
|
radios/radioparadiseservice.cpp
|
||||||
|
radios/radiomimedata.cpp
|
||||||
|
|
||||||
scrobbler/audioscrobbler.cpp
|
scrobbler/audioscrobbler.cpp
|
||||||
scrobbler/scrobblersettings.cpp
|
scrobbler/scrobblersettings.cpp
|
||||||
@@ -294,6 +311,8 @@ set(SOURCES
|
|||||||
|
|
||||||
organize/organize.cpp
|
organize/organize.cpp
|
||||||
organize/organizeformat.cpp
|
organize/organizeformat.cpp
|
||||||
|
organize/organizeformatvalidator.cpp
|
||||||
|
organize/organizesyntaxhighlighter.cpp
|
||||||
organize/organizedialog.cpp
|
organize/organizedialog.cpp
|
||||||
organize/organizeerrordialog.cpp
|
organize/organizeerrordialog.cpp
|
||||||
|
|
||||||
@@ -396,13 +415,18 @@ set(HEADERS
|
|||||||
smartplaylists/playlistquerygenerator.h
|
smartplaylists/playlistquerygenerator.h
|
||||||
smartplaylists/playlistgeneratormimedata.h
|
smartplaylists/playlistgeneratormimedata.h
|
||||||
smartplaylists/smartplaylistquerywizardplugin.h
|
smartplaylists/smartplaylistquerywizardplugin.h
|
||||||
|
smartplaylists/smartplaylistquerywizardpluginsortpage.h
|
||||||
|
smartplaylists/smartplaylistquerywizardpluginsearchpage.h
|
||||||
smartplaylists/smartplaylistsearchpreview.h
|
smartplaylists/smartplaylistsearchpreview.h
|
||||||
smartplaylists/smartplaylistsearchtermwidget.h
|
smartplaylists/smartplaylistsearchtermwidget.h
|
||||||
|
smartplaylists/smartplaylistsearchtermwidgetoverlay.h
|
||||||
smartplaylists/smartplaylistsmodel.h
|
smartplaylists/smartplaylistsmodel.h
|
||||||
smartplaylists/smartplaylistsviewcontainer.h
|
smartplaylists/smartplaylistsviewcontainer.h
|
||||||
smartplaylists/smartplaylistsview.h
|
smartplaylists/smartplaylistsview.h
|
||||||
smartplaylists/smartplaylistwizard.h
|
smartplaylists/smartplaylistwizard.h
|
||||||
smartplaylists/smartplaylistwizardplugin.h
|
smartplaylists/smartplaylistwizardplugin.h
|
||||||
|
smartplaylists/smartplaylistwizardtypepage.h
|
||||||
|
smartplaylists/smartplaylistwizardfinishpage.h
|
||||||
|
|
||||||
covermanager/albumcovermanager.h
|
covermanager/albumcovermanager.h
|
||||||
covermanager/albumcovermanagerlist.h
|
covermanager/albumcovermanagerlist.h
|
||||||
@@ -443,6 +467,7 @@ set(HEADERS
|
|||||||
lyrics/azlyricscomlyricsprovider.h
|
lyrics/azlyricscomlyricsprovider.h
|
||||||
lyrics/elyricsnetlyricsprovider.h
|
lyrics/elyricsnetlyricsprovider.h
|
||||||
lyrics/letraslyricsprovider.h
|
lyrics/letraslyricsprovider.h
|
||||||
|
lyrics/lyricfindlyricsprovider.h
|
||||||
|
|
||||||
settings/settingsdialog.h
|
settings/settingsdialog.h
|
||||||
settings/settingspage.h
|
settings/settingspage.h
|
||||||
@@ -476,6 +501,8 @@ set(HEADERS
|
|||||||
widgets/busyindicator.h
|
widgets/busyindicator.h
|
||||||
widgets/clickablelabel.h
|
widgets/clickablelabel.h
|
||||||
widgets/fancytabwidget.h
|
widgets/fancytabwidget.h
|
||||||
|
widgets/fancytabbar.h
|
||||||
|
widgets/fancytabdata.h
|
||||||
widgets/favoritewidget.h
|
widgets/favoritewidget.h
|
||||||
widgets/fileview.h
|
widgets/fileview.h
|
||||||
widgets/fileviewlist.h
|
widgets/fileviewlist.h
|
||||||
@@ -495,7 +522,7 @@ set(HEADERS
|
|||||||
widgets/tracksliderpopup.h
|
widgets/tracksliderpopup.h
|
||||||
widgets/tracksliderslider.h
|
widgets/tracksliderslider.h
|
||||||
widgets/loginstatewidget.h
|
widgets/loginstatewidget.h
|
||||||
widgets/qsearchfield.h
|
widgets/searchfield.h
|
||||||
widgets/ratingwidget.h
|
widgets/ratingwidget.h
|
||||||
widgets/forcescrollperpixel.h
|
widgets/forcescrollperpixel.h
|
||||||
widgets/resizabletextedit.h
|
widgets/resizabletextedit.h
|
||||||
@@ -536,6 +563,8 @@ set(HEADERS
|
|||||||
scrobbler/lastfmimport.h
|
scrobbler/lastfmimport.h
|
||||||
|
|
||||||
organize/organize.h
|
organize/organize.h
|
||||||
|
organize/organizeformatvalidator.h
|
||||||
|
organize/organizesyntaxhighlighter.h
|
||||||
organize/organizedialog.h
|
organize/organizedialog.h
|
||||||
organize/organizeerrordialog.h
|
organize/organizeerrordialog.h
|
||||||
|
|
||||||
@@ -621,7 +650,7 @@ option(USE_INSTALL_PREFIX "Look for data in CMAKE_INSTALL_PREFIX" ON)
|
|||||||
|
|
||||||
if(NOT APPLE)
|
if(NOT APPLE)
|
||||||
set(NOT_APPLE ON)
|
set(NOT_APPLE ON)
|
||||||
optional_source(NOT_APPLE SOURCES widgets/qsearchfield_qt.cpp core/qtsystemtrayicon.cpp HEADERS core/qtsystemtrayicon.h)
|
optional_source(NOT_APPLE SOURCES widgets/searchfield_qt.cpp widgets/searchfield_qt_private.cpp core/qtsystemtrayicon.cpp HEADERS core/qtsystemtrayicon.h widgets/searchfield_qt_private.h)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_GLOBALSHORTCUTS)
|
if(HAVE_GLOBALSHORTCUTS)
|
||||||
@@ -760,6 +789,7 @@ optional_source(HAVE_LIBPULSE SOURCES engine/pulsedevicefinder.cpp)
|
|||||||
optional_source(HAVE_GSTREAMER
|
optional_source(HAVE_GSTREAMER
|
||||||
SOURCES
|
SOURCES
|
||||||
transcoder/transcoder.cpp
|
transcoder/transcoder.cpp
|
||||||
|
transcoder/transcoderoptionsinterface.cpp
|
||||||
transcoder/transcodedialog.cpp
|
transcoder/transcodedialog.cpp
|
||||||
transcoder/transcoderoptionsdialog.cpp
|
transcoder/transcoderoptionsdialog.cpp
|
||||||
transcoder/transcoderoptionsflac.cpp
|
transcoder/transcoderoptionsflac.cpp
|
||||||
@@ -838,7 +868,7 @@ optional_source(APPLE
|
|||||||
core/macsystemtrayicon.mm
|
core/macsystemtrayicon.mm
|
||||||
core/macfslistener.mm
|
core/macfslistener.mm
|
||||||
osd/osdmac.mm
|
osd/osdmac.mm
|
||||||
widgets/qsearchfield_mac.mm
|
widgets/searchfield_mac.mm
|
||||||
engine/macosdevicefinder.cpp
|
engine/macosdevicefinder.cpp
|
||||||
globalshortcuts/globalshortcutsbackend-macos.mm
|
globalshortcuts/globalshortcutsbackend-macos.mm
|
||||||
globalshortcuts/globalshortcutgrabber.mm
|
globalshortcuts/globalshortcutgrabber.mm
|
||||||
@@ -1000,95 +1030,20 @@ if(HAVE_TRANSLATIONS)
|
|||||||
endif(NOT LINGUAS OR LINGUAS STREQUAL "None")
|
endif(NOT LINGUAS OR LINGUAS STREQUAL "None")
|
||||||
endif(LINGUAS STREQUAL "All")
|
endif(LINGUAS STREQUAL "All")
|
||||||
|
|
||||||
add_pot(POT
|
if(NOT MSVC)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/translations/header
|
add_pot(POT
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/translations/translations.pot
|
${CMAKE_CURRENT_SOURCE_DIR}/translations/header
|
||||||
${SOURCES}
|
${CMAKE_CURRENT_SOURCE_DIR}/translations/translations.pot
|
||||||
${MOC}
|
${SOURCES}
|
||||||
${UIC}
|
${MOC}
|
||||||
${CMAKE_SOURCE_DIR}/data/html/oauthsuccess.html
|
${UIC}
|
||||||
)
|
${CMAKE_SOURCE_DIR}/data/html/oauthsuccess.html
|
||||||
|
)
|
||||||
|
endif()
|
||||||
add_po(PO strawberry_ LANGUAGES ${LANGUAGES} DIRECTORY translations)
|
add_po(PO strawberry_ LANGUAGES ${LANGUAGES} DIRECTORY translations)
|
||||||
|
|
||||||
endif(HAVE_TRANSLATIONS)
|
endif(HAVE_TRANSLATIONS)
|
||||||
|
|
||||||
link_directories(
|
|
||||||
${Boost_LIBRARY_DIRS}
|
|
||||||
${GLIB_LIBRARY_DIRS}
|
|
||||||
${GOBJECT_LIBRARY_DIRS}
|
|
||||||
${SQLITE_LIBRARY_DIRS}
|
|
||||||
${PROTOBUF_LIBRARY_DIRS}
|
|
||||||
${SINGLEAPPLICATION_LIBRARY_DIRS}
|
|
||||||
${ICU_LIBRARY_DIRS}
|
|
||||||
)
|
|
||||||
|
|
||||||
if(HAVE_ALSA)
|
|
||||||
link_directories(${ALSA_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_LIBPULSE)
|
|
||||||
link_directories(${LIBPULSE_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_GSTREAMER)
|
|
||||||
link_directories(
|
|
||||||
${GSTREAMER_LIBRARY_DIRS}
|
|
||||||
${GSTREAMER_BASE_LIBRARY_DIRS}
|
|
||||||
${GSTREAMER_APP_LIBRARY_DIRS}
|
|
||||||
${GSTREAMER_AUDIO_LIBRARY_DIRS}
|
|
||||||
${GSTREAMER_TAG_LIBRARY_DIRS}
|
|
||||||
${GSTREAMER_PBUTILS_LIBRARY_DIRS}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_VLC)
|
|
||||||
link_directories(${LIBVLC_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_SONGFINGERPRINTING OR HAVE_MUSICBRAINZ)
|
|
||||||
link_directories(${CHROMAPRINT_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(X11_FOUND)
|
|
||||||
link_directories(${X11_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(XCB_FOUND)
|
|
||||||
link_directories(${XCB_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_GIO)
|
|
||||||
link_directories(${GIO_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_GIO_UNIX)
|
|
||||||
link_directories(${GIO_UNIX_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_AUDIOCD)
|
|
||||||
link_directories(${LIBCDIO_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_LIBGPOD)
|
|
||||||
link_directories(${LIBGPOD_LIBRARY_DIRS} ${GDK_PIXBUF_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_LIBMTP)
|
|
||||||
link_directories(${LIBMTP_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_TAGLIB)
|
|
||||||
link_directories(${TAGLIB_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_TAGPARSER)
|
|
||||||
link_directories(${TAGPARSER_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_QTSPARKLE)
|
|
||||||
link_directories(${QTSPARKLE_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(strawberry_lib STATIC
|
add_library(strawberry_lib STATIC
|
||||||
${SOURCES}
|
${SOURCES}
|
||||||
${MOC}
|
${MOC}
|
||||||
@@ -1123,6 +1078,16 @@ target_include_directories(strawberry_lib PUBLIC
|
|||||||
${SINGLEAPPLICATION_INCLUDE_DIRS}
|
${SINGLEAPPLICATION_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_link_directories(strawberry_lib PUBLIC
|
||||||
|
${Boost_LIBRARY_DIRS}
|
||||||
|
${GLIB_LIBRARY_DIRS}
|
||||||
|
${GOBJECT_LIBRARY_DIRS}
|
||||||
|
${SQLITE_LIBRARY_DIRS}
|
||||||
|
${PROTOBUF_LIBRARY_DIRS}
|
||||||
|
${SINGLEAPPLICATION_LIBRARY_DIRS}
|
||||||
|
${ICU_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
target_link_libraries(strawberry_lib PUBLIC
|
target_link_libraries(strawberry_lib PUBLIC
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
${CMAKE_THREAD_LIBS_INIT}
|
||||||
${GLIB_LIBRARIES}
|
${GLIB_LIBRARIES}
|
||||||
@@ -1151,11 +1116,13 @@ endif()
|
|||||||
|
|
||||||
if(HAVE_ALSA)
|
if(HAVE_ALSA)
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${ALSA_INCLUDE_DIRS})
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${ALSA_INCLUDE_DIRS})
|
||||||
|
target_link_directories(strawberry_lib PRIVATE ${ALSA_LIBRARY_DIRS})
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${ALSA_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${ALSA_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_LIBPULSE)
|
if(HAVE_LIBPULSE)
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBPULSE_INCLUDE_DIRS})
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBPULSE_INCLUDE_DIRS})
|
||||||
|
target_link_directories(strawberry_lib PRIVATE ${LIBPULSE_LIBRARY_DIRS})
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${LIBPULSE_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${LIBPULSE_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -1168,6 +1135,14 @@ if(HAVE_GSTREAMER)
|
|||||||
${GSTREAMER_TAG_INCLUDE_DIRS}
|
${GSTREAMER_TAG_INCLUDE_DIRS}
|
||||||
${GSTREAMER_PBUTILS_INCLUDE_DIRS}
|
${GSTREAMER_PBUTILS_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
target_link_directories(strawberry_lib PRIVATE
|
||||||
|
${GSTREAMER_LIBRARY_DIRS}
|
||||||
|
${GSTREAMER_BASE_LIBRARY_DIRS}
|
||||||
|
${GSTREAMER_APP_LIBRARY_DIRS}
|
||||||
|
${GSTREAMER_AUDIO_LIBRARY_DIRS}
|
||||||
|
${GSTREAMER_TAG_LIBRARY_DIRS}
|
||||||
|
${GSTREAMER_PBUTILS_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
target_link_libraries(strawberry_lib PRIVATE
|
target_link_libraries(strawberry_lib PRIVATE
|
||||||
${GSTREAMER_LIBRARIES}
|
${GSTREAMER_LIBRARIES}
|
||||||
${GSTREAMER_BASE_LIBRARIES}
|
${GSTREAMER_BASE_LIBRARIES}
|
||||||
@@ -1184,11 +1159,13 @@ endif()
|
|||||||
|
|
||||||
if(HAVE_VLC)
|
if(HAVE_VLC)
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBVLC_INCLUDE_DIRS})
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBVLC_INCLUDE_DIRS})
|
||||||
|
target_link_directories(strawberry_lib PRIVATE ${LIBVLC_LIBRARY_DIRS})
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${LIBVLC_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${LIBVLC_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_SONGFINGERPRINTING OR HAVE_MUSICBRAINZ)
|
if(HAVE_SONGFINGERPRINTING OR HAVE_MUSICBRAINZ)
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${CHROMAPRINT_INCLUDE_DIRS})
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${CHROMAPRINT_INCLUDE_DIRS})
|
||||||
|
target_link_directories(strawberry_lib PRIVATE ${CHROMAPRINT_LIBRARY_DIRS})
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${CHROMAPRINT_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${CHROMAPRINT_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -1198,36 +1175,43 @@ endif()
|
|||||||
|
|
||||||
if(X11_FOUND)
|
if(X11_FOUND)
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${X11_INCLUDE_DIR})
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${X11_INCLUDE_DIR})
|
||||||
|
target_link_directories(strawberry_lib PRIVATE ${X11_LIBRARY_DIRS})
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${X11_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${X11_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(XCB_FOUND)
|
if(XCB_FOUND)
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${XCB_INCLUDE_DIR})
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${XCB_INCLUDE_DIR})
|
||||||
|
target_link_directories(strawberry_lib PRIVATE ${XCB_LIBRARY_DIRS})
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${XCB_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${XCB_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_GIO)
|
if(HAVE_GIO)
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${GIO_INCLUDE_DIRS})
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${GIO_INCLUDE_DIRS})
|
||||||
|
target_link_directories(strawberry_lib PRIVATE ${GIO_LIBRARY_DIRS})
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${GIO_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${GIO_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_GIO_UNIX)
|
if(HAVE_GIO_UNIX)
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${GIO_UNIX_INCLUDE_DIRS})
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${GIO_UNIX_INCLUDE_DIRS})
|
||||||
|
target_link_directories(strawberry_lib PRIVATE ${GIO_UNIX_LIBRARY_DIRS})
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${GIO_UNIX_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${GIO_UNIX_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_AUDIOCD)
|
if(HAVE_AUDIOCD)
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBCDIO_INCLUDE_DIRS})
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBCDIO_INCLUDE_DIRS})
|
||||||
|
target_link_directories(strawberry_lib PRIVATE ${LIBCDIO_LIBRARY_DIRS})
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${LIBCDIO_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${LIBCDIO_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_LIBGPOD)
|
if(HAVE_LIBGPOD)
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBGPOD_INCLUDE_DIRS} ${GDK_PIXBUF_INCLUDE_DIRS})
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBGPOD_INCLUDE_DIRS} ${GDK_PIXBUF_INCLUDE_DIRS})
|
||||||
|
target_link_directories(strawberry_lib PRIVATE ${LIBGPOD_LIBRARY_DIRS} ${GDK_PIXBUF_LIBRARY_DIRS})
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${LIBGPOD_LIBRARIES} ${GDK_PIXBUF_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${LIBGPOD_LIBRARIES} ${GDK_PIXBUF_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_LIBMTP)
|
if(HAVE_LIBMTP)
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBMTP_INCLUDE_DIRS})
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBMTP_INCLUDE_DIRS})
|
||||||
|
target_link_directories(strawberry_lib PRIVATE ${LIBMTP_LIBRARY_DIRS})
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${LIBMTP_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${LIBMTP_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -1259,6 +1243,7 @@ endif()
|
|||||||
|
|
||||||
if(HAVE_QTSPARKLE)
|
if(HAVE_QTSPARKLE)
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${QTSPARKLE_INCLUDE_DIRS})
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${QTSPARKLE_INCLUDE_DIRS})
|
||||||
|
target_link_directories(strawberry_lib PRIVATE ${QTSPARKLE_LIBRARY_DIRS})
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${QTSPARKLE_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${QTSPARKLE_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ void AnalyzerContainer::ShowPopupMenu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AnalyzerContainer::wheelEvent(QWheelEvent *e) {
|
void AnalyzerContainer::wheelEvent(QWheelEvent *e) {
|
||||||
emit WheelEvent(e->angleDelta().y());
|
Q_EMIT WheelEvent(e->angleDelta().y());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalyzerContainer::SetEngine(SharedPtr<EngineBase> engine) {
|
void AnalyzerContainer::SetEngine(SharedPtr<EngineBase> engine) {
|
||||||
@@ -149,7 +149,7 @@ void AnalyzerContainer::DisableAnalyzer() {
|
|||||||
|
|
||||||
void AnalyzerContainer::ChangeAnalyzer(const int id) {
|
void AnalyzerContainer::ChangeAnalyzer(const int id) {
|
||||||
|
|
||||||
QObject *instance = analyzer_types_[id]->newInstance(Q_ARG(QWidget*, this));
|
QObject *instance = analyzer_types_.at(id)->newInstance(Q_ARG(QWidget*, this));
|
||||||
|
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
qLog(Warning) << "Couldn't initialize a new" << analyzer_types_[id]->className();
|
qLog(Warning) << "Couldn't initialize a new" << analyzer_types_[id]->className();
|
||||||
@@ -200,18 +200,25 @@ void AnalyzerContainer::Load() {
|
|||||||
for (int i = 0; i < analyzer_types_.count(); ++i) {
|
for (int i = 0; i < analyzer_types_.count(); ++i) {
|
||||||
if (type == QString::fromLatin1(analyzer_types_[i]->className())) {
|
if (type == QString::fromLatin1(analyzer_types_[i]->className())) {
|
||||||
ChangeAnalyzer(i);
|
ChangeAnalyzer(i);
|
||||||
actions_[i]->setChecked(true);
|
QAction *action = actions_.value(i);
|
||||||
|
action->setChecked(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!current_analyzer_) {
|
||||||
|
ChangeAnalyzer(0);
|
||||||
|
QAction *action = actions_.value(0);
|
||||||
|
action->setChecked(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Framerate
|
// Framerate
|
||||||
QList<QAction*> actions = group_framerate_->actions();
|
const QList<QAction*> actions = group_framerate_->actions();
|
||||||
for (int i = 0; i < framerate_list_.count(); ++i) {
|
for (int i = 0; i < framerate_list_.count(); ++i) {
|
||||||
if (current_framerate_ == framerate_list_[i]) {
|
if (current_framerate_ == framerate_list_.value(i)) {
|
||||||
ChangeFramerate(current_framerate_);
|
ChangeFramerate(current_framerate_);
|
||||||
actions[i]->setChecked(true);
|
QAction *action = actions[i];
|
||||||
|
action->setChecked(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,14 +50,14 @@ class AnalyzerContainer : public QWidget {
|
|||||||
static const char *kSettingsGroup;
|
static const char *kSettingsGroup;
|
||||||
static const char *kSettingsFramerate;
|
static const char *kSettingsFramerate;
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void WheelEvent(const int delta);
|
void WheelEvent(const int delta);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
void wheelEvent(QWheelEvent *e) override;
|
void wheelEvent(QWheelEvent *e) override;
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void ChangeAnalyzer(const int id);
|
void ChangeAnalyzer(const int id);
|
||||||
void ChangeFramerate(int new_framerate);
|
void ChangeFramerate(int new_framerate);
|
||||||
void DisableAnalyzer();
|
void DisableAnalyzer();
|
||||||
|
|||||||
@@ -36,12 +36,14 @@
|
|||||||
#include "analyzerbase.h"
|
#include "analyzerbase.h"
|
||||||
#include "fht.h"
|
#include "fht.h"
|
||||||
|
|
||||||
const int BlockAnalyzer::kHeight = 2;
|
namespace {
|
||||||
const int BlockAnalyzer::kWidth = 4;
|
constexpr int kHeight = 2;
|
||||||
const int BlockAnalyzer::kMinRows = 3; // arbitrary
|
constexpr int kWidth = 4;
|
||||||
const int BlockAnalyzer::kMinColumns = 32; // arbitrary
|
constexpr int kMinRows = 3; // arbitrary
|
||||||
const int BlockAnalyzer::kMaxColumns = 256; // must be 2**n
|
constexpr int kMinColumns = 32; // arbitrary
|
||||||
const int BlockAnalyzer::kFadeSize = 90;
|
constexpr int kMaxColumns = 256; // must be 2**n
|
||||||
|
constexpr int kFadeSize = 90;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
const char *BlockAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Block analyzer");
|
const char *BlockAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Block analyzer");
|
||||||
|
|
||||||
@@ -165,11 +167,12 @@ void BlockAnalyzer::analyze(QPainter &p, const Scope &s, const bool new_frame) {
|
|||||||
|
|
||||||
for (int x = 0, y = 0; x < static_cast<int>(scope_.size()); ++x) {
|
for (int x = 0, y = 0; x < static_cast<int>(scope_.size()); ++x) {
|
||||||
// determine y
|
// determine y
|
||||||
for (y = 0; scope_[x] < yscale_[y]; ++y);
|
for (y = 0; scope_[x] < yscale_.at(y); ++y);
|
||||||
|
|
||||||
// This is opposite to what you'd think, higher than y means the bar is lower than y (physically)
|
// This is opposite to what you'd think, higher than y means the bar is lower than y (physically)
|
||||||
if (static_cast<double>(y) > store_[x]) {
|
if (static_cast<double>(y) > store_.at(x)) {
|
||||||
y = static_cast<int>(store_[x] += step_);
|
store_[x] += step_;
|
||||||
|
y = static_cast<int>(store_.value(x));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
store_[x] = y;
|
store_[x] = y;
|
||||||
@@ -177,18 +180,19 @@ void BlockAnalyzer::analyze(QPainter &p, const Scope &s, const bool new_frame) {
|
|||||||
|
|
||||||
// If y is lower than fade_pos_, then the bar has exceeded the height of the fadeout
|
// If y is lower than fade_pos_, then the bar has exceeded the height of the fadeout
|
||||||
// if the fadeout is quite faded now, then display the new one
|
// if the fadeout is quite faded now, then display the new one
|
||||||
if (y <= fade_pos_[x] /*|| fade_intensity_[x] < kFadeSize / 3*/) {
|
if (y <= fade_pos_.at(x) /*|| fade_intensity_[x] < kFadeSize / 3*/) {
|
||||||
fade_pos_[x] = y;
|
fade_pos_[x] = y;
|
||||||
fade_intensity_[x] = kFadeSize;
|
fade_intensity_[x] = kFadeSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fade_intensity_[x] > 0) {
|
if (fade_intensity_.at(x) > 0) {
|
||||||
const int offset = --fade_intensity_[x];
|
--fade_intensity_[x];
|
||||||
const int y2 = y_ + (fade_pos_[x] * (kHeight + 1));
|
const int offset = fade_intensity_.value(x);
|
||||||
|
const int y2 = y_ + (fade_pos_.value(x) * (kHeight + 1));
|
||||||
canvas_painter.drawPixmap(x * (kWidth + 1), y2, fade_bars_[offset], 0, 0, kWidth, height() - y2);
|
canvas_painter.drawPixmap(x * (kWidth + 1), y2, fade_bars_[offset], 0, 0, kWidth, height() - y2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fade_intensity_[x] == 0) fade_pos_[x] = rows_;
|
if (fade_intensity_.at(x) == 0) fade_pos_[x] = rows_;
|
||||||
|
|
||||||
// REMEMBER: y is a number from 0 to rows_, 0 means all blocks are glowing, rows_ means none are
|
// REMEMBER: y is a number from 0 to rows_, 0 means all blocks are glowing, rows_ means none are
|
||||||
canvas_painter.drawPixmap(x * (kWidth + 1), y * (kHeight + 1) + y_, *bar(), 0, y * (kHeight + 1), bar()->width(), bar()->height());
|
canvas_painter.drawPixmap(x * (kWidth + 1), y * (kHeight + 1) + y_, *bar(), 0, y * (kHeight + 1), bar()->width(), bar()->height());
|
||||||
|
|||||||
@@ -43,13 +43,6 @@ class BlockAnalyzer : public AnalyzerBase {
|
|||||||
public:
|
public:
|
||||||
Q_INVOKABLE explicit BlockAnalyzer(QWidget*);
|
Q_INVOKABLE explicit BlockAnalyzer(QWidget*);
|
||||||
|
|
||||||
static const int kHeight;
|
|
||||||
static const int kWidth;
|
|
||||||
static const int kMinRows;
|
|
||||||
static const int kMinColumns;
|
|
||||||
static const int kMaxColumns;
|
|
||||||
static const int kFadeSize;
|
|
||||||
|
|
||||||
static const char *kName;
|
static const char *kName;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class BoomAnalyzer : public AnalyzerBase {
|
|||||||
void transform(Scope &s) override;
|
void transform(Scope &s) override;
|
||||||
void analyze(QPainter &p, const Scope &scope, const bool new_frame) override;
|
void analyze(QPainter &p, const Scope &scope, const bool new_frame) override;
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void changeK_barHeight(int);
|
void changeK_barHeight(int);
|
||||||
void changeF_peakSpeed(int);
|
void changeF_peakSpeed(int);
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ SCollection::SCollection(Application *app, QObject *parent)
|
|||||||
save_playcounts_to_files_(false),
|
save_playcounts_to_files_(false),
|
||||||
save_ratings_to_files_(false) {
|
save_ratings_to_files_(false) {
|
||||||
|
|
||||||
|
setObjectName(QLatin1String(metaObject()->className()));
|
||||||
|
|
||||||
original_thread_ = thread();
|
original_thread_ = thread();
|
||||||
|
|
||||||
backend_ = make_shared<CollectionBackend>();
|
backend_ = make_shared<CollectionBackend>();
|
||||||
@@ -80,7 +82,7 @@ SCollection::SCollection(Application *app, QObject *parent)
|
|||||||
SCollection::~SCollection() {
|
SCollection::~SCollection() {
|
||||||
|
|
||||||
if (watcher_) {
|
if (watcher_) {
|
||||||
watcher_->Stop();
|
watcher_->Abort();
|
||||||
watcher_->deleteLater();
|
watcher_->deleteLater();
|
||||||
}
|
}
|
||||||
if (watcher_thread_) {
|
if (watcher_thread_) {
|
||||||
@@ -94,6 +96,7 @@ void SCollection::Init() {
|
|||||||
|
|
||||||
watcher_ = new CollectionWatcher(Song::Source::Collection);
|
watcher_ = new CollectionWatcher(Song::Source::Collection);
|
||||||
watcher_thread_ = new Thread(this);
|
watcher_thread_ = new Thread(this);
|
||||||
|
watcher_thread_->setObjectName(watcher_->objectName());
|
||||||
|
|
||||||
watcher_thread_->SetIoPriority(Utilities::IoPriority::IOPRIO_CLASS_IDLE);
|
watcher_thread_->SetIoPriority(Utilities::IoPriority::IOPRIO_CLASS_IDLE);
|
||||||
|
|
||||||
@@ -151,7 +154,7 @@ void SCollection::ExitReceived() {
|
|||||||
QObject::disconnect(obj, nullptr, this, nullptr);
|
QObject::disconnect(obj, nullptr, this, nullptr);
|
||||||
qLog(Debug) << obj << "successfully exited.";
|
qLog(Debug) << obj << "successfully exited.";
|
||||||
wait_for_exit_.removeAll(obj);
|
wait_for_exit_.removeAll(obj);
|
||||||
if (wait_for_exit_.isEmpty()) emit ExitFinished();
|
if (wait_for_exit_.isEmpty()) Q_EMIT ExitFinished();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +162,7 @@ void SCollection::IncrementalScan() { watcher_->IncrementalScanAsync(); }
|
|||||||
|
|
||||||
void SCollection::FullScan() { watcher_->FullScanAsync(); }
|
void SCollection::FullScan() { watcher_->FullScanAsync(); }
|
||||||
|
|
||||||
void SCollection::AbortScan() { watcher_->Stop(); }
|
void SCollection::StopScan() { watcher_->Stop(); }
|
||||||
|
|
||||||
void SCollection::Rescan(const SongList &songs) {
|
void SCollection::Rescan(const SongList &songs) {
|
||||||
|
|
||||||
|
|||||||
@@ -64,24 +64,24 @@ class SCollection : public QObject {
|
|||||||
private:
|
private:
|
||||||
void SyncPlaycountAndRatingToFiles();
|
void SyncPlaycountAndRatingToFiles();
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
|
|
||||||
void PauseWatcher();
|
void PauseWatcher();
|
||||||
void ResumeWatcher();
|
void ResumeWatcher();
|
||||||
|
|
||||||
void FullScan();
|
void FullScan();
|
||||||
void AbortScan();
|
void StopScan();
|
||||||
void Rescan(const SongList &songs);
|
void Rescan(const SongList &songs);
|
||||||
|
|
||||||
void IncrementalScan();
|
void IncrementalScan();
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void ExitReceived();
|
void ExitReceived();
|
||||||
void SongsPlaycountChanged(const SongList &songs, const bool save_tags = false);
|
void SongsPlaycountChanged(const SongList &songs, const bool save_tags = false);
|
||||||
void SongsRatingChanged(const SongList &songs, const bool save_tags = false);
|
void SongsRatingChanged(const SongList &songs, const bool save_tags = false);
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void Error(const QString &error);
|
void Error(const QString &error);
|
||||||
void ExitFinished();
|
void ExitFinished();
|
||||||
|
|
||||||
|
|||||||
@@ -72,17 +72,21 @@ CollectionBackend::CollectionBackend(QObject *parent)
|
|||||||
|
|
||||||
CollectionBackend::~CollectionBackend() {
|
CollectionBackend::~CollectionBackend() {
|
||||||
|
|
||||||
qLog(Debug) << "Collection backend" << this << "for" << Song::TextForSource(source_) << "deleted";
|
qLog(Debug) << "Collection backend" << this << "deleted";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionBackend::Init(SharedPtr<Database> db, SharedPtr<TaskManager> task_manager, const Song::Source source, const QString &songs_table, const QString &dirs_table, const QString &subdirs_table) {
|
void CollectionBackend::Init(SharedPtr<Database> db, SharedPtr<TaskManager> task_manager, const Song::Source source, const QString &songs_table, const QString &dirs_table, const QString &subdirs_table) {
|
||||||
|
|
||||||
|
setObjectName(source == Song::Source::Collection ? QLatin1String(metaObject()->className()) : QStringLiteral("%1%2").arg(Song::DescriptionForSource(source), QLatin1String(metaObject()->className())));
|
||||||
|
|
||||||
db_ = db;
|
db_ = db;
|
||||||
task_manager_ = task_manager;
|
task_manager_ = task_manager;
|
||||||
source_ = source;
|
source_ = source;
|
||||||
songs_table_ = songs_table;
|
songs_table_ = songs_table;
|
||||||
dirs_table_ = dirs_table;
|
dirs_table_ = dirs_table;
|
||||||
subdirs_table_ = subdirs_table;
|
subdirs_table_ = subdirs_table;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionBackend::Close() {
|
void CollectionBackend::Close() {
|
||||||
@@ -103,7 +107,7 @@ void CollectionBackend::Exit() {
|
|||||||
Q_ASSERT(QThread::currentThread() == thread());
|
Q_ASSERT(QThread::currentThread() == thread());
|
||||||
|
|
||||||
moveToThread(original_thread_);
|
moveToThread(original_thread_);
|
||||||
emit ExitFinished();
|
Q_EMIT ExitFinished();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,8 +118,8 @@ void CollectionBackend::ReportErrors(const CollectionQuery &query) {
|
|||||||
qLog(Error) << "Unable to execute collection SQL query:" << sql_error;
|
qLog(Error) << "Unable to execute collection SQL query:" << sql_error;
|
||||||
qLog(Error) << "Failed SQL query:" << query.lastQuery();
|
qLog(Error) << "Failed SQL query:" << query.lastQuery();
|
||||||
qLog(Error) << "Bound SQL values:" << query.boundValues();
|
qLog(Error) << "Bound SQL values:" << query.boundValues();
|
||||||
emit Error(tr("Unable to execute collection SQL query: %1").arg(sql_error.text()));
|
Q_EMIT Error(tr("Unable to execute collection SQL query: %1").arg(sql_error.text()));
|
||||||
emit Error(tr("Failed SQL query: %1").arg(query.lastQuery()));
|
Q_EMIT Error(tr("Failed SQL query: %1").arg(query.lastQuery()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -134,7 +138,7 @@ void CollectionBackend::GetAllSongs(const int id) {
|
|||||||
q.prepare(QStringLiteral("SELECT %1 FROM %2").arg(Song::kRowIdColumnSpec, songs_table_));
|
q.prepare(QStringLiteral("SELECT %1 FROM %2").arg(Song::kRowIdColumnSpec, songs_table_));
|
||||||
if (!q.exec()) {
|
if (!q.exec()) {
|
||||||
db_->ReportErrors(q);
|
db_->ReportErrors(q);
|
||||||
emit GotSongs(SongList(), id);
|
Q_EMIT GotSongs(SongList(), id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +149,7 @@ void CollectionBackend::GetAllSongs(const int id) {
|
|||||||
songs << song;
|
songs << song;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit GotSongs(songs, id);
|
Q_EMIT GotSongs(songs, id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +193,7 @@ void CollectionBackend::LoadDirectories() {
|
|||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
|
|
||||||
for (const CollectionDirectory &dir : dirs) {
|
for (const CollectionDirectory &dir : dirs) {
|
||||||
emit DirectoryAdded(dir, SubdirsInDirectory(dir.id, db));
|
Q_EMIT DirectoryAdded(dir, SubdirsInDirectory(dir.id, db));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -317,7 +321,7 @@ void CollectionBackend::UpdateTotalSongCount() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit TotalSongCountUpdated(q.value(0).toInt());
|
Q_EMIT TotalSongCountUpdated(q.value(0).toInt());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,7 +341,7 @@ void CollectionBackend::UpdateTotalArtistCount() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit TotalArtistCountUpdated(q.value(0).toInt());
|
Q_EMIT TotalArtistCountUpdated(q.value(0).toInt());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,7 +361,7 @@ void CollectionBackend::UpdateTotalAlbumCount() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit TotalAlbumCountUpdated(q.value(0).toInt());
|
Q_EMIT TotalAlbumCountUpdated(q.value(0).toInt());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +399,7 @@ void CollectionBackend::AddDirectory(const QString &path) {
|
|||||||
dir.path = path;
|
dir.path = path;
|
||||||
dir.id = q.lastInsertId().toInt();
|
dir.id = q.lastInsertId().toInt();
|
||||||
|
|
||||||
emit DirectoryAdded(dir, CollectionSubdirectoryList());
|
Q_EMIT DirectoryAdded(dir, CollectionSubdirectoryList());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,7 +441,7 @@ void CollectionBackend::RemoveDirectory(const CollectionDirectory &dir) {
|
|||||||
|
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
|
|
||||||
emit DirectoryDeleted(dir);
|
Q_EMIT DirectoryDeleted(dir);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -717,8 +721,8 @@ void CollectionBackend::AddOrUpdateSongs(const SongList &songs) {
|
|||||||
|
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
|
|
||||||
if (!added_songs.isEmpty()) emit SongsAdded(added_songs);
|
if (!added_songs.isEmpty()) Q_EMIT SongsAdded(added_songs);
|
||||||
if (!changed_songs.isEmpty()) emit SongsChanged(changed_songs);
|
if (!changed_songs.isEmpty()) Q_EMIT SongsChanged(changed_songs);
|
||||||
|
|
||||||
UpdateTotalSongCountAsync();
|
UpdateTotalSongCountAsync();
|
||||||
UpdateTotalArtistCountAsync();
|
UpdateTotalArtistCountAsync();
|
||||||
@@ -819,9 +823,9 @@ void CollectionBackend::UpdateSongsBySongID(const SongMap &new_songs) {
|
|||||||
|
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
|
|
||||||
if (!deleted_songs.isEmpty()) emit SongsDeleted(deleted_songs);
|
if (!deleted_songs.isEmpty()) Q_EMIT SongsDeleted(deleted_songs);
|
||||||
if (!added_songs.isEmpty()) emit SongsAdded(added_songs);
|
if (!added_songs.isEmpty()) Q_EMIT SongsAdded(added_songs);
|
||||||
if (!changed_songs.isEmpty()) emit SongsChanged(changed_songs);
|
if (!changed_songs.isEmpty()) Q_EMIT SongsChanged(changed_songs);
|
||||||
|
|
||||||
UpdateTotalSongCountAsync();
|
UpdateTotalSongCountAsync();
|
||||||
UpdateTotalArtistCountAsync();
|
UpdateTotalArtistCountAsync();
|
||||||
@@ -867,7 +871,7 @@ void CollectionBackend::DeleteSongs(const SongList &songs) {
|
|||||||
|
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
|
|
||||||
emit SongsDeleted(songs);
|
Q_EMIT SongsDeleted(songs);
|
||||||
|
|
||||||
UpdateTotalSongCountAsync();
|
UpdateTotalSongCountAsync();
|
||||||
UpdateTotalArtistCountAsync();
|
UpdateTotalArtistCountAsync();
|
||||||
@@ -894,10 +898,10 @@ void CollectionBackend::MarkSongsUnavailable(const SongList &songs, const bool u
|
|||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
|
|
||||||
if (unavailable) {
|
if (unavailable) {
|
||||||
emit SongsDeleted(songs);
|
Q_EMIT SongsDeleted(songs);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
emit SongsAdded(songs);
|
Q_EMIT SongsAdded(songs);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateTotalSongCountAsync();
|
UpdateTotalSongCountAsync();
|
||||||
@@ -1410,7 +1414,7 @@ void CollectionBackend::CompilationsNeedUpdating() {
|
|||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
|
|
||||||
if (!changed_songs.isEmpty()) {
|
if (!changed_songs.isEmpty()) {
|
||||||
emit SongsChanged(changed_songs);
|
Q_EMIT SongsChanged(changed_songs);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1497,7 +1501,8 @@ CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist,
|
|||||||
album_info.art_embedded = query.Value(6).toBool();
|
album_info.art_embedded = query.Value(6).toBool();
|
||||||
|
|
||||||
const QString art_automatic = query.Value(7).toString();
|
const QString art_automatic = query.Value(7).toString();
|
||||||
if (art_automatic.contains(QRegularExpression(QStringLiteral("..+:.*")))) {
|
static const QRegularExpression regex_url_schema(QStringLiteral("..+:.*"));
|
||||||
|
if (art_automatic.contains(regex_url_schema)) {
|
||||||
album_info.art_automatic = QUrl::fromEncoded(art_automatic.toUtf8());
|
album_info.art_automatic = QUrl::fromEncoded(art_automatic.toUtf8());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1505,7 +1510,7 @@ CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const QString art_manual = query.Value(8).toString();
|
const QString art_manual = query.Value(8).toString();
|
||||||
if (art_manual.contains(QRegularExpression(QStringLiteral("..+:.*")))) {
|
if (art_manual.contains(regex_url_schema)) {
|
||||||
album_info.art_manual = QUrl::fromEncoded(art_manual.toUtf8());
|
album_info.art_manual = QUrl::fromEncoded(art_manual.toUtf8());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1616,7 +1621,7 @@ void CollectionBackend::UpdateEmbeddedAlbumArt(const QString &effective_albumart
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!songs.isEmpty()) {
|
if (!songs.isEmpty()) {
|
||||||
emit SongsChanged(songs);
|
Q_EMIT SongsChanged(songs);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1662,7 +1667,7 @@ void CollectionBackend::UpdateManualAlbumArt(const QString &effective_albumartis
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!songs.isEmpty()) {
|
if (!songs.isEmpty()) {
|
||||||
emit SongsChanged(songs);
|
Q_EMIT SongsChanged(songs);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1707,7 +1712,7 @@ void CollectionBackend::UnsetAlbumArt(const QString &effective_albumartist, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!songs.isEmpty()) {
|
if (!songs.isEmpty()) {
|
||||||
emit SongsChanged(songs);
|
Q_EMIT SongsChanged(songs);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1753,7 +1758,7 @@ void CollectionBackend::ClearAlbumArt(const QString &effective_albumartist, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!songs.isEmpty()) {
|
if (!songs.isEmpty()) {
|
||||||
emit SongsChanged(songs);
|
Q_EMIT SongsChanged(songs);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1802,7 +1807,7 @@ void CollectionBackend::ForceCompilation(const QString &album, const QStringList
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!songs.isEmpty()) {
|
if (!songs.isEmpty()) {
|
||||||
emit SongsChanged(songs);
|
Q_EMIT SongsChanged(songs);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1824,7 +1829,7 @@ void CollectionBackend::IncrementPlayCount(const int id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Song new_song = GetSongById(id, db);
|
Song new_song = GetSongById(id, db);
|
||||||
emit SongsStatisticsChanged(SongList() << new_song);
|
Q_EMIT SongsStatisticsChanged(SongList() << new_song);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1846,7 +1851,7 @@ void CollectionBackend::IncrementSkipCount(const int id, const float progress) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Song new_song = GetSongById(id, db);
|
Song new_song = GetSongById(id, db);
|
||||||
emit SongsStatisticsChanged(SongList() << new_song);
|
Q_EMIT SongsStatisticsChanged(SongList() << new_song);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1871,7 +1876,7 @@ void CollectionBackend::ResetPlayStatistics(const QList<int> &id_list, const boo
|
|||||||
const bool success = ResetPlayStatistics(id_str_list);
|
const bool success = ResetPlayStatistics(id_str_list);
|
||||||
if (success) {
|
if (success) {
|
||||||
const SongList songs = GetSongsById(id_list);
|
const SongList songs = GetSongsById(id_list);
|
||||||
emit SongsStatisticsChanged(songs, save_tags);
|
Q_EMIT SongsStatisticsChanged(songs, save_tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1920,7 +1925,7 @@ void CollectionBackend::DeleteAll() {
|
|||||||
t.Commit();
|
t.Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit DatabaseReset();
|
Q_EMIT DatabaseReset();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2013,7 +2018,7 @@ void CollectionBackend::UpdateLastPlayed(const QString &artist, const QString &a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emit SongsStatisticsChanged(SongList() << songs);
|
Q_EMIT SongsStatisticsChanged(SongList() << songs);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2039,7 +2044,7 @@ void CollectionBackend::UpdatePlayCount(const QString &artist, const QString &ti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emit SongsStatisticsChanged(SongList() << songs, save_tags);
|
Q_EMIT SongsStatisticsChanged(SongList() << songs, save_tags);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2074,7 +2079,7 @@ void CollectionBackend::UpdateSongsRating(const QList<int> &id_list, const float
|
|||||||
|
|
||||||
SongList new_song_list = GetSongsById(id_str_list, db);
|
SongList new_song_list = GetSongsById(id_str_list, db);
|
||||||
|
|
||||||
emit SongsRatingChanged(new_song_list, save_tags);
|
Q_EMIT SongsRatingChanged(new_song_list, save_tags);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ class CollectionBackend : public CollectionBackendInterface {
|
|||||||
void UpdateSongRatingAsync(const int id, const float rating, const bool save_tags = false);
|
void UpdateSongRatingAsync(const int id, const float rating, const bool save_tags = false);
|
||||||
void UpdateSongsRatingAsync(const QList<int> &ids, const float rating, const bool save_tags = false);
|
void UpdateSongsRatingAsync(const QList<int> &ids, const float rating, const bool save_tags = false);
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void Exit();
|
void Exit();
|
||||||
void GetAllSongs(const int id);
|
void GetAllSongs(const int id);
|
||||||
void LoadDirectories();
|
void LoadDirectories();
|
||||||
@@ -275,7 +275,7 @@ class CollectionBackend : public CollectionBackendInterface {
|
|||||||
void UpdateLastSeen(const int directory_id, const int expire_unavailable_songs_days);
|
void UpdateLastSeen(const int directory_id, const int expire_unavailable_songs_days);
|
||||||
void ExpireSongs(const int directory_id, const int expire_unavailable_songs_days);
|
void ExpireSongs(const int directory_id, const int expire_unavailable_songs_days);
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void DirectoryAdded(const CollectionDirectory &dir, const CollectionSubdirectoryList &subdir);
|
void DirectoryAdded(const CollectionDirectory &dir, const CollectionSubdirectoryList &subdir);
|
||||||
void DirectoryDeleted(const CollectionDirectory &dir);
|
void DirectoryDeleted(const CollectionDirectory &dir);
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class CollectionDirectoryModel : public QStandardItemModel {
|
|||||||
QMap<int, CollectionDirectory> directories() const { return directories_; }
|
QMap<int, CollectionDirectory> directories() const { return directories_; }
|
||||||
QStringList paths() const { return paths_; }
|
QStringList paths() const { return paths_; }
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void AddDirectory(const CollectionDirectory &directory);
|
void AddDirectory(const CollectionDirectory &directory);
|
||||||
void RemoveDirectory(const CollectionDirectory &directory);
|
void RemoveDirectory(const CollectionDirectory &directory);
|
||||||
|
|
||||||
|
|||||||
@@ -61,9 +61,9 @@ bool CollectionFilter::filterAcceptsRow(const int source_row, const QModelIndex
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
const size_t hash = qHash(filter_string_);
|
size_t hash = qHash(filter_string_);
|
||||||
#else
|
#else
|
||||||
const uint hash = qHash(filter_string_);
|
uint hash = qHash(filter_string_);
|
||||||
#endif
|
#endif
|
||||||
if (hash != query_hash_) {
|
if (hash != query_hash_) {
|
||||||
FilterParser p(filter_string_);
|
FilterParser p(filter_string_);
|
||||||
|
|||||||
@@ -57,10 +57,14 @@
|
|||||||
#include "collectionfilterwidget.h"
|
#include "collectionfilterwidget.h"
|
||||||
#include "groupbydialog.h"
|
#include "groupbydialog.h"
|
||||||
#include "ui_collectionfilterwidget.h"
|
#include "ui_collectionfilterwidget.h"
|
||||||
#include "widgets/qsearchfield.h"
|
#include "widgets/searchfield.h"
|
||||||
#include "settings/collectionsettingspage.h"
|
#include "settings/collectionsettingspage.h"
|
||||||
#include "settings/appearancesettingspage.h"
|
#include "settings/appearancesettingspage.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr int kFilterDelay = 500; // msec
|
||||||
|
}
|
||||||
|
|
||||||
CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
|
CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
ui_(new Ui_CollectionFilterWidget),
|
ui_(new Ui_CollectionFilterWidget),
|
||||||
@@ -80,7 +84,7 @@ CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
|
|||||||
|
|
||||||
ui_->search_field->setToolTip(FilterParser::ToolTip());
|
ui_->search_field->setToolTip(FilterParser::ToolTip());
|
||||||
|
|
||||||
QObject::connect(ui_->search_field, &QSearchField::returnPressed, this, &CollectionFilterWidget::ReturnPressed);
|
QObject::connect(ui_->search_field, &SearchField::returnPressed, this, &CollectionFilterWidget::ReturnPressed);
|
||||||
QObject::connect(timer_filter_delay_, &QTimer::timeout, this, &CollectionFilterWidget::FilterDelayTimeout);
|
QObject::connect(timer_filter_delay_, &QTimer::timeout, this, &CollectionFilterWidget::FilterDelayTimeout);
|
||||||
|
|
||||||
timer_filter_delay_->setInterval(kFilterDelay);
|
timer_filter_delay_->setInterval(kFilterDelay);
|
||||||
@@ -123,7 +127,7 @@ CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
|
|||||||
collection_menu_->addSeparator();
|
collection_menu_->addSeparator();
|
||||||
ui_->options->setMenu(collection_menu_);
|
ui_->options->setMenu(collection_menu_);
|
||||||
|
|
||||||
QObject::connect(ui_->search_field, &QSearchField::textChanged, this, &CollectionFilterWidget::FilterTextChanged);
|
QObject::connect(ui_->search_field, &SearchField::textChanged, this, &CollectionFilterWidget::FilterTextChanged);
|
||||||
QObject::connect(ui_->options, &QToolButton::clicked, ui_->options, &QToolButton::showMenu);
|
QObject::connect(ui_->options, &QToolButton::clicked, ui_->options, &QToolButton::showMenu);
|
||||||
|
|
||||||
ReloadSettings();
|
ReloadSettings();
|
||||||
@@ -154,7 +158,7 @@ void CollectionFilterWidget::Init(CollectionModel *model, CollectionFilter *filt
|
|||||||
|
|
||||||
const QList<QAction*> actions = filter_max_ages_.keys();
|
const QList<QAction*> actions = filter_max_ages_.keys();
|
||||||
for (QAction *action : actions) {
|
for (QAction *action : actions) {
|
||||||
int filter_max_age = filter_max_ages_[action];
|
const int filter_max_age = filter_max_ages_.value(action);
|
||||||
QObject::connect(action, &QAction::triggered, this, [this, filter_max_age]() { model_->SetFilterMaxAge(filter_max_age); } );
|
QObject::connect(action, &QAction::triggered, this, [this, filter_max_age]() { model_->SetFilterMaxAge(filter_max_age); } );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,12 +479,12 @@ void CollectionFilterWidget::keyReleaseEvent(QKeyEvent *e) {
|
|||||||
|
|
||||||
switch (e->key()) {
|
switch (e->key()) {
|
||||||
case Qt::Key_Up:
|
case Qt::Key_Up:
|
||||||
emit UpPressed();
|
Q_EMIT UpPressed();
|
||||||
e->accept();
|
e->accept();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Qt::Key_Down:
|
case Qt::Key_Down:
|
||||||
emit DownPressed();
|
Q_EMIT DownPressed();
|
||||||
e->accept();
|
e->accept();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -51,8 +51,6 @@ class CollectionFilterWidget : public QWidget {
|
|||||||
explicit CollectionFilterWidget(QWidget *parent = nullptr);
|
explicit CollectionFilterWidget(QWidget *parent = nullptr);
|
||||||
~CollectionFilterWidget() override;
|
~CollectionFilterWidget() override;
|
||||||
|
|
||||||
static const int kFilterDelay = 500; // msec
|
|
||||||
|
|
||||||
enum class DelayBehaviour {
|
enum class DelayBehaviour {
|
||||||
AlwaysInstant,
|
AlwaysInstant,
|
||||||
DelayedOnLargeLibraries,
|
DelayedOnLargeLibraries,
|
||||||
@@ -88,12 +86,12 @@ class CollectionFilterWidget : public QWidget {
|
|||||||
bool SearchFieldHasFocus() const;
|
bool SearchFieldHasFocus() const;
|
||||||
void FocusSearchField();
|
void FocusSearchField();
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void UpdateGroupByActions();
|
void UpdateGroupByActions();
|
||||||
void SetFilterMode(CollectionFilterOptions::FilterMode filter_mode);
|
void SetFilterMode(CollectionFilterOptions::FilterMode filter_mode);
|
||||||
void FocusOnFilter(QKeyEvent *e);
|
void FocusOnFilter(QKeyEvent *e);
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void UpPressed();
|
void UpPressed();
|
||||||
void DownPressed();
|
void DownPressed();
|
||||||
void ReturnPressed();
|
void ReturnPressed();
|
||||||
@@ -101,7 +99,7 @@ class CollectionFilterWidget : public QWidget {
|
|||||||
protected:
|
protected:
|
||||||
void keyReleaseEvent(QKeyEvent *e) override;
|
void keyReleaseEvent(QKeyEvent *e) override;
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void GroupingChanged(const CollectionModel::Grouping g, const bool separate_albums_by_grouping);
|
void GroupingChanged(const CollectionModel::Grouping g, const bool separate_albums_by_grouping);
|
||||||
void GroupByClicked(QAction *action);
|
void GroupByClicked(QAction *action);
|
||||||
void SaveGroupBy();
|
void SaveGroupBy();
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QSearchField" name="search_field" native="true">
|
<widget class="SearchField" name="search_field" native="true">
|
||||||
<property name="placeholderText" stdset="0">
|
<property name="placeholderText" stdset="0">
|
||||||
<string>Enter search terms here</string>
|
<string>Enter search terms here</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -123,9 +123,9 @@
|
|||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>QSearchField</class>
|
<class>SearchField</class>
|
||||||
<extends>QWidget</extends>
|
<extends>QWidget</extends>
|
||||||
<header>widgets/qsearchfield.h</header>
|
<header>widgets/searchfield.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class CollectionItemDelegate : public QStyledItemDelegate {
|
|||||||
explicit CollectionItemDelegate(QObject *parent);
|
explicit CollectionItemDelegate(QObject *parent);
|
||||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &idx) const override;
|
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &idx) const override;
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &idx) override;
|
bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &idx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,11 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrentRun>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
@@ -75,6 +76,8 @@
|
|||||||
#include "covermanager/albumcoverloader.h"
|
#include "covermanager/albumcoverloader.h"
|
||||||
#include "settings/collectionsettingspage.h"
|
#include "settings/collectionsettingspage.h"
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
const int CollectionModel::kPrettyCoverSize = 32;
|
const int CollectionModel::kPrettyCoverSize = 32;
|
||||||
namespace {
|
namespace {
|
||||||
constexpr char kPixmapDiskCacheDir[] = "pixmapcache";
|
constexpr char kPixmapDiskCacheDir[] = "pixmapcache";
|
||||||
@@ -98,6 +101,8 @@ CollectionModel::CollectionModel(SharedPtr<CollectionBackend> backend, Applicati
|
|||||||
total_album_count_(0),
|
total_album_count_(0),
|
||||||
loading_(false) {
|
loading_(false) {
|
||||||
|
|
||||||
|
setObjectName(backend_->source() == Song::Source::Collection ? QLatin1String(metaObject()->className()) : QStringLiteral("%1%2").arg(Song::DescriptionForSource(backend_->source()), QLatin1String(metaObject()->className())));
|
||||||
|
|
||||||
filter_->setSourceModel(this);
|
filter_->setSourceModel(this);
|
||||||
filter_->setSortRole(Role_SortText);
|
filter_->setSortRole(Role_SortText);
|
||||||
filter_->sort(0);
|
filter_->sort(0);
|
||||||
@@ -133,11 +138,11 @@ CollectionModel::CollectionModel(SharedPtr<CollectionBackend> backend, Applicati
|
|||||||
backend_->UpdateTotalAlbumCountAsync();
|
backend_->UpdateTotalAlbumCountAsync();
|
||||||
|
|
||||||
timer_reload_->setSingleShot(true);
|
timer_reload_->setSingleShot(true);
|
||||||
timer_reload_->setInterval(300);
|
timer_reload_->setInterval(300ms);
|
||||||
QObject::connect(timer_reload_, &QTimer::timeout, this, &CollectionModel::Reload);
|
QObject::connect(timer_reload_, &QTimer::timeout, this, &CollectionModel::Reload);
|
||||||
|
|
||||||
timer_update_->setSingleShot(false);
|
timer_update_->setSingleShot(false);
|
||||||
timer_update_->setInterval(20);
|
timer_update_->setInterval(20ms);
|
||||||
QObject::connect(timer_update_, &QTimer::timeout, this, &CollectionModel::ProcessUpdate);
|
QObject::connect(timer_update_, &QTimer::timeout, this, &CollectionModel::ProcessUpdate);
|
||||||
|
|
||||||
ReloadSettings();
|
ReloadSettings();
|
||||||
@@ -146,7 +151,7 @@ CollectionModel::CollectionModel(SharedPtr<CollectionBackend> backend, Applicati
|
|||||||
|
|
||||||
CollectionModel::~CollectionModel() {
|
CollectionModel::~CollectionModel() {
|
||||||
|
|
||||||
qLog(Debug) << "Collection model" << this << "for" << Song::TextForSource(backend_->source()) << "deleted";
|
qLog(Debug) << "Collection model" << this << "deleted";
|
||||||
|
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
Clear();
|
Clear();
|
||||||
@@ -266,7 +271,7 @@ void CollectionModel::SetGroupBy(const Grouping g, const std::optional<bool> sep
|
|||||||
|
|
||||||
ScheduleReset();
|
ScheduleReset();
|
||||||
|
|
||||||
emit GroupingChanged(g, options_current_.separate_albums_by_grouping);
|
Q_EMIT GroupingChanged(g, options_current_.separate_albums_by_grouping);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,7 +519,7 @@ void CollectionModel::AddReAddOrUpdateSongsInternal(const SongList &songs) {
|
|||||||
songs_added << new_song;
|
songs_added << new_song;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const Song &old_song = song_nodes_[new_song.id()]->metadata;
|
const Song old_song = song_nodes_.value(new_song.id())->metadata;
|
||||||
bool container_key_changed = false;
|
bool container_key_changed = false;
|
||||||
bool has_unique_album_identifier_1 = false;
|
bool has_unique_album_identifier_1 = false;
|
||||||
bool has_unique_album_identifier_2 = false;
|
bool has_unique_album_identifier_2 = false;
|
||||||
@@ -606,7 +611,7 @@ void CollectionModel::UpdateSongsInternal(const SongList &songs) {
|
|||||||
qLog(Error) << "Song does not exist in model" << new_song.id() << new_song.PrettyTitleWithArtist();
|
qLog(Error) << "Song does not exist in model" << new_song.id() << new_song.PrettyTitleWithArtist();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
CollectionItem *item = song_nodes_[new_song.id()];
|
CollectionItem *item = song_nodes_.value(new_song.id());
|
||||||
const Song &old_song = item->metadata;
|
const Song &old_song = item->metadata;
|
||||||
const bool song_title_data_changed = IsSongTitleDataChanged(old_song, new_song);
|
const bool song_title_data_changed = IsSongTitleDataChanged(old_song, new_song);
|
||||||
const bool art_changed = !old_song.IsArtEqual(new_song);
|
const bool art_changed = !old_song.IsArtEqual(new_song);
|
||||||
@@ -622,18 +627,18 @@ void CollectionModel::UpdateSongsInternal(const SongList &songs) {
|
|||||||
qLog(Debug) << "Song metadata and title for" << new_song.id() << new_song.PrettyTitleWithArtist() << "changed, informing model";
|
qLog(Debug) << "Song metadata and title for" << new_song.id() << new_song.PrettyTitleWithArtist() << "changed, informing model";
|
||||||
const QModelIndex idx = ItemToIndex(item);
|
const QModelIndex idx = ItemToIndex(item);
|
||||||
if (!idx.isValid()) continue;
|
if (!idx.isValid()) continue;
|
||||||
emit dataChanged(idx, idx);
|
Q_EMIT dataChanged(idx, idx);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
qLog(Debug) << "Song metadata for" << new_song.id() << new_song.PrettyTitleWithArtist() << "changed";
|
qLog(Debug) << "Song metadata for" << new_song.id() << new_song.PrettyTitleWithArtist() << "changed";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (CollectionItem *item : album_parents) {
|
for (CollectionItem *item : std::as_const(album_parents)) {
|
||||||
ClearItemPixmapCache(item);
|
ClearItemPixmapCache(item);
|
||||||
const QModelIndex idx = ItemToIndex(item);
|
const QModelIndex idx = ItemToIndex(item);
|
||||||
if (idx.isValid()) {
|
if (idx.isValid()) {
|
||||||
emit dataChanged(idx, idx);
|
Q_EMIT dataChanged(idx, idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -648,7 +653,7 @@ void CollectionModel::RemoveSongsInternal(const SongList &songs) {
|
|||||||
for (const Song &song : songs) {
|
for (const Song &song : songs) {
|
||||||
|
|
||||||
if (song_nodes_.contains(song.id())) {
|
if (song_nodes_.contains(song.id())) {
|
||||||
CollectionItem *node = song_nodes_[song.id()];
|
CollectionItem *node = song_nodes_.value(song.id());
|
||||||
|
|
||||||
if (node->parent != root_) parents << node->parent;
|
if (node->parent != root_) parents << node->parent;
|
||||||
|
|
||||||
@@ -706,7 +711,7 @@ void CollectionModel::RemoveSongsInternal(const SongList &songs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove the divider
|
// Remove the divider
|
||||||
int row = divider_nodes_[divider_key]->row;
|
const int row = divider_nodes_.value(divider_key)->row;
|
||||||
beginRemoveRows(ItemToIndex(root_), row, row);
|
beginRemoveRows(ItemToIndex(root_), row, row);
|
||||||
root_->Delete(row);
|
root_->Delete(row);
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
@@ -989,7 +994,7 @@ void CollectionModel::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderR
|
|||||||
const QModelIndex idx = ItemToIndex(item);
|
const QModelIndex idx = ItemToIndex(item);
|
||||||
if (!idx.isValid()) return;
|
if (!idx.isValid()) return;
|
||||||
|
|
||||||
emit dataChanged(idx, idx);
|
Q_EMIT dataChanged(idx, idx);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1163,7 +1168,8 @@ QString CollectionModel::SortText(QString text) {
|
|||||||
else {
|
else {
|
||||||
text = text.toLower();
|
text = text.toLower();
|
||||||
}
|
}
|
||||||
text = text.remove(QRegularExpression(QStringLiteral("[^\\w ]"), QRegularExpression::UseUnicodePropertiesOption));
|
static const QRegularExpression regex_not_words(QStringLiteral("[^\\w ]"), QRegularExpression::UseUnicodePropertiesOption);
|
||||||
|
text = text.remove(regex_not_words);
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
|
|
||||||
@@ -1531,21 +1537,21 @@ CollectionModel::GroupBy &CollectionModel::Grouping::operator[](const int i) {
|
|||||||
void CollectionModel::TotalSongCountUpdatedSlot(const int count) {
|
void CollectionModel::TotalSongCountUpdatedSlot(const int count) {
|
||||||
|
|
||||||
total_song_count_ = count;
|
total_song_count_ = count;
|
||||||
emit TotalSongCountUpdated(count);
|
Q_EMIT TotalSongCountUpdated(count);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionModel::TotalArtistCountUpdatedSlot(const int count) {
|
void CollectionModel::TotalArtistCountUpdatedSlot(const int count) {
|
||||||
|
|
||||||
total_artist_count_ = count;
|
total_artist_count_ = count;
|
||||||
emit TotalArtistCountUpdated(count);
|
Q_EMIT TotalArtistCountUpdated(count);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionModel::TotalAlbumCountUpdatedSlot(const int count) {
|
void CollectionModel::TotalAlbumCountUpdatedSlot(const int count) {
|
||||||
|
|
||||||
total_album_count_ = count;
|
total_album_count_ = count;
|
||||||
emit TotalAlbumCountUpdated(count);
|
Q_EMIT TotalAlbumCountUpdated(count);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1553,18 +1559,6 @@ void CollectionModel::ClearDiskCache() {
|
|||||||
if (sIconCache) sIconCache->clear();
|
if (sIconCache) sIconCache->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionModel::ExpandAll(CollectionItem *item) const {
|
|
||||||
|
|
||||||
if (!root_) return;
|
|
||||||
|
|
||||||
if (!item) item = root_;
|
|
||||||
|
|
||||||
for (CollectionItem *child : item->children) {
|
|
||||||
ExpandAll(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CollectionModel::RowsInserted(const QModelIndex &parent, const int first, const int last) {
|
void CollectionModel::RowsInserted(const QModelIndex &parent, const int first, const int last) {
|
||||||
|
|
||||||
SongList songs;
|
SongList songs;
|
||||||
@@ -1577,7 +1571,7 @@ void CollectionModel::RowsInserted(const QModelIndex &parent, const int first, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!songs.isEmpty()) {
|
if (!songs.isEmpty()) {
|
||||||
emit SongsAdded(songs);
|
Q_EMIT SongsAdded(songs);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1593,7 +1587,7 @@ void CollectionModel::RowsRemoved(const QModelIndex &parent, const int first, co
|
|||||||
songs << item->metadata;
|
songs << item->metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit SongsRemoved(songs);
|
Q_EMIT SongsRemoved(songs);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -199,11 +199,9 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
SongList GetChildSongs(const QModelIndex &idx) const;
|
SongList GetChildSongs(const QModelIndex &idx) const;
|
||||||
SongList GetChildSongs(const QModelIndexList &indexes) const;
|
SongList GetChildSongs(const QModelIndexList &indexes) const;
|
||||||
|
|
||||||
void ExpandAll(CollectionItem *item = nullptr) const;
|
|
||||||
|
|
||||||
bool CompareItems(const CollectionItem *a, const CollectionItem *b) const;
|
bool CompareItems(const CollectionItem *a, const CollectionItem *b) const;
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void TotalSongCountUpdated(const int count);
|
void TotalSongCountUpdated(const int count);
|
||||||
void TotalArtistCountUpdated(const int count);
|
void TotalArtistCountUpdated(const int count);
|
||||||
void TotalAlbumCountUpdated(const int count);
|
void TotalAlbumCountUpdated(const int count);
|
||||||
@@ -211,7 +209,7 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
void SongsAdded(const SongList &songs);
|
void SongsAdded(const SongList &songs);
|
||||||
void SongsRemoved(const SongList &songs);
|
void SongsRemoved(const SongList &songs);
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void SetFilterMode(const CollectionFilterOptions::FilterMode filter_mode);
|
void SetFilterMode(const CollectionFilterOptions::FilterMode filter_mode);
|
||||||
void SetFilterMaxAge(const int filter_max_age);
|
void SetFilterMaxAge(const int filter_max_age);
|
||||||
|
|
||||||
@@ -255,7 +253,7 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
void ClearItemPixmapCache(CollectionItem *item);
|
void ClearItemPixmapCache(CollectionItem *item);
|
||||||
static qint64 MaximumCacheSize(Settings *s, const char *size_id, const char *size_unit_id, const qint64 cache_size_default);
|
static qint64 MaximumCacheSize(Settings *s, const char *size_id, const char *size_unit_id, const qint64 cache_size_default);
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void Reload();
|
void Reload();
|
||||||
void ScheduleReset();
|
void ScheduleReset();
|
||||||
void ProcessUpdate();
|
void ProcessUpdate();
|
||||||
|
|||||||
@@ -19,5 +19,5 @@
|
|||||||
|
|
||||||
#include "collectionmodelupdate.h"
|
#include "collectionmodelupdate.h"
|
||||||
|
|
||||||
CollectionModelUpdate::CollectionModelUpdate(const Type &_type, const SongList &_songs)
|
CollectionModelUpdate::CollectionModelUpdate(const Type _type, const SongList &_songs)
|
||||||
: type(_type), songs(_songs) {}
|
: type(_type), songs(_songs) {}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class CollectionModelUpdate {
|
|||||||
Update,
|
Update,
|
||||||
Remove,
|
Remove,
|
||||||
};
|
};
|
||||||
explicit CollectionModelUpdate(const Type &_type, const SongList &_songs);
|
explicit CollectionModelUpdate(const Type _type, const SongList &_songs);
|
||||||
Type type;
|
Type type;
|
||||||
SongList songs;
|
SongList songs;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
@@ -44,7 +46,7 @@ CollectionQuery::CollectionQuery(const QSqlDatabase &db, const QString &songs_ta
|
|||||||
limit_(-1) {
|
limit_(-1) {
|
||||||
|
|
||||||
if (filter_options.max_age() != -1) {
|
if (filter_options.max_age() != -1) {
|
||||||
qint64 cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - filter_options.max_age();
|
qint64 cutoff = QDateTime::currentSecsSinceEpoch() - filter_options.max_age();
|
||||||
|
|
||||||
where_clauses_ << QStringLiteral("ctime > ?");
|
where_clauses_ << QStringLiteral("ctime > ?");
|
||||||
bound_values_ << cutoff;
|
bound_values_ << cutoff;
|
||||||
@@ -62,7 +64,7 @@ void CollectionQuery::AddWhere(const QString &column, const QVariant &value, con
|
|||||||
|
|
||||||
// Ignore 'literal' for IN
|
// Ignore 'literal' for IN
|
||||||
if (op.compare(QLatin1String("IN"), Qt::CaseInsensitive) == 0) {
|
if (op.compare(QLatin1String("IN"), Qt::CaseInsensitive) == 0) {
|
||||||
QStringList values = value.toStringList();
|
const QStringList values = value.toStringList();
|
||||||
QStringList final_values;
|
QStringList final_values;
|
||||||
final_values.reserve(values.count());
|
final_values.reserve(values.count());
|
||||||
for (const QString &single_value : values) {
|
for (const QString &single_value : values) {
|
||||||
@@ -134,7 +136,7 @@ bool CollectionQuery::Exec() {
|
|||||||
if (!QSqlQuery::prepare(sql)) return false;
|
if (!QSqlQuery::prepare(sql)) return false;
|
||||||
|
|
||||||
// Bind values
|
// Bind values
|
||||||
for (const QVariant &value : bound_values_) {
|
for (const QVariant &value : std::as_const(bound_values_)) {
|
||||||
QSqlQuery::addBindValue(value);
|
QSqlQuery::addBindValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ CollectionView::CollectionView(QWidget *parent)
|
|||||||
is_in_keyboard_search_(false),
|
is_in_keyboard_search_(false),
|
||||||
delete_files_(false) {
|
delete_files_(false) {
|
||||||
|
|
||||||
|
setObjectName(QLatin1String(metaObject()->className()));
|
||||||
|
|
||||||
setItemDelegate(new CollectionItemDelegate(this));
|
setItemDelegate(new CollectionItemDelegate(this));
|
||||||
setAttribute(Qt::WA_MacShowFocusRect, false);
|
setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||||
setHeaderHidden(true);
|
setHeaderHidden(true);
|
||||||
@@ -273,7 +275,7 @@ void CollectionView::TotalSongCountUpdated(const int count) {
|
|||||||
unsetCursor();
|
unsetCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit TotalSongCountUpdated_();
|
Q_EMIT TotalSongCountUpdated_();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,7 +292,7 @@ void CollectionView::TotalArtistCountUpdated(const int count) {
|
|||||||
unsetCursor();
|
unsetCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit TotalArtistCountUpdated_();
|
Q_EMIT TotalArtistCountUpdated_();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,7 +309,7 @@ void CollectionView::TotalAlbumCountUpdated(const int count) {
|
|||||||
unsetCursor();
|
unsetCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit TotalAlbumCountUpdated_();
|
Q_EMIT TotalAlbumCountUpdated_();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,7 +350,7 @@ void CollectionView::mouseReleaseEvent(QMouseEvent *e) {
|
|||||||
QTreeView::mouseReleaseEvent(e);
|
QTreeView::mouseReleaseEvent(e);
|
||||||
|
|
||||||
if (total_song_count_ == 0) {
|
if (total_song_count_ == 0) {
|
||||||
emit ShowConfigDialog();
|
Q_EMIT ShowConfigDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -538,13 +540,13 @@ void CollectionView::Load() {
|
|||||||
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
|
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
|
||||||
mimedata->clear_first_ = true;
|
mimedata->clear_first_ = true;
|
||||||
}
|
}
|
||||||
emit AddToPlaylistSignal(q_mimedata);
|
Q_EMIT AddToPlaylistSignal(q_mimedata);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionView::AddToPlaylist() {
|
void CollectionView::AddToPlaylist() {
|
||||||
|
|
||||||
emit AddToPlaylistSignal(model()->mimeData(selectedIndexes()));
|
Q_EMIT AddToPlaylistSignal(model()->mimeData(selectedIndexes()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,7 +556,7 @@ void CollectionView::AddToPlaylistEnqueue() {
|
|||||||
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
|
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
|
||||||
mimedata->enqueue_now_ = true;
|
mimedata->enqueue_now_ = true;
|
||||||
}
|
}
|
||||||
emit AddToPlaylistSignal(q_mimedata);
|
Q_EMIT AddToPlaylistSignal(q_mimedata);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,7 +566,7 @@ void CollectionView::AddToPlaylistEnqueueNext() {
|
|||||||
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
|
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
|
||||||
mimedata->enqueue_next_now_ = true;
|
mimedata->enqueue_next_now_ = true;
|
||||||
}
|
}
|
||||||
emit AddToPlaylistSignal(q_mimedata);
|
Q_EMIT AddToPlaylistSignal(q_mimedata);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,13 +576,13 @@ void CollectionView::OpenInNewPlaylist() {
|
|||||||
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
|
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
|
||||||
mimedata->open_in_new_playlist_ = true;
|
mimedata->open_in_new_playlist_ = true;
|
||||||
}
|
}
|
||||||
emit AddToPlaylistSignal(q_mimedata);
|
Q_EMIT AddToPlaylistSignal(q_mimedata);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionView::SearchForThis() {
|
void CollectionView::SearchForThis() {
|
||||||
|
|
||||||
QModelIndex current = currentIndex();
|
const QModelIndex current = currentIndex();
|
||||||
const QVariant role_type = model()->data(current, CollectionModel::Role_Type);
|
const QVariant role_type = model()->data(current, CollectionModel::Role_Type);
|
||||||
if (!role_type.isValid()) {
|
if (!role_type.isValid()) {
|
||||||
return;
|
return;
|
||||||
@@ -599,7 +601,7 @@ void CollectionView::SearchForThis() {
|
|||||||
if (!songs.isEmpty()) {
|
if (!songs.isEmpty()) {
|
||||||
last_selected_song_ = songs.last();
|
last_selected_song_ = songs.last();
|
||||||
}
|
}
|
||||||
search = QStringLiteral("title:%1").arg(last_selected_song_.title());
|
search = QStringLiteral("title:\"%1\"").arg(last_selected_song_.title());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -609,28 +611,29 @@ void CollectionView::SearchForThis() {
|
|||||||
|
|
||||||
case CollectionItem::Type::Container:{
|
case CollectionItem::Type::Container:{
|
||||||
CollectionItem *item = app_->collection_model()->IndexToItem(index);
|
CollectionItem *item = app_->collection_model()->IndexToItem(index);
|
||||||
|
const CollectionModel::GroupBy group_by = app_->collection_model()->GetGroupBy()[item->container_level];
|
||||||
|
while (!item->children.isEmpty()) {
|
||||||
|
item = item->children.constFirst();
|
||||||
|
}
|
||||||
|
|
||||||
int container_level = item->container_level;
|
switch (group_by) {
|
||||||
CollectionModel::GroupBy container_group_by = app_->collection_model()->GetGroupBy()[container_level];
|
|
||||||
|
|
||||||
switch (container_group_by) {
|
|
||||||
case CollectionModel::GroupBy::AlbumArtist:
|
case CollectionModel::GroupBy::AlbumArtist:
|
||||||
search = QStringLiteral("albumartist:%1").arg(item->metadata.effective_albumartist());
|
search = QStringLiteral("albumartist:\"%1\"").arg(item->metadata.effective_albumartist());
|
||||||
break;
|
break;
|
||||||
case CollectionModel::GroupBy::Artist:
|
case CollectionModel::GroupBy::Artist:
|
||||||
search = QStringLiteral("artist:%1").arg(item->metadata.artist());
|
search = QStringLiteral("artist:\"%1\"").arg(item->metadata.artist());
|
||||||
break;
|
break;
|
||||||
case CollectionModel::GroupBy::Album:
|
case CollectionModel::GroupBy::Album:
|
||||||
case CollectionModel::GroupBy::AlbumDisc:
|
case CollectionModel::GroupBy::AlbumDisc:
|
||||||
search = QStringLiteral("album:%1").arg(item->metadata.album());
|
search = QStringLiteral("album:\"%1\"").arg(item->metadata.album());
|
||||||
break;
|
break;
|
||||||
case CollectionModel::GroupBy::YearAlbum:
|
case CollectionModel::GroupBy::YearAlbum:
|
||||||
case CollectionModel::GroupBy::YearAlbumDisc:
|
case CollectionModel::GroupBy::YearAlbumDisc:
|
||||||
search = QStringLiteral("year:%1 album:%2").arg(item->metadata.year()).arg(item->metadata.album());
|
search = QStringLiteral("year:%1 album:\"%2\"").arg(item->metadata.year()).arg(item->metadata.album());
|
||||||
break;
|
break;
|
||||||
case CollectionModel::GroupBy::OriginalYearAlbum:
|
case CollectionModel::GroupBy::OriginalYearAlbum:
|
||||||
case CollectionModel::GroupBy::OriginalYearAlbumDisc:
|
case CollectionModel::GroupBy::OriginalYearAlbumDisc:
|
||||||
search = QStringLiteral("year:%1 album:%2").arg(item->metadata.effective_originalyear()).arg(item->metadata.album());
|
search = QStringLiteral("year:%1 album:\"%2\"").arg(item->metadata.effective_originalyear()).arg(item->metadata.album());
|
||||||
break;
|
break;
|
||||||
case CollectionModel::GroupBy::Year:
|
case CollectionModel::GroupBy::Year:
|
||||||
search = QStringLiteral("year:%1").arg(item->metadata.year());
|
search = QStringLiteral("year:%1").arg(item->metadata.year());
|
||||||
@@ -639,16 +642,16 @@ void CollectionView::SearchForThis() {
|
|||||||
search = QStringLiteral("year:%1").arg(item->metadata.effective_originalyear());
|
search = QStringLiteral("year:%1").arg(item->metadata.effective_originalyear());
|
||||||
break;
|
break;
|
||||||
case CollectionModel::GroupBy::Genre:
|
case CollectionModel::GroupBy::Genre:
|
||||||
search = QStringLiteral("genre:%1").arg(item->metadata.genre());
|
search = QStringLiteral("genre:\"%1\"").arg(item->metadata.genre());
|
||||||
break;
|
break;
|
||||||
case CollectionModel::GroupBy::Composer:
|
case CollectionModel::GroupBy::Composer:
|
||||||
search = QStringLiteral("composer:%1").arg(item->metadata.composer());
|
search = QStringLiteral("composer:\"%1\"").arg(item->metadata.composer());
|
||||||
break;
|
break;
|
||||||
case CollectionModel::GroupBy::Performer:
|
case CollectionModel::GroupBy::Performer:
|
||||||
search = QStringLiteral("performer:%1").arg(item->metadata.performer());
|
search = QStringLiteral("performer:\"%1\"").arg(item->metadata.performer());
|
||||||
break;
|
break;
|
||||||
case CollectionModel::GroupBy::Grouping:
|
case CollectionModel::GroupBy::Grouping:
|
||||||
search = QStringLiteral("grouping:%1").arg(item->metadata.grouping());
|
search = QStringLiteral("grouping:\"%1\"").arg(item->metadata.grouping());
|
||||||
break;
|
break;
|
||||||
case CollectionModel::GroupBy::Samplerate:
|
case CollectionModel::GroupBy::Samplerate:
|
||||||
search = QStringLiteral("samplerate:%1").arg(item->metadata.samplerate());
|
search = QStringLiteral("samplerate:%1").arg(item->metadata.samplerate());
|
||||||
@@ -730,7 +733,7 @@ void CollectionView::EditTracks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CollectionView::EditTagError(const QString &message) {
|
void CollectionView::EditTagError(const QString &message) {
|
||||||
emit Error(message);
|
Q_EMIT Error(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionView::RescanSongs() {
|
void CollectionView::RescanSongs() {
|
||||||
@@ -772,7 +775,7 @@ void CollectionView::FilterReturnPressed() {
|
|||||||
|
|
||||||
if (!currentIndex().isValid()) return;
|
if (!currentIndex().isValid()) return;
|
||||||
|
|
||||||
emit doubleClicked(currentIndex());
|
Q_EMIT doubleClicked(currentIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionView::ShowInBrowser() const {
|
void CollectionView::ShowInBrowser() const {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class CollectionView : public AutoExpandingTreeView {
|
|||||||
int TotalArtists() const;
|
int TotalArtists() const;
|
||||||
int TotalAlbums() const;
|
int TotalAlbums() const;
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void TotalSongCountUpdated(const int count);
|
void TotalSongCountUpdated(const int count);
|
||||||
void TotalArtistCountUpdated(const int count);
|
void TotalArtistCountUpdated(const int count);
|
||||||
void TotalAlbumCountUpdated(const int count);
|
void TotalAlbumCountUpdated(const int count);
|
||||||
@@ -82,7 +82,7 @@ class CollectionView : public AutoExpandingTreeView {
|
|||||||
|
|
||||||
void EditTagError(const QString &message);
|
void EditTagError(const QString &message);
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void ShowConfigDialog();
|
void ShowConfigDialog();
|
||||||
|
|
||||||
void TotalSongCountUpdated_();
|
void TotalSongCountUpdated_();
|
||||||
@@ -97,7 +97,7 @@ class CollectionView : public AutoExpandingTreeView {
|
|||||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
void contextMenuEvent(QContextMenuEvent *e) override;
|
void contextMenuEvent(QContextMenuEvent *e) override;
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void Load();
|
void Load();
|
||||||
void AddToPlaylist();
|
void AddToPlaylist();
|
||||||
void AddToPlaylistEnqueue();
|
void AddToPlaylistEnqueue();
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
#include <QMutexLocker>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
|
||||||
#include "core/filesystemwatcherinterface.h"
|
#include "core/filesystemwatcherinterface.h"
|
||||||
@@ -72,7 +73,6 @@
|
|||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
QStringList CollectionWatcher::sValidImages = QStringList() << QStringLiteral("jpg") << QStringLiteral("png") << QStringLiteral("gif") << QStringLiteral("jpeg");
|
QStringList CollectionWatcher::sValidImages = QStringList() << QStringLiteral("jpg") << QStringLiteral("png") << QStringLiteral("gif") << QStringLiteral("jpeg");
|
||||||
QStringList CollectionWatcher::kIgnoredExtensions = QStringList() << QStringLiteral("tmp") << QStringLiteral("tar") << QStringLiteral("gz") << QStringLiteral("bz2") << QStringLiteral("xz") << QStringLiteral("tbz") << QStringLiteral("tgz") << QStringLiteral("z") << QStringLiteral("zip") << QStringLiteral("rar");
|
|
||||||
|
|
||||||
CollectionWatcher::CollectionWatcher(Song::Source source, QObject *parent)
|
CollectionWatcher::CollectionWatcher(Song::Source source, QObject *parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
@@ -98,6 +98,8 @@ CollectionWatcher::CollectionWatcher(Song::Source source, QObject *parent)
|
|||||||
cue_parser_(new CueParser(backend_, this)),
|
cue_parser_(new CueParser(backend_, this)),
|
||||||
last_scan_time_(0) {
|
last_scan_time_(0) {
|
||||||
|
|
||||||
|
setObjectName(source_ == Song::Source::Collection ? QLatin1String(metaObject()->className()) : QStringLiteral("%1%2").arg(Song::DescriptionForSource(source_), QLatin1String(metaObject()->className())));
|
||||||
|
|
||||||
original_thread_ = thread();
|
original_thread_ = thread();
|
||||||
|
|
||||||
rescan_timer_->setInterval(2s);
|
rescan_timer_->setInterval(2s);
|
||||||
@@ -135,10 +137,51 @@ void CollectionWatcher::Exit() {
|
|||||||
|
|
||||||
Q_ASSERT(QThread::currentThread() == thread());
|
Q_ASSERT(QThread::currentThread() == thread());
|
||||||
|
|
||||||
Stop();
|
Abort();
|
||||||
if (backend_) backend_->Close();
|
if (backend_) backend_->Close();
|
||||||
moveToThread(original_thread_);
|
moveToThread(original_thread_);
|
||||||
emit ExitFinished();
|
Q_EMIT ExitFinished();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectionWatcher::Stop() {
|
||||||
|
|
||||||
|
QMutexLocker l(&mutex_stop_);
|
||||||
|
stop_requested_ = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectionWatcher::CancelStop() {
|
||||||
|
|
||||||
|
QMutexLocker l(&mutex_stop_);
|
||||||
|
stop_requested_ = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CollectionWatcher::stop_requested() const {
|
||||||
|
|
||||||
|
QMutexLocker l(&mutex_stop_);
|
||||||
|
return stop_requested_;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectionWatcher::Abort() {
|
||||||
|
|
||||||
|
QMutexLocker l(&mutex_abort_);
|
||||||
|
abort_requested_ = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CollectionWatcher::abort_requested() const {
|
||||||
|
|
||||||
|
QMutexLocker l(&mutex_abort_);
|
||||||
|
return abort_requested_;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CollectionWatcher::stop_or_abort_requested() const {
|
||||||
|
|
||||||
|
return stop_requested() || abort_requested();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,14 +266,14 @@ CollectionWatcher::ScanTransaction::ScanTransaction(CollectionWatcher *watcher,
|
|||||||
}
|
}
|
||||||
|
|
||||||
task_id_ = watcher_->task_manager_->StartTask(description);
|
task_id_ = watcher_->task_manager_->StartTask(description);
|
||||||
emit watcher_->ScanStarted(task_id_);
|
Q_EMIT watcher_->ScanStarted(task_id_);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionWatcher::ScanTransaction::~ScanTransaction() {
|
CollectionWatcher::ScanTransaction::~ScanTransaction() {
|
||||||
|
|
||||||
// If we're stopping then don't commit the transaction
|
// If we're stopping then don't commit the transaction
|
||||||
if (!watcher_->stop_requested_ && !watcher_->abort_requested_) {
|
if (!watcher_->stop_or_abort_requested()) {
|
||||||
CommitNewOrUpdatedSongs();
|
CommitNewOrUpdatedSongs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,35 +299,35 @@ void CollectionWatcher::ScanTransaction::CommitNewOrUpdatedSongs() {
|
|||||||
|
|
||||||
if (!deleted_songs.isEmpty()) {
|
if (!deleted_songs.isEmpty()) {
|
||||||
if (mark_songs_unavailable_ && watcher_->source() == Song::Source::Collection) {
|
if (mark_songs_unavailable_ && watcher_->source() == Song::Source::Collection) {
|
||||||
emit watcher_->SongsUnavailable(deleted_songs);
|
Q_EMIT watcher_->SongsUnavailable(deleted_songs);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
emit watcher_->SongsDeleted(deleted_songs);
|
Q_EMIT watcher_->SongsDeleted(deleted_songs);
|
||||||
}
|
}
|
||||||
deleted_songs.clear();
|
deleted_songs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!new_songs.isEmpty()) {
|
if (!new_songs.isEmpty()) {
|
||||||
emit watcher_->NewOrUpdatedSongs(new_songs);
|
Q_EMIT watcher_->NewOrUpdatedSongs(new_songs);
|
||||||
new_songs.clear();
|
new_songs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!touched_songs.isEmpty()) {
|
if (!touched_songs.isEmpty()) {
|
||||||
emit watcher_->SongsMTimeUpdated(touched_songs);
|
Q_EMIT watcher_->SongsMTimeUpdated(touched_songs);
|
||||||
touched_songs.clear();
|
touched_songs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!readded_songs.isEmpty()) {
|
if (!readded_songs.isEmpty()) {
|
||||||
emit watcher_->SongsReadded(readded_songs);
|
Q_EMIT watcher_->SongsReadded(readded_songs);
|
||||||
readded_songs.clear();
|
readded_songs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!new_subdirs.isEmpty()) {
|
if (!new_subdirs.isEmpty()) {
|
||||||
emit watcher_->SubdirsDiscovered(new_subdirs);
|
Q_EMIT watcher_->SubdirsDiscovered(new_subdirs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!touched_subdirs.isEmpty()) {
|
if (!touched_subdirs.isEmpty()) {
|
||||||
emit watcher_->SubdirsMTimeUpdated(touched_subdirs);
|
Q_EMIT watcher_->SubdirsMTimeUpdated(touched_subdirs);
|
||||||
touched_subdirs.clear();
|
touched_subdirs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,7 +349,7 @@ void CollectionWatcher::ScanTransaction::CommitNewOrUpdatedSongs() {
|
|||||||
new_subdirs.clear();
|
new_subdirs.clear();
|
||||||
|
|
||||||
if (incremental_ || ignores_mtime_) {
|
if (incremental_ || ignores_mtime_) {
|
||||||
emit watcher_->UpdateLastSeen(dir_, expire_unavailable_songs_days_);
|
Q_EMIT watcher_->UpdateLastSeen(dir_, expire_unavailable_songs_days_);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -407,7 +450,7 @@ CollectionSubdirectoryList CollectionWatcher::ScanTransaction::GetAllSubdirs() {
|
|||||||
|
|
||||||
void CollectionWatcher::AddDirectory(const CollectionDirectory &dir, const CollectionSubdirectoryList &subdirs) {
|
void CollectionWatcher::AddDirectory(const CollectionDirectory &dir, const CollectionSubdirectoryList &subdirs) {
|
||||||
|
|
||||||
stop_requested_ = false;
|
CancelStop();
|
||||||
|
|
||||||
watched_dirs_[dir.id] = dir;
|
watched_dirs_[dir.id] = dir;
|
||||||
|
|
||||||
@@ -421,25 +464,29 @@ void CollectionWatcher::AddDirectory(const CollectionDirectory &dir, const Colle
|
|||||||
last_scan_time_ = QDateTime::currentSecsSinceEpoch();
|
last_scan_time_ = QDateTime::currentSecsSinceEpoch();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// We can do an incremental scan - looking at the mtimes of each subdirectory and only rescan if the directory has changed.
|
if (monitor_) {
|
||||||
ScanTransaction transaction(this, dir.id, true, false, mark_songs_unavailable_);
|
for (const CollectionSubdirectory &subdir : subdirs) {
|
||||||
QMap<QString, quint64> subdir_files_count;
|
AddWatch(dir, subdir.path);
|
||||||
const quint64 files_count = FilesCountForSubdirs(&transaction, subdirs, subdir_files_count);
|
}
|
||||||
transaction.SetKnownSubdirs(subdirs);
|
}
|
||||||
transaction.AddToProgressMax(files_count);
|
if (scan_on_startup_) {
|
||||||
for (const CollectionSubdirectory &subdir : subdirs) {
|
// We can do an incremental scan - looking at the mtimes of each subdirectory and only rescan if the directory has changed.
|
||||||
if (stop_requested_ || abort_requested_) break;
|
ScanTransaction transaction(this, dir.id, true, false, mark_songs_unavailable_);
|
||||||
|
QMap<QString, quint64> subdir_files_count;
|
||||||
if (scan_on_startup_) ScanSubdirectory(subdir.path, subdir, subdir_files_count[subdir.path], &transaction);
|
const quint64 files_count = FilesCountForSubdirs(&transaction, subdirs, subdir_files_count);
|
||||||
|
transaction.SetKnownSubdirs(subdirs);
|
||||||
if (monitor_) AddWatch(dir, subdir.path);
|
transaction.AddToProgressMax(files_count);
|
||||||
|
for (const CollectionSubdirectory &subdir : subdirs) {
|
||||||
|
if (stop_or_abort_requested()) break;
|
||||||
|
ScanSubdirectory(subdir.path, subdir, subdir_files_count[subdir.path], &transaction);
|
||||||
|
}
|
||||||
|
if (!stop_or_abort_requested()) {
|
||||||
|
last_scan_time_ = QDateTime::currentSecsSinceEpoch();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
last_scan_time_ = QDateTime::currentSecsSinceEpoch();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emit CompilationsNeedUpdating();
|
Q_EMIT CompilationsNeedUpdating();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,7 +540,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const CollectionSu
|
|||||||
QDirIterator it(path, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
|
QDirIterator it(path, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
|
|
||||||
if (stop_requested_ || abort_requested_) return;
|
if (stop_or_abort_requested()) return;
|
||||||
|
|
||||||
QString child(it.next());
|
QString child(it.next());
|
||||||
QFileInfo child_info(child);
|
QFileInfo child_info(child);
|
||||||
@@ -512,7 +559,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const CollectionSu
|
|||||||
else {
|
else {
|
||||||
QString ext_part(ExtensionPart(child));
|
QString ext_part(ExtensionPart(child));
|
||||||
QString dir_part(DirectoryPart(child));
|
QString dir_part(DirectoryPart(child));
|
||||||
if (kIgnoredExtensions.contains(child_info.suffix(), Qt::CaseInsensitive) || child_info.baseName() == QLatin1String("qt_temp")) {
|
if (Song::kRejectedExtensions.contains(child_info.suffix(), Qt::CaseInsensitive) || child_info.baseName() == QLatin1String("qt_temp")) {
|
||||||
t->AddToProgress(1);
|
t->AddToProgress(1);
|
||||||
}
|
}
|
||||||
else if (sValidImages.contains(ext_part)) {
|
else if (sValidImages.contains(ext_part)) {
|
||||||
@@ -528,7 +575,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const CollectionSu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stop_requested_ || abort_requested_) return;
|
if (stop_or_abort_requested()) return;
|
||||||
|
|
||||||
// Ask the database for a list of files in this directory
|
// Ask the database for a list of files in this directory
|
||||||
SongList songs_in_db = t->FindSongsInSubdirectory(path);
|
SongList songs_in_db = t->FindSongsInSubdirectory(path);
|
||||||
@@ -539,7 +586,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const CollectionSu
|
|||||||
QStringList files_on_disk_copy = files_on_disk;
|
QStringList files_on_disk_copy = files_on_disk;
|
||||||
for (const QString &file : files_on_disk_copy) {
|
for (const QString &file : files_on_disk_copy) {
|
||||||
|
|
||||||
if (stop_requested_ || abort_requested_) return;
|
if (stop_or_abort_requested()) return;
|
||||||
|
|
||||||
// Associated CUE
|
// Associated CUE
|
||||||
QString new_cue = CueParser::FindCueFilename(file);
|
QString new_cue = CueParser::FindCueFilename(file);
|
||||||
@@ -741,7 +788,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const CollectionSu
|
|||||||
|
|
||||||
// Recurse into the new subdirs that we found
|
// Recurse into the new subdirs that we found
|
||||||
for (const CollectionSubdirectory &my_new_subdir : std::as_const(my_new_subdirs)) {
|
for (const CollectionSubdirectory &my_new_subdir : std::as_const(my_new_subdirs)) {
|
||||||
if (stop_requested_ || abort_requested_) return;
|
if (stop_or_abort_requested()) return;
|
||||||
ScanSubdirectory(my_new_subdir.path, my_new_subdir, 0, t, true);
|
ScanSubdirectory(my_new_subdir.path, my_new_subdir, 0, t, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -797,6 +844,7 @@ void CollectionWatcher::UpdateCueAssociatedSongs(const QString &file,
|
|||||||
t->deleted_songs << old_cue;
|
t->deleted_songs << old_cue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionWatcher::UpdateNonCueAssociatedSong(const QString &file,
|
void CollectionWatcher::UpdateNonCueAssociatedSong(const QString &file,
|
||||||
@@ -1008,8 +1056,8 @@ void CollectionWatcher::RemoveDirectory(const CollectionDirectory &dir) {
|
|||||||
watched_dirs_.remove(dir.id);
|
watched_dirs_.remove(dir.id);
|
||||||
|
|
||||||
// Stop watching the directory's subdirectories
|
// Stop watching the directory's subdirectories
|
||||||
QStringList subdir_paths = subdir_mapping_.keys(dir);
|
const QStringList subdir_paths = subdir_mapping_.keys(dir);
|
||||||
for (const QString &subdir_path : std::as_const(subdir_paths)) {
|
for (const QString &subdir_path : subdir_paths) {
|
||||||
fs_watcher_->RemovePath(subdir_path);
|
fs_watcher_->RemovePath(subdir_path);
|
||||||
subdir_mapping_.remove(subdir_path);
|
subdir_mapping_.remove(subdir_path);
|
||||||
}
|
}
|
||||||
@@ -1030,8 +1078,8 @@ bool CollectionWatcher::FindSongsByPath(const SongList &songs, const QString &pa
|
|||||||
|
|
||||||
bool CollectionWatcher::FindSongsByFingerprint(const QString &file, const QString &fingerprint, SongList *out) {
|
bool CollectionWatcher::FindSongsByFingerprint(const QString &file, const QString &fingerprint, SongList *out) {
|
||||||
|
|
||||||
SongList songs = backend_->GetSongsByFingerprint(fingerprint);
|
const SongList songs = backend_->GetSongsByFingerprint(fingerprint);
|
||||||
for (const Song &song : std::as_const(songs)) {
|
for (const Song &song : songs) {
|
||||||
QString filename = song.url().toLocalFile();
|
QString filename = song.url().toLocalFile();
|
||||||
QFileInfo info(filename);
|
QFileInfo info(filename);
|
||||||
// Allow mulitiple songs in different directories with the same fingerprint.
|
// Allow mulitiple songs in different directories with the same fingerprint.
|
||||||
@@ -1081,10 +1129,10 @@ void CollectionWatcher::RescanPathsNow() {
|
|||||||
|
|
||||||
const QList<int> dirs = rescan_queue_.keys();
|
const QList<int> dirs = rescan_queue_.keys();
|
||||||
for (const int dir : dirs) {
|
for (const int dir : dirs) {
|
||||||
if (stop_requested_ || abort_requested_) break;
|
if (stop_or_abort_requested()) break;
|
||||||
ScanTransaction transaction(this, dir, false, false, mark_songs_unavailable_);
|
ScanTransaction transaction(this, dir, false, false, mark_songs_unavailable_);
|
||||||
|
|
||||||
const QStringList paths = rescan_queue_[dir];
|
const QStringList paths = rescan_queue_.value(dir);
|
||||||
|
|
||||||
QMap<QString, quint64> subdir_files_count;
|
QMap<QString, quint64> subdir_files_count;
|
||||||
for (const QString &path : paths) {
|
for (const QString &path : paths) {
|
||||||
@@ -1094,7 +1142,7 @@ void CollectionWatcher::RescanPathsNow() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const QString &path : paths) {
|
for (const QString &path : paths) {
|
||||||
if (stop_requested_ || abort_requested_) break;
|
if (stop_or_abort_requested()) break;
|
||||||
CollectionSubdirectory subdir;
|
CollectionSubdirectory subdir;
|
||||||
subdir.directory_id = dir;
|
subdir.directory_id = dir;
|
||||||
subdir.mtime = 0;
|
subdir.mtime = 0;
|
||||||
@@ -1105,7 +1153,7 @@ void CollectionWatcher::RescanPathsNow() {
|
|||||||
|
|
||||||
rescan_queue_.clear();
|
rescan_queue_.clear();
|
||||||
|
|
||||||
emit CompilationsNeedUpdating();
|
Q_EMIT CompilationsNeedUpdating();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1139,7 +1187,7 @@ QString CollectionWatcher::PickBestArt(const QStringList &art_automatic_list) {
|
|||||||
QString biggest_path;
|
QString biggest_path;
|
||||||
|
|
||||||
for (const QString &path : std::as_const(filtered)) {
|
for (const QString &path : std::as_const(filtered)) {
|
||||||
if (stop_requested_ || abort_requested_) break;
|
if (stop_or_abort_requested()) break;
|
||||||
|
|
||||||
QImage image(path);
|
QImage image(path);
|
||||||
if (image.isNull()) continue;
|
if (image.isNull()) continue;
|
||||||
@@ -1215,14 +1263,14 @@ void CollectionWatcher::FullScanNow() { PerformScan(false, true); }
|
|||||||
|
|
||||||
void CollectionWatcher::PerformScan(const bool incremental, const bool ignore_mtimes) {
|
void CollectionWatcher::PerformScan(const bool incremental, const bool ignore_mtimes) {
|
||||||
|
|
||||||
stop_requested_ = false;
|
CancelStop();
|
||||||
|
|
||||||
for (const CollectionDirectory &dir : std::as_const(watched_dirs_)) {
|
for (const CollectionDirectory &dir : std::as_const(watched_dirs_)) {
|
||||||
|
|
||||||
if (stop_requested_ || abort_requested_) break;
|
if (stop_or_abort_requested()) break;
|
||||||
|
|
||||||
ScanTransaction transaction(this, dir.id, incremental, ignore_mtimes, mark_songs_unavailable_);
|
ScanTransaction transaction(this, dir.id, incremental, ignore_mtimes, mark_songs_unavailable_);
|
||||||
CollectionSubdirectoryList subdirs(transaction.GetAllSubdirs());
|
CollectionSubdirectoryList subdirs = transaction.GetAllSubdirs();
|
||||||
|
|
||||||
if (subdirs.isEmpty()) {
|
if (subdirs.isEmpty()) {
|
||||||
qLog(Debug) << "Collection directory wasn't in subdir list.";
|
qLog(Debug) << "Collection directory wasn't in subdir list.";
|
||||||
@@ -1237,7 +1285,7 @@ void CollectionWatcher::PerformScan(const bool incremental, const bool ignore_mt
|
|||||||
transaction.AddToProgressMax(files_count);
|
transaction.AddToProgressMax(files_count);
|
||||||
|
|
||||||
for (const CollectionSubdirectory &subdir : std::as_const(subdirs)) {
|
for (const CollectionSubdirectory &subdir : std::as_const(subdirs)) {
|
||||||
if (stop_requested_ || abort_requested_) break;
|
if (stop_or_abort_requested()) break;
|
||||||
ScanSubdirectory(subdir.path, subdir, subdir_files_count[subdir.path], &transaction);
|
ScanSubdirectory(subdir.path, subdir, subdir_files_count[subdir.path], &transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1245,7 +1293,7 @@ void CollectionWatcher::PerformScan(const bool incremental, const bool ignore_mt
|
|||||||
|
|
||||||
last_scan_time_ = QDateTime::currentSecsSinceEpoch();
|
last_scan_time_ = QDateTime::currentSecsSinceEpoch();
|
||||||
|
|
||||||
emit CompilationsNeedUpdating();
|
Q_EMIT CompilationsNeedUpdating();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1255,7 +1303,7 @@ quint64 CollectionWatcher::FilesCountForPath(ScanTransaction *t, const QString &
|
|||||||
QDirIterator it(path, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
|
QDirIterator it(path, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
|
|
||||||
if (stop_requested_ || abort_requested_) break;
|
if (stop_or_abort_requested()) break;
|
||||||
|
|
||||||
QString child = it.next();
|
QString child = it.next();
|
||||||
QFileInfo path_info(child);
|
QFileInfo path_info(child);
|
||||||
@@ -1289,7 +1337,7 @@ quint64 CollectionWatcher::FilesCountForSubdirs(ScanTransaction *t, const Collec
|
|||||||
|
|
||||||
quint64 i = 0;
|
quint64 i = 0;
|
||||||
for (const CollectionSubdirectory &subdir : subdirs) {
|
for (const CollectionSubdirectory &subdir : subdirs) {
|
||||||
if (stop_requested_ || abort_requested_) break;
|
if (stop_or_abort_requested()) break;
|
||||||
const quint64 files_count = FilesCountForPath(t, subdir.path);
|
const quint64 files_count = FilesCountForPath(t, subdir.path);
|
||||||
subdir_files_count[subdir.path] = files_count;
|
subdir_files_count[subdir.path] = files_count;
|
||||||
i += files_count;
|
i += files_count;
|
||||||
@@ -1307,17 +1355,17 @@ void CollectionWatcher::RescanSongsAsync(const SongList &songs) {
|
|||||||
|
|
||||||
void CollectionWatcher::RescanSongs(const SongList &songs) {
|
void CollectionWatcher::RescanSongs(const SongList &songs) {
|
||||||
|
|
||||||
stop_requested_ = false;
|
CancelStop();
|
||||||
|
|
||||||
QStringList scanned_paths;
|
QStringList scanned_paths;
|
||||||
for (const Song &song : songs) {
|
for (const Song &song : songs) {
|
||||||
if (stop_requested_ || abort_requested_) break;
|
if (stop_or_abort_requested()) break;
|
||||||
const QString song_path = song.url().toLocalFile().section(QLatin1Char('/'), 0, -2);
|
const QString song_path = song.url().toLocalFile().section(QLatin1Char('/'), 0, -2);
|
||||||
if (scanned_paths.contains(song_path)) continue;
|
if (scanned_paths.contains(song_path)) continue;
|
||||||
ScanTransaction transaction(this, song.directory_id(), false, true, mark_songs_unavailable_);
|
ScanTransaction transaction(this, song.directory_id(), false, true, mark_songs_unavailable_);
|
||||||
const CollectionSubdirectoryList subdirs = transaction.GetAllSubdirs();
|
const CollectionSubdirectoryList subdirs = transaction.GetAllSubdirs();
|
||||||
for (const CollectionSubdirectory &subdir : subdirs) {
|
for (const CollectionSubdirectory &subdir : subdirs) {
|
||||||
if (stop_requested_ || abort_requested_) break;
|
if (stop_or_abort_requested()) break;
|
||||||
if (subdir.path != song_path) continue;
|
if (subdir.path != song_path) continue;
|
||||||
qLog(Debug) << "Rescan for directory ID" << song.directory_id() << "directory" << subdir.path;
|
qLog(Debug) << "Rescan for directory ID" << song.directory_id() << "directory" << subdir.path;
|
||||||
quint64 files_count = FilesCountForPath(&transaction, subdir.path);
|
quint64 files_count = FilesCountForPath(&transaction, subdir.path);
|
||||||
@@ -1326,6 +1374,6 @@ void CollectionWatcher::RescanSongs(const SongList &songs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emit CompilationsNeedUpdating();
|
Q_EMIT CompilationsNeedUpdating();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <QMutex>
|
||||||
|
|
||||||
#include "collectiondirectory.h"
|
#include "collectiondirectory.h"
|
||||||
#include "core/shared_ptr.h"
|
#include "core/shared_ptr.h"
|
||||||
@@ -64,14 +65,15 @@ class CollectionWatcher : public QObject {
|
|||||||
void SetRescanPausedAsync(const bool pause);
|
void SetRescanPausedAsync(const bool pause);
|
||||||
void ReloadSettingsAsync();
|
void ReloadSettingsAsync();
|
||||||
|
|
||||||
void Stop() { stop_requested_ = true; }
|
void Stop();
|
||||||
void Abort() { abort_requested_ = true; }
|
void CancelStop();
|
||||||
|
void Abort();
|
||||||
|
|
||||||
void ExitAsync();
|
void ExitAsync();
|
||||||
|
|
||||||
void RescanSongsAsync(const SongList &songs);
|
void RescanSongsAsync(const SongList &songs);
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void NewOrUpdatedSongs(const SongList &songs);
|
void NewOrUpdatedSongs(const SongList &songs);
|
||||||
void SongsMTimeUpdated(const SongList &songs);
|
void SongsMTimeUpdated(const SongList &songs);
|
||||||
void SongsDeleted(const SongList &songs);
|
void SongsDeleted(const SongList &songs);
|
||||||
@@ -85,7 +87,7 @@ class CollectionWatcher : public QObject {
|
|||||||
|
|
||||||
void ScanStarted(const int task_id);
|
void ScanStarted(const int task_id);
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void AddDirectory(const CollectionDirectory &dir, const CollectionSubdirectoryList &subdirs);
|
void AddDirectory(const CollectionDirectory &dir, const CollectionSubdirectoryList &subdirs);
|
||||||
void RemoveDirectory(const CollectionDirectory &dir);
|
void RemoveDirectory(const CollectionDirectory &dir);
|
||||||
void SetRescanPaused(bool pause);
|
void SetRescanPaused(bool pause);
|
||||||
@@ -166,7 +168,7 @@ class CollectionWatcher : public QObject {
|
|||||||
bool known_subdirs_dirty_;
|
bool known_subdirs_dirty_;
|
||||||
};
|
};
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
void Exit();
|
void Exit();
|
||||||
void DirectoryChanged(const QString &subdir);
|
void DirectoryChanged(const QString &subdir);
|
||||||
@@ -178,6 +180,9 @@ class CollectionWatcher : public QObject {
|
|||||||
void RescanSongs(const SongList &songs);
|
void RescanSongs(const SongList &songs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool stop_requested() const;
|
||||||
|
bool abort_requested() const;
|
||||||
|
bool stop_or_abort_requested() const;
|
||||||
static bool FindSongsByPath(const SongList &songs, const QString &path, SongList *out);
|
static bool FindSongsByPath(const SongList &songs, const QString &path, SongList *out);
|
||||||
bool FindSongsByFingerprint(const QString &file, const QString &fingerprint, SongList *out);
|
bool FindSongsByFingerprint(const QString &file, const QString &fingerprint, SongList *out);
|
||||||
static bool FindSongsByFingerprint(const QString &file, const SongList &songs, const QString &fingerprint, SongList *out);
|
static bool FindSongsByFingerprint(const QString &file, const SongList &songs, const QString &fingerprint, SongList *out);
|
||||||
@@ -231,7 +236,10 @@ class CollectionWatcher : public QObject {
|
|||||||
bool overwrite_playcount_;
|
bool overwrite_playcount_;
|
||||||
bool overwrite_rating_;
|
bool overwrite_rating_;
|
||||||
|
|
||||||
|
mutable QMutex mutex_stop_;
|
||||||
bool stop_requested_;
|
bool stop_requested_;
|
||||||
|
|
||||||
|
mutable QMutex mutex_abort_;
|
||||||
bool abort_requested_;
|
bool abort_requested_;
|
||||||
|
|
||||||
QMap<int, CollectionDirectory> watched_dirs_;
|
QMap<int, CollectionDirectory> watched_dirs_;
|
||||||
@@ -245,7 +253,6 @@ class CollectionWatcher : public QObject {
|
|||||||
CueParser *cue_parser_;
|
CueParser *cue_parser_;
|
||||||
|
|
||||||
static QStringList sValidImages;
|
static QStringList sValidImages;
|
||||||
static QStringList kIgnoredExtensions;
|
|
||||||
|
|
||||||
qint64 last_scan_time_;
|
qint64 last_scan_time_;
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ void GroupByDialog::Reset() {
|
|||||||
|
|
||||||
void GroupByDialog::accept() {
|
void GroupByDialog::accept() {
|
||||||
|
|
||||||
emit Accepted(CollectionModel::Grouping(
|
Q_EMIT Accepted(CollectionModel::Grouping(
|
||||||
p_->mapping_.get<tag_index>().find(ui_->combobox_first->currentIndex())->group_by,
|
p_->mapping_.get<tag_index>().find(ui_->combobox_first->currentIndex())->group_by,
|
||||||
p_->mapping_.get<tag_index>().find(ui_->combobox_second->currentIndex())->group_by,
|
p_->mapping_.get<tag_index>().find(ui_->combobox_second->currentIndex())->group_by,
|
||||||
p_->mapping_.get<tag_index>().find(ui_->combobox_third->currentIndex())->group_by),
|
p_->mapping_.get<tag_index>().find(ui_->combobox_third->currentIndex())->group_by),
|
||||||
|
|||||||
@@ -43,14 +43,14 @@ class GroupByDialog : public QDialog {
|
|||||||
explicit GroupByDialog(QWidget *parent = nullptr);
|
explicit GroupByDialog(QWidget *parent = nullptr);
|
||||||
~GroupByDialog() override;
|
~GroupByDialog() override;
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void CollectionGroupingChanged(const CollectionModel::Grouping g, const bool separate_albums_by_grouping);
|
void CollectionGroupingChanged(const CollectionModel::Grouping g, const bool separate_albums_by_grouping);
|
||||||
void accept() override;
|
void accept() override;
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void Accepted(const CollectionModel::Grouping g, const bool separate_albums_by_grouping);
|
void Accepted(const CollectionModel::Grouping g, const bool separate_albums_by_grouping);
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ void SavedGroupingManager::Remove() {
|
|||||||
}
|
}
|
||||||
UpdateModel();
|
UpdateModel();
|
||||||
|
|
||||||
emit UpdateGroupByActions();
|
Q_EMIT UpdateGroupByActions();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,10 +51,10 @@ class SavedGroupingManager : public QDialog {
|
|||||||
|
|
||||||
static QString GroupByToString(const CollectionModel::GroupBy g);
|
static QString GroupByToString(const CollectionModel::GroupBy g);
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void UpdateGroupByActions();
|
void UpdateGroupByActions();
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void UpdateButtonState();
|
void UpdateButtonState();
|
||||||
void Remove();
|
void Remove();
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
@@ -202,7 +203,7 @@ void ContextAlbum::DrawSpinner(QPainter *p) {
|
|||||||
|
|
||||||
void ContextAlbum::DrawPreviousCovers(QPainter *p) {
|
void ContextAlbum::DrawPreviousCovers(QPainter *p) {
|
||||||
|
|
||||||
for (SharedPtr<PreviousCover> previous_cover : previous_covers_) {
|
for (SharedPtr<PreviousCover> previous_cover : std::as_const(previous_covers_)) {
|
||||||
DrawImage(p, previous_cover->pixmap, previous_cover->opacity);
|
DrawImage(p, previous_cover->pixmap, previous_cover->opacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,7 +221,7 @@ void ContextAlbum::FadeCurrentCover(const qreal value) {
|
|||||||
void ContextAlbum::FadeCurrentCoverFinished() {
|
void ContextAlbum::FadeCurrentCoverFinished() {
|
||||||
|
|
||||||
if (image_original_ == image_strawberry_) {
|
if (image_original_ == image_strawberry_) {
|
||||||
emit FadeStopFinished();
|
Q_EMIT FadeStopFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -254,7 +255,7 @@ void ContextAlbum::ScaleCover() {
|
|||||||
|
|
||||||
void ContextAlbum::ScalePreviousCovers() {
|
void ContextAlbum::ScalePreviousCovers() {
|
||||||
|
|
||||||
for (SharedPtr<PreviousCover> previous_cover : previous_covers_) {
|
for (SharedPtr<PreviousCover> previous_cover : std::as_const(previous_covers_)) {
|
||||||
QImage image = ImageUtils::ScaleImage(previous_cover->image, QSize(desired_height_, desired_height_), devicePixelRatioF(), true);
|
QImage image = ImageUtils::ScaleImage(previous_cover->image, QSize(desired_height_, desired_height_), devicePixelRatioF(), true);
|
||||||
if (image.isNull()) {
|
if (image.isNull()) {
|
||||||
previous_cover->pixmap = QPixmap();
|
previous_cover->pixmap = QPixmap();
|
||||||
|
|||||||
@@ -78,18 +78,18 @@ class ContextAlbum : public QWidget {
|
|||||||
void ScaleCover();
|
void ScaleCover();
|
||||||
void ScalePreviousCovers();
|
void ScalePreviousCovers();
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void FadeStopFinished();
|
void FadeStopFinished();
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void Update() { update(); }
|
void Update() { update(); }
|
||||||
void AutomaticCoverSearchDone();
|
void AutomaticCoverSearchDone();
|
||||||
void FadeCurrentCover(const qreal value);
|
void FadeCurrentCover(const qreal value);
|
||||||
void FadeCurrentCoverFinished();
|
void FadeCurrentCoverFinished();
|
||||||
void FadePreviousCover(SharedPtr<PreviousCover> previous_cover);
|
void FadePreviousCover(SharedPtr<ContextAlbum::PreviousCover> previous_cover);
|
||||||
void FadePreviousCoverFinished(SharedPtr<PreviousCover> previous_cover);
|
void FadePreviousCoverFinished(SharedPtr<ContextAlbum::PreviousCover> previous_cover);
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void SearchCoverInProgress();
|
void SearchCoverInProgress();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
@@ -65,7 +67,9 @@
|
|||||||
#include "contextview.h"
|
#include "contextview.h"
|
||||||
#include "contextalbum.h"
|
#include "contextalbum.h"
|
||||||
|
|
||||||
const int ContextView::kWidgetSpacing = 50;
|
namespace {
|
||||||
|
constexpr int kWidgetSpacing = 50;
|
||||||
|
}
|
||||||
|
|
||||||
ContextView::ContextView(QWidget *parent)
|
ContextView::ContextView(QWidget *parent)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
@@ -427,10 +431,10 @@ void ContextView::NoSong() {
|
|||||||
|
|
||||||
void ContextView::UpdateFonts() {
|
void ContextView::UpdateFonts() {
|
||||||
|
|
||||||
for (QLabel *l : labels_play_all_) {
|
for (QLabel *l : std::as_const(labels_play_all_)) {
|
||||||
l->setFont(font_normal_);
|
l->setFont(font_normal_);
|
||||||
}
|
}
|
||||||
for (QTextEdit *e : textedit_play_) {
|
for (QTextEdit *e : std::as_const(textedit_play_)) {
|
||||||
e->setFont(font_normal_);
|
e->setFont(font_normal_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,7 +456,7 @@ void ContextView::SetSong() {
|
|||||||
widget_album_->hide();
|
widget_album_->hide();
|
||||||
widget_album_changed = true;
|
widget_album_changed = true;
|
||||||
}
|
}
|
||||||
if (widget_album_changed) emit AlbumEnabledChanged();
|
if (widget_album_changed) Q_EMIT AlbumEnabledChanged();
|
||||||
|
|
||||||
if (action_show_data_->isChecked()) {
|
if (action_show_data_->isChecked()) {
|
||||||
widget_play_data_->show();
|
widget_play_data_->show();
|
||||||
@@ -547,7 +551,10 @@ void ContextView::SetSong() {
|
|||||||
|
|
||||||
void ContextView::UpdateSong(const Song &song) {
|
void ContextView::UpdateSong(const Song &song) {
|
||||||
|
|
||||||
textedit_top_->SetText(QStringLiteral("<b>%1</b><br />%2").arg(Utilities::ReplaceMessage(title_fmt_, song, QStringLiteral("<br />"), true), Utilities::ReplaceMessage(summary_fmt_, song, QStringLiteral("<br />"), true)));
|
const QString top_text = QStringLiteral("<b>%1</b><br />%2").arg(Utilities::ReplaceMessage(title_fmt_, song, QStringLiteral("<br />"), true), Utilities::ReplaceMessage(summary_fmt_, song, QStringLiteral("<br />"), true));
|
||||||
|
if (top_text != textedit_top_->Text()) {
|
||||||
|
textedit_top_->SetText(top_text);
|
||||||
|
}
|
||||||
|
|
||||||
if (action_show_data_->isChecked()) {
|
if (action_show_data_->isChecked()) {
|
||||||
if (song.filetype() != song_playing_.filetype()) label_filetype_->setText(song.TextForFiletype());
|
if (song.filetype() != song_playing_.filetype()) label_filetype_->setText(song.TextForFiletype());
|
||||||
@@ -615,11 +622,11 @@ void ContextView::UpdateSong(const Song &song) {
|
|||||||
|
|
||||||
void ContextView::ResetSong() {
|
void ContextView::ResetSong() {
|
||||||
|
|
||||||
for (QLabel *l : labels_play_data_) {
|
for (QLabel *l : std::as_const(labels_play_data_)) {
|
||||||
l->clear();
|
l->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (QTextEdit *l : textedit_play_) {
|
for (QTextEdit *l : std::as_const(textedit_play_)) {
|
||||||
l->clear();
|
l->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,10 +80,10 @@ class ContextView : public QWidget {
|
|||||||
void SearchLyrics();
|
void SearchLyrics();
|
||||||
void UpdateFonts();
|
void UpdateFonts();
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void AlbumEnabledChanged();
|
void AlbumEnabledChanged();
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void ActionShowAlbum();
|
void ActionShowAlbum();
|
||||||
void ActionShowData();
|
void ActionShowData();
|
||||||
void ActionShowLyrics();
|
void ActionShowLyrics();
|
||||||
@@ -92,7 +92,7 @@ class ContextView : public QWidget {
|
|||||||
void FadeStopFinished();
|
void FadeStopFinished();
|
||||||
void UpdateLyrics(const quint64 id, const QString &provider, const QString &lyrics);
|
void UpdateLyrics(const quint64 id, const QString &provider, const QString &lyrics);
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
void Playing();
|
void Playing();
|
||||||
void Stopped();
|
void Stopped();
|
||||||
@@ -101,8 +101,6 @@ class ContextView : public QWidget {
|
|||||||
void AlbumCoverLoaded(const Song &song, const QImage &image);
|
void AlbumCoverLoaded(const Song &song, const QImage &image);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int kWidgetSpacing;
|
|
||||||
|
|
||||||
Application *app_;
|
Application *app_;
|
||||||
CollectionView *collectionview_;
|
CollectionView *collectionview_;
|
||||||
AlbumCoverChoiceController *album_cover_choice_controller_;
|
AlbumCoverChoiceController *album_cover_choice_controller_;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
@@ -68,6 +69,7 @@
|
|||||||
#include "lyrics/azlyricscomlyricsprovider.h"
|
#include "lyrics/azlyricscomlyricsprovider.h"
|
||||||
#include "lyrics/elyricsnetlyricsprovider.h"
|
#include "lyrics/elyricsnetlyricsprovider.h"
|
||||||
#include "lyrics/letraslyricsprovider.h"
|
#include "lyrics/letraslyricsprovider.h"
|
||||||
|
#include "lyrics/lyricfindlyricsprovider.h"
|
||||||
|
|
||||||
#include "scrobbler/audioscrobbler.h"
|
#include "scrobbler/audioscrobbler.h"
|
||||||
#include "scrobbler/lastfmscrobbler.h"
|
#include "scrobbler/lastfmscrobbler.h"
|
||||||
@@ -169,15 +171,16 @@ class ApplicationImpl {
|
|||||||
lyrics_providers_([app]() {
|
lyrics_providers_([app]() {
|
||||||
LyricsProviders *lyrics_providers = new LyricsProviders(app);
|
LyricsProviders *lyrics_providers = new LyricsProviders(app);
|
||||||
// Initialize the repository of lyrics providers.
|
// Initialize the repository of lyrics providers.
|
||||||
lyrics_providers->AddProvider(new GeniusLyricsProvider(app->network()));
|
lyrics_providers->AddProvider(new GeniusLyricsProvider(lyrics_providers->network()));
|
||||||
lyrics_providers->AddProvider(new OVHLyricsProvider(app->network()));
|
lyrics_providers->AddProvider(new OVHLyricsProvider(lyrics_providers->network()));
|
||||||
lyrics_providers->AddProvider(new LoloLyricsProvider(app->network()));
|
lyrics_providers->AddProvider(new LoloLyricsProvider(lyrics_providers->network()));
|
||||||
lyrics_providers->AddProvider(new MusixmatchLyricsProvider(app->network()));
|
lyrics_providers->AddProvider(new MusixmatchLyricsProvider(lyrics_providers->network()));
|
||||||
lyrics_providers->AddProvider(new ChartLyricsProvider(app->network()));
|
lyrics_providers->AddProvider(new ChartLyricsProvider(lyrics_providers->network()));
|
||||||
lyrics_providers->AddProvider(new SongLyricsComLyricsProvider(app->network()));
|
lyrics_providers->AddProvider(new SongLyricsComLyricsProvider(lyrics_providers->network()));
|
||||||
lyrics_providers->AddProvider(new AzLyricsComLyricsProvider(app->network()));
|
lyrics_providers->AddProvider(new AzLyricsComLyricsProvider(lyrics_providers->network()));
|
||||||
lyrics_providers->AddProvider(new ElyricsNetLyricsProvider(app->network()));
|
lyrics_providers->AddProvider(new ElyricsNetLyricsProvider(lyrics_providers->network()));
|
||||||
lyrics_providers->AddProvider(new LetrasLyricsProvider(app->network()));
|
lyrics_providers->AddProvider(new LetrasLyricsProvider(lyrics_providers->network()));
|
||||||
|
lyrics_providers->AddProvider(new LyricFindLyricsProvider(lyrics_providers->network()));
|
||||||
lyrics_providers->ReloadSettings();
|
lyrics_providers->ReloadSettings();
|
||||||
return lyrics_providers;
|
return lyrics_providers;
|
||||||
}),
|
}),
|
||||||
@@ -245,6 +248,8 @@ class ApplicationImpl {
|
|||||||
Application::Application(QObject *parent)
|
Application::Application(QObject *parent)
|
||||||
: QObject(parent), p_(new ApplicationImpl(this)) {
|
: QObject(parent), p_(new ApplicationImpl(this)) {
|
||||||
|
|
||||||
|
setObjectName(QLatin1String(metaObject()->className()));
|
||||||
|
|
||||||
device_finders()->Init();
|
device_finders()->Init();
|
||||||
collection()->Init();
|
collection()->Init();
|
||||||
tag_reader_client();
|
tag_reader_client();
|
||||||
@@ -257,11 +262,11 @@ Application::~Application() {
|
|||||||
|
|
||||||
qLog(Debug) << "Terminating application";
|
qLog(Debug) << "Terminating application";
|
||||||
|
|
||||||
for (QThread *thread : threads_) {
|
for (QThread *thread : std::as_const(threads_)) {
|
||||||
thread->quit();
|
thread->quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (QThread *thread : threads_) {
|
for (QThread *thread : std::as_const(threads_)) {
|
||||||
thread->wait();
|
thread->wait();
|
||||||
thread->deleteLater();
|
thread->deleteLater();
|
||||||
}
|
}
|
||||||
@@ -272,6 +277,8 @@ QThread *Application::MoveToNewThread(QObject *object) {
|
|||||||
|
|
||||||
QThread *thread = new QThread(this);
|
QThread *thread = new QThread(this);
|
||||||
|
|
||||||
|
thread->setObjectName(object->objectName());
|
||||||
|
|
||||||
MoveToThread(object, thread);
|
MoveToThread(object, thread);
|
||||||
|
|
||||||
thread->start();
|
thread->start();
|
||||||
@@ -340,9 +347,9 @@ void Application::ExitReceived() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::AddError(const QString &message) { emit ErrorAdded(message); }
|
void Application::AddError(const QString &message) { Q_EMIT ErrorAdded(message); }
|
||||||
void Application::ReloadSettings() { emit SettingsChanged(); }
|
void Application::ReloadSettings() { Q_EMIT SettingsChanged(); }
|
||||||
void Application::OpenSettingsDialogAtPage(SettingsDialog::Page page) { emit SettingsDialogRequested(page); }
|
void Application::OpenSettingsDialogAtPage(SettingsDialog::Page page) { Q_EMIT SettingsDialogRequested(page); }
|
||||||
|
|
||||||
SharedPtr<TagReaderClient> Application::tag_reader_client() const { return p_->tag_reader_client_.ptr(); }
|
SharedPtr<TagReaderClient> Application::tag_reader_client() const { return p_->tag_reader_client_.ptr(); }
|
||||||
SharedPtr<Database> Application::database() const { return p_->database_.ptr(); }
|
SharedPtr<Database> Application::database() const { return p_->database_.ptr(); }
|
||||||
|
|||||||
@@ -112,15 +112,15 @@ class Application : public QObject {
|
|||||||
QThread *MoveToNewThread(QObject *object);
|
QThread *MoveToNewThread(QObject *object);
|
||||||
static void MoveToThread(QObject *object, QThread *thread);
|
static void MoveToThread(QObject *object, QThread *thread);
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void ExitReceived();
|
void ExitReceived();
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void AddError(const QString &message);
|
void AddError(const QString &message);
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
void OpenSettingsDialogAtPage(SettingsDialog::Page page);
|
void OpenSettingsDialogAtPage(SettingsDialog::Page page);
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void ErrorAdded(const QString &message);
|
void ErrorAdded(const QString &message);
|
||||||
void SettingsChanged();
|
void SettingsChanged();
|
||||||
void SettingsDialogRequested(const SettingsDialog::Page page);
|
void SettingsDialogRequested(const SettingsDialog::Page page);
|
||||||
|
|||||||
@@ -46,7 +46,9 @@
|
|||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
const char *CommandlineOptions::kHelpText =
|
namespace {
|
||||||
|
|
||||||
|
constexpr char kHelpText[] =
|
||||||
"%1: strawberry [%2] [%3]\n"
|
"%1: strawberry [%2] [%3]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"%4:\n"
|
"%4:\n"
|
||||||
@@ -83,7 +85,9 @@ const char *CommandlineOptions::kHelpText =
|
|||||||
" --log-levels <levels> %33\n"
|
" --log-levels <levels> %33\n"
|
||||||
" --version %34\n";
|
" --version %34\n";
|
||||||
|
|
||||||
const char *CommandlineOptions::kVersionText = "Strawberry %1";
|
constexpr char kVersionText[] = "Strawberry %1";
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
CommandlineOptions::CommandlineOptions(int argc, char **argv)
|
CommandlineOptions::CommandlineOptions(int argc, char **argv)
|
||||||
: argc_(argc),
|
: argc_(argc),
|
||||||
@@ -202,7 +206,7 @@ bool CommandlineOptions::Parse() {
|
|||||||
|
|
||||||
// Parse the arguments
|
// Parse the arguments
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
forever {
|
Q_FOREVER {
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
int c = getopt_long(argc_, argv_, L"hptusqrfv:c:alk:i:oyg:w:", kOptions, nullptr);
|
int c = getopt_long(argc_, argv_, L"hptusqrfv:c:alk:i:oyg:w:", kOptions, nullptr);
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -41,9 +41,6 @@ class CommandlineOptions {
|
|||||||
public:
|
public:
|
||||||
explicit CommandlineOptions(int argc = 0, char **argv = nullptr);
|
explicit CommandlineOptions(int argc = 0, char **argv = nullptr);
|
||||||
|
|
||||||
static const char *kHelpText;
|
|
||||||
static const char *kVersionText;
|
|
||||||
|
|
||||||
// Don't change the values or order, these get serialised and sent to
|
// Don't change the values or order, these get serialised and sent to
|
||||||
// possibly a different version of Strawberry
|
// possibly a different version of Strawberry
|
||||||
enum class UrlListAction {
|
enum class UrlListAction {
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ Database::Database(Application *app, QObject *parent, const QString &database_na
|
|||||||
startup_schema_version_(-1),
|
startup_schema_version_(-1),
|
||||||
original_thread_(nullptr) {
|
original_thread_(nullptr) {
|
||||||
|
|
||||||
|
setObjectName(QLatin1String(metaObject()->className()));
|
||||||
|
|
||||||
original_thread_ = thread();
|
original_thread_ = thread();
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -105,7 +107,7 @@ void Database::Exit() {
|
|||||||
Q_ASSERT(QThread::currentThread() == thread());
|
Q_ASSERT(QThread::currentThread() == thread());
|
||||||
Close();
|
Close();
|
||||||
moveToThread(original_thread_);
|
moveToThread(original_thread_);
|
||||||
emit ExitFinished();
|
Q_EMIT ExitFinished();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +163,7 @@ QSqlDatabase Database::Connect() {
|
|||||||
// Attach external databases
|
// Attach external databases
|
||||||
QStringList keys = attached_databases_.keys();
|
QStringList keys = attached_databases_.keys();
|
||||||
for (const QString &key : std::as_const(keys)) {
|
for (const QString &key : std::as_const(keys)) {
|
||||||
QString filename = attached_databases_[key].filename_;
|
QString filename = attached_databases_.value(key).filename_;
|
||||||
|
|
||||||
if (!injected_database_name_.isNull()) filename = injected_database_name_;
|
if (!injected_database_name_.isNull()) filename = injected_database_name_;
|
||||||
|
|
||||||
@@ -182,7 +184,7 @@ QSqlDatabase Database::Connect() {
|
|||||||
// We might have to initialize the schema in some attached databases now, if they were deleted and don't match up with the main schema version.
|
// We might have to initialize the schema in some attached databases now, if they were deleted and don't match up with the main schema version.
|
||||||
keys = attached_databases_.keys();
|
keys = attached_databases_.keys();
|
||||||
for (const QString &key : std::as_const(keys)) {
|
for (const QString &key : std::as_const(keys)) {
|
||||||
if (attached_databases_[key].is_temporary_ && attached_databases_[key].schema_.isEmpty()) {
|
if (attached_databases_.value(key).is_temporary_ && attached_databases_.value(key).schema_.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Find out if there are any tables in this database
|
// Find out if there are any tables in this database
|
||||||
@@ -258,7 +260,7 @@ void Database::RecreateAttachedDb(const QString &database_name) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString filename = attached_databases_[database_name].filename_;
|
const QString filename = attached_databases_.value(database_name).filename_;
|
||||||
|
|
||||||
QMutexLocker l(&mutex_);
|
QMutexLocker l(&mutex_);
|
||||||
{
|
{
|
||||||
@@ -388,7 +390,8 @@ void Database::ExecSchemaCommandsFromFile(QSqlDatabase &db, const QString &filen
|
|||||||
void Database::ExecSchemaCommands(QSqlDatabase &db, const QString &schema, int schema_version, bool in_transaction) {
|
void Database::ExecSchemaCommands(QSqlDatabase &db, const QString &schema, int schema_version, bool in_transaction) {
|
||||||
|
|
||||||
// Run each command
|
// Run each command
|
||||||
QStringList commands = schema.split(QRegularExpression(QStringLiteral("; *\n\n")));
|
static const QRegularExpression regex_split_commands(QStringLiteral("; *\n\n"));
|
||||||
|
QStringList commands = schema.split(regex_split_commands);
|
||||||
|
|
||||||
// We don't want this list to reflect possible DB schema changes, so we initialize it before executing any statements.
|
// 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!
|
// If no outer transaction is provided the song tables need to be queried before beginning an inner transaction!
|
||||||
@@ -481,8 +484,8 @@ void Database::ReportErrors(const SqlQuery &query) {
|
|||||||
if (sql_error.isValid()) {
|
if (sql_error.isValid()) {
|
||||||
qLog(Error) << "Unable to execute SQL query:" << sql_error;
|
qLog(Error) << "Unable to execute SQL query:" << sql_error;
|
||||||
qLog(Error) << "Failed SQL query:" << query.LastQuery();
|
qLog(Error) << "Failed SQL query:" << query.LastQuery();
|
||||||
emit Error(tr("Unable to execute SQL query: %1").arg(sql_error.text()));
|
Q_EMIT Error(tr("Unable to execute SQL query: %1").arg(sql_error.text()));
|
||||||
emit Error(tr("Failed SQL query: %1").arg(query.LastQuery()));
|
Q_EMIT Error(tr("Failed SQL query: %1").arg(query.LastQuery()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,15 +83,15 @@ class Database : public QObject {
|
|||||||
void AttachDatabaseOnDbConnection(const QString &database_name, const AttachedDatabase &database, QSqlDatabase &db);
|
void AttachDatabaseOnDbConnection(const QString &database_name, const AttachedDatabase &database, QSqlDatabase &db);
|
||||||
void DetachDatabase(const QString &database_name);
|
void DetachDatabase(const QString &database_name);
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void ExitFinished();
|
void ExitFinished();
|
||||||
void Error(const QString &error);
|
void Error(const QString &error);
|
||||||
void Errors(const QStringList &errors);
|
void Errors(const QStringList &errors);
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void Exit();
|
void Exit();
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void DoBackup();
|
void DoBackup();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -34,7 +34,9 @@
|
|||||||
#include "deletefiles.h"
|
#include "deletefiles.h"
|
||||||
#include "musicstorage.h"
|
#include "musicstorage.h"
|
||||||
|
|
||||||
const int DeleteFiles::kBatchSize = 50;
|
namespace {
|
||||||
|
constexpr int kBatchSize = 50;
|
||||||
|
}
|
||||||
|
|
||||||
DeleteFiles::DeleteFiles(SharedPtr<TaskManager> task_manager, SharedPtr<MusicStorage> storage, const bool use_trash, QObject *parent)
|
DeleteFiles::DeleteFiles(SharedPtr<TaskManager> task_manager, SharedPtr<MusicStorage> storage, const bool use_trash, QObject *parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
@@ -97,7 +99,7 @@ void DeleteFiles::ProcessSomeFiles() {
|
|||||||
|
|
||||||
task_manager_->SetTaskFinished(task_id_);
|
task_manager_->SetTaskFinished(task_id_);
|
||||||
|
|
||||||
emit Finished(songs_with_errors_);
|
Q_EMIT Finished(songs_with_errors_);
|
||||||
|
|
||||||
// Move back to the original thread so deleteLater() can get called in the main thread's event loop
|
// Move back to the original thread so deleteLater() can get called in the main thread's event loop
|
||||||
moveToThread(original_thread_);
|
moveToThread(original_thread_);
|
||||||
@@ -114,7 +116,7 @@ void DeleteFiles::ProcessSomeFiles() {
|
|||||||
for (; progress_ < n; ++progress_) {
|
for (; progress_ < n; ++progress_) {
|
||||||
task_manager_->SetTaskProgress(task_id_, progress_, songs_.count());
|
task_manager_->SetTaskProgress(task_id_, progress_, songs_.count());
|
||||||
|
|
||||||
const Song &song = songs_[progress_];
|
const Song song = songs_.value(progress_);
|
||||||
|
|
||||||
MusicStorage::DeleteJob job;
|
MusicStorage::DeleteJob job;
|
||||||
job.metadata_ = song;
|
job.metadata_ = song;
|
||||||
|
|||||||
@@ -41,15 +41,13 @@ class DeleteFiles : public QObject {
|
|||||||
explicit DeleteFiles(SharedPtr<TaskManager> task_manager, SharedPtr<MusicStorage> storage, const bool use_trash, QObject *parent = nullptr);
|
explicit DeleteFiles(SharedPtr<TaskManager> task_manager, SharedPtr<MusicStorage> storage, const bool use_trash, QObject *parent = nullptr);
|
||||||
~DeleteFiles() override;
|
~DeleteFiles() override;
|
||||||
|
|
||||||
static const int kBatchSize;
|
|
||||||
|
|
||||||
void Start(const SongList &songs);
|
void Start(const SongList &songs);
|
||||||
void Start(const QStringList &filenames);
|
void Start(const QStringList &filenames);
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void Finished(const SongList &songs_with_errors);
|
void Finished(const SongList &songs_with_errors);
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void ProcessSomeFiles();
|
void ProcessSomeFiles();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class FileSystemWatcherInterface : public QObject {
|
|||||||
|
|
||||||
static FileSystemWatcherInterface *Create(QObject *parent = nullptr);
|
static FileSystemWatcherInterface *Create(QObject *parent = nullptr);
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void PathChanged(const QString &path);
|
void PathChanged(const QString &path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ void LocalRedirectServer::incomingConnection(qintptr socket_descriptor) {
|
|||||||
delete tcp_socket;
|
delete tcp_socket;
|
||||||
close();
|
close();
|
||||||
error_ = QLatin1String("Unable to set socket descriptor");
|
error_ = QLatin1String("Unable to set socket descriptor");
|
||||||
emit Finished();
|
Q_EMIT Finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
socket_ = tcp_socket;
|
socket_ = tcp_socket;
|
||||||
@@ -114,7 +114,7 @@ void LocalRedirectServer::ReadyRead() {
|
|||||||
socket_ = nullptr;
|
socket_ = nullptr;
|
||||||
request_url_ = ParseUrlFromRequest(buffer_);
|
request_url_ = ParseUrlFromRequest(buffer_);
|
||||||
close();
|
close();
|
||||||
emit Finished();
|
Q_EMIT Finished();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
QObject::connect(socket_, &QAbstractSocket::readyRead, this, &LocalRedirectServer::ReadyRead);
|
QObject::connect(socket_, &QAbstractSocket::readyRead, this, &LocalRedirectServer::ReadyRead);
|
||||||
@@ -129,9 +129,9 @@ void LocalRedirectServer::WriteTemplate() const {
|
|||||||
QString page_data = QString::fromUtf8(page_file.readAll());
|
QString page_data = QString::fromUtf8(page_file.readAll());
|
||||||
page_file.close();
|
page_file.close();
|
||||||
|
|
||||||
QRegularExpression tr_regexp(QStringLiteral("tr\\(\"([^\"]+)\"\\)"));
|
static const QRegularExpression tr_regexp(QStringLiteral("tr\\(\"([^\"]+)\"\\)"));
|
||||||
qint64 offset = 0;
|
qint64 offset = 0;
|
||||||
forever {
|
Q_FOREVER {
|
||||||
QRegularExpressionMatch re_match = tr_regexp.match(page_data, offset);
|
QRegularExpressionMatch re_match = tr_regexp.match(page_data, offset);
|
||||||
if (!re_match.hasMatch()) break;
|
if (!re_match.hasMatch()) break;
|
||||||
offset = re_match.capturedStart();
|
offset = re_match.capturedStart();
|
||||||
|
|||||||
@@ -45,10 +45,10 @@ class LocalRedirectServer : public QTcpServer {
|
|||||||
const QUrl &request_url() const { return request_url_; }
|
const QUrl &request_url() const { return request_url_; }
|
||||||
const QString &error() const { return error_; }
|
const QString &error() const { return error_; }
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void Finished();
|
void Finished();
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void NewConnection();
|
void NewConnection();
|
||||||
void incomingConnection(qintptr socket_descriptor) override;
|
void incomingConnection(qintptr socket_descriptor) override;
|
||||||
void Encrypted();
|
void Encrypted();
|
||||||
@@ -57,7 +57,6 @@ class LocalRedirectServer : public QTcpServer {
|
|||||||
void ReadyRead();
|
void ReadyRead();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool GenerateCertificate();
|
|
||||||
void WriteTemplate() const;
|
void WriteTemplate() const;
|
||||||
QUrl ParseUrlFromRequest(const QByteArray &request) const;
|
QUrl ParseUrlFromRequest(const QByteArray &request) const;
|
||||||
|
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ class MacFSListener : public FileSystemWatcherInterface {
|
|||||||
void RemovePath(const QString &path);
|
void RemovePath(const QString &path);
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void PathChanged(const QString &path);
|
void PathChanged(const QString &path);
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void UpdateStream();
|
void UpdateStream();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -34,9 +34,9 @@
|
|||||||
|
|
||||||
MacFSListener::MacFSListener(QObject *parent)
|
MacFSListener::MacFSListener(QObject *parent)
|
||||||
: FileSystemWatcherInterface(parent),
|
: FileSystemWatcherInterface(parent),
|
||||||
run_loop_(nullptr),
|
run_loop_(nullptr),
|
||||||
stream_(nullptr),
|
stream_(nullptr),
|
||||||
update_timer_(new QTimer(this)) {
|
update_timer_(new QTimer(this)) {
|
||||||
|
|
||||||
update_timer_->setSingleShot(true);
|
update_timer_->setSingleShot(true);
|
||||||
update_timer_->setInterval(2000);
|
update_timer_->setInterval(2000);
|
||||||
@@ -60,7 +60,7 @@ void MacFSListener::EventStreamCallback(ConstFSEventStreamRef stream, void *user
|
|||||||
while (path.endsWith(QLatin1Char('/'))) {
|
while (path.endsWith(QLatin1Char('/'))) {
|
||||||
path.chop(1);
|
path.chop(1);
|
||||||
}
|
}
|
||||||
emit me->PathChanged(path);
|
Q_EMIT me->PathChanged(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,10 +71,10 @@ class SystemTrayIcon : public QObject {
|
|||||||
QPixmap CreateIcon(const QPixmap &icon, const QPixmap &grey_icon);
|
QPixmap CreateIcon(const QPixmap &icon, const QPixmap &grey_icon);
|
||||||
void UpdateIcon();
|
void UpdateIcon();
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void ActionChanged();
|
void ActionChanged();
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void ChangeVolume(const int delta);
|
void ChangeVolume(const int delta);
|
||||||
void SeekForward();
|
void SeekForward();
|
||||||
void SeekBackward();
|
void SeekBackward();
|
||||||
|
|||||||
@@ -23,8 +23,9 @@
|
|||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <functional>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <utility>
|
||||||
|
#include <functional>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -399,16 +400,16 @@ MainWindow::MainWindow(Application *app, SharedPtr<SystemTrayIcon> tray_icon, OS
|
|||||||
ui_->tabs->AddTab(tidal_view_, QStringLiteral("tidal"), IconLoader::Load(QStringLiteral("tidal"), true, 0, 32), tr("Tidal"));
|
ui_->tabs->AddTab(tidal_view_, QStringLiteral("tidal"), IconLoader::Load(QStringLiteral("tidal"), true, 0, 32), tr("Tidal"));
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SPOTIFY
|
#ifdef HAVE_SPOTIFY
|
||||||
ui_->tabs->AddTab(spotify_view_, QLatin1String("spotify"), IconLoader::Load(QStringLiteral("spotify"), true, 0, 32), tr("Spotify"));
|
ui_->tabs->AddTab(spotify_view_, QStringLiteral("spotify"), IconLoader::Load(QStringLiteral("spotify"), true, 0, 32), tr("Spotify"));
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_QOBUZ
|
#ifdef HAVE_QOBUZ
|
||||||
ui_->tabs->AddTab(qobuz_view_, QStringLiteral("qobuz"), IconLoader::Load(QStringLiteral("qobuz"), true, 0, 32), tr("Qobuz"));
|
ui_->tabs->AddTab(qobuz_view_, QStringLiteral("qobuz"), IconLoader::Load(QStringLiteral("qobuz"), true, 0, 32), tr("Qobuz"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Add the playing widget to the fancy tab widget
|
// Add the playing widget to the fancy tab widget
|
||||||
ui_->tabs->addBottomWidget(ui_->widget_playing);
|
ui_->tabs->AddBottomWidget(ui_->widget_playing);
|
||||||
ui_->tabs->setBackgroundPixmap(QPixmap(QStringLiteral(":/pictures/sidebar-background.png")));
|
ui_->tabs->SetBackgroundPixmap(QPixmap(QStringLiteral(":/pictures/sidebar-background.png")));
|
||||||
ui_->tabs->Load(QLatin1String(kSettingsGroup));
|
ui_->tabs->LoadSettings(QLatin1String(kSettingsGroup));
|
||||||
|
|
||||||
track_position_timer_->setInterval(kTrackPositionUpdateTimeMs);
|
track_position_timer_->setInterval(kTrackPositionUpdateTimeMs);
|
||||||
QObject::connect(track_position_timer_, &QTimer::timeout, this, &MainWindow::UpdateTrackPosition);
|
QObject::connect(track_position_timer_, &QTimer::timeout, this, &MainWindow::UpdateTrackPosition);
|
||||||
@@ -489,7 +490,7 @@ MainWindow::MainWindow(Application *app, SharedPtr<SystemTrayIcon> tray_icon, OS
|
|||||||
ui_->action_transcoder->setIcon(IconLoader::Load(QStringLiteral("tools-wizard")));
|
ui_->action_transcoder->setIcon(IconLoader::Load(QStringLiteral("tools-wizard")));
|
||||||
ui_->action_update_collection->setIcon(IconLoader::Load(QStringLiteral("view-refresh")));
|
ui_->action_update_collection->setIcon(IconLoader::Load(QStringLiteral("view-refresh")));
|
||||||
ui_->action_full_collection_scan->setIcon(IconLoader::Load(QStringLiteral("view-refresh")));
|
ui_->action_full_collection_scan->setIcon(IconLoader::Load(QStringLiteral("view-refresh")));
|
||||||
ui_->action_abort_collection_scan->setIcon(IconLoader::Load(QStringLiteral("dialog-error")));
|
ui_->action_stop_collection_scan->setIcon(IconLoader::Load(QStringLiteral("dialog-error")));
|
||||||
ui_->action_settings->setIcon(IconLoader::Load(QStringLiteral("configure")));
|
ui_->action_settings->setIcon(IconLoader::Load(QStringLiteral("configure")));
|
||||||
ui_->action_import_data_from_last_fm->setIcon(IconLoader::Load(QStringLiteral("scrobble")));
|
ui_->action_import_data_from_last_fm->setIcon(IconLoader::Load(QStringLiteral("scrobble")));
|
||||||
ui_->action_console->setIcon(IconLoader::Load(QStringLiteral("keyboard")));
|
ui_->action_console->setIcon(IconLoader::Load(QStringLiteral("keyboard")));
|
||||||
@@ -555,7 +556,7 @@ MainWindow::MainWindow(Application *app, SharedPtr<SystemTrayIcon> tray_icon, OS
|
|||||||
QObject::connect(ui_->action_jump, &QAction::triggered, ui_->playlist->view(), &PlaylistView::JumpToCurrentlyPlayingTrack);
|
QObject::connect(ui_->action_jump, &QAction::triggered, ui_->playlist->view(), &PlaylistView::JumpToCurrentlyPlayingTrack);
|
||||||
QObject::connect(ui_->action_update_collection, &QAction::triggered, &*app_->collection(), &SCollection::IncrementalScan);
|
QObject::connect(ui_->action_update_collection, &QAction::triggered, &*app_->collection(), &SCollection::IncrementalScan);
|
||||||
QObject::connect(ui_->action_full_collection_scan, &QAction::triggered, &*app_->collection(), &SCollection::FullScan);
|
QObject::connect(ui_->action_full_collection_scan, &QAction::triggered, &*app_->collection(), &SCollection::FullScan);
|
||||||
QObject::connect(ui_->action_abort_collection_scan, &QAction::triggered, &*app_->collection(), &SCollection::AbortScan);
|
QObject::connect(ui_->action_stop_collection_scan, &QAction::triggered, &*app_->collection(), &SCollection::StopScan);
|
||||||
#if defined(HAVE_GSTREAMER)
|
#if defined(HAVE_GSTREAMER)
|
||||||
QObject::connect(ui_->action_add_files_to_transcoder, &QAction::triggered, this, &MainWindow::AddFilesToTranscoder);
|
QObject::connect(ui_->action_add_files_to_transcoder, &QAction::triggered, this, &MainWindow::AddFilesToTranscoder);
|
||||||
ui_->action_add_files_to_transcoder->setIcon(IconLoader::Load(QStringLiteral("tools-wizard")));
|
ui_->action_add_files_to_transcoder->setIcon(IconLoader::Load(QStringLiteral("tools-wizard")));
|
||||||
@@ -621,6 +622,7 @@ MainWindow::MainWindow(Application *app, SharedPtr<SystemTrayIcon> tray_icon, OS
|
|||||||
QObject::connect(&*app_->player(), &Player::VolumeChanged, ui_->volume, &VolumeSlider::SetValue);
|
QObject::connect(&*app_->player(), &Player::VolumeChanged, ui_->volume, &VolumeSlider::SetValue);
|
||||||
QObject::connect(&*app_->player(), &Player::ForceShowOSD, this, &MainWindow::ForceShowOSD);
|
QObject::connect(&*app_->player(), &Player::ForceShowOSD, this, &MainWindow::ForceShowOSD);
|
||||||
|
|
||||||
|
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::AllPlaylistsLoaded, &*app->player(), &Player::PlaylistsLoaded);
|
||||||
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::CurrentSongChanged, this, &MainWindow::SongChanged);
|
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::CurrentSongChanged, this, &MainWindow::SongChanged);
|
||||||
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::CurrentSongChanged, &*app_->player(), &Player::CurrentMetadataChanged);
|
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::CurrentSongChanged, &*app_->player(), &Player::CurrentMetadataChanged);
|
||||||
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::EditingFinished, this, &MainWindow::PlaylistEditFinished);
|
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::EditingFinished, this, &MainWindow::PlaylistEditFinished);
|
||||||
@@ -844,7 +846,7 @@ MainWindow::MainWindow(Application *app, SharedPtr<SystemTrayIcon> tray_icon, OS
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Fancy tabs
|
// Fancy tabs
|
||||||
QObject::connect(ui_->tabs, &FancyTabWidget::CurrentChanged, this, &MainWindow::TabSwitched);
|
QObject::connect(ui_->tabs, &FancyTabWidget::CurrentTabChanged, this, &MainWindow::TabSwitched);
|
||||||
|
|
||||||
// Context
|
// Context
|
||||||
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::CurrentSongChanged, context_view_, &ContextView::SongChanged);
|
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::CurrentSongChanged, context_view_, &ContextView::SongChanged);
|
||||||
@@ -1023,9 +1025,6 @@ MainWindow::MainWindow(Application *app, SharedPtr<SystemTrayIcon> tray_icon, OS
|
|||||||
|
|
||||||
CommandlineOptionsReceived(options);
|
CommandlineOptionsReceived(options);
|
||||||
|
|
||||||
if (!options.contains_play_options()) {
|
|
||||||
LoadPlaybackStatus();
|
|
||||||
}
|
|
||||||
if (app_->scrobbler()->enabled() && !app_->scrobbler()->offline()) {
|
if (app_->scrobbler()->enabled() && !app_->scrobbler()->offline()) {
|
||||||
app_->scrobbler()->Submit();
|
app_->scrobbler()->Submit();
|
||||||
}
|
}
|
||||||
@@ -1280,8 +1279,8 @@ void MainWindow::RefreshStyleSheet() {
|
|||||||
void MainWindow::SaveSettings() {
|
void MainWindow::SaveSettings() {
|
||||||
|
|
||||||
SaveGeometry();
|
SaveGeometry();
|
||||||
SavePlaybackStatus();
|
|
||||||
app_->player()->SaveVolume();
|
app_->player()->SaveVolume();
|
||||||
|
app_->player()->SavePlaybackStatus();
|
||||||
ui_->tabs->SaveSettings(QLatin1String(kSettingsGroup));
|
ui_->tabs->SaveSettings(QLatin1String(kSettingsGroup));
|
||||||
ui_->playlist->view()->SaveSettings();
|
ui_->playlist->view()->SaveSettings();
|
||||||
app_->scrobbler()->WriteCache();
|
app_->scrobbler()->WriteCache();
|
||||||
@@ -1307,7 +1306,7 @@ void MainWindow::Exit() {
|
|||||||
else {
|
else {
|
||||||
if (app_->player()->engine()->is_fadeout_enabled()) {
|
if (app_->player()->engine()->is_fadeout_enabled()) {
|
||||||
// To shut down the application when fadeout will be finished
|
// To shut down the application when fadeout will be finished
|
||||||
QObject::connect(&*app_->player()->engine(), &EngineBase::FadeoutFinishedSignal, this, &MainWindow::DoExit);
|
QObject::connect(&*app_->player()->engine(), &EngineBase::Finished, this, &MainWindow::DoExit);
|
||||||
if (app_->player()->GetState() == EngineBase::State::Playing) {
|
if (app_->player()->GetState() == EngineBase::State::Playing) {
|
||||||
app_->player()->Stop();
|
app_->player()->Stop();
|
||||||
ignore_close_ = true;
|
ignore_close_ = true;
|
||||||
@@ -1371,8 +1370,12 @@ void MainWindow::MediaStopped() {
|
|||||||
ui_->button_love->setEnabled(false);
|
ui_->button_love->setEnabled(false);
|
||||||
tray_icon_->LoveStateChanged(false);
|
tray_icon_->LoveStateChanged(false);
|
||||||
|
|
||||||
track_position_timer_->stop();
|
if (track_position_timer_->isActive()) {
|
||||||
track_slider_timer_->stop();
|
track_position_timer_->stop();
|
||||||
|
}
|
||||||
|
if (track_slider_timer_->isActive()) {
|
||||||
|
track_slider_timer_->stop();
|
||||||
|
}
|
||||||
ui_->track_slider->SetStopped();
|
ui_->track_slider->SetStopped();
|
||||||
tray_icon_->SetProgress(0);
|
tray_icon_->SetProgress(0);
|
||||||
tray_icon_->SetStopped();
|
tray_icon_->SetStopped();
|
||||||
@@ -1400,8 +1403,12 @@ void MainWindow::MediaPaused() {
|
|||||||
|
|
||||||
ui_->action_play_pause->setEnabled(true);
|
ui_->action_play_pause->setEnabled(true);
|
||||||
|
|
||||||
track_position_timer_->stop();
|
if (!track_position_timer_->isActive()) {
|
||||||
track_slider_timer_->stop();
|
track_position_timer_->start();
|
||||||
|
}
|
||||||
|
if (!track_slider_timer_->isActive()) {
|
||||||
|
track_slider_timer_->start();
|
||||||
|
}
|
||||||
|
|
||||||
tray_icon_->SetPaused();
|
tray_icon_->SetPaused();
|
||||||
|
|
||||||
@@ -1426,8 +1433,13 @@ void MainWindow::MediaPlaying() {
|
|||||||
ui_->track_slider->SetCanSeek(can_seek);
|
ui_->track_slider->SetCanSeek(can_seek);
|
||||||
tray_icon_->SetPlaying(enable_play_pause);
|
tray_icon_->SetPlaying(enable_play_pause);
|
||||||
|
|
||||||
track_position_timer_->start();
|
if (!track_position_timer_->isActive()) {
|
||||||
track_slider_timer_->start();
|
track_position_timer_->start();
|
||||||
|
}
|
||||||
|
if (!track_slider_timer_->isActive()) {
|
||||||
|
track_slider_timer_->start();
|
||||||
|
}
|
||||||
|
|
||||||
UpdateTrackPosition();
|
UpdateTrackPosition();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1535,80 +1547,6 @@ void MainWindow::SaveGeometry() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::SavePlaybackStatus() {
|
|
||||||
|
|
||||||
Settings s;
|
|
||||||
|
|
||||||
s.beginGroup(Player::kSettingsGroup);
|
|
||||||
s.setValue("playback_state", static_cast<int>(app_->player()->GetState()));
|
|
||||||
if (app_->player()->GetState() == EngineBase::State::Playing || app_->player()->GetState() == EngineBase::State::Paused) {
|
|
||||||
s.setValue("playback_playlist", app_->playlist_manager()->active()->id());
|
|
||||||
s.setValue("playback_position", app_->player()->engine()->position_nanosec() / kNsecPerSec);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
s.setValue("playback_playlist", -1);
|
|
||||||
s.setValue("playback_position", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
s.endGroup();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::LoadPlaybackStatus() {
|
|
||||||
|
|
||||||
Settings s;
|
|
||||||
|
|
||||||
s.beginGroup(BehaviourSettingsPage::kSettingsGroup);
|
|
||||||
const bool resume_playback = s.value("resumeplayback", false).toBool();
|
|
||||||
s.endGroup();
|
|
||||||
|
|
||||||
s.beginGroup(Player::kSettingsGroup);
|
|
||||||
const EngineBase::State playback_state = static_cast<EngineBase::State>(s.value("playback_state", static_cast<int>(EngineBase::State::Empty)).toInt());
|
|
||||||
s.endGroup();
|
|
||||||
|
|
||||||
if (resume_playback && playback_state != EngineBase::State::Empty && playback_state != EngineBase::State::Idle) {
|
|
||||||
SharedPtr<QMetaObject::Connection> connection = make_shared<QMetaObject::Connection>();
|
|
||||||
*connection = QObject::connect(&*app_->playlist_manager(), &PlaylistManager::AllPlaylistsLoaded, this, [this, connection]() {
|
|
||||||
QObject::disconnect(*connection);
|
|
||||||
QTimer::singleShot(400ms, this, &MainWindow::ResumePlayback);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::ResumePlayback() {
|
|
||||||
|
|
||||||
qLog(Debug) << "Resuming playback";
|
|
||||||
|
|
||||||
Settings s;
|
|
||||||
s.beginGroup(Player::kSettingsGroup);
|
|
||||||
const EngineBase::State playback_state = static_cast<EngineBase::State>(s.value("playback_state", static_cast<int>(EngineBase::State::Empty)).toInt());
|
|
||||||
int playback_playlist = s.value("playback_playlist", -1).toInt();
|
|
||||||
int playback_position = s.value("playback_position", 0).toInt();
|
|
||||||
s.endGroup();
|
|
||||||
|
|
||||||
if (playback_playlist == app_->playlist_manager()->current()->id()) {
|
|
||||||
// Set active to current to resume playback on correct playlist.
|
|
||||||
app_->playlist_manager()->SetActiveToCurrent();
|
|
||||||
if (playback_state == EngineBase::State::Paused) {
|
|
||||||
SharedPtr<QMetaObject::Connection> connection = make_shared<QMetaObject::Connection>();
|
|
||||||
*connection = QObject::connect(&*app_->player(), &Player::Playing, &*app_->player(), [this, connection]() {
|
|
||||||
QObject::disconnect(*connection);
|
|
||||||
QTimer::singleShot(300, &*app_->player(), &Player::PlayPauseHelper);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
app_->player()->Play(playback_position * kNsecPerSec);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset saved playback status so we don't resume again from the same position.
|
|
||||||
s.beginGroup(Player::kSettingsGroup);
|
|
||||||
s.setValue("playback_state", static_cast<int>(EngineBase::State::Empty));
|
|
||||||
s.setValue("playback_playlist", -1);
|
|
||||||
s.setValue("playback_position", 0);
|
|
||||||
s.endGroup();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::PlayIndex(const QModelIndex &idx, Playlist::AutoScroll autoscroll) {
|
void MainWindow::PlayIndex(const QModelIndex &idx, Playlist::AutoScroll autoscroll) {
|
||||||
|
|
||||||
if (!idx.isValid()) return;
|
if (!idx.isValid()) return;
|
||||||
@@ -1620,7 +1558,7 @@ void MainWindow::PlayIndex(const QModelIndex &idx, Playlist::AutoScroll autoscro
|
|||||||
}
|
}
|
||||||
|
|
||||||
app_->playlist_manager()->SetActiveToCurrent();
|
app_->playlist_manager()->SetActiveToCurrent();
|
||||||
app_->player()->PlayAt(row, 0, EngineBase::TrackChangeType::Manual, autoscroll, true);
|
app_->player()->PlayAt(row, false, 0, EngineBase::TrackChangeType::Manual, autoscroll, true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1637,14 +1575,14 @@ void MainWindow::PlaylistDoubleClick(const QModelIndex &idx) {
|
|||||||
switch (doubleclick_playlist_addmode_) {
|
switch (doubleclick_playlist_addmode_) {
|
||||||
case BehaviourSettingsPage::PlaylistAddBehaviour::Play:
|
case BehaviourSettingsPage::PlaylistAddBehaviour::Play:
|
||||||
app_->playlist_manager()->SetActiveToCurrent();
|
app_->playlist_manager()->SetActiveToCurrent();
|
||||||
app_->player()->PlayAt(source_idx.row(), 0, EngineBase::TrackChangeType::Manual, Playlist::AutoScroll::Never, true, true);
|
app_->player()->PlayAt(source_idx.row(), false, 0, EngineBase::TrackChangeType::Manual, Playlist::AutoScroll::Never, true, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BehaviourSettingsPage::PlaylistAddBehaviour::Enqueue:
|
case BehaviourSettingsPage::PlaylistAddBehaviour::Enqueue:
|
||||||
app_->playlist_manager()->current()->queue()->ToggleTracks(QModelIndexList() << source_idx);
|
app_->playlist_manager()->current()->queue()->ToggleTracks(QModelIndexList() << source_idx);
|
||||||
if (app_->player()->GetState() != EngineBase::State::Playing) {
|
if (app_->player()->GetState() != EngineBase::State::Playing) {
|
||||||
app_->playlist_manager()->SetActiveToCurrent();
|
app_->playlist_manager()->SetActiveToCurrent();
|
||||||
app_->player()->PlayAt(app_->playlist_manager()->current()->queue()->TakeNext(), 0, EngineBase::TrackChangeType::Manual, Playlist::AutoScroll::Never, true);
|
app_->player()->PlayAt(app_->playlist_manager()->current()->queue()->TakeNext(), false, 0, EngineBase::TrackChangeType::Manual, Playlist::AutoScroll::Never, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1652,7 +1590,7 @@ void MainWindow::PlaylistDoubleClick(const QModelIndex &idx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::VolumeWheelEvent(const int delta) {
|
void MainWindow::VolumeWheelEvent(const int delta) {
|
||||||
ui_->volume->setValue(ui_->volume->value() + delta / 30);
|
ui_->volume->HandleWheel(delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::ToggleShowHide() {
|
void MainWindow::ToggleShowHide() {
|
||||||
@@ -1686,7 +1624,7 @@ void MainWindow::ToggleHide() {
|
|||||||
|
|
||||||
void MainWindow::StopAfterCurrent() {
|
void MainWindow::StopAfterCurrent() {
|
||||||
app_->playlist_manager()->current()->StopAfter(app_->playlist_manager()->current()->current_row());
|
app_->playlist_manager()->current()->StopAfter(app_->playlist_manager()->current()->current_row());
|
||||||
emit StopAfterToggled(app_->playlist_manager()->active()->stop_after_current());
|
Q_EMIT StopAfterToggled(app_->playlist_manager()->active()->stop_after_current());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::showEvent(QShowEvent *e) {
|
void MainWindow::showEvent(QShowEvent *e) {
|
||||||
@@ -1896,7 +1834,8 @@ void MainWindow::AddToPlaylistFromAction(QAction *action) {
|
|||||||
SongList songs;
|
SongList songs;
|
||||||
|
|
||||||
// Get the selected playlist items
|
// Get the selected playlist items
|
||||||
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
const QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
|
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||||
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
||||||
if (!source_index.isValid()) continue;
|
if (!source_index.isValid()) continue;
|
||||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
||||||
@@ -1963,7 +1902,7 @@ void MainWindow::PlaylistRightClick(const QPoint global_pos, const QModelIndex &
|
|||||||
playlist_stop_after_->setEnabled(source_index.isValid());
|
playlist_stop_after_->setEnabled(source_index.isValid());
|
||||||
|
|
||||||
// Are any of the selected songs editable or queued?
|
// Are any of the selected songs editable or queued?
|
||||||
QModelIndexList selection = ui_->playlist->view()->selectionModel()->selectedRows();
|
const QModelIndexList selection = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
bool cue_selected = false;
|
bool cue_selected = false;
|
||||||
qint64 selected = ui_->playlist->view()->selectionModel()->selectedRows().count();
|
qint64 selected = ui_->playlist->view()->selectionModel()->selectedRows().count();
|
||||||
int editable = 0;
|
int editable = 0;
|
||||||
@@ -2110,7 +2049,7 @@ void MainWindow::PlaylistRightClick(const QPoint global_pos, const QModelIndex &
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Remove old item actions, if any.
|
// Remove old item actions, if any.
|
||||||
for (QAction *action : playlistitem_actions_) {
|
for (QAction *action : std::as_const(playlistitem_actions_)) {
|
||||||
playlist_menu_->removeAction(action);
|
playlist_menu_->removeAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2120,7 +2059,7 @@ void MainWindow::PlaylistRightClick(const QPoint global_pos, const QModelIndex &
|
|||||||
playlist_menu_->insertActions(playlistitem_actions_separator_, playlistitem_actions_);
|
playlist_menu_->insertActions(playlistitem_actions_separator_, playlistitem_actions_);
|
||||||
}
|
}
|
||||||
|
|
||||||
//if it isn't the first time we right click, we need to remove the menu previously created
|
// If it isn't the first time we right click, we need to remove the menu previously created
|
||||||
if (playlist_add_to_another_ != nullptr) {
|
if (playlist_add_to_another_ != nullptr) {
|
||||||
playlist_menu_->removeAction(playlist_add_to_another_);
|
playlist_menu_->removeAction(playlist_add_to_another_);
|
||||||
delete playlist_add_to_another_;
|
delete playlist_add_to_another_;
|
||||||
@@ -2132,18 +2071,19 @@ void MainWindow::PlaylistRightClick(const QPoint global_pos, const QModelIndex &
|
|||||||
QMenu *add_to_another_menu = new QMenu(tr("Add to another playlist"), this);
|
QMenu *add_to_another_menu = new QMenu(tr("Add to another playlist"), this);
|
||||||
add_to_another_menu->setIcon(IconLoader::Load(QStringLiteral("list-add")));
|
add_to_another_menu->setIcon(IconLoader::Load(QStringLiteral("list-add")));
|
||||||
|
|
||||||
for (const PlaylistBackend::Playlist &playlist : app_->playlist_backend()->GetAllOpenPlaylists()) {
|
const QList<int> playlist_ids = app_->playlist_manager()->playlist_ids();
|
||||||
// don't add the current playlist
|
for (const int playlist_id : playlist_ids) {
|
||||||
if (playlist.id != app_->playlist_manager()->current()->id()) {
|
// Don't add the current playlist
|
||||||
|
if (playlist_id != app_->playlist_manager()->current()->id()) {
|
||||||
QAction *existing_playlist = new QAction(this);
|
QAction *existing_playlist = new QAction(this);
|
||||||
existing_playlist->setText(playlist.name);
|
existing_playlist->setText(app_->playlist_manager()->playlist_name(playlist_id));
|
||||||
existing_playlist->setData(playlist.id);
|
existing_playlist->setData(playlist_id);
|
||||||
add_to_another_menu->addAction(existing_playlist);
|
add_to_another_menu->addAction(existing_playlist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add_to_another_menu->addSeparator();
|
add_to_another_menu->addSeparator();
|
||||||
// add to a new playlist
|
// Add to a new playlist
|
||||||
QAction *new_playlist = new QAction(this);
|
QAction *new_playlist = new QAction(this);
|
||||||
new_playlist->setText(tr("New playlist"));
|
new_playlist->setText(tr("New playlist"));
|
||||||
new_playlist->setData(-1); // fake id
|
new_playlist->setData(-1); // fake id
|
||||||
@@ -2177,7 +2117,8 @@ void MainWindow::RescanSongs() {
|
|||||||
|
|
||||||
SongList songs;
|
SongList songs;
|
||||||
|
|
||||||
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
const QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
|
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||||
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
||||||
if (!source_index.isValid()) continue;
|
if (!source_index.isValid()) continue;
|
||||||
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
|
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
|
||||||
@@ -2202,7 +2143,8 @@ void MainWindow::EditTracks() {
|
|||||||
SongList songs;
|
SongList songs;
|
||||||
PlaylistItemPtrList items;
|
PlaylistItemPtrList items;
|
||||||
|
|
||||||
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
const QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
|
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||||
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
||||||
if (!source_index.isValid()) continue;
|
if (!source_index.isValid()) continue;
|
||||||
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
|
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
|
||||||
@@ -2224,7 +2166,8 @@ void MainWindow::EditTracks() {
|
|||||||
|
|
||||||
void MainWindow::EditTagDialogAccepted() {
|
void MainWindow::EditTagDialogAccepted() {
|
||||||
|
|
||||||
for (PlaylistItemPtr item : edit_tag_dialog_->playlist_items()) {
|
const PlaylistItemPtrList items = edit_tag_dialog_->playlist_items();
|
||||||
|
for (PlaylistItemPtr item : items) {
|
||||||
item->Reload();
|
item->Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2243,13 +2186,13 @@ void MainWindow::RenumberTracks() {
|
|||||||
// Get the index list in order
|
// Get the index list in order
|
||||||
std::stable_sort(indexes.begin(), indexes.end());
|
std::stable_sort(indexes.begin(), indexes.end());
|
||||||
|
|
||||||
// if first selected song has a track number set, start from that offset
|
// If first selected song has a track number set, start from that offset
|
||||||
if (!indexes.isEmpty()) {
|
if (!indexes.isEmpty()) {
|
||||||
const Song first_song = app_->playlist_manager()->current()->item_at(indexes[0].row())->OriginalMetadata();
|
const Song first_song = app_->playlist_manager()->current()->item_at(indexes[0].row())->OriginalMetadata();
|
||||||
if (first_song.track() > 0) track = first_song.track();
|
if (first_song.track() > 0) track = first_song.track();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QModelIndex &proxy_index : indexes) {
|
for (const QModelIndex &proxy_index : std::as_const(indexes)) {
|
||||||
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
||||||
if (!source_index.isValid()) continue;
|
if (!source_index.isValid()) continue;
|
||||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
||||||
@@ -2280,7 +2223,8 @@ void MainWindow::SelectionSetValue() {
|
|||||||
Playlist::Column column = static_cast<Playlist::Column>(playlist_menu_index_.column());
|
Playlist::Column column = static_cast<Playlist::Column>(playlist_menu_index_.column());
|
||||||
QVariant column_value = app_->playlist_manager()->current()->data(playlist_menu_index_);
|
QVariant column_value = app_->playlist_manager()->current()->data(playlist_menu_index_);
|
||||||
|
|
||||||
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
const QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
|
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||||
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
||||||
if (!source_index.isValid()) continue;
|
if (!source_index.isValid()) continue;
|
||||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
||||||
@@ -2327,7 +2271,7 @@ void MainWindow::AddFile() {
|
|||||||
PlaylistParser parser(app_->collection_backend());
|
PlaylistParser parser(app_->collection_backend());
|
||||||
|
|
||||||
// Show dialog
|
// Show dialog
|
||||||
QStringList filenames = QFileDialog::getOpenFileNames(this, tr("Add file"), directory, QStringLiteral("%1 (%2);;%3;;%4").arg(tr("Music"), QLatin1String(FileView::kFileFilter), parser.filters(PlaylistParser::Type::Load), tr(kAllFilesFilterSpec)));
|
const QStringList filenames = QFileDialog::getOpenFileNames(this, tr("Add file"), directory, QStringLiteral("%1 (%2);;%3;;%4").arg(tr("Music"), QLatin1String(FileView::kFileFilter), parser.filters(PlaylistParser::Type::Load), tr(kAllFilesFilterSpec)));
|
||||||
|
|
||||||
if (filenames.isEmpty()) return;
|
if (filenames.isEmpty()) return;
|
||||||
|
|
||||||
@@ -2394,7 +2338,8 @@ void MainWindow::ShowInCollection() {
|
|||||||
// Show the first valid selected track artist/album in CollectionView
|
// Show the first valid selected track artist/album in CollectionView
|
||||||
|
|
||||||
SongList songs;
|
SongList songs;
|
||||||
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
const QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
|
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||||
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
||||||
if (!source_index.isValid()) continue;
|
if (!source_index.isValid()) continue;
|
||||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
||||||
@@ -2538,9 +2483,10 @@ void MainWindow::CommandlineOptionsReceived(const CommandlineOptions &options) {
|
|||||||
if (!options.urls().empty()) {
|
if (!options.urls().empty()) {
|
||||||
|
|
||||||
#ifdef HAVE_TIDAL
|
#ifdef HAVE_TIDAL
|
||||||
for (const QUrl &url : options.urls()) {
|
const QList<QUrl> urls = options.urls();
|
||||||
|
for (const QUrl &url : urls) {
|
||||||
if (url.scheme() == QLatin1String("tidal") && url.host() == QLatin1String("login")) {
|
if (url.scheme() == QLatin1String("tidal") && url.host() == QLatin1String("login")) {
|
||||||
emit AuthorizationUrlReceived(url);
|
Q_EMIT AuthorizationUrlReceived(url);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2585,7 +2531,7 @@ void MainWindow::CommandlineOptionsReceived(const CommandlineOptions &options) {
|
|||||||
app_->player()->SeekTo(app_->player()->engine()->position_nanosec() / kNsecPerSec + options.seek_by());
|
app_->player()->SeekTo(app_->player()->engine()->position_nanosec() / kNsecPerSec + options.seek_by());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.play_track_at() != -1) app_->player()->PlayAt(options.play_track_at(), 0, EngineBase::TrackChangeType::Manual, Playlist::AutoScroll::Maybe, true);
|
if (options.play_track_at() != -1) app_->player()->PlayAt(options.play_track_at(), false, 0, EngineBase::TrackChangeType::Manual, Playlist::AutoScroll::Maybe, true);
|
||||||
|
|
||||||
if (options.show_osd()) app_->player()->ShowOSD();
|
if (options.show_osd()) app_->player()->ShowOSD();
|
||||||
|
|
||||||
@@ -2618,7 +2564,7 @@ bool MainWindow::LoadUrl(const QString &url) {
|
|||||||
}
|
}
|
||||||
#ifdef HAVE_TIDAL
|
#ifdef HAVE_TIDAL
|
||||||
if (url.startsWith(QLatin1String("tidal://login"))) {
|
if (url.startsWith(QLatin1String("tidal://login"))) {
|
||||||
emit AuthorizationUrlReceived(QUrl(url));
|
Q_EMIT AuthorizationUrlReceived(QUrl(url));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -2641,7 +2587,8 @@ void MainWindow::AddFilesToTranscoder() {
|
|||||||
|
|
||||||
QStringList filenames;
|
QStringList filenames;
|
||||||
|
|
||||||
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
const QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
|
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||||
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
||||||
if (!source_index.isValid()) continue;
|
if (!source_index.isValid()) continue;
|
||||||
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
|
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
|
||||||
@@ -2753,7 +2700,8 @@ void MainWindow::PlaylistMoveToCollection() {
|
|||||||
void MainWindow::PlaylistOrganizeSelected(const bool copy) {
|
void MainWindow::PlaylistOrganizeSelected(const bool copy) {
|
||||||
|
|
||||||
SongList songs;
|
SongList songs;
|
||||||
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
const QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
|
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||||
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
||||||
if (!source_index.isValid()) continue;
|
if (!source_index.isValid()) continue;
|
||||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
||||||
@@ -2775,7 +2723,8 @@ void MainWindow::PlaylistOrganizeSelected(const bool copy) {
|
|||||||
void MainWindow::PlaylistOpenInBrowser() {
|
void MainWindow::PlaylistOpenInBrowser() {
|
||||||
|
|
||||||
QList<QUrl> urls;
|
QList<QUrl> urls;
|
||||||
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
const QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
|
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||||
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
||||||
if (!source_index.isValid()) continue;
|
if (!source_index.isValid()) continue;
|
||||||
urls << QUrl(source_index.sibling(source_index.row(), static_cast<int>(Playlist::Column::Filename)).data().toString());
|
urls << QUrl(source_index.sibling(source_index.row(), static_cast<int>(Playlist::Column::Filename)).data().toString());
|
||||||
@@ -2788,7 +2737,8 @@ void MainWindow::PlaylistOpenInBrowser() {
|
|||||||
void MainWindow::PlaylistCopyUrl() {
|
void MainWindow::PlaylistCopyUrl() {
|
||||||
|
|
||||||
QList<QUrl> urls;
|
QList<QUrl> urls;
|
||||||
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
const QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
|
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||||
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
||||||
if (!source_index.isValid()) continue;
|
if (!source_index.isValid()) continue;
|
||||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
||||||
@@ -2819,7 +2769,7 @@ void MainWindow::PlaylistQueue() {
|
|||||||
|
|
||||||
void MainWindow::PlaylistQueuePlayNext() {
|
void MainWindow::PlaylistQueuePlayNext() {
|
||||||
|
|
||||||
QModelIndexList selected_rows = ui_->playlist->view()->selectionModel()->selectedRows();
|
const QModelIndexList selected_rows = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
QModelIndexList indexes;
|
QModelIndexList indexes;
|
||||||
indexes.reserve(selected_rows.count());
|
indexes.reserve(selected_rows.count());
|
||||||
for (const QModelIndex &proxy_index : selected_rows) {
|
for (const QModelIndex &proxy_index : selected_rows) {
|
||||||
@@ -2849,7 +2799,8 @@ void MainWindow::PlaylistCopyToDevice() {
|
|||||||
|
|
||||||
SongList songs;
|
SongList songs;
|
||||||
|
|
||||||
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
const QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
|
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||||
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
||||||
if (!source_index.isValid()) continue;
|
if (!source_index.isValid()) continue;
|
||||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
|
||||||
@@ -2964,7 +2915,7 @@ void MainWindow::CheckFullRescanRevisions() {
|
|||||||
int from = app_->database()->startup_schema_version();
|
int from = app_->database()->startup_schema_version();
|
||||||
int to = app_->database()->current_schema_version();
|
int to = app_->database()->current_schema_version();
|
||||||
|
|
||||||
// if we're restoring DB from scratch or nothing has changed, do nothing
|
// If we're restoring DB from scratch or nothing has changed, do nothing
|
||||||
if (from == 0 || from == to) {
|
if (from == 0 || from == to) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2978,7 +2929,7 @@ void MainWindow::CheckFullRescanRevisions() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have any...
|
// If we have any...
|
||||||
if (!reasons.isEmpty()) {
|
if (!reasons.isEmpty()) {
|
||||||
QString message = tr("The version of Strawberry you've just updated to requires a full collection rescan because of the new features listed below:") + QStringLiteral("<ul>");
|
QString message = tr("The version of Strawberry you've just updated to requires a full collection rescan because of the new features listed below:") + QStringLiteral("<ul>");
|
||||||
for (const QString &reason : reasons) {
|
for (const QString &reason : reasons) {
|
||||||
@@ -3050,7 +3001,8 @@ void MainWindow::AutoCompleteTags() {
|
|||||||
|
|
||||||
// Get the selected songs and start fetching tags for them
|
// Get the selected songs and start fetching tags for them
|
||||||
SongList songs;
|
SongList songs;
|
||||||
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
const QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
|
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||||
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
|
||||||
if (!source_index.isValid()) continue;
|
if (!source_index.isValid()) continue;
|
||||||
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
|
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
|
||||||
@@ -3075,7 +3027,7 @@ void MainWindow::AutoCompleteTags() {
|
|||||||
|
|
||||||
void MainWindow::AutoCompleteTagsAccepted() {
|
void MainWindow::AutoCompleteTagsAccepted() {
|
||||||
|
|
||||||
for (PlaylistItemPtr item : autocomplete_tag_items_) {
|
for (PlaylistItemPtr item : std::as_const(autocomplete_tag_items_)) {
|
||||||
item->Reload();
|
item->Reload();
|
||||||
}
|
}
|
||||||
autocomplete_tag_items_.clear();
|
autocomplete_tag_items_.clear();
|
||||||
@@ -3180,7 +3132,7 @@ void MainWindow::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult
|
|||||||
song_ = song;
|
song_ = song;
|
||||||
album_cover_ = result.album_cover;
|
album_cover_ = result.album_cover;
|
||||||
|
|
||||||
emit AlbumCoverReady(song, result.album_cover.image);
|
Q_EMIT AlbumCoverReady(song, result.album_cover.image);
|
||||||
|
|
||||||
const bool enable_change_art = song.is_collection_song() && !song.effective_albumartist().isEmpty() && !song.album().isEmpty();
|
const bool enable_change_art = song.is_collection_song() && !song.effective_albumartist().isEmpty() && !song.album().isEmpty();
|
||||||
album_cover_choice_controller_->show_cover_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::Unset);
|
album_cover_choice_controller_->show_cover_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::Unset);
|
||||||
@@ -3208,7 +3160,7 @@ void MainWindow::GetCoverAutomatically() {
|
|||||||
!song_.effective_album().isEmpty();
|
!song_.effective_album().isEmpty();
|
||||||
|
|
||||||
if (search) {
|
if (search) {
|
||||||
emit SearchCoverInProgress();
|
Q_EMIT SearchCoverInProgress();
|
||||||
album_cover_choice_controller_->SearchCoverAutomatically(song_);
|
album_cover_choice_controller_->SearchCoverAutomatically(song_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3267,7 +3219,8 @@ void MainWindow::PlaylistDelete() {
|
|||||||
SongList selected_songs;
|
SongList selected_songs;
|
||||||
QStringList files;
|
QStringList files;
|
||||||
bool is_current_item = false;
|
bool is_current_item = false;
|
||||||
for (const QModelIndex &proxy_idx : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
const QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
|
for (const QModelIndex &proxy_idx : proxy_indexes) {
|
||||||
QModelIndex source_idx = app_->playlist_manager()->current()->filter()->mapToSource(proxy_idx);
|
QModelIndex source_idx = app_->playlist_manager()->current()->filter()->mapToSource(proxy_idx);
|
||||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_idx.row());
|
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_idx.row());
|
||||||
if (!item || !item->Metadata().url().isLocalFile()) continue;
|
if (!item || !item->Metadata().url().isLocalFile()) continue;
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
|||||||
void Activate() override;
|
void Activate() override;
|
||||||
bool LoadUrl(const QString &url) override;
|
bool LoadUrl(const QString &url) override;
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void AlbumCoverReady(const Song &song, const QImage &image);
|
void AlbumCoverReady(const Song &song, const QImage &image);
|
||||||
void SearchCoverInProgress();
|
void SearchCoverInProgress();
|
||||||
// Signals that stop playing after track was toggled.
|
// Signals that stop playing after track was toggled.
|
||||||
@@ -139,7 +139,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
|||||||
|
|
||||||
void AuthorizationUrlReceived(const QUrl &url);
|
void AuthorizationUrlReceived(const QUrl &url);
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void FilePathChanged(const QString &path);
|
void FilePathChanged(const QString &path);
|
||||||
|
|
||||||
void EngineChanged(const EngineBase::Type enginetype);
|
void EngineChanged(const EngineBase::Type enginetype);
|
||||||
@@ -238,9 +238,6 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
|||||||
void ToggleSidebar(const bool checked);
|
void ToggleSidebar(const bool checked);
|
||||||
void ToggleSearchCoverAuto(const bool checked);
|
void ToggleSearchCoverAuto(const bool checked);
|
||||||
void SaveGeometry();
|
void SaveGeometry();
|
||||||
void SavePlaybackStatus();
|
|
||||||
void LoadPlaybackStatus();
|
|
||||||
void ResumePlayback();
|
|
||||||
|
|
||||||
void Exit();
|
void Exit();
|
||||||
void DoExit();
|
void DoExit();
|
||||||
@@ -274,7 +271,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
|||||||
|
|
||||||
void DeleteFilesFinished(const SongList &songs_with_errors);
|
void DeleteFilesFinished(const SongList &songs_with_errors);
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void CommandlineOptionsReceived(const QByteArray &string_options);
|
void CommandlineOptionsReceived(const QByteArray &string_options);
|
||||||
void Raise();
|
void Raise();
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QSplitter" name="splitter">
|
<widget class="QSplitter" name="splitter">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="sidebar_layout">
|
<widget class="QWidget" name="sidebar_layout">
|
||||||
<layout class="QVBoxLayout" name="layout_left">
|
<layout class="QVBoxLayout" name="layout_left">
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line_6">
|
<widget class="Line" name="line_6">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -102,7 +102,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QFrame" name="player_controls">
|
<widget class="QFrame" name="player_controls">
|
||||||
<property name="frameShape">
|
<property name="frameShape">
|
||||||
<enum>QFrame::NoFrame</enum>
|
<enum>QFrame::Shape::NoFrame</enum>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="layout_player_controls">
|
<layout class="QHBoxLayout" name="layout_player_controls">
|
||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
@@ -167,7 +167,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="popupMode">
|
<property name="popupMode">
|
||||||
<enum>QToolButton::MenuButtonPopup</enum>
|
<enum>QToolButton::ToolButtonPopupMode::MenuButtonPopup</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="autoRaise">
|
<property name="autoRaise">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@@ -211,7 +211,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line_love">
|
<widget class="Line" name="line_love">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -237,7 +237,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line_buttons">
|
<widget class="Line" name="line_buttons">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -260,10 +260,10 @@
|
|||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeType">
|
<property name="sizeType">
|
||||||
<enum>QSizePolicy::Expanding</enum>
|
<enum>QSizePolicy::Policy::Expanding</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
@@ -276,7 +276,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line_volume">
|
<widget class="Line" name="line_volume">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -292,7 +292,7 @@
|
|||||||
<number>100</number>
|
<number>100</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -326,7 +326,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="status_bar_line">
|
<widget class="Line" name="status_bar_line">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -380,7 +380,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="playlist_summary">
|
<widget class="QLabel" name="playlist_summary">
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -391,7 +391,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line_5">
|
<widget class="Line" name="line_5">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -401,7 +401,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line_2">
|
<widget class="Line" name="line_2">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -524,7 +524,7 @@
|
|||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="action_update_collection"/>
|
<addaction name="action_update_collection"/>
|
||||||
<addaction name="action_full_collection_scan"/>
|
<addaction name="action_full_collection_scan"/>
|
||||||
<addaction name="action_abort_collection_scan"/>
|
<addaction name="action_stop_collection_scan"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="action_settings"/>
|
<addaction name="action_settings"/>
|
||||||
<addaction name="action_import_data_from_last_fm"/>
|
<addaction name="action_import_data_from_last_fm"/>
|
||||||
@@ -580,7 +580,7 @@
|
|||||||
<string>Ctrl+Q</string>
|
<string>Ctrl+Q</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="menuRole">
|
<property name="menuRole">
|
||||||
<enum>QAction::QuitRole</enum>
|
<enum>QAction::MenuRole::QuitRole</enum>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_stop_after_this_track">
|
<action name="action_stop_after_this_track">
|
||||||
@@ -644,7 +644,7 @@
|
|||||||
<string>Ctrl+P</string>
|
<string>Ctrl+P</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="menuRole">
|
<property name="menuRole">
|
||||||
<enum>QAction::PreferencesRole</enum>
|
<enum>QAction::MenuRole::PreferencesRole</enum>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_about_strawberry">
|
<action name="action_about_strawberry">
|
||||||
@@ -659,7 +659,7 @@
|
|||||||
<string>F1</string>
|
<string>F1</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="menuRole">
|
<property name="menuRole">
|
||||||
<enum>QAction::AboutRole</enum>
|
<enum>QAction::MenuRole::AboutRole</enum>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_shuffle">
|
<action name="action_shuffle">
|
||||||
@@ -785,7 +785,7 @@
|
|||||||
<string>About &Qt</string>
|
<string>About &Qt</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="menuRole">
|
<property name="menuRole">
|
||||||
<enum>QAction::AboutQtRole</enum>
|
<enum>QAction::MenuRole::AboutQtRole</enum>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_mute">
|
<action name="action_mute">
|
||||||
@@ -804,9 +804,12 @@
|
|||||||
<string>&Do a full collection rescan</string>
|
<string>&Do a full collection rescan</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_abort_collection_scan">
|
<action name="action_stop_collection_scan">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Abort collection scan</string>
|
<string>Stop collection scan</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Stop collection scan</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_auto_complete_tags">
|
<action name="action_auto_complete_tags">
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ void MergedProxyModel::SubModelResetSlot() {
|
|||||||
endInsertRows();
|
endInsertRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit SubModelReset(proxy_parent, submodel);
|
Q_EMIT SubModelReset(proxy_parent, submodel);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,7 +516,7 @@ QAbstractItemModel *MergedProxyModel::GetModel(const QModelIndex &source_index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MergedProxyModel::DataChanged(const QModelIndex &top_left, const QModelIndex &bottom_right) {
|
void MergedProxyModel::DataChanged(const QModelIndex &top_left, const QModelIndex &bottom_right) {
|
||||||
emit dataChanged(mapFromSource(top_left), mapFromSource(bottom_right));
|
Q_EMIT dataChanged(mapFromSource(top_left), mapFromSource(bottom_right));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MergedProxyModel::LayoutAboutToBeChanged() {
|
void MergedProxyModel::LayoutAboutToBeChanged() {
|
||||||
@@ -535,8 +535,8 @@ void MergedProxyModel::LayoutChanged() {
|
|||||||
for (QAbstractItemModel *model : models) {
|
for (QAbstractItemModel *model : models) {
|
||||||
if (!old_merge_points_.contains(model)) continue;
|
if (!old_merge_points_.contains(model)) continue;
|
||||||
|
|
||||||
const int old_row = old_merge_points_[model].row();
|
const int old_row = old_merge_points_.value(model).row();
|
||||||
const int new_row = merge_points_[model].row();
|
const int new_row = merge_points_.value(model).row();
|
||||||
|
|
||||||
if (old_row != new_row) {
|
if (old_row != new_row) {
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
|||||||
@@ -85,10 +85,10 @@ class MergedProxyModel : public QAbstractProxyModel {
|
|||||||
QModelIndexList mapFromSource(const QModelIndexList &source_indexes) const;
|
QModelIndexList mapFromSource(const QModelIndexList &source_indexes) const;
|
||||||
QModelIndexList mapToSource(const QModelIndexList &proxy_indexes) const;
|
QModelIndexList mapToSource(const QModelIndexList &proxy_indexes) const;
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void SubModelReset(const QModelIndex root, QAbstractItemModel *model);
|
void SubModelReset(const QModelIndex root, QAbstractItemModel *model);
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void SourceModelReset();
|
void SourceModelReset();
|
||||||
void SubModelAboutToBeReset();
|
void SubModelAboutToBeReset();
|
||||||
void SubModelResetSlot();
|
void SubModelResetSlot();
|
||||||
|
|||||||
@@ -81,6 +81,8 @@
|
|||||||
#include "smartplaylists/smartplaylistsearchterm.h"
|
#include "smartplaylists/smartplaylistsearchterm.h"
|
||||||
#include "smartplaylists/smartplaylistsitem.h"
|
#include "smartplaylists/smartplaylistsitem.h"
|
||||||
|
|
||||||
|
#include "lyrics/lyricssearchresult.h"
|
||||||
|
|
||||||
void RegisterMetaTypes() {
|
void RegisterMetaTypes() {
|
||||||
|
|
||||||
qRegisterMetaType<const char*>("const char*");
|
qRegisterMetaType<const char*>("const char*");
|
||||||
@@ -167,4 +169,6 @@ void RegisterMetaTypes() {
|
|||||||
qRegisterMetaType<SmartPlaylistSearchTerm::DateType>("SmartPlaylistSearchTerm::DateType");
|
qRegisterMetaType<SmartPlaylistSearchTerm::DateType>("SmartPlaylistSearchTerm::DateType");
|
||||||
qRegisterMetaType<SmartPlaylistsItem::Type>("SmartPlaylistsItem::Type");
|
qRegisterMetaType<SmartPlaylistsItem::Type>("SmartPlaylistsItem::Type");
|
||||||
|
|
||||||
|
qRegisterMetaType<LyricsSearchResults>("LyricsSearchResults");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
44
src/core/mimedata.cpp
Normal file
44
src/core/mimedata.cpp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Strawberry Music Player
|
||||||
|
* This file was part of Clementine.
|
||||||
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2018-2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
|
*
|
||||||
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "mimedata.h"
|
||||||
|
|
||||||
|
MimeData::MimeData(const bool clear, const bool play_now, const bool enqueue, const bool enqueue_next_now, const bool open_in_new_playlist, QObject *parent)
|
||||||
|
: override_user_settings_(false),
|
||||||
|
clear_first_(clear),
|
||||||
|
play_now_(play_now),
|
||||||
|
enqueue_now_(enqueue),
|
||||||
|
enqueue_next_now_(enqueue_next_now),
|
||||||
|
open_in_new_playlist_(open_in_new_playlist),
|
||||||
|
name_for_new_playlist_(QString()),
|
||||||
|
from_doubleclick_(false) {
|
||||||
|
|
||||||
|
Q_UNUSED(parent);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MimeData::get_name_for_new_playlist() const {
|
||||||
|
return name_for_new_playlist_.isEmpty() ? tr("Playlist") : name_for_new_playlist_;
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2018-2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,9 +22,6 @@
|
|||||||
#ifndef MIMEDATA_H
|
#ifndef MIMEDATA_H
|
||||||
#define MIMEDATA_H
|
#define MIMEDATA_H
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
@@ -31,15 +29,7 @@ class MimeData : public QMimeData {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit MimeData(const bool clear = false, const bool play_now = false, const bool enqueue = false, const bool enqueue_next_now = false, const bool open_in_new_playlist = false, QObject* = nullptr)
|
explicit MimeData(const bool clear = false, const bool play_now = false, const bool enqueue = false, const bool enqueue_next_now = false, const bool open_in_new_playlist = false, QObject *parent = nullptr);
|
||||||
: override_user_settings_(false),
|
|
||||||
clear_first_(clear),
|
|
||||||
play_now_(play_now),
|
|
||||||
enqueue_now_(enqueue),
|
|
||||||
enqueue_next_now_(enqueue_next_now),
|
|
||||||
open_in_new_playlist_(open_in_new_playlist),
|
|
||||||
name_for_new_playlist_(QString()),
|
|
||||||
from_doubleclick_(false) {}
|
|
||||||
|
|
||||||
// If this is set then MainWindow will not touch any of the other flags.
|
// If this is set then MainWindow will not touch any of the other flags.
|
||||||
bool override_user_settings_;
|
bool override_user_settings_;
|
||||||
@@ -69,9 +59,7 @@ class MimeData : public QMimeData {
|
|||||||
|
|
||||||
// Returns a pretty name for a playlist containing songs described by this MimeData object.
|
// Returns a pretty name for a playlist containing songs described by this MimeData object.
|
||||||
// By pretty name we mean the value of 'name_for_new_playlist_' or generic "Playlist" string if the 'name_for_new_playlist_' attribute is empty.
|
// By pretty name we mean the value of 'name_for_new_playlist_' or generic "Playlist" string if the 'name_for_new_playlist_' attribute is empty.
|
||||||
QString get_name_for_new_playlist() {
|
QString get_name_for_new_playlist() const;
|
||||||
return name_for_new_playlist_.isEmpty() ? tr("Playlist") : name_for_new_playlist_;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MIMEDATA_H
|
#endif // MIMEDATA_H
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <utility>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@@ -141,7 +142,7 @@ Mpris2::Mpris2(Application *app, QObject *parent)
|
|||||||
data_dirs.append(QStringLiteral("/usr/share"));
|
data_dirs.append(QStringLiteral("/usr/share"));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QString &data_dir : data_dirs) {
|
for (const QString &data_dir : std::as_const(data_dirs)) {
|
||||||
const QString desktopfilepath = QStringLiteral("%1/applications/%2.desktop").arg(data_dir, QGuiApplication::desktopFileName());
|
const QString desktopfilepath = QStringLiteral("%1/applications/%2.desktop").arg(data_dir, QGuiApplication::desktopFileName());
|
||||||
if (QFile::exists(desktopfilepath)) {
|
if (QFile::exists(desktopfilepath)) {
|
||||||
desktopfilepath_ = desktopfilepath;
|
desktopfilepath_ = desktopfilepath;
|
||||||
@@ -240,7 +241,7 @@ QString Mpris2::DesktopEntryAbsolutePath() const {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Mpris2::DesktopEntry() const { return QGuiApplication::desktopFileName() + QLatin1String(".desktop"); }
|
QString Mpris2::DesktopEntry() const { return QGuiApplication::desktopFileName(); }
|
||||||
|
|
||||||
QStringList Mpris2::SupportedUriSchemes() const {
|
QStringList Mpris2::SupportedUriSchemes() const {
|
||||||
|
|
||||||
@@ -288,7 +289,7 @@ QStringList Mpris2::SupportedMimeTypes() const {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mpris2::Raise() { emit RaiseMainWindow(); }
|
void Mpris2::Raise() { Q_EMIT RaiseMainWindow(); }
|
||||||
|
|
||||||
void Mpris2::Quit() { QCoreApplication::quit(); }
|
void Mpris2::Quit() { QCoreApplication::quit(); }
|
||||||
|
|
||||||
@@ -618,7 +619,7 @@ MprisPlaylistList Mpris2::GetPlaylists(quint32 index, quint32 max_count, const Q
|
|||||||
|
|
||||||
Q_UNUSED(order);
|
Q_UNUSED(order);
|
||||||
|
|
||||||
QList<Playlist*> playlists = app_->playlist_manager()->GetAllPlaylists();
|
const QList<Playlist*> playlists = app_->playlist_manager()->GetAllPlaylists();
|
||||||
MprisPlaylistList ret;
|
MprisPlaylistList ret;
|
||||||
ret.reserve(playlists.count());
|
ret.reserve(playlists.count());
|
||||||
for (Playlist *p : playlists) {
|
for (Playlist *p : playlists) {
|
||||||
@@ -642,7 +643,7 @@ void Mpris2::PlaylistChangedSlot(Playlist *playlist) {
|
|||||||
mpris_playlist.id = MakePlaylistPath(playlist->id());
|
mpris_playlist.id = MakePlaylistPath(playlist->id());
|
||||||
mpris_playlist.name = app_->playlist_manager()->GetPlaylistName(playlist->id());
|
mpris_playlist.name = app_->playlist_manager()->GetPlaylistName(playlist->id());
|
||||||
|
|
||||||
emit PlaylistChanged(mpris_playlist);
|
Q_EMIT PlaylistChanged(mpris_playlist);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,9 +33,8 @@
|
|||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QtDBus>
|
#include <QDBusObjectPath>
|
||||||
#include <QDBusArgument>
|
#include <QDBusArgument>
|
||||||
#include <qdbusextratypes.h>
|
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
|
||||||
#include "engine/enginebase.h"
|
#include "engine/enginebase.h"
|
||||||
@@ -191,7 +190,7 @@ class Mpris2 : public QObject {
|
|||||||
void ActivatePlaylist(const QDBusObjectPath &playlist_id);
|
void ActivatePlaylist(const QDBusObjectPath &playlist_id);
|
||||||
MprisPlaylistList GetPlaylists(quint32 index, quint32 max_count, const QString &order, bool reverse_order);
|
MprisPlaylistList GetPlaylists(quint32 index, quint32 max_count, const QString &order, bool reverse_order);
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
// Player
|
// Player
|
||||||
void Seeked(const qint64 position);
|
void Seeked(const qint64 position);
|
||||||
|
|
||||||
@@ -206,7 +205,7 @@ class Mpris2 : public QObject {
|
|||||||
// Playlist
|
// Playlist
|
||||||
void PlaylistChanged(const MprisPlaylist &playlist);
|
void PlaylistChanged(const MprisPlaylist &playlist);
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result = AlbumCoverLoaderResult());
|
void AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result = AlbumCoverLoaderResult());
|
||||||
void EngineStateChanged(EngineBase::State newState);
|
void EngineStateChanged(EngineBase::State newState);
|
||||||
void VolumeChanged();
|
void VolumeChanged();
|
||||||
|
|||||||
65
src/core/mutex_protected.h
Normal file
65
src/core/mutex_protected.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Strawberry Music Player
|
||||||
|
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
|
*
|
||||||
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MUTEX_PROTECTED_H
|
||||||
|
#define MUTEX_PROTECTED_H
|
||||||
|
|
||||||
|
#include <boost/noncopyable.hpp>
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QMutexLocker>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class mutex_protected : public boost::noncopyable {
|
||||||
|
public:
|
||||||
|
mutex_protected(const mutex_protected &value) : value_(value.value()) {}
|
||||||
|
mutex_protected(const T value) : value_(value) {}
|
||||||
|
~mutex_protected() {}
|
||||||
|
|
||||||
|
T value() const {
|
||||||
|
QMutexLocker l(&mutex_);
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
T operator==(const mutex_protected &value) const {
|
||||||
|
QMutexLocker l(&mutex_);
|
||||||
|
return value == value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
T operator==(const T value) const {
|
||||||
|
QMutexLocker l(&mutex_);
|
||||||
|
return value == value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(const mutex_protected &value) {
|
||||||
|
QMutexLocker l(&mutex_);
|
||||||
|
value_ = value.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(const T value) {
|
||||||
|
QMutexLocker l(&mutex_);
|
||||||
|
value_ = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T value_;
|
||||||
|
mutable QMutex mutex_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MUTEX_PROTECTED_H
|
||||||
@@ -42,7 +42,7 @@ class NetworkTimeouts : public QObject {
|
|||||||
protected:
|
protected:
|
||||||
void timerEvent(QTimerEvent *e) override;
|
void timerEvent(QTimerEvent *e) override;
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void ReplyFinished();
|
void ReplyFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ Player::Player(Application *app, QObject *parent)
|
|||||||
analyzer_(nullptr),
|
analyzer_(nullptr),
|
||||||
equalizer_(nullptr),
|
equalizer_(nullptr),
|
||||||
timer_save_volume_(new QTimer(this)),
|
timer_save_volume_(new QTimer(this)),
|
||||||
|
playlists_loaded_(false),
|
||||||
|
play_requested_(false),
|
||||||
stream_change_type_(EngineBase::TrackChangeType::First),
|
stream_change_type_(EngineBase::TrackChangeType::First),
|
||||||
autoscroll_(Playlist::AutoScroll::Maybe),
|
autoscroll_(Playlist::AutoScroll::Maybe),
|
||||||
last_state_(EngineBase::State::Empty),
|
last_state_(EngineBase::State::Empty),
|
||||||
@@ -99,6 +101,8 @@ Player::Player(Application *app, QObject *parent)
|
|||||||
volume_increment_(5),
|
volume_increment_(5),
|
||||||
play_offset_nanosec_(0) {
|
play_offset_nanosec_(0) {
|
||||||
|
|
||||||
|
setObjectName(QLatin1String(metaObject()->className()));
|
||||||
|
|
||||||
Settings s;
|
Settings s;
|
||||||
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
||||||
EngineBase::Type enginetype = EngineBase::TypeFromName(s.value("engine", EngineBase::Name(EngineBase::Type::GStreamer)).toString().toLower());
|
EngineBase::Type enginetype = EngineBase::TypeFromName(s.value("engine", EngineBase::Name(EngineBase::Type::GStreamer)).toString().toLower());
|
||||||
@@ -156,7 +160,7 @@ EngineBase::Type Player::CreateEngine(EngineBase::Type enginetype) {
|
|||||||
qFatal("Failed to create engine!");
|
qFatal("Failed to create engine!");
|
||||||
}
|
}
|
||||||
|
|
||||||
emit EngineChanged(use_enginetype);
|
Q_EMIT EngineChanged(use_enginetype);
|
||||||
|
|
||||||
return use_enginetype;
|
return use_enginetype;
|
||||||
|
|
||||||
@@ -245,6 +249,80 @@ void Player::SaveVolume() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::SavePlaybackStatus() {
|
||||||
|
|
||||||
|
Settings s;
|
||||||
|
|
||||||
|
s.beginGroup(kSettingsGroup);
|
||||||
|
s.setValue("playback_state", static_cast<int>(app_->player()->GetState()));
|
||||||
|
if (app_->player()->GetState() == EngineBase::State::Playing || app_->player()->GetState() == EngineBase::State::Paused) {
|
||||||
|
s.setValue("playback_playlist", app_->playlist_manager()->active()->id());
|
||||||
|
s.setValue("playback_position", app_->player()->engine()->position_nanosec() / kNsecPerSec);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s.setValue("playback_playlist", -1);
|
||||||
|
s.setValue("playback_position", 0);
|
||||||
|
}
|
||||||
|
s.endGroup();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::PlaylistsLoaded() {
|
||||||
|
|
||||||
|
playlists_loaded_ = true;
|
||||||
|
|
||||||
|
Settings s;
|
||||||
|
|
||||||
|
s.beginGroup(BehaviourSettingsPage::kSettingsGroup);
|
||||||
|
const bool resume_playback = s.value("resumeplayback", false).toBool();
|
||||||
|
s.endGroup();
|
||||||
|
|
||||||
|
s.beginGroup(Player::kSettingsGroup);
|
||||||
|
const EngineBase::State playback_state = static_cast<EngineBase::State>(s.value("playback_state", static_cast<int>(EngineBase::State::Empty)).toInt());
|
||||||
|
s.endGroup();
|
||||||
|
|
||||||
|
if (resume_playback && (playback_state == EngineBase::State::Playing || playback_state == EngineBase::State::Paused)) {
|
||||||
|
ResumePlayback();
|
||||||
|
}
|
||||||
|
else if (play_requested_) {
|
||||||
|
Play();
|
||||||
|
}
|
||||||
|
|
||||||
|
play_requested_ = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::ResumePlayback() {
|
||||||
|
|
||||||
|
qLog(Debug) << "Resuming playback";
|
||||||
|
|
||||||
|
Settings s;
|
||||||
|
s.beginGroup(kSettingsGroup);
|
||||||
|
const EngineBase::State playback_state = static_cast<EngineBase::State>(s.value("playback_state", static_cast<int>(EngineBase::State::Empty)).toInt());
|
||||||
|
const int playback_playlist = s.value("playback_playlist", -1).toInt();
|
||||||
|
const int playback_position = s.value("playback_position", 0).toInt();
|
||||||
|
s.endGroup();
|
||||||
|
|
||||||
|
if (playback_playlist == app_->playlist_manager()->current()->id()) {
|
||||||
|
// Set active to current to resume playback on correct playlist.
|
||||||
|
app_->playlist_manager()->SetActiveToCurrent();
|
||||||
|
if (playback_state == EngineBase::State::Playing) {
|
||||||
|
Play(playback_position * kNsecPerSec);
|
||||||
|
}
|
||||||
|
else if (playback_state == EngineBase::State::Paused) {
|
||||||
|
PlayWithPause(playback_position * kNsecPerSec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset saved playback status so we don't resume again from the same position.
|
||||||
|
s.beginGroup(kSettingsGroup);
|
||||||
|
s.setValue("playback_state", static_cast<int>(EngineBase::State::Empty));
|
||||||
|
s.setValue("playback_playlist", -1);
|
||||||
|
s.setValue("playback_position", 0);
|
||||||
|
s.endGroup();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
|
void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
|
||||||
|
|
||||||
if (loading_async_.contains(result.media_url_)) {
|
if (loading_async_.contains(result.media_url_)) {
|
||||||
@@ -285,7 +363,7 @@ void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
|
|||||||
if (is_current) {
|
if (is_current) {
|
||||||
InvalidSongRequested(result.media_url_);
|
InvalidSongRequested(result.media_url_);
|
||||||
}
|
}
|
||||||
emit Error(result.error_);
|
Q_EMIT Error(result.error_);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UrlHandler::LoadResult::Type::NoMoreTracks:
|
case UrlHandler::LoadResult::Type::NoMoreTracks:
|
||||||
@@ -354,7 +432,7 @@ void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
|
|||||||
|
|
||||||
if (is_current) {
|
if (is_current) {
|
||||||
qLog(Debug) << "Playing song" << current_item->Metadata().title() << result.stream_url_ << "position" << play_offset_nanosec_;
|
qLog(Debug) << "Playing song" << current_item->Metadata().title() << result.stream_url_ << "position" << play_offset_nanosec_;
|
||||||
engine_->Play(result.media_url_, result.stream_url_, stream_change_type_, song.has_cue(), song.beginning_nanosec(), song.end_nanosec(), play_offset_nanosec_, song.ebur128_integrated_loudness_lufs());
|
engine_->Play(result.media_url_, result.stream_url_, pause_, stream_change_type_, song.has_cue(), song.beginning_nanosec(), song.end_nanosec(), play_offset_nanosec_, song.ebur128_integrated_loudness_lufs());
|
||||||
current_item_ = current_item;
|
current_item_ = current_item;
|
||||||
play_offset_nanosec_ = 0;
|
play_offset_nanosec_ = 0;
|
||||||
}
|
}
|
||||||
@@ -421,12 +499,12 @@ void Player::NextItem(const EngineBase::TrackChangeFlags change, const Playlist:
|
|||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
app_->playlist_manager()->active()->set_current_row(i);
|
app_->playlist_manager()->active()->set_current_row(i);
|
||||||
app_->playlist_manager()->active()->reset_last_played();
|
app_->playlist_manager()->active()->reset_last_played();
|
||||||
emit PlaylistFinished();
|
Q_EMIT PlaylistFinished();
|
||||||
Stop();
|
Stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayAt(i, 0, change, autoscroll, false, true);
|
PlayAt(i, false, 0, change, autoscroll, false, true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,11 +539,10 @@ void Player::PlayPlaylistInternal(const EngineBase::TrackChangeFlags change, con
|
|||||||
if (i == -1) i = app_->playlist_manager()->active()->last_played_row();
|
if (i == -1) i = app_->playlist_manager()->active()->last_played_row();
|
||||||
if (i == -1) i = 0;
|
if (i == -1) i = 0;
|
||||||
|
|
||||||
PlayAt(i, 0, change, autoscroll, true);
|
PlayAt(i, false, 0, change, autoscroll, true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Player::HandleStopAfter(const Playlist::AutoScroll autoscroll) {
|
bool Player::HandleStopAfter(const Playlist::AutoScroll autoscroll) {
|
||||||
|
|
||||||
if (app_->playlist_manager()->active()->stop_after_current()) {
|
if (app_->playlist_manager()->active()->stop_after_current()) {
|
||||||
@@ -502,7 +579,7 @@ void Player::PlayPause(const quint64 offset_nanosec, const Playlist::AutoScroll
|
|||||||
switch (engine_->state()) {
|
switch (engine_->state()) {
|
||||||
case EngineBase::State::Paused:
|
case EngineBase::State::Paused:
|
||||||
UnPause();
|
UnPause();
|
||||||
emit Resumed();
|
Q_EMIT Resumed();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EngineBase::State::Playing:{
|
case EngineBase::State::Playing:{
|
||||||
@@ -527,7 +604,7 @@ void Player::PlayPause(const quint64 offset_nanosec, const Playlist::AutoScroll
|
|||||||
int i = app_->playlist_manager()->active()->current_row();
|
int i = app_->playlist_manager()->active()->current_row();
|
||||||
if (i == -1) i = app_->playlist_manager()->active()->last_played_row();
|
if (i == -1) i = app_->playlist_manager()->active()->last_played_row();
|
||||||
if (i == -1) i = 0;
|
if (i == -1) i = 0;
|
||||||
PlayAt(i, offset_nanosec, EngineBase::TrackChangeType::First, autoscroll, true);
|
PlayAt(i, false, offset_nanosec, EngineBase::TrackChangeType::First, autoscroll, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -543,7 +620,8 @@ void Player::UnPause() {
|
|||||||
if (time >= 30) { // Stream URL might be expired.
|
if (time >= 30) { // Stream URL might be expired.
|
||||||
qLog(Debug) << "Re-requesting stream URL for" << song.url();
|
qLog(Debug) << "Re-requesting stream URL for" << song.url();
|
||||||
play_offset_nanosec_ = engine_->position_nanosec();
|
play_offset_nanosec_ = engine_->position_nanosec();
|
||||||
HandleLoadResult(url_handlers_[song.url().scheme()]->StartLoading(song.url()));
|
UrlHandler *url_handler = url_handlers_.value(song.url().scheme());
|
||||||
|
HandleLoadResult(url_handler->StartLoading(song.url()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -606,7 +684,7 @@ void Player::PreviousItem(const EngineBase::TrackChangeFlags change) {
|
|||||||
QDateTime now = QDateTime::currentDateTime();
|
QDateTime now = QDateTime::currentDateTime();
|
||||||
if (last_pressed_previous_.isValid() && last_pressed_previous_.secsTo(now) >= 2) {
|
if (last_pressed_previous_.isValid() && last_pressed_previous_.secsTo(now) >= 2) {
|
||||||
last_pressed_previous_ = now;
|
last_pressed_previous_ = now;
|
||||||
PlayAt(app_->playlist_manager()->active()->current_row(), 0, change, Playlist::AutoScroll::Always, false, true);
|
PlayAt(app_->playlist_manager()->active()->current_row(), false, 0, change, Playlist::AutoScroll::Always, false, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
last_pressed_previous_ = now;
|
last_pressed_previous_ = now;
|
||||||
@@ -616,11 +694,11 @@ void Player::PreviousItem(const EngineBase::TrackChangeFlags change) {
|
|||||||
app_->playlist_manager()->active()->set_current_row(i, Playlist::AutoScroll::Always, false);
|
app_->playlist_manager()->active()->set_current_row(i, Playlist::AutoScroll::Always, false);
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
Stop();
|
Stop();
|
||||||
PlayAt(i, 0, change, Playlist::AutoScroll::Always, true);
|
PlayAt(i, false, 0, change, Playlist::AutoScroll::Always, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayAt(i, 0, change, Playlist::AutoScroll::Always, false);
|
PlayAt(i, false, 0, change, Playlist::AutoScroll::Always, false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,21 +715,21 @@ void Player::EngineStateChanged(const EngineBase::State state) {
|
|||||||
case EngineBase::State::Paused:
|
case EngineBase::State::Paused:
|
||||||
pause_time_ = QDateTime::currentDateTime();
|
pause_time_ = QDateTime::currentDateTime();
|
||||||
play_offset_nanosec_ = engine_->position_nanosec();
|
play_offset_nanosec_ = engine_->position_nanosec();
|
||||||
emit Paused();
|
Q_EMIT Paused();
|
||||||
break;
|
break;
|
||||||
case EngineBase::State::Playing:
|
case EngineBase::State::Playing:
|
||||||
pause_time_ = QDateTime();
|
pause_time_ = QDateTime();
|
||||||
play_offset_nanosec_ = 0;
|
play_offset_nanosec_ = 0;
|
||||||
emit Playing();
|
Q_EMIT Playing();
|
||||||
break;
|
break;
|
||||||
case EngineBase::State::Error:
|
case EngineBase::State::Error:
|
||||||
emit Error();
|
Q_EMIT Error();
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case EngineBase::State::Empty:
|
case EngineBase::State::Empty:
|
||||||
case EngineBase::State::Idle:
|
case EngineBase::State::Idle:
|
||||||
pause_time_ = QDateTime();
|
pause_time_ = QDateTime();
|
||||||
play_offset_nanosec_ = 0;
|
play_offset_nanosec_ = 0;
|
||||||
emit Stopped();
|
Q_EMIT Stopped();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -671,7 +749,7 @@ void Player::SetVolumeFromSlider(const int value) {
|
|||||||
if (volume != volume_) {
|
if (volume != volume_) {
|
||||||
volume_ = volume;
|
volume_ = volume;
|
||||||
engine_->SetVolume(volume);
|
engine_->SetVolume(volume);
|
||||||
emit VolumeChanged(volume);
|
Q_EMIT VolumeChanged(volume);
|
||||||
timer_save_volume_->start();
|
timer_save_volume_->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -682,7 +760,7 @@ void Player::SetVolumeFromEngine(const uint volume) {
|
|||||||
const uint new_volume = qBound(0U, volume, 100U);
|
const uint new_volume = qBound(0U, volume, 100U);
|
||||||
if (new_volume != volume_) {
|
if (new_volume != volume_) {
|
||||||
volume_ = new_volume;
|
volume_ = new_volume;
|
||||||
emit VolumeChanged(new_volume);
|
Q_EMIT VolumeChanged(new_volume);
|
||||||
timer_save_volume_->start();
|
timer_save_volume_->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -694,7 +772,7 @@ void Player::SetVolume(const uint volume) {
|
|||||||
if (new_volume != volume_) {
|
if (new_volume != volume_) {
|
||||||
volume_ = new_volume;
|
volume_ = new_volume;
|
||||||
engine_->SetVolume(new_volume);
|
engine_->SetVolume(new_volume);
|
||||||
emit VolumeChanged(new_volume);
|
Q_EMIT VolumeChanged(new_volume);
|
||||||
timer_save_volume_->start();
|
timer_save_volume_->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -718,13 +796,13 @@ void Player::VolumeDown() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::PlayAt(const int index, const quint64 offset_nanosec, EngineBase::TrackChangeFlags change, const Playlist::AutoScroll autoscroll, const bool reshuffle, const bool force_inform) {
|
void Player::PlayAt(const int index, const bool pause, const quint64 offset_nanosec, EngineBase::TrackChangeFlags change, const Playlist::AutoScroll autoscroll, const bool reshuffle, const bool force_inform) {
|
||||||
|
|
||||||
pause_time_ = QDateTime();
|
pause_time_ = pause ? QDateTime::currentDateTime() : QDateTime();
|
||||||
play_offset_nanosec_ = offset_nanosec;
|
play_offset_nanosec_ = offset_nanosec;
|
||||||
|
|
||||||
if (current_item_ && change & EngineBase::TrackChangeType::Manual && engine_->position_nanosec() != engine_->length_nanosec()) {
|
if (current_item_ && change & EngineBase::TrackChangeType::Manual && engine_->position_nanosec() != engine_->length_nanosec()) {
|
||||||
emit TrackSkipped(current_item_);
|
Q_EMIT TrackSkipped(current_item_);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_item_ && app_->playlist_manager()->active()->has_item_at(index) && current_item_->Metadata().IsOnSameAlbum(app_->playlist_manager()->active()->item_at(index)->Metadata())) {
|
if (current_item_ && app_->playlist_manager()->active()->has_item_at(index) && current_item_->Metadata().IsOnSameAlbum(app_->playlist_manager()->active()->item_at(index)->Metadata())) {
|
||||||
@@ -748,13 +826,15 @@ void Player::PlayAt(const int index, const quint64 offset_nanosec, EngineBase::T
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pause_ = pause;
|
||||||
stream_change_type_ = change;
|
stream_change_type_ = change;
|
||||||
autoscroll_ = autoscroll;
|
autoscroll_ = autoscroll;
|
||||||
HandleLoadResult(url_handlers_[url.scheme()]->StartLoading(url));
|
UrlHandler *url_handler = url_handlers_.value(url.scheme());
|
||||||
|
HandleLoadResult(url_handler->StartLoading(url));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
qLog(Debug) << "Playing song" << current_item_->Metadata().title() << url << "position" << offset_nanosec;
|
qLog(Debug) << "Playing song" << current_item_->Metadata().title() << url << "position" << offset_nanosec;
|
||||||
engine_->Play(current_item_->Url(), url, change, current_item_->Metadata().has_cue(), current_item_->effective_beginning_nanosec(), current_item_->effective_end_nanosec(), offset_nanosec, current_item_->effective_ebur128_integrated_loudness_lufs());
|
engine_->Play(current_item_->Url(), url, pause, change, current_item_->Metadata().has_cue(), current_item_->effective_beginning_nanosec(), current_item_->effective_end_nanosec(), offset_nanosec, current_item_->effective_ebur128_integrated_loudness_lufs());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -781,7 +861,7 @@ void Player::SeekTo(const quint64 seconds) {
|
|||||||
qLog(Debug) << "Track seeked to" << nanosec << "ns - updating scrobble point";
|
qLog(Debug) << "Track seeked to" << nanosec << "ns - updating scrobble point";
|
||||||
app_->playlist_manager()->active()->UpdateScrobblePoint(nanosec);
|
app_->playlist_manager()->active()->UpdateScrobblePoint(nanosec);
|
||||||
|
|
||||||
emit Seeked(nanosec / 1000);
|
Q_EMIT Seeked(nanosec / 1000);
|
||||||
|
|
||||||
if (seconds == 0) {
|
if (seconds == 0) {
|
||||||
app_->playlist_manager()->active()->InformOfCurrentSongChange(false);
|
app_->playlist_manager()->active()->InformOfCurrentSongChange(false);
|
||||||
@@ -852,6 +932,11 @@ void Player::Pause() { engine_->Pause(); }
|
|||||||
|
|
||||||
void Player::Play(const quint64 offset_nanosec) {
|
void Player::Play(const quint64 offset_nanosec) {
|
||||||
|
|
||||||
|
if (!playlists_loaded_) {
|
||||||
|
play_requested_ = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (GetState()) {
|
switch (GetState()) {
|
||||||
case EngineBase::State::Playing:
|
case EngineBase::State::Playing:
|
||||||
SeekTo(offset_nanosec);
|
SeekTo(offset_nanosec);
|
||||||
@@ -866,12 +951,25 @@ void Player::Play(const quint64 offset_nanosec) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::PlayWithPause(const quint64 offset_nanosec) {
|
||||||
|
|
||||||
|
pause_time_ = QDateTime();
|
||||||
|
play_offset_nanosec_ = offset_nanosec;
|
||||||
|
app_->playlist_manager()->SetActivePlaylist(app_->playlist_manager()->current_id());
|
||||||
|
if (app_->playlist_manager()->active()->rowCount() == 0) return;
|
||||||
|
int i = app_->playlist_manager()->active()->current_row();
|
||||||
|
if (i == -1) i = app_->playlist_manager()->active()->last_played_row();
|
||||||
|
if (i == -1) i = 0;
|
||||||
|
PlayAt(i, true, offset_nanosec, EngineBase::TrackChangeType::First, Playlist::AutoScroll::Always, true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void Player::ShowOSD() {
|
void Player::ShowOSD() {
|
||||||
if (current_item_) emit ForceShowOSD(current_item_->Metadata(), false);
|
if (current_item_) Q_EMIT ForceShowOSD(current_item_->Metadata(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::TogglePrettyOSD() {
|
void Player::TogglePrettyOSD() {
|
||||||
if (current_item_) emit ForceShowOSD(current_item_->Metadata(), true);
|
if (current_item_) Q_EMIT ForceShowOSD(current_item_->Metadata(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::TrackAboutToEnd() {
|
void Player::TrackAboutToEnd() {
|
||||||
@@ -909,10 +1007,11 @@ void Player::TrackAboutToEnd() {
|
|||||||
if (url_handlers_.contains(url.scheme())) {
|
if (url_handlers_.contains(url.scheme())) {
|
||||||
if (loading_async_.contains(url)) return;
|
if (loading_async_.contains(url)) return;
|
||||||
autoscroll_ = Playlist::AutoScroll::Maybe;
|
autoscroll_ = Playlist::AutoScroll::Maybe;
|
||||||
UrlHandler::LoadResult result = url_handlers_[url.scheme()]->StartLoading(url);
|
UrlHandler *url_handler = url_handlers_.value(url.scheme());
|
||||||
|
const UrlHandler::LoadResult result = url_handler->StartLoading(url);
|
||||||
switch (result.type_) {
|
switch (result.type_) {
|
||||||
case UrlHandler::LoadResult::Type::Error:
|
case UrlHandler::LoadResult::Type::Error:
|
||||||
emit Error(result.error_);
|
Q_EMIT Error(result.error_);
|
||||||
return;
|
return;
|
||||||
case UrlHandler::LoadResult::Type::NoMoreTracks:
|
case UrlHandler::LoadResult::Type::NoMoreTracks:
|
||||||
return;
|
return;
|
||||||
@@ -945,12 +1044,12 @@ void Player::FatalError() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Player::ValidSongRequested(const QUrl &url) {
|
void Player::ValidSongRequested(const QUrl &url) {
|
||||||
emit SongChangeRequestProcessed(url, true);
|
Q_EMIT SongChangeRequestProcessed(url, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::InvalidSongRequested(const QUrl &url) {
|
void Player::InvalidSongRequested(const QUrl &url) {
|
||||||
|
|
||||||
if (greyout_) emit SongChangeRequestProcessed(url, false);
|
if (greyout_) Q_EMIT SongChangeRequestProcessed(url, false);
|
||||||
|
|
||||||
if (!continue_on_error_) {
|
if (!continue_on_error_) {
|
||||||
FatalError();
|
FatalError();
|
||||||
@@ -1013,5 +1112,5 @@ void Player::UrlHandlerDestroyed(QObject *object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Player::HandleAuthentication() {
|
void Player::HandleAuthentication() {
|
||||||
emit Authenticated();
|
Q_EMIT Authenticated();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,13 +64,16 @@ class PlayerInterface : public QObject {
|
|||||||
virtual void RegisterUrlHandler(UrlHandler *handler) = 0;
|
virtual void RegisterUrlHandler(UrlHandler *handler) = 0;
|
||||||
virtual void UnregisterUrlHandler(UrlHandler *handler) = 0;
|
virtual void UnregisterUrlHandler(UrlHandler *handler) = 0;
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
virtual void ReloadSettings() = 0;
|
virtual void ReloadSettings() = 0;
|
||||||
virtual void LoadVolume() = 0;
|
virtual void LoadVolume() = 0;
|
||||||
virtual void SaveVolume() = 0;
|
virtual void SaveVolume() = 0;
|
||||||
|
virtual void SavePlaybackStatus() = 0;
|
||||||
|
|
||||||
|
virtual void PlaylistsLoaded() = 0;
|
||||||
|
|
||||||
// Manual track change to the specified track
|
// Manual track change to the specified track
|
||||||
virtual void PlayAt(const int index, const quint64 offset_nanosec, EngineBase::TrackChangeFlags change, const Playlist::AutoScroll autoscroll, const bool reshuffle, const bool force_inform = false) = 0;
|
virtual void PlayAt(const int index, const bool pause, const quint64 offset_nanosec, EngineBase::TrackChangeFlags change, const Playlist::AutoScroll autoscroll, const bool reshuffle, const bool force_inform = false) = 0;
|
||||||
|
|
||||||
// If there's currently a song playing, pause it, otherwise play the track that was playing last, or the first one on the playlist
|
// If there's currently a song playing, pause it, otherwise play the track that was playing last, or the first one on the playlist
|
||||||
virtual void PlayPause(const quint64 offset_nanosec = 0, const Playlist::AutoScroll autoscroll = Playlist::AutoScroll::Always) = 0;
|
virtual void PlayPause(const quint64 offset_nanosec = 0, const Playlist::AutoScroll autoscroll = Playlist::AutoScroll::Always) = 0;
|
||||||
@@ -98,10 +101,11 @@ class PlayerInterface : public QObject {
|
|||||||
virtual void Pause() = 0;
|
virtual void Pause() = 0;
|
||||||
virtual void Stop(const bool stop_after = false) = 0;
|
virtual void Stop(const bool stop_after = false) = 0;
|
||||||
virtual void Play(const quint64 offset_nanosec = 0) = 0;
|
virtual void Play(const quint64 offset_nanosec = 0) = 0;
|
||||||
|
virtual void PlayWithPause(const quint64 offset_nanosec) = 0;
|
||||||
virtual void PlayHelper() = 0;
|
virtual void PlayHelper() = 0;
|
||||||
virtual void ShowOSD() = 0;
|
virtual void ShowOSD() = 0;
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void Playing();
|
void Playing();
|
||||||
void Paused();
|
void Paused();
|
||||||
// Emitted only when playback is manually resumed
|
// Emitted only when playback is manually resumed
|
||||||
@@ -154,12 +158,14 @@ class Player : public PlayerInterface {
|
|||||||
void SetAnalyzer(AnalyzerContainer *analyzer) { analyzer_ = analyzer; }
|
void SetAnalyzer(AnalyzerContainer *analyzer) { analyzer_ = analyzer; }
|
||||||
void SetEqualizer(SharedPtr<Equalizer> equalizer) { equalizer_ = equalizer; }
|
void SetEqualizer(SharedPtr<Equalizer> equalizer) { equalizer_ = equalizer; }
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void ReloadSettings() override;
|
void ReloadSettings() override;
|
||||||
void LoadVolume() override;
|
void LoadVolume() override;
|
||||||
void SaveVolume() override;
|
void SaveVolume() override;
|
||||||
|
void SavePlaybackStatus() override;
|
||||||
|
void PlaylistsLoaded() override;
|
||||||
|
|
||||||
void PlayAt(const int index, const quint64 offset_nanosec, EngineBase::TrackChangeFlags change, const Playlist::AutoScroll autoscroll, const bool reshuffle, const bool force_inform = false) override;
|
void PlayAt(const int index, const bool pause, const quint64 offset_nanosec, EngineBase::TrackChangeFlags change, const Playlist::AutoScroll autoscroll, const bool reshuffle, const bool force_inform = false) override;
|
||||||
void PlayPause(const quint64 offset_nanosec = 0, const Playlist::AutoScroll autoscroll = Playlist::AutoScroll::Always) override;
|
void PlayPause(const quint64 offset_nanosec = 0, const Playlist::AutoScroll autoscroll = Playlist::AutoScroll::Always) override;
|
||||||
void PlayPauseHelper() override { PlayPause(play_offset_nanosec_); }
|
void PlayPauseHelper() override { PlayPause(play_offset_nanosec_); }
|
||||||
void RestartOrPrevious() override;
|
void RestartOrPrevious() override;
|
||||||
@@ -182,16 +188,17 @@ class Player : public PlayerInterface {
|
|||||||
void Stop(const bool stop_after = false) override;
|
void Stop(const bool stop_after = false) override;
|
||||||
void StopAfterCurrent();
|
void StopAfterCurrent();
|
||||||
void Play(const quint64 offset_nanosec = 0) override;
|
void Play(const quint64 offset_nanosec = 0) override;
|
||||||
|
void PlayWithPause(const quint64 offset_nanosec) override;
|
||||||
void PlayHelper() override { Play(); }
|
void PlayHelper() override { Play(); }
|
||||||
void ShowOSD() override;
|
void ShowOSD() override;
|
||||||
void TogglePrettyOSD();
|
void TogglePrettyOSD();
|
||||||
|
|
||||||
void HandleAuthentication();
|
void HandleAuthentication();
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void EngineChanged(const EngineBase::Type Type);
|
void EngineChanged(const EngineBase::Type Type);
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void EngineStateChanged(const EngineBase::State);
|
void EngineStateChanged(const EngineBase::State);
|
||||||
void EngineMetadataReceived(const EngineMetadata &engine_metadata);
|
void EngineMetadataReceived(const EngineMetadata &engine_metadata);
|
||||||
void TrackAboutToEnd();
|
void TrackAboutToEnd();
|
||||||
@@ -211,6 +218,8 @@ class Player : public PlayerInterface {
|
|||||||
void HandleLoadResult(const UrlHandler::LoadResult &result);
|
void HandleLoadResult(const UrlHandler::LoadResult &result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void ResumePlayback();
|
||||||
|
|
||||||
// Returns true if we were supposed to stop after this track.
|
// Returns true if we were supposed to stop after this track.
|
||||||
bool HandleStopAfter(const Playlist::AutoScroll autoscroll);
|
bool HandleStopAfter(const Playlist::AutoScroll autoscroll);
|
||||||
|
|
||||||
@@ -226,8 +235,12 @@ class Player : public PlayerInterface {
|
|||||||
SharedPtr<Equalizer> equalizer_;
|
SharedPtr<Equalizer> equalizer_;
|
||||||
QTimer *timer_save_volume_;
|
QTimer *timer_save_volume_;
|
||||||
|
|
||||||
|
bool playlists_loaded_;
|
||||||
|
bool play_requested_;
|
||||||
|
|
||||||
PlaylistItemPtr current_item_;
|
PlaylistItemPtr current_item_;
|
||||||
|
|
||||||
|
bool pause_;
|
||||||
EngineBase::TrackChangeFlags stream_change_type_;
|
EngineBase::TrackChangeFlags stream_change_type_;
|
||||||
Playlist::AutoScroll autoscroll_;
|
Playlist::AutoScroll autoscroll_;
|
||||||
EngineBase::State last_state_;
|
EngineBase::State last_state_;
|
||||||
|
|||||||
34
src/core/potranslator.cpp
Normal file
34
src/core/potranslator.cpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Strawberry Music Player
|
||||||
|
* This file was part of Clementine.
|
||||||
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2018-2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
|
*
|
||||||
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Strawberry is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "potranslator.h"
|
||||||
|
|
||||||
|
PoTranslator::PoTranslator(QObject *parent) : QTranslator(parent) {}
|
||||||
|
|
||||||
|
QString PoTranslator::translate(const char *context, const char *source_text, const char *disambiguation, const int n) const {
|
||||||
|
|
||||||
|
QString ret = QTranslator::translate(context, source_text, disambiguation, n);
|
||||||
|
if (!ret.isEmpty()) return ret;
|
||||||
|
return QTranslator::translate(nullptr, source_text, disambiguation, n);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2018-2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
#define POTRANSLATOR_H
|
#define POTRANSLATOR_H
|
||||||
|
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
// We convert from .po files to .qm files, which loses context information.
|
// We convert from .po files to .qm files, which loses context information.
|
||||||
// This translator tries loading strings with an empty context if it can't find any others.
|
// This translator tries loading strings with an empty context if it can't find any others.
|
||||||
@@ -30,12 +32,8 @@ class PoTranslator : public QTranslator {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PoTranslator(QObject *parent = nullptr) : QTranslator(parent) {}
|
explicit PoTranslator(QObject *parent = nullptr);
|
||||||
QString translate(const char *context, const char *source_text, const char *disambiguation = nullptr, int n = -1) const override {
|
QString translate(const char *context, const char *source_text, const char *disambiguation = nullptr, int n = -1) const override;
|
||||||
QString ret = QTranslator::translate(context, source_text, disambiguation, n);
|
|
||||||
if (!ret.isEmpty()) return ret;
|
|
||||||
return QTranslator::translate(nullptr, source_text, disambiguation, n);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // POTRANSLATOR_H
|
#endif // POTRANSLATOR_H
|
||||||
|
|||||||
@@ -113,11 +113,11 @@ void SystemTrayIcon::Clicked(const QSystemTrayIcon::ActivationReason reason) {
|
|||||||
switch (reason) {
|
switch (reason) {
|
||||||
case QSystemTrayIcon::DoubleClick:
|
case QSystemTrayIcon::DoubleClick:
|
||||||
case QSystemTrayIcon::Trigger:
|
case QSystemTrayIcon::Trigger:
|
||||||
emit ShowHide();
|
Q_EMIT ShowHide();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QSystemTrayIcon::MiddleClick:
|
case QSystemTrayIcon::MiddleClick:
|
||||||
emit PlayPause();
|
Q_EMIT PlayPause();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class SystemTrayIcon : public QSystemTrayIcon {
|
|||||||
QPixmap CreateIcon(const QPixmap &icon, const QPixmap &grey_icon);
|
QPixmap CreateIcon(const QPixmap &icon, const QPixmap &grey_icon);
|
||||||
void UpdateIcon();
|
void UpdateIcon();
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void ChangeVolume(const int delta);
|
void ChangeVolume(const int delta);
|
||||||
void SeekForward();
|
void SeekForward();
|
||||||
void SeekBackward();
|
void SeekBackward();
|
||||||
@@ -77,7 +77,7 @@ class SystemTrayIcon : public QSystemTrayIcon {
|
|||||||
void ShowHide();
|
void ShowHide();
|
||||||
void PlayPause();
|
void PlayPause();
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void Clicked(const QSystemTrayIcon::ActivationReason);
|
void Clicked(const QSystemTrayIcon::ActivationReason);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user