Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd490ca946 | ||
|
|
793f6b00e6 | ||
|
|
c1ec568fda | ||
|
|
4e2b52975e | ||
|
|
c141df6b86 | ||
|
|
63b781765a | ||
|
|
c121e141e7 | ||
|
|
7544c9a9f5 | ||
|
|
722a088515 | ||
|
|
0ce75bff58 | ||
|
|
3744b6d3de | ||
|
|
a4ebd91e8d | ||
|
|
3bb0ee916d | ||
|
|
fd6afdf5f3 | ||
|
|
47c13a840e | ||
|
|
5b61992b3c | ||
|
|
36331dc253 | ||
|
|
4265cf31b2 | ||
|
|
337e47269f | ||
|
|
7039234471 | ||
|
|
f7f9333d91 | ||
|
|
bf35665932 | ||
|
|
089a2271c2 | ||
|
|
f8e83e3631 | ||
|
|
46fd329913 | ||
|
|
6b9ba96e77 | ||
|
|
b7d360d850 | ||
|
|
8e226302ab | ||
|
|
7795b9edaf | ||
|
|
9375d9699a | ||
|
|
cf0442d5b8 | ||
|
|
b386ca14df | ||
|
|
ea47fae31e | ||
|
|
e0fed07b10 | ||
|
|
779d5ff7b6 | ||
|
|
eb6fbd03ec | ||
|
|
95409d1b0e | ||
|
|
49599c8731 | ||
|
|
572f94e000 | ||
|
|
c0a2ad5f50 | ||
|
|
71fa5acc74 | ||
|
|
bac5b7679d | ||
|
|
93ade821a5 | ||
|
|
a718e19979 | ||
|
|
8ac83a46f5 | ||
|
|
1b65dcd7df | ||
|
|
bbad45f1e7 | ||
|
|
331b9cca18 | ||
|
|
a9accb7d85 | ||
|
|
1862e70628 | ||
|
|
c4f7054ca6 | ||
|
|
175e568a28 | ||
|
|
c8d580e7de | ||
|
|
bc0c50ee65 | ||
|
|
45e9dd96d1 | ||
|
|
1cc73562a3 | ||
|
|
d870ef0bd5 | ||
|
|
53d308dac5 | ||
|
|
89b06ae7c7 | ||
|
|
d38485a8ad | ||
|
|
834877c503 | ||
|
|
d033b79af4 | ||
|
|
daec2cc203 | ||
|
|
4e593cebab | ||
|
|
73d7701e94 | ||
|
|
24f1d7a72f | ||
|
|
6387a01d7b | ||
|
|
e838840548 | ||
|
|
6a430b441e | ||
|
|
7b977ea839 | ||
|
|
62b8521cbe | ||
|
|
308244d901 | ||
|
|
6f521183f9 | ||
|
|
76c6f7e733 | ||
|
|
80ebfbeb6b | ||
|
|
793901b319 | ||
|
|
3950df8ec9 | ||
|
|
e800b236aa | ||
|
|
4ab7871106 | ||
|
|
3de85549b6 | ||
|
|
73164f7182 | ||
|
|
004b000890 | ||
|
|
d9c703d944 | ||
|
|
364b650033 | ||
|
|
156eb874db | ||
|
|
1a28dd0311 | ||
|
|
e29b4b8609 | ||
|
|
c02997e6d9 | ||
|
|
7c9fc91af9 | ||
|
|
cf5198ac64 | ||
|
|
e76ddd6dd2 | ||
|
|
e3a4cf1cf5 | ||
|
|
5844616ea8 | ||
|
|
abeb580228 | ||
|
|
4d888dfce8 | ||
|
|
08ff6f0ede | ||
|
|
c458c27231 | ||
|
|
9821b70c38 | ||
|
|
8ab8401110 | ||
|
|
4f798c85cf | ||
|
|
1949bdb43f | ||
|
|
8cf2e6b31b | ||
|
|
b1069f9f18 | ||
|
|
fb8dfa9ae9 | ||
|
|
4402a56e94 | ||
|
|
f449808ba3 | ||
|
|
5599739433 | ||
|
|
197cf85f56 | ||
|
|
8c039c9c8b | ||
|
|
c1d9bc046d | ||
|
|
cd99fac7ed | ||
|
|
f4489e6807 | ||
|
|
f2078271b6 | ||
|
|
a3ae9acebb | ||
|
|
b0580265ca | ||
|
|
b4f012392a | ||
|
|
1598809f55 | ||
|
|
6d4f7aa61f |
2
.github/FUNDING.yml
vendored
@@ -1 +1 @@
|
||||
custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FRJUYV5QP6HW8
|
||||
github: jonaski
|
||||
|
||||
48
.github/workflows/ccpp.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: C/C++ CI
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install Packages
|
||||
run:
|
||||
sudo apt-get install -y git make cmake g++ gettext libglib2.0-dev libdbus-1-dev libboost-dev libprotobuf-dev protobuf-compiler libsqlite3-dev sqlite3 libgnutls28-dev libasound2-dev libpulse-dev qtbase5-dev qtbase5-dev-tools qtbase5-private-dev libqt5core5a libqt5gui5 libqt5widgets5 libqt5concurrent5 libqt5network5 libqt5sql5 libqt5x11extras5-dev libqt5dbus5 qttools5-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-good1.0-dev gstreamer1.0-alsa gstreamer1.0-pulseaudio libgstreamer1.0-0 libgstreamer-plugins-base1.0-0 libgstreamer-plugins-good1.0-0 libgstreamer-plugins-bad1.0-0 libchromaprint-dev libfftw3-dev libcdio-dev libmtp-dev libgpod-dev libimobiledevice-dev libplist-dev libusbmuxd-dev libxine2-dev libvlc-dev
|
||||
- name: Create Build Environment
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
- name: Configure CMake
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Update HomeBrew
|
||||
run: brew update
|
||||
- name: Install Packages
|
||||
run: brew install glib pkgconfig boost libffi protobuf protobuf-c qt gettext gnutls fftw sqlite chromaprint gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav libcdio libmtp libimobiledevice libplist create-dmg
|
||||
- name: Create Build Environment
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
- name: Configure CMake
|
||||
env:
|
||||
Qt5_DIR: /usr/local/opt/qt5/lib/cmake
|
||||
Qt5LinguistTools_DIR: /usr/local/opt/qt5/lib/cmake/Qt5LinguistTools
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DUSE_BUNDLE=ON
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
- name: Install
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: make install
|
||||
@@ -7,7 +7,6 @@ services:
|
||||
- docker
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
before_install:
|
||||
- if ! [ "$DEPLOY_KEY_ENC" == "" ]; then
|
||||
@@ -42,7 +41,7 @@ script:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
||||
make -j8 || travis_terminate 1;
|
||||
make install || travis_terminate 1;
|
||||
sudo make dmg;
|
||||
make dmg;
|
||||
fi
|
||||
after_success:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ls -lh strawberry*.dmg; fi
|
||||
|
||||
6
3rdparty/singleapplication/CMakeLists.txt
vendored
@@ -5,10 +5,10 @@ include(CheckFunctionExists)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -U__STRICT_ANSI__ -Wall -Woverloaded-virtual -Wno-sign-compare -fpermissive")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -U__STRICT_ANSI__ -Wall -Wextra -Wpedantic -Woverloaded-virtual -fpermissive")
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wpedantic")
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
|
||||
endif()
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER 3.0)
|
||||
|
||||
@@ -114,12 +114,9 @@ void SingleApplicationPrivate::genBlockServerName() {
|
||||
#ifdef Q_OS_UNIX
|
||||
QByteArray username;
|
||||
#if defined(HAVE_GETEUID) && defined(HAVE_GETPWUID)
|
||||
uid_t uid = geteuid();
|
||||
if (uid != -1) {
|
||||
struct passwd *pw = getpwuid(uid);
|
||||
if (pw) {
|
||||
username = pw->pw_name;
|
||||
}
|
||||
struct passwd *pw = getpwuid(geteuid());
|
||||
if (pw) {
|
||||
username = pw->pw_name;
|
||||
}
|
||||
#endif
|
||||
if (username.isEmpty()) username = qgetenv("USER");
|
||||
|
||||
@@ -114,12 +114,9 @@ void SingleCoreApplicationPrivate::genBlockServerName() {
|
||||
#ifdef Q_OS_UNIX
|
||||
QByteArray username;
|
||||
#if defined(HAVE_GETEUID) && defined(HAVE_GETPWUID)
|
||||
uid_t uid = geteuid();
|
||||
if (uid != -1) {
|
||||
struct passwd *pw = getpwuid(uid);
|
||||
if (pw) {
|
||||
username = pw->pw_name;
|
||||
}
|
||||
struct passwd *pw = getpwuid(geteuid());
|
||||
if (pw) {
|
||||
username = pw->pw_name;
|
||||
}
|
||||
#endif
|
||||
if (username.isEmpty()) username = qgetenv("USER");
|
||||
|
||||
@@ -56,32 +56,17 @@ if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
|
||||
set(DEBUG ON)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER MATCHES ".*clang")
|
||||
set(CMAKE_COMPILER_IS_CLANGXX 1)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-uninitialized")
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --stdlib=libc++")
|
||||
endif(APPLE)
|
||||
|
||||
find_program(CCACHE_EXECUTABLE NAMES ccache)
|
||||
if (CCACHE_EXECUTABLE)
|
||||
message(STATUS "ccache found: will be used for compilation and linkage")
|
||||
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_EXECUTABLE})
|
||||
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_EXECUTABLE})
|
||||
endif ()
|
||||
find_program(QT_LCONVERT_EXECUTABLE NAMES lconvert lconvert-qt5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH)
|
||||
find_program(QT_LCONVERT_EXECUTABLE NAMES lconvert lconvert-qt5)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(GLIB REQUIRED glib-2.0)
|
||||
pkg_check_modules(GIO REQUIRED gio-2.0)
|
||||
pkg_check_modules(GOBJECT REQUIRED gobject-2.0)
|
||||
pkg_check_modules(CDIO libcdio)
|
||||
find_package(Boost REQUIRED)
|
||||
find_package(Threads)
|
||||
find_package(GnuTLS)
|
||||
find_package(Boost REQUIRED)
|
||||
find_package(Protobuf REQUIRED)
|
||||
find_library(PROTOBUF_STATIC_LIBRARY libprotobuf.a libprotobuf)
|
||||
if(LINUX)
|
||||
@@ -98,6 +83,10 @@ endif()
|
||||
if(X11_FOUND)
|
||||
set(HAVE_X11 ON)
|
||||
endif()
|
||||
pkg_check_modules(GLIB REQUIRED glib-2.0)
|
||||
pkg_check_modules(GIO REQUIRED gio-2.0)
|
||||
pkg_check_modules(GOBJECT REQUIRED gobject-2.0)
|
||||
pkg_check_modules(LIBCDIO libcdio)
|
||||
pkg_check_modules(GSTREAMER gstreamer-1.0)
|
||||
pkg_check_modules(GSTREAMER_BASE gstreamer-base-1.0)
|
||||
pkg_check_modules(GSTREAMER_AUDIO gstreamer-audio-1.0)
|
||||
@@ -303,7 +292,7 @@ optional_component(GLOBALSHORTCUTS ON "Global shortcuts"
|
||||
)
|
||||
|
||||
optional_component(AUDIOCD ON "Devices: Audio CD support"
|
||||
DEPENDS "libcdio" CDIO_FOUND
|
||||
DEPENDS "libcdio" LIBCDIO_FOUND
|
||||
)
|
||||
|
||||
optional_component(UDISKS2 ON "Devices: UDisks2 backend"
|
||||
@@ -327,7 +316,7 @@ optional_component(IMOBILEDEVICE ON "Devices: iPhone, iPod Touch, iPad and Apple
|
||||
DEPENDS "libimobiledevice" LIBIMOBILEDEVICE_FOUND
|
||||
DEPENDS "libplist" LIBPLIST_FOUND
|
||||
DEPENDS "libusbmuxd" LIBUSBMUXD_FOUND
|
||||
DEPENDS "libgpod" LIBGPOD_FOUND
|
||||
DEPENDS "libgpod" HAVE_LIBGPOD
|
||||
)
|
||||
|
||||
optional_component(SPARKLE ON "Sparkle integration"
|
||||
|
||||
44
Changelog
@@ -2,6 +2,50 @@ Strawberry Music Player
|
||||
=======================
|
||||
ChangeLog
|
||||
|
||||
Version 0.6.7:
|
||||
|
||||
* Fixed crash when cancelling scrobbler authentication
|
||||
* Fixed "Double clicking a song in the playlist" behaviour setting
|
||||
* Fixed "Pressing Previous in player" behaviour setting
|
||||
* Fixed updating compilations where there are spaces or special characters in filenames
|
||||
* Fixed cases where songs were stuck in "Various Artists" because not all songs in
|
||||
the same compilation was removed from the model before readded with actual artist.
|
||||
* Fixed a bug when importing playlists where metadata was reset
|
||||
* Fixed scrobbler to also scrobble songs without album title
|
||||
* Fixed text for replay gain setting not loading in backend setting
|
||||
* Added back lyrics from Chartlyrics
|
||||
* Added ability to show fullsize cover on doubleclick in playing widget
|
||||
* Added seperator between "unset cover" and "show fullsize" in popup menu
|
||||
* Removed left click on analyzer to popup menu
|
||||
* (Windows) Added killproc executable to terminate running process before uninstalling
|
||||
|
||||
Version 0.6.6:
|
||||
|
||||
* Fixed lowercased album artist in playlist column
|
||||
* Fixed compiling with different optional features turned off
|
||||
* Fixed hang in stream discoverer with certain formats
|
||||
* Fixed Subsonic to correctly read disc
|
||||
* Fixed preventing system logoff or shutdown
|
||||
* Fixed correctly updating compilations
|
||||
* Simplified gstreamer pipeline code
|
||||
* Disabled showing analyzer for bit depths not supported by the analyzer
|
||||
* Made stereo balancer independent from equalizer
|
||||
* Added option to prefer album artist when sending scrobbles
|
||||
* Removed lines in settings
|
||||
* Added limit for number of tagreader processes to 2
|
||||
* Improved system theme icon option to better pick correct icons
|
||||
* Added option to automatically select current playing track
|
||||
* (Windows) Added support for WASAPI
|
||||
|
||||
Version 0.6.5:
|
||||
|
||||
* Fixed scrobbler not to send scrobbles multiple times when metadata is updated
|
||||
* Fixed Listenbrainz scrobbler not don't send "various artists" as album artist
|
||||
* Fixed missing cover image in OSD pretty reposition image
|
||||
* Fixed OSD pretty upper left positioning
|
||||
* Fixed OSD pretty positioning on Windows on screens with negative geometry
|
||||
* Fixed appdata file to pass full validation
|
||||
|
||||
Version 0.6.4:
|
||||
|
||||
* Added setting for fancy tabbar background color
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from jonaski/opensuse:tumbleweed
|
||||
from jonaski/opensuse:lp151
|
||||
|
||||
run mkdir -p /usr/src/app
|
||||
workdir /usr/src/app
|
||||
|
||||
@@ -20,13 +20,16 @@ Strawberry is a music player and music collection organizer. It is a fork of Cle
|
||||
* Edit tags on music files
|
||||
* Fetch tags from MusicBrainz
|
||||
* Album cover art from Last.fm, Musicbrainz, Discogs, Deezer and Tidal
|
||||
* Song lyrics from AudD, lyrics.ovh and lololyrics.com
|
||||
* Song lyrics from AudD, ChartLyrics, lyrics.ovh and lololyrics.com
|
||||
* Support for multiple backends
|
||||
* Audio analyzer
|
||||
* Audio equalizer
|
||||
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
|
||||
* Streaming support for Tidal, Qobuz and Subsonic
|
||||
* Subsonic streaming support
|
||||
* Unofficial streaming support for Tidal and Qobuz
|
||||
* Scrobbler with support for Last.fm, Libre.fm and ListenBrainz
|
||||
|
||||
**Tidal and Qobuz streaming in Strawberry is unofficial. You need an official API token (or App ID/Secret) to use it, we can not provide API tokens, or help getting them. Tidal will not work with Tidal Masters (MQA), because MQA is a proprietary format in lossy quality without an open source decoder, we can't support it.**
|
||||
|
||||
It has so far been tested to work on Linux, OpenBSD, macOS and Windows.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
add_custom_target(dmg
|
||||
COMMAND sudo /usr/local/opt/qt5/bin/macdeployqt strawberry.app
|
||||
COMMAND sudo ${CMAKE_SOURCE_DIR}/dist/macos/macdeploy.py strawberry.app
|
||||
COMMAND sudo ${CMAKE_SOURCE_DIR}/dist/macos/create-dmg.sh strawberry.app
|
||||
COMMAND /usr/local/opt/qt5/bin/macdeployqt strawberry.app
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/dist/macos/macdeploy.py strawberry.app
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/dist/macos/create-dmg.sh strawberry.app
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
set(STRAWBERRY_VERSION_MAJOR 0)
|
||||
set(STRAWBERRY_VERSION_MINOR 6)
|
||||
set(STRAWBERRY_VERSION_PATCH 4)
|
||||
set(STRAWBERRY_VERSION_PATCH 7)
|
||||
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
||||
|
||||
set(INCLUDE_GIT_REVISION OFF)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<file>icons/128x128/applications-internet.png</file>
|
||||
<file>icons/128x128/bluetooth.png</file>
|
||||
<file>icons/128x128/cdcase.png</file>
|
||||
<file>icons/128x128/cd.png</file>
|
||||
<file>icons/128x128/media-optical.png</file>
|
||||
<file>icons/128x128/configure.png</file>
|
||||
<file>icons/128x128/device-ipod-nano.png</file>
|
||||
<file>icons/128x128/device-ipod.png</file>
|
||||
@@ -57,9 +57,9 @@
|
||||
<file>icons/128x128/mcintosh-player.png</file>
|
||||
<file>icons/128x128/mcintosh-text.png</file>
|
||||
<file>icons/128x128/media-eject.png</file>
|
||||
<file>icons/128x128/media-pause.png</file>
|
||||
<file>icons/128x128/media-play.png</file>
|
||||
<file>icons/128x128/media-stop.png</file>
|
||||
<file>icons/128x128/media-playback-pause.png</file>
|
||||
<file>icons/128x128/media-playback-start.png</file>
|
||||
<file>icons/128x128/media-playback-stop.png</file>
|
||||
<file>icons/128x128/media-skip-forward.png</file>
|
||||
<file>icons/128x128/media-skip-backward.png</file>
|
||||
<file>icons/128x128/media-seek-forward.png</file>
|
||||
@@ -79,7 +79,7 @@
|
||||
<file>icons/128x128/view-media-playlist.png</file>
|
||||
<file>icons/128x128/view-media-visualization.png</file>
|
||||
<file>icons/128x128/view-refresh.png</file>
|
||||
<file>icons/128x128/vinyl.png</file>
|
||||
<file>icons/128x128/library-music.png</file>
|
||||
<file>icons/128x128/vlc.png</file>
|
||||
<file>icons/128x128/xine.png</file>
|
||||
<file>icons/128x128/zoom-in.png</file>
|
||||
@@ -97,7 +97,7 @@
|
||||
<file>icons/64x64/applications-internet.png</file>
|
||||
<file>icons/64x64/bluetooth.png</file>
|
||||
<file>icons/64x64/cdcase.png</file>
|
||||
<file>icons/64x64/cd.png</file>
|
||||
<file>icons/64x64/media-optical.png</file>
|
||||
<file>icons/64x64/configure.png</file>
|
||||
<file>icons/64x64/device-ipod-nano.png</file>
|
||||
<file>icons/64x64/device-ipod.png</file>
|
||||
@@ -148,9 +148,9 @@
|
||||
<file>icons/64x64/mcintosh-player.png</file>
|
||||
<file>icons/64x64/mcintosh-text.png</file>
|
||||
<file>icons/64x64/media-eject.png</file>
|
||||
<file>icons/64x64/media-pause.png</file>
|
||||
<file>icons/64x64/media-play.png</file>
|
||||
<file>icons/64x64/media-stop.png</file>
|
||||
<file>icons/64x64/media-playback-pause.png</file>
|
||||
<file>icons/64x64/media-playback-start.png</file>
|
||||
<file>icons/64x64/media-playback-stop.png</file>
|
||||
<file>icons/64x64/media-skip-forward.png</file>
|
||||
<file>icons/64x64/media-skip-backward.png</file>
|
||||
<file>icons/64x64/media-seek-forward.png</file>
|
||||
@@ -171,7 +171,7 @@
|
||||
<file>icons/64x64/view-media-playlist.png</file>
|
||||
<file>icons/64x64/view-media-visualization.png</file>
|
||||
<file>icons/64x64/view-refresh.png</file>
|
||||
<file>icons/64x64/vinyl.png</file>
|
||||
<file>icons/64x64/library-music.png</file>
|
||||
<file>icons/64x64/vlc.png</file>
|
||||
<file>icons/64x64/xine.png</file>
|
||||
<file>icons/64x64/zoom-in.png</file>
|
||||
@@ -189,7 +189,7 @@
|
||||
<file>icons/48x48/applications-internet.png</file>
|
||||
<file>icons/48x48/bluetooth.png</file>
|
||||
<file>icons/48x48/cdcase.png</file>
|
||||
<file>icons/48x48/cd.png</file>
|
||||
<file>icons/48x48/media-optical.png</file>
|
||||
<file>icons/48x48/configure.png</file>
|
||||
<file>icons/48x48/device-ipod-nano.png</file>
|
||||
<file>icons/48x48/device-ipod.png</file>
|
||||
@@ -241,11 +241,11 @@
|
||||
<file>icons/48x48/mcintosh.png</file>
|
||||
<file>icons/48x48/mcintosh-text.png</file>
|
||||
<file>icons/48x48/media-eject.png</file>
|
||||
<file>icons/48x48/media-pause.png</file>
|
||||
<file>icons/48x48/media-playback-pause.png</file>
|
||||
<file>icons/48x48/media-playlist-repeat.png</file>
|
||||
<file>icons/48x48/media-playlist-shuffle.png</file>
|
||||
<file>icons/48x48/media-play.png</file>
|
||||
<file>icons/48x48/media-stop.png</file>
|
||||
<file>icons/48x48/media-playback-start.png</file>
|
||||
<file>icons/48x48/media-playback-stop.png</file>
|
||||
<file>icons/48x48/media-skip-forward.png</file>
|
||||
<file>icons/48x48/media-skip-backward.png</file>
|
||||
<file>icons/48x48/media-seek-forward.png</file>
|
||||
@@ -266,7 +266,7 @@
|
||||
<file>icons/48x48/view-media-playlist.png</file>
|
||||
<file>icons/48x48/view-media-visualization.png</file>
|
||||
<file>icons/48x48/view-refresh.png</file>
|
||||
<file>icons/48x48/vinyl.png</file>
|
||||
<file>icons/48x48/library-music.png</file>
|
||||
<file>icons/48x48/vlc.png</file>
|
||||
<file>icons/48x48/xine.png</file>
|
||||
<file>icons/48x48/zoom-in.png</file>
|
||||
@@ -284,7 +284,7 @@
|
||||
<file>icons/32x32/applications-internet.png</file>
|
||||
<file>icons/32x32/bluetooth.png</file>
|
||||
<file>icons/32x32/cdcase.png</file>
|
||||
<file>icons/32x32/cd.png</file>
|
||||
<file>icons/32x32/media-optical.png</file>
|
||||
<file>icons/32x32/configure.png</file>
|
||||
<file>icons/32x32/device-ipod-nano.png</file>
|
||||
<file>icons/32x32/device-ipod.png</file>
|
||||
@@ -336,11 +336,11 @@
|
||||
<file>icons/32x32/mcintosh.png</file>
|
||||
<file>icons/32x32/mcintosh-text.png</file>
|
||||
<file>icons/32x32/media-eject.png</file>
|
||||
<file>icons/32x32/media-pause.png</file>
|
||||
<file>icons/32x32/media-playback-pause.png</file>
|
||||
<file>icons/32x32/media-playlist-repeat.png</file>
|
||||
<file>icons/32x32/media-playlist-shuffle.png</file>
|
||||
<file>icons/32x32/media-play.png</file>
|
||||
<file>icons/32x32/media-stop.png</file>
|
||||
<file>icons/32x32/media-playback-start.png</file>
|
||||
<file>icons/32x32/media-playback-stop.png</file>
|
||||
<file>icons/32x32/media-skip-forward.png</file>
|
||||
<file>icons/32x32/media-skip-backward.png</file>
|
||||
<file>icons/32x32/media-seek-forward.png</file>
|
||||
@@ -361,7 +361,7 @@
|
||||
<file>icons/32x32/view-media-playlist.png</file>
|
||||
<file>icons/32x32/view-media-visualization.png</file>
|
||||
<file>icons/32x32/view-refresh.png</file>
|
||||
<file>icons/32x32/vinyl.png</file>
|
||||
<file>icons/32x32/library-music.png</file>
|
||||
<file>icons/32x32/vlc.png</file>
|
||||
<file>icons/32x32/xine.png</file>
|
||||
<file>icons/32x32/zoom-in.png</file>
|
||||
@@ -379,7 +379,7 @@
|
||||
<file>icons/22x22/applications-internet.png</file>
|
||||
<file>icons/22x22/bluetooth.png</file>
|
||||
<file>icons/22x22/cdcase.png</file>
|
||||
<file>icons/22x22/cd.png</file>
|
||||
<file>icons/22x22/media-optical.png</file>
|
||||
<file>icons/22x22/configure.png</file>
|
||||
<file>icons/22x22/device-ipod-nano.png</file>
|
||||
<file>icons/22x22/device-ipod.png</file>
|
||||
@@ -431,11 +431,11 @@
|
||||
<file>icons/22x22/mcintosh.png</file>
|
||||
<file>icons/22x22/mcintosh-text.png</file>
|
||||
<file>icons/22x22/media-eject.png</file>
|
||||
<file>icons/22x22/media-pause.png</file>
|
||||
<file>icons/22x22/media-playback-pause.png</file>
|
||||
<file>icons/22x22/media-playlist-repeat.png</file>
|
||||
<file>icons/22x22/media-playlist-shuffle.png</file>
|
||||
<file>icons/22x22/media-play.png</file>
|
||||
<file>icons/22x22/media-stop.png</file>
|
||||
<file>icons/22x22/media-playback-start.png</file>
|
||||
<file>icons/22x22/media-playback-stop.png</file>
|
||||
<file>icons/22x22/media-skip-forward.png</file>
|
||||
<file>icons/22x22/media-skip-backward.png</file>
|
||||
<file>icons/22x22/media-seek-forward.png</file>
|
||||
@@ -456,7 +456,7 @@
|
||||
<file>icons/22x22/view-media-playlist.png</file>
|
||||
<file>icons/22x22/view-media-visualization.png</file>
|
||||
<file>icons/22x22/view-refresh.png</file>
|
||||
<file>icons/22x22/vinyl.png</file>
|
||||
<file>icons/22x22/library-music.png</file>
|
||||
<file>icons/22x22/vlc.png</file>
|
||||
<file>icons/22x22/xine.png</file>
|
||||
<file>icons/22x22/zoom-in.png</file>
|
||||
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 908 B After Width: | Height: | Size: 908 B |
|
Before Width: | Height: | Size: 921 B After Width: | Height: | Size: 921 B |
|
Before Width: | Height: | Size: 921 B After Width: | Height: | Size: 921 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 162 KiB After Width: | Height: | Size: 162 KiB |
BIN
data/icons/full/love.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
BIN
data/icons/full/subsonic.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
2
debian/control
vendored
@@ -58,7 +58,7 @@ Description: Audio player and music collection organizer
|
||||
- Edit tags on music files
|
||||
- Fetch tags from MusicBrainz
|
||||
- Album cover art from Lastfm, Musicbrainz, Discogs, Deezer and Tidal
|
||||
- Song lyrics from AudD, lyrics.ovh and lololyrics.com
|
||||
- Song lyrics from AudD, ChartLyrics, lyrics.ovh and lololyrics.com
|
||||
- Support for multiple backends
|
||||
- Audio analyzer
|
||||
- Audio equalizer
|
||||
|
||||
48
debian/copyright
vendored
@@ -17,6 +17,9 @@ Copyright: 2011, 2012, David Sansome <me@davidsansome.com>
|
||||
License: Apache-2.0
|
||||
|
||||
Files: src/core/main.h
|
||||
src/core/iconloader.cpp
|
||||
src/core/iconloader.h
|
||||
src/core/iconmapper.h
|
||||
src/config.h.in
|
||||
src/version.h.in
|
||||
src/context/contextview.cpp
|
||||
@@ -25,6 +28,8 @@ Files: src/core/main.h
|
||||
src/engine/enginetype.h
|
||||
src/engine/alsadevicefinder.cpp
|
||||
src/engine/alsadevicefinder.h
|
||||
src/engine/mmdevicefinder.cpp
|
||||
src/engine/mmdevicefinder.h
|
||||
src/engine/devicefinder.cpp
|
||||
src/engine/devicefinder.h
|
||||
src/engine/enginedevice.cpp
|
||||
@@ -33,6 +38,8 @@ Files: src/core/main.h
|
||||
src/engine/phononengine.h
|
||||
src/internet/internetservice.cpp
|
||||
src/internet/internetservice.h
|
||||
src/internet/internettabsview.cpp
|
||||
src/internet/internettabsview.h
|
||||
src/settings/backendsettingspage.cpp
|
||||
src/settings/backendsettingspage.h
|
||||
src/settings/scrobblersettingspage.cpp
|
||||
@@ -72,28 +79,50 @@ Files: src/core/main.cpp
|
||||
src/core/player.h
|
||||
src/core/song.cpp
|
||||
src/core/song.h
|
||||
src/core/songloader.cpp
|
||||
src/core/songloader.h
|
||||
src/core/urlhandler.cpp
|
||||
src/core/urlhandler.h
|
||||
src/core/utilities.cpp
|
||||
src/core/utilities.h
|
||||
src/core/iconloader.cpp
|
||||
src/core/iconloader.h
|
||||
src/core/network.cpp
|
||||
src/core/network.h
|
||||
src/core/filesystemmusicstorage.cpp
|
||||
src/core/filesystemmusicstorage.h
|
||||
src/core/stylesheetloader.cpp
|
||||
src/core/stylesheetloader.h
|
||||
src/engine/gstenginepipeline.cpp
|
||||
src/engine/gstenginepipeline.h
|
||||
src/engine/vlcengine.cpp
|
||||
src/engine/vlcengine.h
|
||||
src/collection/collectionwatcher.cpp
|
||||
src/collection/collectionwatcher.h
|
||||
src/collection/collectionbackend.cpp
|
||||
src/collection/collectionbackend.h
|
||||
src/collection/collectionmodel.cpp
|
||||
src/collection/collectionmodel.h
|
||||
src/context/contextalbumsmodel.cpp
|
||||
src/context/contextalbumsview.cpp
|
||||
src/context/contextalbumsmodel.h
|
||||
src/context/contextalbumsview.h
|
||||
src/widgets/playingwidget.cpp
|
||||
src/widgets/playingwidget.h
|
||||
src/widgets/osdpretty.cpp
|
||||
src/widgets/osdpretty.h
|
||||
src/dialogs/about.cpp
|
||||
src/dialogs/about.h
|
||||
src/playlist/playlist.cpp
|
||||
src/playlist/playlist.h
|
||||
src/playlist/playlistitem.cpp
|
||||
src/playlist/playlistitem.h
|
||||
src/playlist/playlistdelegates.cpp
|
||||
src/playlist/playlistdelegates.h
|
||||
src/playlist/playlistbackend.cpp
|
||||
src/playlist/playlistbackend.h
|
||||
src/playlist/playlistview.cpp
|
||||
src/playlist/playlistview.h
|
||||
src/playlist/songplaylistitem.cpp
|
||||
src/playlist/songplaylistitem.h
|
||||
src/internet/internetplaylistitem.cpp
|
||||
src/internet/internetsearch.cpp
|
||||
src/internet/internetsearch.h
|
||||
@@ -101,6 +130,10 @@ Files: src/core/main.cpp
|
||||
src/internet/internetsearchview.h
|
||||
src/internet/internetservices.cpp
|
||||
src/internet/internetservices.h
|
||||
src/internet/internetsongsview.cpp
|
||||
src/internet/internetsongsview.h
|
||||
src/internet/internetcollectionview.cpp
|
||||
src/internet/internetcollectionview.h
|
||||
ext/libstrawberry-tagreader/tagreader.cpp
|
||||
ext/libstrawberry-tagreader/tagreader.h
|
||||
src/device/devicemanager.cpp
|
||||
@@ -113,10 +146,16 @@ Files: src/core/main.cpp
|
||||
src/device/deviceview.h
|
||||
src/device/connecteddevice.cpp
|
||||
src/device/connecteddevice.h
|
||||
src/device/mtpconnection.cpp
|
||||
src/device/mtpconnection.h
|
||||
src/device/mtpdevice.cpp
|
||||
src/device/mtpdevice.h
|
||||
src/globalshortcuts/globalshortcuts.cpp
|
||||
src/globalshortcuts/globalshortcuts.h
|
||||
src/settings/shortcutssettingspage.cpp
|
||||
src/settings/shortcutssettingspage.h
|
||||
src/settings/appearancesettingspage.cpp
|
||||
src/settings/appearancesettingspage.h
|
||||
src/organise/organise.cpp
|
||||
src/organise/organise.h
|
||||
src/organise/organisedialog.cpp
|
||||
@@ -125,8 +164,10 @@ Files: src/core/main.cpp
|
||||
src/organise/organiseerrordialog.h
|
||||
src/transcoder/transcoder.cpp
|
||||
src/transcoder/transcoder.h
|
||||
src/musicbrainz/musicbrainzclient.cpp
|
||||
src/musicbrainz/musicbrainzclient.h
|
||||
Copyright: 2010, 2012-2014 David Sansome <me@davidsansome.com>
|
||||
2012-2014, 2017-2018 Jonas Kvinge <jonas@jkvinge.net>
|
||||
2012-2014, 2017-2019 Jonas Kvinge <jonas@jkvinge.net>
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/engine/enginebase.cpp
|
||||
@@ -262,6 +303,7 @@ Files: src/internet/localredirectserver.cpp
|
||||
src/internet/localredirectserver.h
|
||||
Copyright: 2012, 2014, John Maguire <john.maguire@gmail.com>
|
||||
2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
2018-2019, Jonas Kvinge <jonas@jkvinge.net>
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/transcoder/transcoderoptionsopus.cpp
|
||||
|
||||
9
dist/macos/macdeploy.py
vendored
@@ -304,10 +304,9 @@ def CopyLibrary(path):
|
||||
new_path = os.path.join(frameworks_dir, os.path.basename(path))
|
||||
#args = ['cp', path, new_path]
|
||||
args = ['ditto', '--arch=i386', '--arch=x86_64', path, new_path]
|
||||
commands.append(args)
|
||||
commands.append(['chmod', '+w', new_path])
|
||||
LOGGER.info("Copying library '%s'", path)
|
||||
commands.append(args)
|
||||
args = ['chmod', 'u+w', new_path]
|
||||
commands.append(args)
|
||||
return new_path
|
||||
|
||||
|
||||
@@ -318,9 +317,8 @@ def CopyPlugin(path, subdir):
|
||||
#args = ['cp', path, new_path]
|
||||
args = ['ditto', '--arch=i386', '--arch=x86_64', path, new_path]
|
||||
commands.append(args)
|
||||
commands.append(['chmod', '+w', new_path])
|
||||
LOGGER.info("Copying plugin '%s'", path)
|
||||
args = ['chmod', 'u+w', new_path]
|
||||
commands.append(args)
|
||||
return new_path
|
||||
|
||||
def CopyFramework(path):
|
||||
@@ -351,6 +349,7 @@ def CopyFramework(src_binary):
|
||||
|
||||
commands.append(['mkdir', '-p', dest_dir])
|
||||
commands.append(['cp', src_binary, dest_binary])
|
||||
commands.append(['chmod', '+w', dest_binary])
|
||||
|
||||
# Copy special files from various places:
|
||||
# QtCore has Resources/qt_menu.nib (copy to app's Resources)
|
||||
|
||||
2
dist/man/strawberry.1
vendored
@@ -27,7 +27,7 @@ Features:
|
||||
.br
|
||||
- Album cover art from Lastfm, Musicbrainz, Discogs, Deezer and Tidal
|
||||
.br
|
||||
- Song lyrics from AudD, lyrics.ovh and lololyrics.com
|
||||
- Song lyrics from AudD, ChartLyrics, lyrics.ovh and lololyrics.com
|
||||
.br
|
||||
- Support for multiple backends
|
||||
.br
|
||||
|
||||
4
dist/rpm/strawberry.spec.in
vendored
@@ -44,7 +44,9 @@ BuildRequires: pkgconfig(dbus-1)
|
||||
BuildRequires: pkgconfig(gnutls)
|
||||
BuildRequires: pkgconfig(alsa)
|
||||
BuildRequires: pkgconfig(protobuf)
|
||||
%if ! 0%{?centos}
|
||||
BuildRequires: pkgconfig(sqlite3) >= 3.9
|
||||
%endif
|
||||
%if ! 0%{?centos} && ! 0%{?mageia}
|
||||
BuildRequires: pkgconfig(taglib)
|
||||
%endif
|
||||
@@ -103,7 +105,7 @@ Features:
|
||||
- Edit tags on music files
|
||||
- Fetch tags from MusicBrainz
|
||||
- Album cover art from Last.fm, Musicbrainz, Discogs, Deezer and Tidal
|
||||
- Song lyrics from AudD, lyrics.ovh and lololyrics.com
|
||||
- Song lyrics from AudD, ChartLyrics, lyrics.ovh and lololyrics.com
|
||||
- Support for multiple backends
|
||||
- Audio analyzer
|
||||
- Audio equalizer
|
||||
|
||||
114
dist/scripts/gen-icons-resource.sh
vendored
@@ -1,114 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
sizes="128x128 64x64 48x48 32x32 22x22"
|
||||
|
||||
#
|
||||
|
||||
for i in full/*
|
||||
do
|
||||
source=$i
|
||||
file=`basename $i`
|
||||
|
||||
id=`identify "$i"` || exit 1
|
||||
if [ "$id" = "" ] ; then
|
||||
echo "ERROR: Cannot determine format and geometry for image: \"$i\"."
|
||||
continue
|
||||
fi
|
||||
g=`echo $id | awk '{print $3}'` || exit 1
|
||||
if [ "$g" = "" ] ; then
|
||||
echo "ERROR: Cannot determine geometry for image: \"$i\"."
|
||||
continue
|
||||
fi
|
||||
|
||||
# Geometry can be 563x144+0+0 or 75x98
|
||||
# we need to get rid of the plus (+) and the x characters:
|
||||
w=`echo $g | sed 's/[^0-9]/ /g' | awk '{print $1}'` || exit 1
|
||||
if [ "$w" = "" ] ; then
|
||||
echo "ERROR: Cannot determine width for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
h=`echo $g | sed 's/[^0-9]/ /g' | awk '{print $2}'` || exit 1
|
||||
if [ "$h" = "" ] ; then
|
||||
echo "ERROR: Cannot determine height for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
|
||||
for x in $sizes
|
||||
do
|
||||
|
||||
dest="$x/$file"
|
||||
if [ -f $dest ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
x_w=$(echo $x | cut -d 'x' -f1)
|
||||
x_h=$(echo $x | cut -d 'x' -f2)
|
||||
|
||||
if [ "$w" -lt "$x_w" ] || [ "$h" -lt "$x_h" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "convert -verbose -resize $x $source $dest"
|
||||
convert -verbose -resize $x $source $dest
|
||||
|
||||
done
|
||||
done
|
||||
|
||||
|
||||
for i in $sizes
|
||||
do
|
||||
for x in $i/*
|
||||
do
|
||||
file=`basename $x`
|
||||
if ! [ -f "full/$file" ]; then
|
||||
echo "Warning: full/$file does not exist, but $x exists."
|
||||
fi
|
||||
|
||||
id=`identify "$x"` || exit 1
|
||||
if [ "$id" = "" ] ; then
|
||||
echo "ERROR: Cannot determine format and geometry for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
g=`echo $id | awk '{print $3}'` || exit 1
|
||||
if [ "$g" = "" ] ; then
|
||||
echo "ERROR: Cannot determine geometry for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
|
||||
# Geometry can be 563x144+0+0 or 75x98
|
||||
# we need to get rid of the plus (+) and the x characters:
|
||||
w=`echo $g | sed 's/[^0-9]/ /g' | awk '{print $1}'` || exit 1
|
||||
if [ "$w" = "" ] ; then
|
||||
echo "ERROR: Cannot determine width for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
h=`echo $g | sed 's/[^0-9]/ /g' | awk '{print $2}'` || exit 1
|
||||
if [ "$h" = "" ] ; then
|
||||
echo "ERROR: Cannot determine height for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! [ "${h}x${w}" = "$i" ]; then
|
||||
echo "Warning: $x is not $i, but ${h}x${w}!"
|
||||
fi
|
||||
|
||||
done
|
||||
done
|
||||
|
||||
file="../icons.qrc"
|
||||
rm -rf "$file"
|
||||
echo "<RCC>" >>$file
|
||||
echo "<qresource prefix=\"/\">" >>$file
|
||||
|
||||
for i in full $sizes
|
||||
do
|
||||
for x in $i/*
|
||||
do
|
||||
f=`basename $x`
|
||||
echo " <file>icons/$i/$f</file>" >>$file
|
||||
done
|
||||
done
|
||||
|
||||
echo "</qresource>" >>$file
|
||||
echo "</RCC>" >>$file
|
||||
|
||||
1
dist/scripts/maketarball.sh.in
vendored
@@ -24,6 +24,7 @@ tar -cJf $name-$version.tar.xz \
|
||||
--exclude=".directory" \
|
||||
--exclude="*.spec" \
|
||||
--exclude="*.nsi" \
|
||||
--exclude="$root/.github" \
|
||||
--exclude="$root/Dockerfile" \
|
||||
--exclude="$root/.travis.yml" \
|
||||
--exclude="$root/CMakeLists.txt.user" \
|
||||
|
||||
137
dist/scripts/verify-icons.sh
vendored
Executable file
@@ -0,0 +1,137 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Strawberry Music Player
|
||||
# Copyright 2019, 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/>.
|
||||
|
||||
sizes="128x128 64x64 48x48 32x32 22x22"
|
||||
|
||||
#
|
||||
|
||||
#for i in full/*
|
||||
#do
|
||||
# source=$i
|
||||
# file=`basename $i`
|
||||
|
||||
# id=`identify "$i"` || exit 1
|
||||
# if [ "$id" = "" ] ; then
|
||||
# echo "ERROR: Cannot determine format and geometry for image: \"$i\"."
|
||||
# continue
|
||||
# fi
|
||||
# g=`echo $id | awk '{print $3}'` || exit 1
|
||||
# if [ "$g" = "" ] ; then
|
||||
# echo "ERROR: Cannot determine geometry for image: \"$i\"."
|
||||
# continue
|
||||
# fi
|
||||
|
||||
# Geometry can be 563x144+0+0 or 75x98
|
||||
# we need to get rid of the plus (+) and the x characters:
|
||||
# w=`echo $g | sed 's/[^0-9]/ /g' | awk '{print $1}'` || exit 1
|
||||
# if [ "$w" = "" ] ; then
|
||||
# echo "ERROR: Cannot determine width for image: \"$x\"."
|
||||
# continue
|
||||
# fi
|
||||
# h=`echo $g | sed 's/[^0-9]/ /g' | awk '{print $2}'` || exit 1
|
||||
# if [ "$h" = "" ] ; then
|
||||
# echo "ERROR: Cannot determine height for image: \"$x\"."
|
||||
# continue
|
||||
# fi
|
||||
|
||||
# for x in $sizes
|
||||
# do
|
||||
|
||||
# dest="$x/$file"
|
||||
# if [ -f $dest ]; then
|
||||
# continue
|
||||
# fi
|
||||
|
||||
# x_w=$(echo $x | cut -d 'x' -f1)
|
||||
# x_h=$(echo $x | cut -d 'x' -f2)
|
||||
|
||||
# if [ "$w" -lt "$x_w" ] || [ "$h" -lt "$x_h" ]; then
|
||||
# continue
|
||||
# fi
|
||||
|
||||
#echo "convert -verbose -resize $x $source $dest"
|
||||
#convert -verbose -resize $x $source $dest
|
||||
|
||||
# done
|
||||
#done
|
||||
|
||||
|
||||
for i in $sizes
|
||||
do
|
||||
for x in $i/*
|
||||
do
|
||||
file=`basename $x`
|
||||
|
||||
for y in $sizes
|
||||
do
|
||||
if [ "$y" = "$i" ]; then
|
||||
continue
|
||||
fi
|
||||
if ! [ -f "$y/$file" ]; then
|
||||
echo "Warning: $y/$file does not exist, but $x exists."
|
||||
fi
|
||||
done
|
||||
|
||||
id=`identify "$x"` || exit 1
|
||||
if [ "$id" = "" ] ; then
|
||||
echo "ERROR: Cannot determine format and geometry for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
g=`echo $id | awk '{print $3}'` || exit 1
|
||||
if [ "$g" = "" ] ; then
|
||||
echo "ERROR: Cannot determine geometry for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
|
||||
# Geometry can be 563x144+0+0 or 75x98
|
||||
# we need to get rid of the plus (+) and the x characters:
|
||||
w=`echo $g | sed 's/[^0-9]/ /g' | awk '{print $1}'` || exit 1
|
||||
if [ "$w" = "" ] ; then
|
||||
echo "ERROR: Cannot determine width for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
h=`echo $g | sed 's/[^0-9]/ /g' | awk '{print $2}'` || exit 1
|
||||
if [ "$h" = "" ] ; then
|
||||
echo "ERROR: Cannot determine height for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! [ "${h}x${w}" = "$i" ]; then
|
||||
echo "Warning: $x is not $i, but ${h}x${w}!"
|
||||
fi
|
||||
|
||||
done
|
||||
done
|
||||
|
||||
#file="../icons.qrc"
|
||||
#rm -rf "$file"
|
||||
#echo "<RCC>" >>$file
|
||||
#echo "<qresource prefix=\"/\">" >>$file
|
||||
|
||||
#for i in full $sizes
|
||||
#do
|
||||
# for x in $i/*
|
||||
# do
|
||||
# f=`basename $x`
|
||||
# echo " <file>icons/$i/$f</file>" >>$file
|
||||
# done
|
||||
#done
|
||||
|
||||
#echo "</qresource>" >>$file
|
||||
#echo "</RCC>" >>$file
|
||||
|
||||
@@ -15,14 +15,12 @@
|
||||
<translation type="qt">strawberry</translation>
|
||||
<description>
|
||||
<p>
|
||||
Strawberry is a music player and music collection organizer.
|
||||
It is a fork of Clementine. The name is inspired by the band Strawbs.
|
||||
Strawberry is a music player and music collection organizer. It is a fork of Clementine released in 2018 aimed at music collectors, audio enthusiasts and audiophiles. The name is inspired by the band Strawbs. It's based on a heavily modified version of Clementine created in 2012-2013. It's written in C++ and Qt 5.
|
||||
</p>
|
||||
<p>Features:</p>
|
||||
<ul>
|
||||
<li>Play and organize music</li>
|
||||
<li>Supports WAV, FLAC, WavPack, DSF, DSDIFF, Ogg FLAC, Ogg Vorbis, Ogg Opus, Ogg Speex, MPC, TrueAudio, AIFF, MP4, MP3, ASF and Monkey's Audio.</li>
|
||||
<li>Audio CD playback</li>
|
||||
<li>Supports most popular audio formats and CD playback</li>
|
||||
<li>Native desktop notifications</li>
|
||||
<li>Playlists in multiple formats</li>
|
||||
<li>Advanced audio output and device configuration for bit-perfect playback on Linux</li>
|
||||
@@ -31,8 +29,7 @@
|
||||
<li>Album cover art from Last.fm, Musicbrainz and Discogs</li>
|
||||
<li>Song lyrics from AudD, lyrics.ovh and lololyrics.com</li>
|
||||
<li>Support for multiple backends</li>
|
||||
<li>Audio analyzer</li>
|
||||
<li>Audio equalizer</li>
|
||||
<li>Audio analyzer and equalizer</li>
|
||||
<li>Transfer music to iPod, iPhone, MTP or mass-storage USB player</li>
|
||||
<li>Streaming support for Tidal, Qobuz and Subsonic</li>
|
||||
<li>Scrobbler with support for Last.fm, Libre.fm and ListenBrainz</li>
|
||||
|
||||
43
dist/windows/strawberry.nsi.in
vendored
@@ -68,13 +68,12 @@ SetCompressor /SOLID lzma
|
||||
!include "MUI2.nsh"
|
||||
!include "FileAssociation.nsh"
|
||||
!include "Capabilities.nsh"
|
||||
!include LogicLib.nsh
|
||||
!include x64.nsh
|
||||
|
||||
!define MUI_ICON "strawberry.ico"
|
||||
|
||||
!define MUI_COMPONENTSPAGE_SMALLDESC
|
||||
;!define MUI_FINISHPAGE_RUN
|
||||
;!define MUI_FINISHPAGE_RUN_TEXT "Run Strawberry"
|
||||
;!define MUI_FINISHPAGE_RUN_FUNCTION "RunStrawberry"
|
||||
|
||||
; Installer pages
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
@@ -144,16 +143,14 @@ Function .onInit
|
||||
|
||||
FunctionEnd
|
||||
|
||||
;Function RunStrawberry
|
||||
;ShellExecAsUser::ShellExecAsUser "" "$INSTDIR/strawberry.exe" ""
|
||||
;FunctionEnd
|
||||
|
||||
Section "Delete old files" oldfiles
|
||||
SectionEnd
|
||||
|
||||
Section "Strawberry" Strawberry
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
nsExec::Exec '"$INSTDIR\killproc.exe" strawberry.exe'
|
||||
|
||||
File "strawberry.exe"
|
||||
File "strawberry-tagreader.exe"
|
||||
File "strawberry.ico"
|
||||
@@ -199,7 +196,7 @@ Section "Strawberry" Strawberry
|
||||
File "libpcre-1.dll"
|
||||
File "libpcre2-16-0.dll"
|
||||
File "libpng16-16.dll"
|
||||
File "libprotobuf-20.dll"
|
||||
File "libprotobuf-22.dll"
|
||||
File "libsoup-2.4-1.dll"
|
||||
File "libspeex-1.dll"
|
||||
File "libsqlite3-0.dll"
|
||||
@@ -243,6 +240,8 @@ Section "Strawberry" Strawberry
|
||||
File "libxine-2.dll"
|
||||
!endif
|
||||
|
||||
File "killproc.exe"
|
||||
|
||||
; Register Strawberry with Default Programs
|
||||
Var /GLOBAL AppIcon
|
||||
Var /GLOBAL AppExe
|
||||
@@ -318,6 +317,7 @@ Section "Gstreamer plugins" gstreamer-plugins
|
||||
File "/oname=libgsttypefindfunctions.dll" "gstreamer-plugins\libgsttypefindfunctions.dll"
|
||||
File "/oname=libgstgio.dll" "gstreamer-plugins\libgstgio.dll"
|
||||
File "/oname=libgstdirectsound.dll" "gstreamer-plugins\libgstdirectsound.dll"
|
||||
File "/oname=libgstwasapi.dll" "gstreamer-plugins\libgstwasapi.dll"
|
||||
File "/oname=libgstapetag.dll" "gstreamer-plugins\libgstapetag.dll"
|
||||
File "/oname=libgsticydemux.dll" "gstreamer-plugins\libgsticydemux.dll"
|
||||
File "/oname=libgstid3demux.dll" "gstreamer-plugins\libgstid3demux.dll"
|
||||
@@ -405,28 +405,8 @@ Section "Uninstaller"
|
||||
SectionEnd
|
||||
|
||||
Section "Uninstall"
|
||||
; Kill strawberry.exe if it's running
|
||||
; This calling convention is retarded...
|
||||
;StrCpy $0 "strawberry.exe"
|
||||
;KillProc::FindProcesses
|
||||
;StrCmp $1 "-1" wooops
|
||||
|
||||
;StrCmp $0 "0" completed
|
||||
|
||||
;DetailPrint "Killing running strawberry.exe..."
|
||||
|
||||
;StrCpy $0 "strawberry.exe"
|
||||
;KillProc::KillProcesses
|
||||
;StrCmp $1 "-1" wooops
|
||||
|
||||
;Sleep 2000
|
||||
;Goto completed
|
||||
|
||||
;wooops:
|
||||
;DetailPrint "-> Error: Something went wrong while killing running strawberry.exe"
|
||||
;Abort
|
||||
|
||||
;completed:
|
||||
nsExec::Exec '"$INSTDIR\killproc.exe" strawberry.exe'
|
||||
|
||||
; Delete all the files
|
||||
|
||||
@@ -475,7 +455,7 @@ Section "Uninstall"
|
||||
Delete "$INSTDIR\libpcre-1.dll"
|
||||
Delete "$INSTDIR\libpcre2-16-0.dll"
|
||||
Delete "$INSTDIR\libpng16-16.dll"
|
||||
Delete "$INSTDIR\libprotobuf-20.dll"
|
||||
Delete "$INSTDIR\libprotobuf-22.dll"
|
||||
Delete "$INSTDIR\libsoup-2.4-1.dll"
|
||||
Delete "$INSTDIR\libspeex-1.dll"
|
||||
Delete "$INSTDIR\libsqlite3-0.dll"
|
||||
@@ -545,6 +525,7 @@ Section "Uninstall"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgsttypefindfunctions.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstgio.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstwasapi.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstapetag.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgsticydemux.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstid3demux.dll"
|
||||
@@ -600,12 +581,14 @@ Section "Uninstall"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_post_visualizations.dll"
|
||||
!endif
|
||||
|
||||
Delete "$INSTDIR\killproc.exe"
|
||||
Delete "$INSTDIR\Uninstall.exe"
|
||||
|
||||
; Remove the installation folders.
|
||||
RMDir "$INSTDIR\platforms"
|
||||
RMDir "$INSTDIR\sqldrivers"
|
||||
RMDir "$INSTDIR\imageformats"
|
||||
RMDir "$INSTDIR\gio-modules"
|
||||
RMDir "$INSTDIR\gstreamer-plugins"
|
||||
RMDir "$INSTDIR\xine-plugins"
|
||||
RMDir "$INSTDIR"
|
||||
|
||||
@@ -2,10 +2,10 @@ cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -U__STRICT_ANSI__ -Wall -Woverloaded-virtual -Wno-sign-compare -fpermissive")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -U__STRICT_ANSI__ -Wall -Wextra -Wpedantic -Woverloaded-virtual -fpermissive")
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wpedantic")
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
@@ -5,10 +5,10 @@ include_directories(${CMAKE_SOURCE_DIR}/src)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -U__STRICT_ANSI__ -Wall -Woverloaded-virtual -Wno-sign-compare -fpermissive")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -U__STRICT_ANSI__ -Wall -Wextra -Wpedantic -Woverloaded-virtual -fpermissive")
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wpedantic")
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
|
||||
endif()
|
||||
|
||||
set(SOURCES
|
||||
|
||||
@@ -158,11 +158,13 @@ WorkerPool<HandlerType>::WorkerPool(QObject *parent)
|
||||
: _WorkerPoolBase(parent),
|
||||
next_worker_(0),
|
||||
next_id_(0) {
|
||||
worker_count_ = qBound(1, QThread::idealThreadCount() / 2, 2);
|
||||
|
||||
worker_count_ = qBound(1, QThread::idealThreadCount() / 2, 4);
|
||||
local_server_name_ = qApp->applicationName().toLower();
|
||||
|
||||
if (local_server_name_.isEmpty())
|
||||
local_server_name_ = "workerpool";
|
||||
|
||||
}
|
||||
|
||||
template <typename HandlerType>
|
||||
|
||||
@@ -7,10 +7,10 @@ include_directories(${CMAKE_BINARY_DIR}/src)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -U__STRICT_ANSI__ -Wall -Woverloaded-virtual -Wno-sign-compare -fpermissive")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -U__STRICT_ANSI__ -Wall -Wextra -Wpedantic -Woverloaded-virtual -fpermissive")
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wpedantic")
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
|
||||
endif()
|
||||
|
||||
set(MESSAGES
|
||||
|
||||
@@ -290,7 +290,7 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
|
||||
if (!map["APIC"].isEmpty()) song->set_art_automatic(kEmbeddedCover);
|
||||
|
||||
// Find a suitable comment tag. For now we ignore iTunNORM comments.
|
||||
for (int i = 0; i < map["COMM"].size(); ++i) {
|
||||
for (uint i = 0; i < map["COMM"].size(); ++i) {
|
||||
const TagLib::ID3v2::CommentsFrame *frame = dynamic_cast<const TagLib::ID3v2::CommentsFrame*>(map["COMM"][i]);
|
||||
|
||||
if (frame && TStringToQString(frame->description()) != "iTunNORM") {
|
||||
@@ -300,7 +300,7 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
|
||||
}
|
||||
|
||||
// Parse FMPS frames
|
||||
for (int i = 0; i < map["TXXX"].size(); ++i) {
|
||||
for (uint i = 0; i < map["TXXX"].size(); ++i) {
|
||||
const TagLib::ID3v2::UserTextIdentificationFrame *frame = dynamic_cast<const TagLib::ID3v2::UserTextIdentificationFrame*>(map["TXXX"][i]);
|
||||
|
||||
if (frame && frame->description().startsWith("FMPS_")) {
|
||||
@@ -836,7 +836,7 @@ QByteArray TagReader::LoadEmbeddedAPEArt(const TagLib::APE::ItemListMap &map) co
|
||||
TagLib::ByteVector data = it->second.binaryData();
|
||||
|
||||
int pos = data.find('\0') + 1;
|
||||
if ((pos > 0) && (pos < data.size())) {
|
||||
if ((pos > 0) && ((uint)pos < data.size())) {
|
||||
ret = QByteArray(data.data() + pos, data.size() - pos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ include_directories(${CMAKE_BINARY_DIR}/src)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -U__STRICT_ANSI__ -Wall -Woverloaded-virtual -Wno-sign-compare -fpermissive")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -U__STRICT_ANSI__ -Wall -Wextra -Wpedantic -Woverloaded-virtual -fpermissive")
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wpedantic")
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
|
||||
endif()
|
||||
|
||||
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: strawberry
|
||||
version: '0.6.4+git'
|
||||
version: '0.6.7+git'
|
||||
summary: music player and collection organizer
|
||||
description: |
|
||||
Strawberry is a music player and collection organizer.
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -U__STRICT_ANSI__ -Wall -Woverloaded-virtual -Wno-sign-compare -fpermissive")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -U__STRICT_ANSI__ -Wall -Wextra -Wpedantic -Woverloaded-virtual -fpermissive")
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wpedantic")
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
|
||||
endif()
|
||||
|
||||
option(BUILD_WERROR "Build with -Werror" OFF)
|
||||
@@ -44,12 +44,11 @@ add_definitions(-DQT_NO_URL_CAST_FROM_STRING)
|
||||
add_definitions(-DBOOST_BIND_NO_PLACEHOLDERS)
|
||||
|
||||
include_directories(${CMAKE_BINARY_DIR})
|
||||
include_directories(${GLIB_INCLUDE_DIRS})
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
include_directories(${GLIBCONFIG_INCLUDE_DIRS})
|
||||
include_directories(${GLIB_INCLUDE_DIRS})
|
||||
include_directories(${GOBJECT_INCLUDE_DIRS})
|
||||
include_directories(${GNUTLS_INCLUDE_DIR})
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
include_directories(${CHROMAPRINT_INCLUDE_DIRS})
|
||||
|
||||
if (X11_FOUND)
|
||||
include_directories(${X11_INCLUDE_DIR})
|
||||
@@ -58,16 +57,31 @@ endif(X11_FOUND)
|
||||
if(HAVE_GSTREAMER)
|
||||
link_directories(${GSTREAMER_LIBRARY_DIRS})
|
||||
include_directories(${GSTREAMER_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_APP_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_AUDIO_INCLUDE_DIRS})
|
||||
link_directories(${GSTREAMER_BASE_LIBRARY_DIRS})
|
||||
include_directories(${GSTREAMER_BASE_INCLUDE_DIRS})
|
||||
link_directories(${GSTREAMER_APP_LIBRARY_DIRS})
|
||||
include_directories(${GSTREAMER_APP_INCLUDE_DIRS})
|
||||
link_directories(${GSTREAMER_AUDIO_LIBRARY_DIRS})
|
||||
include_directories(${GSTREAMER_AUDIO_INCLUDE_DIRS})
|
||||
link_directories(${GSTREAMER_TAG_LIBRARY_DIRS})
|
||||
include_directories(${GSTREAMER_TAG_INCLUDE_DIRS})
|
||||
link_directories(${GSTREAMER_PBUTILS_LIBRARY_DIRS})
|
||||
include_directories(${GSTREAMER_PBUTILS_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif(HAVE_GSTREAMER)
|
||||
|
||||
if(HAVE_PHONON)
|
||||
include_directories(${PHONON_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif(HAVE_PHONON)
|
||||
|
||||
if(HAVE_CHROMAPRINT)
|
||||
link_directories(${CHROMAPRINT_LIBRARY_DIRS})
|
||||
include_directories(${CHROMAPRINT_INCLUDE_DIRS})
|
||||
endif(HAVE_CHROMAPRINT)
|
||||
|
||||
if(HAVE_AUDIOCD)
|
||||
link_directories(${LIBCDIO_LIBRARY_DIRS})
|
||||
include_directories(${LIBCDIO_INCLUDE_DIRS})
|
||||
endif(HAVE_AUDIOCD)
|
||||
|
||||
link_directories(${TAGLIB_LIBRARY_DIRS})
|
||||
include_directories(${TAGLIB_INCLUDE_DIRS})
|
||||
@@ -77,6 +91,11 @@ link_directories(${SINGLECOREAPPLICATION_LIBRARY_DIRS})
|
||||
include_directories(${SINGLEAPPLICATION_INCLUDE_DIRS})
|
||||
include_directories(${SINGLECOREAPPLICATION_INCLUDE_DIRS})
|
||||
|
||||
if(HAVE_LIBMTP)
|
||||
link_directories(${LIBMTP_LIBRARY_DIRS})
|
||||
include_directories(${LIBMTP_INCLUDE_DIRS})
|
||||
endif(HAVE_LIBMTP)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/ext/libstrawberry-common)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/ext/libstrawberry-tagreader)
|
||||
include_directories(${CMAKE_BINARY_DIR}/ext/libstrawberry-tagreader)
|
||||
@@ -121,7 +140,7 @@ set(SOURCES
|
||||
|
||||
engine/enginetype.cpp
|
||||
engine/enginebase.cpp
|
||||
engine/enginedevice.cpp
|
||||
engine/devicefinders.cpp
|
||||
engine/devicefinder.cpp
|
||||
|
||||
analyzer/fht.cpp
|
||||
@@ -216,6 +235,7 @@ set(SOURCES
|
||||
lyrics/auddlyricsprovider.cpp
|
||||
lyrics/ovhlyricsprovider.cpp
|
||||
lyrics/lololyricsprovider.cpp
|
||||
lyrics/chartlyricsprovider.cpp
|
||||
|
||||
settings/settingsdialog.cpp
|
||||
settings/settingspage.cpp
|
||||
@@ -315,7 +335,7 @@ set(HEADERS
|
||||
core/mimedata.h
|
||||
|
||||
engine/enginebase.h
|
||||
engine/enginedevice.h
|
||||
engine/devicefinders.h
|
||||
|
||||
analyzer/analyzerbase.h
|
||||
analyzer/analyzercontainer.h
|
||||
@@ -400,6 +420,7 @@ set(HEADERS
|
||||
lyrics/auddlyricsprovider.h
|
||||
lyrics/ovhlyricsprovider.h
|
||||
lyrics/lololyricsprovider.h
|
||||
lyrics/chartlyricsprovider.h
|
||||
|
||||
settings/settingsdialog.h
|
||||
settings/settingspage.h
|
||||
@@ -877,6 +898,7 @@ endif()
|
||||
optional_source(WIN32
|
||||
SOURCES
|
||||
engine/directsounddevicefinder.cpp
|
||||
engine/mmdevicefinder.cpp
|
||||
widgets/osd_win.cpp
|
||||
core/windows7thumbbar.cpp
|
||||
HEADERS
|
||||
@@ -1068,7 +1090,7 @@ if(HAVE_GIO)
|
||||
endif(HAVE_GIO)
|
||||
|
||||
if(HAVE_AUDIOCD)
|
||||
target_link_libraries(strawberry_lib ${CDIO_LIBRARIES})
|
||||
target_link_libraries(strawberry_lib ${LIBCDIO_LIBRARIES})
|
||||
endif(HAVE_AUDIOCD)
|
||||
|
||||
if(HAVE_IMOBILEDEVICE)
|
||||
|
||||
@@ -72,7 +72,7 @@ void Analyzer::Base::showEvent(QShowEvent*) { timer_.start(timeout(), this); }
|
||||
void Analyzer::Base::transform(Scope& scope) {
|
||||
|
||||
QVector<float> aux(fht_->size());
|
||||
if (aux.size() >= scope.size()) {
|
||||
if ((long unsigned int)aux.size() >= scope.size()) {
|
||||
std::copy(scope.begin(), scope.end(), aux.begin());
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -59,7 +59,6 @@ AnalyzerContainer::AnalyzerContainer(QWidget *parent)
|
||||
context_menu_framerate_(new QMenu(tr("Framerate"), this)),
|
||||
group_(new QActionGroup(this)),
|
||||
group_framerate_(new QActionGroup(this)),
|
||||
visualisation_action_(nullptr),
|
||||
double_click_timer_(new QTimer(this)),
|
||||
ignore_next_click_(false),
|
||||
current_analyzer_(nullptr),
|
||||
@@ -88,7 +87,6 @@ AnalyzerContainer::AnalyzerContainer(QWidget *parent)
|
||||
group_->addAction(disable_action_);
|
||||
|
||||
context_menu_->addSeparator();
|
||||
// Visualisation action gets added in SetActions
|
||||
|
||||
double_click_timer_->setSingleShot(true);
|
||||
double_click_timer_->setInterval(250);
|
||||
@@ -98,26 +96,11 @@ AnalyzerContainer::AnalyzerContainer(QWidget *parent)
|
||||
|
||||
}
|
||||
|
||||
void AnalyzerContainer::SetActions(QAction *visualisation) {
|
||||
visualisation_action_ = visualisation;
|
||||
context_menu_->addAction(visualisation_action_);
|
||||
}
|
||||
|
||||
void AnalyzerContainer::mouseReleaseEvent(QMouseEvent *e) {
|
||||
|
||||
if (engine_->type() != Engine::EngineType::GStreamer && engine_->type() != Engine::EngineType::Xine) return;
|
||||
|
||||
if (e->button() == Qt::LeftButton) {
|
||||
if (ignore_next_click_) {
|
||||
ignore_next_click_ = false;
|
||||
}
|
||||
else {
|
||||
// Might be the first click in a double click, so wait a while before actually doing anything
|
||||
double_click_timer_->start();
|
||||
last_click_pos_ = e->globalPos();
|
||||
}
|
||||
}
|
||||
else if (e->button() == Qt::RightButton) {
|
||||
if (e->button() == Qt::RightButton) {
|
||||
context_menu_->popup(e->globalPos());
|
||||
}
|
||||
|
||||
@@ -127,16 +110,6 @@ void AnalyzerContainer::ShowPopupMenu() {
|
||||
context_menu_->popup(last_click_pos_);
|
||||
}
|
||||
|
||||
void AnalyzerContainer::mouseDoubleClickEvent(QMouseEvent*) {
|
||||
|
||||
if (engine_->type() != Engine::EngineType::GStreamer && engine_->type() != Engine::EngineType::Xine) return;
|
||||
|
||||
double_click_timer_->stop();
|
||||
ignore_next_click_ = true;
|
||||
|
||||
if (visualisation_action_) visualisation_action_->trigger();
|
||||
}
|
||||
|
||||
void AnalyzerContainer::wheelEvent(QWheelEvent *e) {
|
||||
emit WheelEvent(e->delta());
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ signals:
|
||||
|
||||
protected:
|
||||
void mouseReleaseEvent(QMouseEvent*);
|
||||
void mouseDoubleClickEvent(QMouseEvent*);
|
||||
void wheelEvent(QWheelEvent *e);
|
||||
|
||||
private slots:
|
||||
@@ -93,7 +92,6 @@ signals:
|
||||
QList<QAction*> actions_;
|
||||
QAction *disable_action_;
|
||||
|
||||
QAction *visualisation_action_;
|
||||
QTimer *double_click_timer_;
|
||||
QPoint last_click_pos_;
|
||||
bool ignore_next_click_;
|
||||
|
||||
@@ -196,7 +196,7 @@ void BlockAnalyzer::analyze(QPainter &p, const Analyzer::Scope &s, bool new_fram
|
||||
canvas_painter.drawPixmap(x * (kWidth + 1), y * (kHeight + 1) + y_, *bar(), 0, y * (kHeight + 1), bar()->width(), bar()->height());
|
||||
}
|
||||
|
||||
for (uint x = 0; x < store_.size(); ++x)
|
||||
for (int x = 0; x < store_.size(); ++x)
|
||||
canvas_painter.drawPixmap(x * (kWidth + 1), static_cast<int>(store_[x]) * (kHeight + 1) + y_, topbarpixmap_);
|
||||
|
||||
p.drawPixmap(0, 0, canvas_);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Strawberry Music Player
|
||||
* This file was part of Clementine.
|
||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -284,12 +285,6 @@ void CollectionBackend::AddDirectory(const QString &path) {
|
||||
QString canonical_path = QFileInfo(path).canonicalFilePath();
|
||||
QString db_path = canonical_path;
|
||||
|
||||
if (Application::kIsPortable && Utilities::UrlOnSameDriveAsStrawberry(QUrl::fromLocalFile(canonical_path))) {
|
||||
|
||||
db_path = Utilities::GetRelativePathToStrawberryBin(QUrl::fromLocalFile(db_path)).toLocalFile();
|
||||
qLog(Debug) << "db_path" << db_path;
|
||||
}
|
||||
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
@@ -350,7 +345,7 @@ SongList CollectionBackend::FindSongsInDirectory(int id) {
|
||||
|
||||
SongList ret;
|
||||
while (q.next()) {
|
||||
Song song;
|
||||
Song song(source_);
|
||||
song.InitFromQuery(q, true);
|
||||
ret << song;
|
||||
}
|
||||
@@ -698,7 +693,7 @@ SongList CollectionBackend::ExecCollectionQuery(CollectionQuery *query) {
|
||||
|
||||
SongList ret;
|
||||
while (query->Next()) {
|
||||
Song song;
|
||||
Song song(source_);
|
||||
song.InitFromQuery(*query, true);
|
||||
ret << song;
|
||||
}
|
||||
@@ -772,7 +767,7 @@ SongList CollectionBackend::GetSongsById(const QStringList &ids, QSqlDatabase &d
|
||||
|
||||
SongList ret;
|
||||
while (q.next()) {
|
||||
Song song;
|
||||
Song song(source_);
|
||||
song.InitFromQuery(q, true);
|
||||
ret << song;
|
||||
}
|
||||
@@ -780,36 +775,52 @@ SongList CollectionBackend::GetSongsById(const QStringList &ids, QSqlDatabase &d
|
||||
|
||||
}
|
||||
|
||||
Song CollectionBackend::GetSongByUrl(const QUrl &url, qint64 beginning) {
|
||||
Song CollectionBackend::GetSongByUrl(const QUrl &url, const qint64 beginning) {
|
||||
|
||||
CollectionQuery query;
|
||||
query.SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
|
||||
query.AddWhere("url", url.toString());
|
||||
query.AddWhere("beginning", beginning);
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
Song song;
|
||||
if (ExecQuery(&query) && query.Next()) {
|
||||
song.InitFromQuery(query, true);
|
||||
QSqlQuery q(db);
|
||||
q.prepare(QString("SELECT ROWID, " + Song::kColumnSpec + " FROM %1 WHERE (url = :url1 OR url = :url2 OR url = :url3 OR url = :url4) AND beginning = :beginning AND unavailable = 0").arg(songs_table_));
|
||||
|
||||
q.bindValue(":url1", url);
|
||||
q.bindValue(":url2", url.toString());
|
||||
q.bindValue(":url3", url.toString(QUrl::FullyEncoded));
|
||||
q.bindValue(":url4", url.toEncoded());
|
||||
q.bindValue(":beginning", beginning);
|
||||
|
||||
Song song(source_);
|
||||
if (q.exec() && q.next()) {
|
||||
song.InitFromQuery(q, true);
|
||||
}
|
||||
|
||||
return song;
|
||||
|
||||
}
|
||||
|
||||
SongList CollectionBackend::GetSongsByUrl(const QUrl &url) {
|
||||
|
||||
CollectionQuery query;
|
||||
query.SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
|
||||
query.AddWhere("url", url.toString());
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
SongList songlist;
|
||||
if (ExecQuery(&query)) {
|
||||
while (query.Next()) {
|
||||
Song song;
|
||||
song.InitFromQuery(query, true);
|
||||
songlist << song;
|
||||
QSqlQuery q(db);
|
||||
q.prepare(QString("SELECT ROWID, " + Song::kColumnSpec + " FROM %1 WHERE (url = :url1 OR url = :url2 OR url = :url3 OR url = :url4) AND unavailable = 0").arg(songs_table_));
|
||||
|
||||
q.bindValue(":url1", url);
|
||||
q.bindValue(":url2", url.toString());
|
||||
q.bindValue(":url3", url.toString(QUrl::FullyEncoded));
|
||||
q.bindValue(":url4", url.toEncoded());
|
||||
|
||||
SongList songs;
|
||||
if (q.exec()) {
|
||||
while (q.next()) {
|
||||
Song song(source_);
|
||||
song.InitFromQuery(q, true);
|
||||
songs << song;
|
||||
}
|
||||
}
|
||||
return songlist;
|
||||
|
||||
return songs;
|
||||
|
||||
}
|
||||
|
||||
@@ -856,7 +867,7 @@ SongList CollectionBackend::GetSongsBySongId(const QStringList &song_ids, QSqlDa
|
||||
|
||||
SongList ret;
|
||||
while (q.next()) {
|
||||
Song song;
|
||||
Song song(source_);
|
||||
song.InitFromQuery(q, true);
|
||||
ret << song;
|
||||
}
|
||||
@@ -880,7 +891,7 @@ SongList CollectionBackend::GetCompilationSongs(const QString &album, const Quer
|
||||
|
||||
SongList ret;
|
||||
while (query.Next()) {
|
||||
Song song;
|
||||
Song song(source_);
|
||||
song.InitFromQuery(query, true);
|
||||
ret << song;
|
||||
}
|
||||
@@ -904,28 +915,29 @@ void CollectionBackend::UpdateCompilations() {
|
||||
while (q.next()) {
|
||||
QString artist = q.value(0).toString();
|
||||
QString album = q.value(1).toString();
|
||||
QString filename = q.value(2).toString();
|
||||
QUrl url = QUrl::fromEncoded(q.value(2).toString().toUtf8());
|
||||
bool compilation_detected = q.value(3).toBool();
|
||||
|
||||
// Ignore songs that don't have an album field set
|
||||
if (album.isEmpty()) continue;
|
||||
|
||||
// Find the directory the song is in
|
||||
int last_separator = filename.lastIndexOf('/');
|
||||
if (last_separator == -1) continue;
|
||||
QString directory = url.toString(QUrl::PreferLocalFile|QUrl::RemoveFilename);
|
||||
|
||||
CompilationInfo &info = compilation_info[album];
|
||||
info.artists.insert(artist);
|
||||
info.directories.insert(filename.left(last_separator));
|
||||
if (compilation_detected) info.has_compilation_detected = true;
|
||||
else info.has_not_compilation_detected = true;
|
||||
CompilationInfo &info = compilation_info[directory + album];
|
||||
info.urls << url;
|
||||
if (!info.artists.contains(artist))
|
||||
info.artists << artist;
|
||||
if (compilation_detected) info.has_compilation_detected++;
|
||||
else info.has_not_compilation_detected++;
|
||||
}
|
||||
|
||||
// Now mark the songs that we think are in compilations
|
||||
QSqlQuery update(db);
|
||||
update.prepare(QString("UPDATE %1 SET compilation_detected = :compilation_detected, compilation_effective = ((compilation OR :compilation_detected OR compilation_on) AND NOT compilation_off) + 0 WHERE album = :album AND unavailable = 0").arg(songs_table_));
|
||||
QSqlQuery find_songs(db);
|
||||
find_songs.prepare(QString("SELECT ROWID, " + Song::kColumnSpec + " FROM %1 WHERE album = :album AND compilation_detected = :compilation_detected AND unavailable = 0").arg(songs_table_));
|
||||
QSqlQuery find_song(db);
|
||||
find_song.prepare(QString("SELECT ROWID, " + Song::kColumnSpec + " FROM %1 WHERE (url = :url1 OR url = :url2 OR url = :url3 OR url = :url4) AND unavailable = 0").arg(songs_table_));
|
||||
|
||||
QSqlQuery update_song(db);
|
||||
update_song.prepare(QString("UPDATE %1 SET compilation_detected = :compilation_detected, compilation_effective = ((compilation OR :compilation_detected OR compilation_on) AND NOT compilation_off) + 0 WHERE (url = :url1 OR url = :url2 OR url = :url3 OR url = :url4) AND unavailable = 0").arg(songs_table_));
|
||||
|
||||
SongList deleted_songs;
|
||||
SongList added_songs;
|
||||
@@ -935,17 +947,18 @@ void CollectionBackend::UpdateCompilations() {
|
||||
QMap<QString, CompilationInfo>::const_iterator it = compilation_info.constBegin();
|
||||
for (; it != compilation_info.constEnd(); ++it) {
|
||||
const CompilationInfo &info = it.value();
|
||||
QString album(it.key());
|
||||
|
||||
// If there were more 'effective album artists' than there were directories for this album then it's a compilation.
|
||||
// If there were more than one 'effective album artist' for this album directory, then it's a compilation.
|
||||
|
||||
if (info.artists.count() > info.directories.count()) {
|
||||
if (info.has_not_compilation_detected)
|
||||
UpdateCompilations(find_songs, update, deleted_songs, added_songs, album, 1);
|
||||
}
|
||||
else {
|
||||
if (info.has_compilation_detected)
|
||||
UpdateCompilations(find_songs, update, deleted_songs, added_songs, album, 0);
|
||||
for (const QUrl &url : info.urls) {
|
||||
if (info.artists.count() > 1) { // This directory+album is a compilation.
|
||||
if (info.has_not_compilation_detected > 0) // Run updates if any of the songs is not marked as compilations.
|
||||
UpdateCompilations(find_song, update_song, deleted_songs, added_songs, url, true);
|
||||
}
|
||||
else {
|
||||
if (info.has_compilation_detected > 0)
|
||||
UpdateCompilations(find_song, update_song, deleted_songs, added_songs, url, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -955,27 +968,35 @@ void CollectionBackend::UpdateCompilations() {
|
||||
emit SongsDeleted(deleted_songs);
|
||||
emit SongsDiscovered(added_songs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CollectionBackend::UpdateCompilations(QSqlQuery &find_songs, QSqlQuery &update, SongList &deleted_songs, SongList &added_songs, const QString &album, int compilation_detected) {
|
||||
void CollectionBackend::UpdateCompilations(QSqlQuery &find_song, QSqlQuery &update_song, SongList &deleted_songs, SongList &added_songs, const QUrl &url, const bool compilation_detected) {
|
||||
|
||||
// Get songs that were already in that album, so we can tell the model they've been updated
|
||||
find_songs.bindValue(":album", album);
|
||||
find_songs.bindValue(":compilation_detected", int(!compilation_detected));
|
||||
find_songs.exec();
|
||||
while (find_songs.next()) {
|
||||
Song song;
|
||||
song.InitFromQuery(find_songs, true);
|
||||
deleted_songs << song;
|
||||
song.set_compilation_detected(true);
|
||||
added_songs << song;
|
||||
// Get song, so we can tell the model its updated
|
||||
find_song.bindValue(":url1", url);
|
||||
find_song.bindValue(":url2", url.toString());
|
||||
find_song.bindValue(":url3", url.toString(QUrl::FullyEncoded));
|
||||
find_song.bindValue(":url4", url.toEncoded());
|
||||
|
||||
if (find_song.exec()) {
|
||||
while (find_song.next()) {
|
||||
Song song(source_);
|
||||
song.InitFromQuery(find_song, true);
|
||||
deleted_songs << song;
|
||||
song.set_compilation_detected(compilation_detected);
|
||||
added_songs << song;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark this album
|
||||
update.bindValue(":compilation_detected", compilation_detected);
|
||||
update.bindValue(":album", album);
|
||||
update.exec();
|
||||
db_->CheckErrors(update);
|
||||
// Update the song
|
||||
update_song.bindValue(":compilation_detected", int(compilation_detected));
|
||||
update_song.bindValue(":url1", url);
|
||||
update_song.bindValue(":url2", url.toString());
|
||||
update_song.bindValue(":url3", url.toString(QUrl::FullyEncoded));
|
||||
update_song.bindValue(":url4", url.toEncoded());
|
||||
update_song.exec();
|
||||
db_->CheckErrors(update_song);
|
||||
|
||||
}
|
||||
|
||||
@@ -1017,7 +1038,7 @@ CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist,
|
||||
info.art_automatic = QUrl::fromEncoded(art_automatic.toUtf8());
|
||||
}
|
||||
else {
|
||||
info.art_automatic = QUrl::fromLocalFile(art_automatic.toUtf8());
|
||||
info.art_automatic = QUrl::fromLocalFile(art_automatic);
|
||||
}
|
||||
|
||||
QString art_manual = query.Value(6).toString();
|
||||
@@ -1025,7 +1046,7 @@ CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist,
|
||||
info.art_manual = QUrl::fromEncoded(art_manual.toUtf8());
|
||||
}
|
||||
else {
|
||||
info.art_manual = QUrl::fromLocalFile(art_manual.toUtf8());
|
||||
info.art_manual = QUrl::fromLocalFile(art_manual);
|
||||
}
|
||||
|
||||
if ((info.artist == last_artist || info.album_artist == last_album_artist) && info.album_name == last_album)
|
||||
@@ -1063,8 +1084,8 @@ CollectionBackend::Album CollectionBackend::GetAlbumArt(const QString &artist, c
|
||||
if (!ExecQuery(&query)) return ret;
|
||||
|
||||
if (query.Next()) {
|
||||
ret.art_automatic = query.Value(0).toUrl();
|
||||
ret.art_manual = query.Value(1).toUrl();
|
||||
ret.art_automatic = QUrl::fromEncoded(query.Value(0).toByteArray());
|
||||
ret.art_manual = QUrl::fromEncoded(query.Value(1).toByteArray());
|
||||
ret.first_url = QUrl::fromEncoded(query.Value(2).toByteArray());
|
||||
}
|
||||
|
||||
@@ -1099,7 +1120,7 @@ void CollectionBackend::UpdateManualAlbumArt(const QString &artist, const QStrin
|
||||
|
||||
SongList deleted_songs;
|
||||
while (query.Next()) {
|
||||
Song song;
|
||||
Song song(source_);
|
||||
song.InitFromQuery(query, true);
|
||||
deleted_songs << song;
|
||||
}
|
||||
@@ -1107,7 +1128,7 @@ void CollectionBackend::UpdateManualAlbumArt(const QString &artist, const QStrin
|
||||
// Update the songs
|
||||
QString sql(QString("UPDATE %1 SET art_manual = :cover WHERE album = :album AND unavailable = 0").arg(songs_table_));
|
||||
|
||||
if (!albumartist.isNull() && !albumartist.isEmpty()) {
|
||||
if (!albumartist.isEmpty()) {
|
||||
sql += " AND albumartist = :albumartist";
|
||||
}
|
||||
else if (!artist.isNull()) {
|
||||
@@ -1116,7 +1137,7 @@ void CollectionBackend::UpdateManualAlbumArt(const QString &artist, const QStrin
|
||||
|
||||
QSqlQuery q(db);
|
||||
q.prepare(sql);
|
||||
q.bindValue(":cover", cover_url);
|
||||
q.bindValue(":cover", cover_url.toString(QUrl::FullyEncoded));
|
||||
q.bindValue(":album", album);
|
||||
if (!albumartist.isEmpty()) {
|
||||
q.bindValue(":albumartist", albumartist);
|
||||
@@ -1133,7 +1154,7 @@ void CollectionBackend::UpdateManualAlbumArt(const QString &artist, const QStrin
|
||||
|
||||
SongList added_songs;
|
||||
while (query.Next()) {
|
||||
Song song;
|
||||
Song song(source_);
|
||||
song.InitFromQuery(query, true);
|
||||
added_songs << song;
|
||||
}
|
||||
@@ -1161,7 +1182,7 @@ void CollectionBackend::ForceCompilation(const QString &album, const QList<QStri
|
||||
if (!ExecQuery(&query)) return;
|
||||
|
||||
while (query.Next()) {
|
||||
Song song;
|
||||
Song song(source_);
|
||||
song.InitFromQuery(query, true);
|
||||
deleted_songs << song;
|
||||
}
|
||||
@@ -1184,7 +1205,7 @@ void CollectionBackend::ForceCompilation(const QString &album, const QList<QStri
|
||||
if (!ExecQuery(&query)) return;
|
||||
|
||||
while (query.Next()) {
|
||||
Song song;
|
||||
Song song(source_);
|
||||
song.InitFromQuery(query, true);
|
||||
added_songs << song;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Strawberry Music Player
|
||||
* This file was part of Clementine.
|
||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -109,7 +110,7 @@ class CollectionBackendInterface : public QObject {
|
||||
virtual SongList GetSongsByUrl(const QUrl &url) = 0;
|
||||
// Returns a section of a song with the given filename and beginning. If the section is not present in collection, returns invalid song.
|
||||
// Using default beginning value is suitable when searching for single-section songs.
|
||||
virtual Song GetSongByUrl(const QUrl &url, qint64 beginning = 0) = 0;
|
||||
virtual Song GetSongByUrl(const QUrl &url, const qint64 beginning = 0) = 0;
|
||||
|
||||
virtual void AddDirectory(const QString &path) = 0;
|
||||
virtual void RemoveDirectory(const Directory &dir) = 0;
|
||||
@@ -225,16 +226,16 @@ class CollectionBackend : public CollectionBackendInterface {
|
||||
|
||||
private:
|
||||
struct CompilationInfo {
|
||||
CompilationInfo() : has_compilation_detected(false), has_not_compilation_detected(false) {}
|
||||
CompilationInfo() : has_compilation_detected(0), has_not_compilation_detected(0) {}
|
||||
|
||||
QSet<QString> artists;
|
||||
QSet<QString> directories;
|
||||
QList<QUrl> urls;
|
||||
QStringList artists;
|
||||
|
||||
bool has_compilation_detected;
|
||||
bool has_not_compilation_detected;
|
||||
int has_compilation_detected;
|
||||
int has_not_compilation_detected;
|
||||
};
|
||||
|
||||
void UpdateCompilations(QSqlQuery &find_songs, QSqlQuery &update, SongList &deleted_songs, SongList &added_songs, const QString &album, int compilation_detected);
|
||||
void UpdateCompilations(QSqlQuery &find_song, QSqlQuery &update_song, SongList &deleted_songs, SongList &added_songs, const QUrl &url, const bool compilation_detected);
|
||||
AlbumList GetAlbums(const QString &artist, const QString &album_artist, bool compilation = false, const QueryOptions &opt = QueryOptions());
|
||||
AlbumList GetAlbums(const QString &artist, bool compilation, const QueryOptions &opt = QueryOptions());
|
||||
SubdirectoryList SubdirsInDirectory(int id, QSqlDatabase &db);
|
||||
|
||||
@@ -53,13 +53,7 @@ CollectionDirectoryModel::~CollectionDirectoryModel() {}
|
||||
|
||||
void CollectionDirectoryModel::DirectoryDiscovered(const Directory &dir) {
|
||||
|
||||
QStandardItem *item;
|
||||
if (Application::kIsPortable && Utilities::UrlOnSameDriveAsStrawberry(QUrl::fromLocalFile(dir.path))) {
|
||||
item = new QStandardItem(Utilities::GetRelativePathToStrawberryBin(QUrl::fromLocalFile(dir.path)).toLocalFile());
|
||||
}
|
||||
else {
|
||||
item = new QStandardItem(dir.path);
|
||||
}
|
||||
QStandardItem *item = new QStandardItem(dir.path);
|
||||
item->setData(dir.id, kIdRole);
|
||||
item->setIcon(dir_icon_);
|
||||
storage_ << std::shared_ptr<MusicStorage>(new FilesystemMusicStorage(dir.path));
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <QVariant>
|
||||
#include <QList>
|
||||
#include <QSet>
|
||||
#include <QMap>
|
||||
#include <QChar>
|
||||
#include <QRegExp>
|
||||
#include <QString>
|
||||
@@ -70,7 +71,7 @@ using std::placeholders::_2;
|
||||
|
||||
const char *CollectionModel::kSavedGroupingsSettingsGroup = "SavedGroupings";
|
||||
const int CollectionModel::kPrettyCoverSize = 32;
|
||||
const qint64 CollectionModel::kIconCacheSize = 100000000; //~100MB
|
||||
const int CollectionModel::kPixmapCacheLimit = QPixmapCache::cacheLimit() * 8;
|
||||
|
||||
static bool IsArtistGroupBy(const CollectionModel::GroupBy by) {
|
||||
return by == CollectionModel::GroupBy_Artist || by == CollectionModel::GroupBy_AlbumArtist;
|
||||
@@ -126,7 +127,7 @@ CollectionModel::CollectionModel(CollectionBackend *backend, Application *app, Q
|
||||
backend_->UpdateTotalArtistCountAsync();
|
||||
backend_->UpdateTotalAlbumCountAsync();
|
||||
|
||||
QPixmapCache::setCacheLimit(61440);
|
||||
QPixmapCache::setCacheLimit(kPixmapCacheLimit);
|
||||
|
||||
}
|
||||
|
||||
@@ -434,26 +435,11 @@ void CollectionModel::SongsDeleted(const SongList &songs) {
|
||||
|
||||
if (node->parent != root_) parents << node->parent;
|
||||
|
||||
// Remove from pixmap cache
|
||||
QModelIndex idx = ItemToIndex(node->parent);
|
||||
const QString cache_key = AlbumIconPixmapCacheKey(idx);
|
||||
QPixmapCache::remove(cache_key);
|
||||
if (pending_cache_keys_.contains(cache_key)) pending_cache_keys_.remove(cache_key);
|
||||
|
||||
// Remove from pending art loading
|
||||
QMapIterator<quint64, ItemAndCacheKey> i(pending_art_);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (i.value().first == node) {
|
||||
pending_art_.remove(i.key());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
beginRemoveRows(idx, node->row, node->row);
|
||||
beginRemoveRows(ItemToIndex(node->parent), node->row, node->row);
|
||||
node->parent->Delete(node->row);
|
||||
song_nodes_.remove(song.id());
|
||||
endRemoveRows();
|
||||
|
||||
}
|
||||
else {
|
||||
// If we get here it means some of the songs we want to delete haven't been lazy-loaded yet.
|
||||
@@ -488,18 +474,20 @@ void CollectionModel::SongsDeleted(const SongList &songs) {
|
||||
container_nodes_[node->container_level].remove(node->key);
|
||||
|
||||
// Remove from pixmap cache
|
||||
QModelIndex idx = ItemToIndex(node->parent);
|
||||
const QString cache_key = AlbumIconPixmapCacheKey(idx);
|
||||
const QString cache_key = AlbumIconPixmapCacheKey(ItemToIndex(node));
|
||||
QPixmapCache::remove(cache_key);
|
||||
if (pending_cache_keys_.contains(cache_key)) pending_cache_keys_.remove(cache_key);
|
||||
if (pending_cache_keys_.contains(cache_key)) {
|
||||
pending_cache_keys_.remove(cache_key);
|
||||
}
|
||||
|
||||
// Remove from pending art loading
|
||||
QMapIterator<quint64, ItemAndCacheKey> i(pending_art_);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
QMap<quint64, ItemAndCacheKey>::iterator i = pending_art_.begin();
|
||||
while (i != pending_art_.end()) {
|
||||
if (i.value().first == node) {
|
||||
pending_art_.remove(i.key());
|
||||
break;
|
||||
i = pending_art_.erase(i);
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,15 +528,7 @@ QString CollectionModel::AlbumIconPixmapCacheKey(const QModelIndex &idx) const {
|
||||
QStringList path;
|
||||
QModelIndex idx_copy(idx);
|
||||
while (idx_copy.isValid()) {
|
||||
//const CollectionItem *item = IndexToItem(idx_copy);
|
||||
//if (item && group_by_[item->container_level] == GroupBy_Album) {
|
||||
// QString album = idx_copy.data().toString();
|
||||
// album.remove(Song::kAlbumRemoveDisc);
|
||||
// path.prepend(album);
|
||||
//}
|
||||
//else {
|
||||
path.prepend(idx_copy.data().toString());
|
||||
//}
|
||||
path.prepend(idx_copy.data().toString());
|
||||
idx_copy = idx_copy.parent();
|
||||
}
|
||||
|
||||
@@ -860,7 +840,6 @@ void CollectionModel::BeginReset() {
|
||||
divider_nodes_.clear();
|
||||
pending_art_.clear();
|
||||
pending_cache_keys_.clear();
|
||||
QPixmapCache::clear();
|
||||
|
||||
root_ = new CollectionItem(this);
|
||||
root_->compilation_artist_node_ = nullptr;
|
||||
|
||||
@@ -70,7 +70,7 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
||||
static const char *kSavedGroupingsSettingsGroup;
|
||||
|
||||
static const int kPrettyCoverSize;
|
||||
static const qint64 kIconCacheSize;
|
||||
static const int kPixmapCacheLimit;
|
||||
|
||||
enum Role {
|
||||
Role_Type = Qt::UserRole + 1,
|
||||
|
||||
@@ -330,8 +330,8 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
||||
|
||||
if (!context_menu_) {
|
||||
context_menu_ = new QMenu(this);
|
||||
add_to_playlist_ = context_menu_->addAction(IconLoader::Load("media-play"), tr("Append to current playlist"), this, SLOT(AddToPlaylist()));
|
||||
load_ = context_menu_->addAction(IconLoader::Load("media-play"), tr("Replace current playlist"), this, SLOT(Load()));
|
||||
add_to_playlist_ = context_menu_->addAction(IconLoader::Load("media-playback-start"), tr("Append to current playlist"), this, SLOT(AddToPlaylist()));
|
||||
load_ = context_menu_->addAction(IconLoader::Load("media-playback-start"), tr("Replace current playlist"), this, SLOT(Load()));
|
||||
open_in_new_playlist_ = context_menu_->addAction(IconLoader::Load("document-new"), tr("Open in new playlist"), this, SLOT(OpenInNewPlaylist()));
|
||||
|
||||
context_menu_->addSeparator();
|
||||
|
||||
@@ -62,18 +62,13 @@ using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
|
||||
const int ContextAlbumsModel::kPrettyCoverSize = 32;
|
||||
const qint64 ContextAlbumsModel::kIconCacheSize = 100000000; //~100MB
|
||||
|
||||
ContextAlbumsModel::ContextAlbumsModel(CollectionBackend *backend, Application *app, QObject *parent) :
|
||||
SimpleTreeModel<CollectionItem>(new CollectionItem(this), parent),
|
||||
backend_(backend),
|
||||
app_(app),
|
||||
artist_icon_(IconLoader::Load("folder-sound")),
|
||||
album_icon_(IconLoader::Load("cdcase")),
|
||||
playlists_dir_icon_(IconLoader::Load("folder-sound")),
|
||||
playlist_icon_(IconLoader::Load("albums")),
|
||||
use_pretty_covers_(true)
|
||||
{
|
||||
playlists_dir_icon_(IconLoader::Load("folder-sound")) {
|
||||
|
||||
root_->lazy_loaded = true;
|
||||
|
||||
@@ -90,15 +85,6 @@ ContextAlbumsModel::ContextAlbumsModel(CollectionBackend *backend, Application *
|
||||
|
||||
ContextAlbumsModel::~ContextAlbumsModel() { delete root_; }
|
||||
|
||||
void ContextAlbumsModel::set_pretty_covers(bool use_pretty_covers) {
|
||||
|
||||
if (use_pretty_covers != use_pretty_covers_) {
|
||||
use_pretty_covers_ = use_pretty_covers;
|
||||
Reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ContextAlbumsModel::AddSongs(const SongList &songs) {
|
||||
|
||||
for (const Song &song : songs) {
|
||||
@@ -199,18 +185,8 @@ QVariant ContextAlbumsModel::data(const QModelIndex &index, int role) const {
|
||||
|
||||
const CollectionItem *item = IndexToItem(index);
|
||||
|
||||
// Handle a special case for returning album artwork instead of a generic CD icon.
|
||||
// This is here instead of in the other data() function to let us use the QModelIndex& version of GetChildSongs,
|
||||
// which satisfies const-ness, instead of the CollectionItem *version, which doesn't.
|
||||
if (use_pretty_covers_) {
|
||||
bool is_album_node = false;
|
||||
if (role == Qt::DecorationRole && item->type == CollectionItem::Type_Container) {
|
||||
is_album_node = (item->container_level == 0);
|
||||
}
|
||||
if (is_album_node) {
|
||||
// It has const behaviour some of the time - that's ok right?
|
||||
return const_cast<ContextAlbumsModel*>(this)->AlbumIcon(index);
|
||||
}
|
||||
if (role == Qt::DecorationRole && item->type == CollectionItem::Type_Container && item->container_level == 0) {
|
||||
return const_cast<ContextAlbumsModel*>(this)->AlbumIcon(index);
|
||||
}
|
||||
|
||||
return data(item, role);
|
||||
@@ -239,9 +215,6 @@ QVariant ContextAlbumsModel::data(const CollectionItem *item, int role) const {
|
||||
case Role_Type:
|
||||
return item->type;
|
||||
|
||||
case Role_IsDivider:
|
||||
return item->type == CollectionItem::Type_Divider;
|
||||
|
||||
case Role_ContainerType:
|
||||
return item->type;
|
||||
|
||||
@@ -265,7 +238,8 @@ QVariant ContextAlbumsModel::data(const CollectionItem *item, int role) const {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -349,11 +323,19 @@ void ContextAlbumsModel::LazyPopulate(CollectionItem *parent, bool signal) {
|
||||
|
||||
void ContextAlbumsModel::Reset() {
|
||||
|
||||
QMap<QString, CollectionItem*>::iterator i = container_nodes_.begin();
|
||||
while (i != container_nodes_.end()) {
|
||||
const QString cache_key = AlbumIconPixmapCacheKey(ItemToIndex(i.value()));
|
||||
QPixmapCache::remove(cache_key);
|
||||
++i;
|
||||
}
|
||||
|
||||
beginResetModel();
|
||||
delete root_;
|
||||
song_nodes_.clear();
|
||||
container_nodes_.clear();
|
||||
pending_art_.clear();
|
||||
pending_cache_keys_.clear();
|
||||
|
||||
root_ = new CollectionItem(this);
|
||||
root_->lazy_loaded = false;
|
||||
@@ -434,7 +416,6 @@ Qt::ItemFlags ContextAlbumsModel::flags(const QModelIndex &index) const {
|
||||
case CollectionItem::Type_Song:
|
||||
case CollectionItem::Type_Container:
|
||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
|
||||
case CollectionItem::Type_Divider:
|
||||
case CollectionItem::Type_Root:
|
||||
case CollectionItem::Type_LoadingIndicator:
|
||||
default:
|
||||
|
||||
@@ -37,11 +37,9 @@
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QMimeData>
|
||||
#include <QImage>
|
||||
#include <QIcon>
|
||||
#include <QPixmap>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QSettings>
|
||||
|
||||
#include "core/simpletreemodel.h"
|
||||
@@ -51,6 +49,8 @@
|
||||
#include "collection/sqlrow.h"
|
||||
#include "covermanager/albumcoverloaderoptions.h"
|
||||
|
||||
class QMimeData;
|
||||
|
||||
class Application;
|
||||
class CollectionBackend;
|
||||
class CollectionItem;
|
||||
@@ -63,7 +63,6 @@ class ContextAlbumsModel : public SimpleTreeModel<CollectionItem> {
|
||||
~ContextAlbumsModel();
|
||||
|
||||
static const int kPrettyCoverSize;
|
||||
static const qint64 kIconCacheSize;
|
||||
|
||||
enum Role {
|
||||
Role_Type = Qt::UserRole + 1,
|
||||
@@ -71,7 +70,6 @@ class ContextAlbumsModel : public SimpleTreeModel<CollectionItem> {
|
||||
Role_SortText,
|
||||
Role_Key,
|
||||
Role_Artist,
|
||||
Role_IsDivider,
|
||||
Role_Editable,
|
||||
LastRole
|
||||
};
|
||||
@@ -81,8 +79,6 @@ class ContextAlbumsModel : public SimpleTreeModel<CollectionItem> {
|
||||
SqlRowList rows;
|
||||
};
|
||||
|
||||
CollectionBackend *backend() const { return backend_; }
|
||||
|
||||
void GetChildSongs(CollectionItem *item, QList<QUrl> *urls, SongList *songs, QSet<int> *song_ids) const;
|
||||
SongList GetChildSongs(const QModelIndex &index) const;
|
||||
SongList GetChildSongs(const QModelIndexList &indexes) const;
|
||||
@@ -93,9 +89,6 @@ class ContextAlbumsModel : public SimpleTreeModel<CollectionItem> {
|
||||
QMimeData *mimeData(const QModelIndexList &indexes) const;
|
||||
bool canFetchMore(const QModelIndex &parent) const;
|
||||
|
||||
void set_pretty_covers(bool use_pretty_covers);
|
||||
bool use_pretty_covers() const { return use_pretty_covers_; }
|
||||
|
||||
static QString TextOrUnknown(const QString &text);
|
||||
static QString SortText(QString text);
|
||||
static QString SortTextForArtist(QString artist);
|
||||
@@ -125,15 +118,11 @@ class ContextAlbumsModel : public SimpleTreeModel<CollectionItem> {
|
||||
CollectionBackend *backend_;
|
||||
Application *app_;
|
||||
QueryOptions query_options_;
|
||||
QMap<int, CollectionItem*> song_nodes_;
|
||||
QMap<QString, CollectionItem*> container_nodes_;
|
||||
QIcon artist_icon_;
|
||||
QMap<int, CollectionItem*> song_nodes_;
|
||||
QIcon album_icon_;
|
||||
QPixmap no_cover_icon_;
|
||||
QIcon playlists_dir_icon_;
|
||||
QIcon playlist_icon_;
|
||||
QNetworkDiskCache *icon_cache_;
|
||||
bool use_pretty_covers_;
|
||||
AlbumCoverLoaderOptions cover_loader_options_;
|
||||
typedef QPair<CollectionItem*, QString> ItemAndCacheKey;
|
||||
QMap<quint64, ItemAndCacheKey> pending_art_;
|
||||
|
||||
@@ -82,76 +82,6 @@
|
||||
|
||||
ContextItemDelegate::ContextItemDelegate(QObject *parent) : QStyledItemDelegate(parent) {}
|
||||
|
||||
void ContextItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt, const QModelIndex &index) const {
|
||||
|
||||
const bool is_divider = index.data(ContextAlbumsModel::Role_IsDivider).toBool();
|
||||
|
||||
if (is_divider) {
|
||||
QString text(index.data().toString());
|
||||
|
||||
painter->save();
|
||||
|
||||
QRect text_rect(opt.rect);
|
||||
|
||||
// Does this item have an icon?
|
||||
QPixmap pixmap;
|
||||
QVariant decoration = index.data(Qt::DecorationRole);
|
||||
if (!decoration.isNull()) {
|
||||
if (decoration.canConvert<QPixmap>()) {
|
||||
pixmap = decoration.value<QPixmap>();
|
||||
}
|
||||
else if (decoration.canConvert<QIcon>()) {
|
||||
pixmap = decoration.value<QIcon>().pixmap(opt.decorationSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the icon at the left of the text rectangle
|
||||
if (!pixmap.isNull()) {
|
||||
QRect icon_rect(text_rect.topLeft(), opt.decorationSize);
|
||||
const int padding = (text_rect.height() - icon_rect.height()) / 2;
|
||||
icon_rect.adjust(padding, padding, padding, padding);
|
||||
text_rect.moveLeft(icon_rect.right() + padding + 6);
|
||||
|
||||
if (pixmap.size() != opt.decorationSize) {
|
||||
pixmap = pixmap.scaled(opt.decorationSize, Qt::KeepAspectRatio);
|
||||
}
|
||||
|
||||
painter->drawPixmap(icon_rect, pixmap);
|
||||
}
|
||||
else {
|
||||
text_rect.setLeft(text_rect.left() + 30);
|
||||
}
|
||||
|
||||
// Draw the text
|
||||
QFont bold_font(opt.font);
|
||||
bold_font.setBold(true);
|
||||
|
||||
painter->setPen(opt.palette.color(QPalette::Text));
|
||||
painter->setFont(bold_font);
|
||||
painter->drawText(text_rect, text);
|
||||
|
||||
// Draw the line under the item
|
||||
QColor line_color = opt.palette.color(QPalette::Text);
|
||||
QLinearGradient grad_color(opt.rect.bottomLeft(), opt.rect.bottomRight());
|
||||
const double fade_start_end = (opt.rect.width()/3.0)/opt.rect.width();
|
||||
line_color.setAlphaF(0.0);
|
||||
grad_color.setColorAt(0, line_color);
|
||||
line_color.setAlphaF(0.5);
|
||||
grad_color.setColorAt(fade_start_end, line_color);
|
||||
grad_color.setColorAt(1.0 - fade_start_end, line_color);
|
||||
line_color.setAlphaF(0.0);
|
||||
grad_color.setColorAt(1, line_color);
|
||||
painter->setPen(QPen(grad_color, 1));
|
||||
painter->drawLine(opt.rect.bottomLeft(), opt.rect.bottomRight());
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
else {
|
||||
if (!is_divider) QStyledItemDelegate::paint(painter, opt, index);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool ContextItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) {
|
||||
|
||||
return true;
|
||||
@@ -311,22 +241,7 @@ bool ContextAlbumsView::RestoreLevelFocus(const QModelIndex &parent) {
|
||||
|
||||
}
|
||||
|
||||
void ContextAlbumsView::ReloadSettings() {
|
||||
|
||||
QSettings settings;
|
||||
|
||||
settings.beginGroup(CollectionSettingsPage::kSettingsGroup);
|
||||
SetAutoOpen(settings.value("auto_open", true).toBool());
|
||||
|
||||
if (app_ && model_) {
|
||||
model_->set_pretty_covers(settings.value("pretty_covers", true).toBool());
|
||||
}
|
||||
|
||||
settings.endGroup();
|
||||
|
||||
}
|
||||
|
||||
void ContextAlbumsView::SetApplication(Application *app) {
|
||||
void ContextAlbumsView::Init(Application *app) {
|
||||
|
||||
app_ = app;
|
||||
|
||||
@@ -338,8 +253,6 @@ void ContextAlbumsView::SetApplication(Application *app) {
|
||||
connect(model_, SIGNAL(modelAboutToBeReset()), this, SLOT(SaveFocus()));
|
||||
connect(model_, SIGNAL(modelReset()), this, SLOT(RestoreFocus()));
|
||||
|
||||
ReloadSettings();
|
||||
|
||||
}
|
||||
|
||||
void ContextAlbumsView::paintEvent(QPaintEvent *event) {
|
||||
@@ -355,8 +268,8 @@ void ContextAlbumsView::contextMenuEvent(QContextMenuEvent *e) {
|
||||
if (!context_menu_) {
|
||||
context_menu_ = new QMenu(this);
|
||||
|
||||
add_to_playlist_ = context_menu_->addAction(IconLoader::Load("media-play"), tr("Append to current playlist"), this, SLOT(AddToPlaylist()));
|
||||
load_ = context_menu_->addAction(IconLoader::Load("media-play"), tr("Replace current playlist"), this, SLOT(Load()));
|
||||
add_to_playlist_ = context_menu_->addAction(IconLoader::Load("media-playback-start"), tr("Append to current playlist"), this, SLOT(AddToPlaylist()));
|
||||
load_ = context_menu_->addAction(IconLoader::Load("media-playback-start"), tr("Replace current playlist"), this, SLOT(Load()));
|
||||
open_in_new_playlist_ = context_menu_->addAction(IconLoader::Load("document-new"), tr("Open in new playlist"), this, SLOT(OpenInNewPlaylist()));
|
||||
|
||||
context_menu_->addSeparator();
|
||||
|
||||
@@ -55,7 +55,6 @@ class ContextItemDelegate : public QStyledItemDelegate {
|
||||
|
||||
public:
|
||||
ContextItemDelegate(QObject *parent);
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
|
||||
public slots:
|
||||
bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index);
|
||||
@@ -72,7 +71,7 @@ class ContextAlbumsView : public AutoExpandingTreeView {
|
||||
// Please note that the selection is recursive meaning that if for example an album is selected this will return all of it's songs.
|
||||
SongList GetSelectedSongs() const;
|
||||
|
||||
void SetApplication(Application *app);
|
||||
void Init(Application *app);
|
||||
|
||||
// QTreeView
|
||||
void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible);
|
||||
@@ -80,14 +79,9 @@ class ContextAlbumsView : public AutoExpandingTreeView {
|
||||
ContextAlbumsModel *albums_model() { return model_; }
|
||||
|
||||
public slots:
|
||||
void ReloadSettings();
|
||||
|
||||
void SaveFocus();
|
||||
void RestoreFocus();
|
||||
|
||||
signals:
|
||||
void ShowConfigDialog();
|
||||
|
||||
protected:
|
||||
// QWidget
|
||||
void paintEvent(QPaintEvent *event);
|
||||
@@ -122,7 +116,6 @@ signals:
|
||||
#ifndef Q_OS_WIN
|
||||
QAction *copy_to_device_;
|
||||
#endif
|
||||
QAction *delete_;
|
||||
QAction *edit_track_;
|
||||
QAction *edit_tracks_;
|
||||
QAction *show_in_browser_;
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
#include "engine/engine_fwd.h"
|
||||
#include "engine/enginebase.h"
|
||||
#include "engine/enginetype.h"
|
||||
#include "engine/enginedevice.h"
|
||||
#include "engine/devicefinders.h"
|
||||
#include "engine/devicefinder.h"
|
||||
#include "collection/collection.h"
|
||||
#include "collection/collectionbackend.h"
|
||||
@@ -110,7 +110,7 @@ void ContextView::Init(Application *app, CollectionView *collectionview, AlbumCo
|
||||
collectionview_ = collectionview;
|
||||
album_cover_choice_controller_ = album_cover_choice_controller;
|
||||
|
||||
ui_->widget_play_albums->SetApplication(app_);
|
||||
ui_->widget_play_albums->Init(app_);
|
||||
lyrics_fetcher_ = new LyricsFetcher(app_->lyrics_providers(), this);
|
||||
|
||||
connect(collectionview_, SIGNAL(TotalSongCountUpdated_()), this, SLOT(UpdateNoSong()));
|
||||
@@ -156,8 +156,8 @@ void ContextView::AddActions() {
|
||||
s.beginGroup(kSettingsGroup);
|
||||
action_show_data_->setChecked(s.value("show_data", true).toBool());
|
||||
action_show_output_->setChecked(s.value("show_output", true).toBool());
|
||||
action_show_albums_->setChecked(s.value("show_albums", true).toBool());
|
||||
action_show_lyrics_->setChecked(s.value("show_lyrics", false).toBool());
|
||||
action_show_albums_->setChecked(s.value("show_albums", false).toBool());
|
||||
action_show_lyrics_->setChecked(s.value("show_lyrics", true).toBool());
|
||||
s.endGroup();
|
||||
|
||||
connect(action_show_data_, SIGNAL(triggered()), this, SLOT(ActionShowData()));
|
||||
@@ -341,7 +341,7 @@ void ContextView::SetSong(const Song &song) {
|
||||
ui_->spacer_play_output->changeSize(20, 20, QSizePolicy::Fixed);
|
||||
|
||||
DeviceFinder::Device device;
|
||||
for (DeviceFinder *f : app_->enginedevice()->device_finders_) {
|
||||
for (DeviceFinder *f : app_->device_finders()->ListFinders()) {
|
||||
for (const DeviceFinder::Device &d : f->ListDevices()) {
|
||||
if (d.value != app_->player()->engine()->device()) continue;
|
||||
device = d;
|
||||
@@ -498,7 +498,7 @@ void ContextView::UpdateSong(const Song &song) {
|
||||
|
||||
void ContextView::UpdateLyrics(const quint64 id, const QString &provider, const QString &lyrics) {
|
||||
|
||||
if (id != lyrics_id_) return;
|
||||
if ((qint64) id != lyrics_id_) return;
|
||||
lyrics_ = lyrics + "\n\n(Lyrics from " + provider + ")\n";
|
||||
lyrics_id_ = -1;
|
||||
if (action_show_lyrics_->isChecked()) {
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "player.h"
|
||||
#include "appearance.h"
|
||||
|
||||
#include "engine/enginedevice.h"
|
||||
#include "engine/devicefinders.h"
|
||||
#ifndef Q_OS_WIN
|
||||
# include "device/devicemanager.h"
|
||||
#endif
|
||||
@@ -61,6 +61,7 @@
|
||||
#include "lyrics/auddlyricsprovider.h"
|
||||
#include "lyrics/ovhlyricsprovider.h"
|
||||
#include "lyrics/lololyricsprovider.h"
|
||||
#include "lyrics/chartlyricsprovider.h"
|
||||
|
||||
#include "scrobbler/audioscrobbler.h"
|
||||
|
||||
@@ -85,8 +86,6 @@
|
||||
# include "moodbar/moodbarloader.h"
|
||||
#endif
|
||||
|
||||
bool Application::kIsPortable = false;
|
||||
|
||||
class ApplicationImpl {
|
||||
public:
|
||||
explicit ApplicationImpl(Application *app) :
|
||||
@@ -105,7 +104,7 @@ class ApplicationImpl {
|
||||
appearance_([=]() { return new Appearance(app); }),
|
||||
task_manager_([=]() { return new TaskManager(app); }),
|
||||
player_([=]() { return new Player(app, app); }),
|
||||
enginedevice_([=]() { return new EngineDevice(app); }),
|
||||
device_finders_([=]() { return new DeviceFinders(app); }),
|
||||
#ifndef Q_OS_WIN
|
||||
device_manager_([=]() { return new DeviceManager(app, app); }),
|
||||
#endif
|
||||
@@ -139,6 +138,7 @@ class ApplicationImpl {
|
||||
lyrics_providers->AddProvider(new AuddLyricsProvider(app));
|
||||
lyrics_providers->AddProvider(new OVHLyricsProvider(app));
|
||||
lyrics_providers->AddProvider(new LoloLyricsProvider(app));
|
||||
lyrics_providers->AddProvider(new ChartLyricsProvider(app));
|
||||
return lyrics_providers;
|
||||
}),
|
||||
internet_services_([=]() {
|
||||
@@ -175,7 +175,7 @@ class ApplicationImpl {
|
||||
Lazy<Appearance> appearance_;
|
||||
Lazy<TaskManager> task_manager_;
|
||||
Lazy<Player> player_;
|
||||
Lazy<EngineDevice> enginedevice_;
|
||||
Lazy<DeviceFinders> device_finders_;
|
||||
#ifndef Q_OS_WIN
|
||||
Lazy<DeviceManager> device_manager_;
|
||||
#endif
|
||||
@@ -205,7 +205,7 @@ class ApplicationImpl {
|
||||
Application::Application(QObject *parent)
|
||||
: QObject(parent), p_(new ApplicationImpl(this)) {
|
||||
|
||||
enginedevice()->Init();
|
||||
device_finders()->Init();
|
||||
collection()->Init();
|
||||
tag_reader_client();
|
||||
|
||||
@@ -307,7 +307,7 @@ Appearance *Application::appearance() const { return p_->appearance_.get(); }
|
||||
Database *Application::database() const { return p_->database_.get(); }
|
||||
TaskManager *Application::task_manager() const { return p_->task_manager_.get(); }
|
||||
Player *Application::player() const { return p_->player_.get(); }
|
||||
EngineDevice *Application::enginedevice() const { return p_->enginedevice_.get(); }
|
||||
DeviceFinders *Application::device_finders() const { return p_->device_finders_.get(); }
|
||||
#ifndef Q_OS_WIN
|
||||
DeviceManager *Application::device_manager() const { return p_->device_manager_.get(); }
|
||||
#endif
|
||||
|
||||
@@ -41,7 +41,7 @@ class TaskManager;
|
||||
class ApplicationImpl;
|
||||
class TagReaderClient;
|
||||
class Database;
|
||||
class EngineDevice;
|
||||
class DeviceFinders;
|
||||
class Player;
|
||||
class Appearance;
|
||||
class SCollection;
|
||||
@@ -68,8 +68,6 @@ class Application : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static bool kIsPortable;
|
||||
|
||||
explicit Application(QObject *parent = nullptr);
|
||||
~Application();
|
||||
|
||||
@@ -78,7 +76,7 @@ class Application : public QObject {
|
||||
Appearance *appearance() const;
|
||||
TaskManager *task_manager() const;
|
||||
Player *player() const;
|
||||
EngineDevice *enginedevice() const;
|
||||
DeviceFinders *device_finders() const;
|
||||
#ifndef Q_OS_WIN
|
||||
DeviceManager *device_manager() const;
|
||||
#endif
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <QSettings>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "iconmapper.h"
|
||||
#include "settings/appearancesettingspage.h"
|
||||
#include "iconloader.h"
|
||||
|
||||
@@ -64,7 +65,17 @@ QIcon IconLoader::Load(const QString &name, const int size) {
|
||||
else sizes << size;
|
||||
|
||||
if (system_icons_) {
|
||||
IconMapper::IconProperties icon_prop;
|
||||
if (IconMapper::iconmapper_.contains(name)) {
|
||||
icon_prop = IconMapper::iconmapper_[name];
|
||||
}
|
||||
ret = QIcon::fromTheme(name);
|
||||
if (ret.isNull()) {
|
||||
for (QString alt_name : icon_prop.names) {
|
||||
ret = QIcon::fromTheme(alt_name);
|
||||
if (!ret.isNull()) break;
|
||||
}
|
||||
}
|
||||
if (!ret.isNull()) return ret;
|
||||
qLog(Warning) << "Couldn't load icon" << name << "from system theme icons.";
|
||||
}
|
||||
|
||||
135
src/core/iconmapper.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Strawberry Music Player
|
||||
* Copyright 2019, 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 <QtGlobal>
|
||||
#include <QMap>
|
||||
|
||||
namespace IconMapper {
|
||||
|
||||
struct IconProperties {
|
||||
IconProperties() : min_size(0), max_size(0) {}
|
||||
IconProperties(const QStringList &_names, const int _min_size, const int _max_size) : names(_names), min_size(_min_size), max_size(_max_size) {}
|
||||
QStringList names;
|
||||
int min_size;
|
||||
int max_size;
|
||||
};
|
||||
|
||||
static const QMap<QString, IconProperties> iconmapper_ = {
|
||||
|
||||
{ "albums", { {"media-optical"}, 0, 0 } },
|
||||
{ "alsa", { {}, 0, 0 } },
|
||||
{ "application-exit", { {}, 0, 0 } },
|
||||
{ "applications-internet", { {}, 0, 0 } },
|
||||
{ "bluetooth", { {"preferences-system-bluetooth", "bluetooth-active"}, 0, 0 } },
|
||||
{ "cdcase", { {"cdcover", "media-optical"}, 0, 0 } },
|
||||
{ "media-optical", { {"cd"}, 0, 0 } },
|
||||
{ "configure", { {}, 0, 0 } },
|
||||
{ "device-ipod-nano", { {}, 0, 0 } },
|
||||
{ "device-ipod", { {}, 0, 0 } },
|
||||
{ "device-phone", { {}, 0, 0 } },
|
||||
{ "device", { {"drive-removable-media-usb-pendrive"}, 0, 0 } },
|
||||
{ "device-usb-drive", { {}, 0, 0 } },
|
||||
{ "device-usb-flash", { {}, 0, 0 } },
|
||||
{ "dialog-error", { {}, 0, 0 } },
|
||||
{ "dialog-information", { {}, 0, 0 } },
|
||||
{ "dialog-ok-apply", { {}, 0, 0 } },
|
||||
{ "dialog-password", { {}, 0, 0 } },
|
||||
{ "dialog-warning", { {}, 0, 0 } },
|
||||
{ "document-download", { {}, 0, 0 } },
|
||||
{ "document-new", { {}, 0, 0 } },
|
||||
{ "document-open-folder", { {}, 0, 0 } },
|
||||
{ "document-open", { {}, 0, 0 } },
|
||||
{ "document-save", { {}, 0, 0 } },
|
||||
{ "document-search", { {}, 0, 0 } },
|
||||
{ "download", { {"applications-internet", "network-workgroup"}, 0, 0 } },
|
||||
{ "edit-clear-list", { {}, 0, 0 } },
|
||||
{ "edit-clear-locationbar-ltr", { {}, 0, 0 } },
|
||||
{ "edit-copy", { {}, 0, 0 } },
|
||||
{ "edit-delete", { {}, 0, 0 } },
|
||||
{ "edit-find", { {}, 0, 0 } },
|
||||
{ "edit-redo", { {}, 0, 0 } },
|
||||
{ "edit-rename", { {}, 0, 0 } },
|
||||
{ "edit-undo", { {}, 0, 0 } },
|
||||
{ "electrocompaniet", { {}, 0, 0 } },
|
||||
{ "equalizer", { {"view-media-equalizer"}, 0, 0 } },
|
||||
{ "folder-new", { {}, 0, 0 } },
|
||||
{ "folder", { {}, 0, 0 } },
|
||||
{ "folder-sound", { {"folder-music"}, 0, 0 } },
|
||||
{ "footsteps", { {"go-jump"}, 0, 0 } },
|
||||
{ "go-down", { {}, 0, 0 } },
|
||||
{ "go-home", { {}, 0, 0 } },
|
||||
{ "go-jump", { {}, 0, 0 } },
|
||||
{ "go-next", { {}, 0, 0 } },
|
||||
{ "go-previous", { {}, 0, 0 } },
|
||||
{ "go-up", { {}, 0, 0 } },
|
||||
{ "gstreamer", { {"phonon-gstreamer"}, 0, 0 } },
|
||||
{ "headset", { {"audio-headset"}, 0, 0 } },
|
||||
{ "help-hint", { {}, 0, 0 } },
|
||||
{ "intel", { {}, 0, 0 } },
|
||||
{ "jack", { {"audio-input-line"}, 0, 0 } },
|
||||
{ "keyboard", { {"input-keyboard"}, 0, 0 } },
|
||||
{ "list-add", { {}, 0, 0 } },
|
||||
{ "list-remove", { {}, 0, 0 } },
|
||||
{ "love", { {"heart", "emblem-favorite"}, 0, 0 } },
|
||||
{ "mcintosh-player", { {}, 0, 0 } },
|
||||
{ "mcintosh", { {}, 0, 0 } },
|
||||
{ "mcintosh-text", { {}, 0, 0 } },
|
||||
{ "media-eject", { {}, 0, 0 } },
|
||||
{ "media-playback-pause", { {"media-pause"}, 0, 0 } },
|
||||
{ "media-playlist-repeat", { {}, 0, 0 } },
|
||||
{ "media-playlist-shuffle", { {""}, 0, 0 } },
|
||||
{ "media-playback-start", { {"media-play", "media-playback-playing"}, 0, 0 } },
|
||||
{ "media-seek-backward", { {}, 0, 0 } },
|
||||
{ "media-seek-forward", { {}, 0, 0 } },
|
||||
{ "media-skip-backward", { {}, 0, 0 } },
|
||||
{ "media-skip-forward", { {}, 0, 0 } },
|
||||
{ "media-playback-stop", { {"media-stop"}, 0, 0 } },
|
||||
{ "moodbar", { {"preferences-desktop-icons"}, 0, 0 } },
|
||||
{ "nvidia", { {}, 0, 0 } },
|
||||
{ "pulseaudio", { {}, 0, 0 } },
|
||||
{ "qobuz", { {}, 0, 0 } },
|
||||
{ "realtek", { {}, 0, 0 } },
|
||||
{ "scrobble-disabled", { {}, 0, 0 } },
|
||||
{ "scrobble", { {}, 0, 0 } },
|
||||
{ "search", { {}, 0, 0 } },
|
||||
{ "soundcard", { {"audiocard", "audio-card"}, 0, 0 } },
|
||||
{ "speaker", { {}, 0, 0 } },
|
||||
{ "star-grey", { {}, 0, 0 } },
|
||||
{ "star", { {}, 0, 0 } },
|
||||
{ "strawberry", { {}, 0, 0 } },
|
||||
{ "subsonic", { {}, 0, 0 } },
|
||||
{ "tidal", { {}, 0, 0 } },
|
||||
{ "tools-wizard", { {}, 0, 0 } },
|
||||
{ "view-choose", { {}, 0, 0 } },
|
||||
{ "view-fullscreen", { {}, 0, 0 } },
|
||||
{ "view-media-lyrics", { {}, 0, 0 } },
|
||||
{ "view-media-playlist", { {}, 0, 0 } },
|
||||
{ "view-media-visualization", { {"preferences-desktop-theme"}, 0, 0 } },
|
||||
{ "view-refresh", { {}, 0, 0 } },
|
||||
{ "library-music", { {"vinyl"}, 0, 0 } },
|
||||
{ "vlc", { {}, 0, 0 } },
|
||||
{ "xine", { {}, 0, 0 } },
|
||||
{ "zoom-in", { {}, 0, 0 } },
|
||||
{ "zoom-out", { {}, 0, 0 } }
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -273,7 +273,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
|
||||
// Add tabs to the fancy tab widget
|
||||
ui_->tabs->AddTab(context_view_, "context", IconLoader::Load("strawberry"), tr("Context"));
|
||||
ui_->tabs->AddTab(collection_view_, "collection", IconLoader::Load("vinyl"), tr("Collection"));
|
||||
ui_->tabs->AddTab(collection_view_, "collection", IconLoader::Load("library-music"), tr("Collection"));
|
||||
ui_->tabs->AddTab(file_view_, "files", IconLoader::Load("document-open"), tr("Files"));
|
||||
ui_->tabs->AddTab(playlist_list_, "playlists", IconLoader::Load("view-media-playlist"), tr("Playlists"));
|
||||
ui_->tabs->AddTab(queue_view_, "queue", IconLoader::Load("footsteps"), tr("Queue"));
|
||||
@@ -346,11 +346,11 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
// Music menu
|
||||
|
||||
ui_->action_open_file->setIcon(IconLoader::Load("document-open"));
|
||||
ui_->action_open_cd->setIcon(IconLoader::Load("cd"));
|
||||
ui_->action_open_cd->setIcon(IconLoader::Load("media-optical"));
|
||||
ui_->action_previous_track->setIcon(IconLoader::Load("media-skip-backward"));
|
||||
ui_->action_play_pause->setIcon(IconLoader::Load("media-play"));
|
||||
ui_->action_stop->setIcon(IconLoader::Load("media-stop"));
|
||||
ui_->action_stop_after_this_track->setIcon(IconLoader::Load("media-stop"));
|
||||
ui_->action_play_pause->setIcon(IconLoader::Load("media-playback-start"));
|
||||
ui_->action_stop->setIcon(IconLoader::Load("media-playback-stop"));
|
||||
ui_->action_stop_after_this_track->setIcon(IconLoader::Load("media-playback-stop"));
|
||||
ui_->action_next_track->setIcon(IconLoader::Load("media-skip-forward"));
|
||||
ui_->action_quit->setIcon(IconLoader::Load("application-exit"));
|
||||
|
||||
@@ -594,7 +594,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
connect(playlist_menu_, SIGNAL(aboutToHide()), SLOT(PlaylistMenuHidden()));
|
||||
playlist_play_pause_ = playlist_menu_->addAction(tr("Play"), this, SLOT(PlaylistPlay()));
|
||||
playlist_menu_->addAction(ui_->action_stop);
|
||||
playlist_stop_after_ = playlist_menu_->addAction(IconLoader::Load("media-stop"), tr("Stop after this track"), this, SLOT(PlaylistStopAfter()));
|
||||
playlist_stop_after_ = playlist_menu_->addAction(IconLoader::Load("media-playback-stop"), tr("Stop after this track"), this, SLOT(PlaylistStopAfter()));
|
||||
playlist_queue_ = playlist_menu_->addAction(IconLoader::Load("go-next"), tr("Toggle queue status"), this, SLOT(PlaylistQueue()));
|
||||
playlist_queue_->setShortcut(QKeySequence("Ctrl+D"));
|
||||
ui_->playlist->addAction(playlist_queue_);
|
||||
@@ -1040,7 +1040,7 @@ void MainWindow::MediaStopped() {
|
||||
|
||||
ui_->action_stop->setEnabled(false);
|
||||
ui_->action_stop_after_this_track->setEnabled(false);
|
||||
ui_->action_play_pause->setIcon(IconLoader::Load("media-play"));
|
||||
ui_->action_play_pause->setIcon(IconLoader::Load("media-playback-start"));
|
||||
ui_->action_play_pause->setText(tr("Play"));
|
||||
|
||||
ui_->action_play_pause->setEnabled(true);
|
||||
@@ -1069,7 +1069,7 @@ void MainWindow::MediaPaused() {
|
||||
|
||||
ui_->action_stop->setEnabled(true);
|
||||
ui_->action_stop_after_this_track->setEnabled(true);
|
||||
ui_->action_play_pause->setIcon(IconLoader::Load("media-play"));
|
||||
ui_->action_play_pause->setIcon(IconLoader::Load("media-playback-start"));
|
||||
ui_->action_play_pause->setText(tr("Play"));
|
||||
|
||||
ui_->action_play_pause->setEnabled(true);
|
||||
@@ -1087,7 +1087,7 @@ void MainWindow::MediaPlaying() {
|
||||
|
||||
ui_->action_stop->setEnabled(true);
|
||||
ui_->action_stop_after_this_track->setEnabled(true);
|
||||
ui_->action_play_pause->setIcon(IconLoader::Load("media-pause"));
|
||||
ui_->action_play_pause->setIcon(IconLoader::Load("media-playback-pause"));
|
||||
ui_->action_play_pause->setText(tr("Pause"));
|
||||
|
||||
bool enable_play_pause(false);
|
||||
@@ -1257,9 +1257,11 @@ void MainWindow::PlayIndex(const QModelIndex &index) {
|
||||
|
||||
app_->playlist_manager()->SetActiveToCurrent();
|
||||
app_->player()->PlayAt(row, Engine::Manual, true);
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::PlaylistDoubleClick(const QModelIndex &index) {
|
||||
|
||||
if (!index.isValid()) return;
|
||||
|
||||
int row = index.row();
|
||||
@@ -1284,6 +1286,7 @@ void MainWindow::PlaylistDoubleClick(const QModelIndex &index) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::VolumeWheelEvent(int delta) {
|
||||
@@ -1315,6 +1318,7 @@ void MainWindow::ToggleShowHide() {
|
||||
activateWindow();
|
||||
raise();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::StopAfterCurrent() {
|
||||
@@ -1330,12 +1334,12 @@ void MainWindow::closeEvent(QCloseEvent *event) {
|
||||
settings.endGroup();
|
||||
|
||||
if (keep_running && event->spontaneous() && QSystemTrayIcon::isSystemTrayAvailable()) {
|
||||
event->ignore();
|
||||
SetHiddenInTray(true);
|
||||
}
|
||||
else {
|
||||
Exit();
|
||||
}
|
||||
event->ignore();
|
||||
|
||||
}
|
||||
|
||||
@@ -1352,6 +1356,7 @@ void MainWindow::SetHiddenInTray(bool hidden) {
|
||||
if (was_maximized_) showMaximized();
|
||||
else show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::FilePathChanged(const QString &path) {
|
||||
@@ -1526,11 +1531,11 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
||||
// Is this song currently playing?
|
||||
if (app_->playlist_manager()->current()->current_row() == source_index.row() && app_->player()->GetState() == Engine::Playing) {
|
||||
playlist_play_pause_->setText(tr("Pause"));
|
||||
playlist_play_pause_->setIcon(IconLoader::Load("media-pause"));
|
||||
playlist_play_pause_->setIcon(IconLoader::Load("media-playback-pause"));
|
||||
}
|
||||
else {
|
||||
playlist_play_pause_->setText(tr("Play"));
|
||||
playlist_play_pause_->setIcon(IconLoader::Load("media-play"));
|
||||
playlist_play_pause_->setIcon(IconLoader::Load("media-playback-start"));
|
||||
}
|
||||
|
||||
// Are we allowed to pause?
|
||||
@@ -1643,7 +1648,7 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
||||
else playlist_queue_->setIcon(IconLoader::Load("go-next"));
|
||||
|
||||
if (in_skipped < selected) playlist_skip_->setIcon(IconLoader::Load("media-skip-forward"));
|
||||
else playlist_skip_->setIcon(IconLoader::Load("media-play"));
|
||||
else playlist_skip_->setIcon(IconLoader::Load("media-playback-start"));
|
||||
|
||||
|
||||
if (!index.isValid()) {
|
||||
@@ -2106,9 +2111,10 @@ void MainWindow::PlaylistUndoRedoChanged(QAction *undo, QAction *redo) {
|
||||
playlist_menu_->insertAction(playlist_undoredo_, redo);
|
||||
}
|
||||
|
||||
#ifdef HAVE_GSTREAMER
|
||||
void MainWindow::AddFilesToTranscoder() {
|
||||
|
||||
#ifdef HAVE_GSTREAMER
|
||||
|
||||
QStringList filenames;
|
||||
|
||||
for (const QModelIndex &index : ui_->playlist->view()->selectionModel()->selection().indexes()) {
|
||||
@@ -2122,21 +2128,24 @@ void MainWindow::AddFilesToTranscoder() {
|
||||
transcode_dialog_->SetFilenames(filenames);
|
||||
|
||||
ShowTranscodeDialog();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::ShowCollectionConfig() {
|
||||
//EnsureSettingsDialogCreated();
|
||||
settings_dialog_->OpenAtPage(SettingsDialog::Page_Collection);
|
||||
}
|
||||
|
||||
void MainWindow::TaskCountChanged(int count) {
|
||||
|
||||
if (count == 0) {
|
||||
ui_->status_bar_stack->setCurrentWidget(ui_->playlist_summary_page);
|
||||
}
|
||||
else {
|
||||
ui_->status_bar_stack->setCurrentWidget(ui_->multi_loading_indicator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::PlayingWidgetPositionChanged(bool above_status_bar) {
|
||||
@@ -2339,13 +2348,13 @@ void MainWindow::ShowAboutDialog() {
|
||||
|
||||
}
|
||||
|
||||
#ifdef HAVE_GSTREAMER
|
||||
void MainWindow::ShowTranscodeDialog() {
|
||||
|
||||
#ifdef HAVE_GSTREAMER
|
||||
transcode_dialog_->show();
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void MainWindow::ShowErrorDialog(const QString &message) {
|
||||
error_dialog_->ShowMessage(message);
|
||||
@@ -2421,9 +2430,10 @@ bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *r
|
||||
|
||||
}
|
||||
|
||||
#if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
|
||||
void MainWindow::AutoCompleteTags() {
|
||||
|
||||
#if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
|
||||
|
||||
// Create the tag fetching stuff if it hasn't been already
|
||||
if (!tag_fetcher_) {
|
||||
tag_fetcher_.reset(new TagFetcher);
|
||||
@@ -2456,6 +2466,9 @@ void MainWindow::AutoCompleteTags() {
|
||||
tag_fetcher_->StartFetch(songs);
|
||||
|
||||
track_selection_dialog_->show();
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::AutoCompleteTagsAccepted() {
|
||||
@@ -2466,8 +2479,8 @@ void MainWindow::AutoCompleteTagsAccepted() {
|
||||
|
||||
// This is really lame but we don't know what rows have changed
|
||||
ui_->playlist->view()->update();
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void MainWindow::HandleNotificationPreview(OSD::Behaviour type, QString line1, QString line2) {
|
||||
|
||||
|
||||
@@ -162,14 +162,10 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
void RenumberTracks();
|
||||
void SelectionSetValue();
|
||||
void EditValue();
|
||||
#if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
|
||||
void AutoCompleteTags();
|
||||
void AutoCompleteTagsAccepted();
|
||||
#endif
|
||||
void PlaylistUndoRedoChanged(QAction *undo, QAction *redo);
|
||||
#ifdef HAVE_GSTREAMER
|
||||
void AddFilesToTranscoder();
|
||||
#endif
|
||||
|
||||
void PlaylistCopyToCollection();
|
||||
void PlaylistMoveToCollection();
|
||||
@@ -225,9 +221,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
void ShowCoverManager();
|
||||
|
||||
void ShowAboutDialog();
|
||||
#ifdef HAVE_GSTREAMER
|
||||
void ShowTranscodeDialog();
|
||||
#endif
|
||||
void ShowErrorDialog(const QString& message);
|
||||
SettingsDialog *CreateSettingsDialog();
|
||||
EditTagDialog *CreateEditTagDialog();
|
||||
@@ -319,9 +313,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
std::unique_ptr<TagFetcher> tag_fetcher_;
|
||||
#endif
|
||||
std::unique_ptr<TrackSelectionDialog> track_selection_dialog_;
|
||||
#if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
|
||||
PlaylistItemList autocomplete_tag_items_;
|
||||
#endif
|
||||
|
||||
InternetTabsView *tidal_view_;
|
||||
InternetTabsView *qobuz_view_;
|
||||
|
||||
@@ -55,7 +55,7 @@ inline void AddMetadata(const QString &key, const QDateTime &metadata, QVariantM
|
||||
if (metadata.isValid()) (*map)[key] = metadata;
|
||||
}
|
||||
|
||||
inline QString AsMPRISDateTimeType(uint time) {
|
||||
inline QString AsMPRISDateTimeType(const int time) {
|
||||
return time != -1 ? QDateTime::fromTime_t(time).toString(Qt::ISODate) : "";
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ Player::Player(Application *app, QObject *parent)
|
||||
last_pressed_previous_(QDateTime::currentDateTime()),
|
||||
continue_on_error_(false),
|
||||
greyout_(true),
|
||||
menu_previousmode_(PreviousBehaviour_DontRestart),
|
||||
menu_previousmode_(BehaviourSettingsPage::PreviousBehaviour_DontRestart),
|
||||
seek_step_sec_(10),
|
||||
volume_control_(true)
|
||||
{
|
||||
@@ -200,14 +200,15 @@ void Player::Init() {
|
||||
connect(engine_.get(), SIGNAL(MetaData(Engine::SimpleMetaBundle)), SLOT(EngineMetadataReceived(Engine::SimpleMetaBundle)));
|
||||
|
||||
// Equalizer
|
||||
qLog(Debug) << "Creating equalizer";
|
||||
connect(equalizer_, SIGNAL(ParametersChanged(int,QList<int>)), app_->player()->engine(), SLOT(SetEqualizerParameters(int,QList<int>)));
|
||||
connect(equalizer_, SIGNAL(EnabledChanged(bool)), app_->player()->engine(), SLOT(SetEqualizerEnabled(bool)));
|
||||
connect(equalizer_, SIGNAL(StereoBalancerEnabledChanged(bool)), app_->player()->engine(), SLOT(SetStereoBalancerEnabled(bool)));
|
||||
connect(equalizer_, SIGNAL(StereoBalanceChanged(float)), app_->player()->engine(), SLOT(SetStereoBalance(float)));
|
||||
connect(equalizer_, SIGNAL(EqualizerEnabledChanged(bool)), app_->player()->engine(), SLOT(SetEqualizerEnabled(bool)));
|
||||
connect(equalizer_, SIGNAL(EqualizerParametersChanged(int, QList<int>)), app_->player()->engine(), SLOT(SetEqualizerParameters(int, QList<int>)));
|
||||
|
||||
engine_->SetEqualizerEnabled(equalizer_->is_enabled());
|
||||
engine_->SetEqualizerParameters(equalizer_->preamp_value(), equalizer_->gain_values());
|
||||
engine_->SetStereoBalancerEnabled(equalizer_->is_stereo_balancer_enabled());
|
||||
engine_->SetStereoBalance(equalizer_->stereo_balance());
|
||||
engine_->SetEqualizerEnabled(equalizer_->is_equalizer_enabled());
|
||||
engine_->SetEqualizerParameters(equalizer_->preamp_value(), equalizer_->gain_values());
|
||||
|
||||
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
||||
volume_control_ = s.value("volume_control", true).toBool();
|
||||
@@ -229,10 +230,10 @@ void Player::ReloadSettings() {
|
||||
s.beginGroup(PlaylistSettingsPage::kSettingsGroup);
|
||||
continue_on_error_ = s.value("continue_on_error", false).toBool();
|
||||
greyout_ = s.value("greyout_songs_play", true).toBool();
|
||||
menu_previousmode_ = PreviousBehaviour(s.value("menu_previousmode", PreviousBehaviour_DontRestart).toInt());
|
||||
s.endGroup();
|
||||
|
||||
s.beginGroup(BehaviourSettingsPage::kSettingsGroup);
|
||||
menu_previousmode_ = BehaviourSettingsPage::PreviousBehaviour(s.value("menu_previousmode", BehaviourSettingsPage::PreviousBehaviour_DontRestart).toInt());
|
||||
seek_step_sec_ = s.value("seek_step_sec", 10).toInt();
|
||||
s.endGroup();
|
||||
|
||||
@@ -502,7 +503,7 @@ void Player::StopAfterCurrent() {
|
||||
bool Player::PreviousWouldRestartTrack() const {
|
||||
|
||||
// Check if it has been over two seconds since previous button was pressed
|
||||
return menu_previousmode_ == PreviousBehaviour_Restart && last_pressed_previous_.isValid() && last_pressed_previous_.secsTo(QDateTime::currentDateTime()) >= 2;
|
||||
return menu_previousmode_ == BehaviourSettingsPage::PreviousBehaviour_Restart && last_pressed_previous_.isValid() && last_pressed_previous_.secsTo(QDateTime::currentDateTime()) >= 2;
|
||||
}
|
||||
|
||||
void Player::Previous() { PreviousItem(Engine::Manual); }
|
||||
@@ -511,7 +512,7 @@ void Player::PreviousItem(Engine::TrackChangeFlags change) {
|
||||
|
||||
const bool ignore_repeat_track = change & Engine::Manual;
|
||||
|
||||
if (menu_previousmode_ == PreviousBehaviour_Restart) {
|
||||
if (menu_previousmode_ == BehaviourSettingsPage::PreviousBehaviour_Restart) {
|
||||
// Check if it has been over two seconds since previous button was pressed
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
if (last_pressed_previous_.isValid() && last_pressed_previous_.secsTo(now) >= 2) {
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "engine/gststartup.h"
|
||||
#endif
|
||||
#include "playlist/playlistitem.h"
|
||||
#include "settings/behavioursettingspage.h"
|
||||
|
||||
class Application;
|
||||
class Song;
|
||||
@@ -136,12 +137,6 @@ class Player : public PlayerInterface {
|
||||
|
||||
static const char *kSettingsGroup;
|
||||
|
||||
// Don't change the values: they are saved in preferences
|
||||
enum PreviousBehaviour {
|
||||
PreviousBehaviour_DontRestart = 1,
|
||||
PreviousBehaviour_Restart = 2
|
||||
};
|
||||
|
||||
Engine::EngineType CreateEngine(Engine::EngineType enginetype);
|
||||
void Init();
|
||||
|
||||
@@ -240,7 +235,7 @@ class Player : public PlayerInterface {
|
||||
|
||||
bool continue_on_error_;
|
||||
bool greyout_;
|
||||
PreviousBehaviour menu_previousmode_;
|
||||
BehaviourSettingsPage::PreviousBehaviour menu_previousmode_;
|
||||
int seek_step_sec_;
|
||||
|
||||
bool volume_control_;
|
||||
|
||||
@@ -190,7 +190,7 @@ void QtSystemTrayIcon::SetPaused() {
|
||||
|
||||
action_stop_->setEnabled(true);
|
||||
action_stop_after_this_track_->setEnabled(true);
|
||||
action_play_pause_->setIcon(IconLoader::Load("media-play"));
|
||||
action_play_pause_->setIcon(IconLoader::Load("media-playback-start"));
|
||||
action_play_pause_->setText(tr("Play"));
|
||||
|
||||
action_play_pause_->setEnabled(true);
|
||||
@@ -203,7 +203,7 @@ void QtSystemTrayIcon::SetPlaying(bool enable_play_pause) {
|
||||
|
||||
action_stop_->setEnabled(true);
|
||||
action_stop_after_this_track_->setEnabled(true);
|
||||
action_play_pause_->setIcon(IconLoader::Load("media-pause"));
|
||||
action_play_pause_->setIcon(IconLoader::Load("media-playback-pause"));
|
||||
action_play_pause_->setText(tr("Pause"));
|
||||
action_play_pause_->setEnabled(enable_play_pause);
|
||||
|
||||
@@ -215,7 +215,7 @@ void QtSystemTrayIcon::SetStopped() {
|
||||
|
||||
action_stop_->setEnabled(false);
|
||||
action_stop_after_this_track_->setEnabled(false);
|
||||
action_play_pause_->setIcon(IconLoader::Load("media-play"));
|
||||
action_play_pause_->setIcon(IconLoader::Load("media-playback-start"));
|
||||
action_play_pause_->setText(tr("Play"));
|
||||
|
||||
action_play_pause_->setEnabled(true);
|
||||
|
||||
@@ -152,6 +152,7 @@ const QString Song::kEmbeddedCover = "(embedded)";
|
||||
const QRegExp Song::kAlbumRemoveDisc(" ?-? ((\\(|\\[)?)(Disc|CD) ?([0-9]{1,2})((\\)|\\])?)$");
|
||||
const QRegExp Song::kAlbumRemoveMisc(" ?-? ((\\(|\\[)?)(Remastered|([0-9]{1,4}) *Remaster) ?((\\)|\\])?)$");
|
||||
const QRegExp Song::kTitleRemoveMisc(" ?-? ((\\(|\\[)?)(Remastered|Live|Remastered Version|([0-9]{1,4}) *Remaster) ?((\\)|\\])?)$");
|
||||
const QString Song::kVariousArtists("various artists");
|
||||
|
||||
const QStringList Song::kArticles = QStringList() << "the " << "a " << "an ";
|
||||
|
||||
@@ -296,14 +297,15 @@ const QString &Song::albumartist() const { return d->albumartist_; }
|
||||
const QString &Song::albumartist_sortable() const { return d->albumartist_sortable_; }
|
||||
const QString &Song::effective_albumartist() const { return d->albumartist_.isEmpty() ? d->artist_ : d->albumartist_; }
|
||||
const QString &Song::effective_albumartist_sortable() const { return d->albumartist_.isEmpty() ? d->artist_sortable_ : d->albumartist_sortable_; }
|
||||
const QString &Song::playlist_albumartist() const { return is_compilation() ? d->albumartist_sortable_ : effective_albumartist_sortable(); }
|
||||
const QString &Song::playlist_albumartist() const { return is_compilation() ? d->albumartist_ : effective_albumartist(); }
|
||||
const QString &Song::playlist_albumartist_sortable() const { return is_compilation() ? d->albumartist_sortable_ : effective_albumartist_sortable(); }
|
||||
int Song::track() const { return d->track_; }
|
||||
int Song::disc() const { return d->disc_; }
|
||||
int Song::year() const { return d->year_; }
|
||||
int Song::originalyear() const { return d->originalyear_; }
|
||||
int Song::effective_originalyear() const { return d->originalyear_ < 0 ? d->year_ : d->originalyear_; }
|
||||
const QString &Song::genre() const { return d->genre_; }
|
||||
bool Song::is_compilation() const { return (d->compilation_ || d->compilation_detected_ || d->compilation_on_) && ! d->compilation_off_; }
|
||||
bool Song::compilation() const { return d->compilation_; }
|
||||
const QString &Song::composer() const { return d->composer_; }
|
||||
const QString &Song::performer() const { return d->performer_; }
|
||||
const QString &Song::grouping() const { return d->grouping_; }
|
||||
@@ -331,6 +333,10 @@ int Song::playcount() const { return d->playcount_; }
|
||||
int Song::skipcount() const { return d->skipcount_; }
|
||||
int Song::lastplayed() const { return d->lastplayed_; }
|
||||
|
||||
bool Song::compilation_detected() const { return d->compilation_detected_; }
|
||||
bool Song::compilation_off() const { return d->compilation_off_; }
|
||||
bool Song::compilation_on() const { return d->compilation_on_; }
|
||||
|
||||
const QUrl &Song::art_automatic() const { return d->art_automatic_; }
|
||||
const QUrl &Song::art_manual() const { return d->art_manual_; }
|
||||
bool Song::has_manually_unset_cover() const { return d->art_manual_.path() == kManuallyUnsetCover; }
|
||||
@@ -346,9 +352,10 @@ const QString &Song::cue_path() const { return d->cue_path_; }
|
||||
bool Song::has_cue() const { return !d->cue_path_.isEmpty(); }
|
||||
|
||||
bool Song::is_collection_song() const { return d->source_ == Source_Collection; }
|
||||
bool Song::is_metadata_good() const { return !d->title_.isEmpty() && !d->album_.isEmpty() && !d->artist_.isEmpty() && !d->url_.isEmpty() && d->end_ > 0; }
|
||||
bool Song::is_metadata_good() const { return !d->title_.isEmpty() && !d->artist_.isEmpty() && !d->url_.isEmpty() && d->end_ > 0; }
|
||||
bool Song::is_stream() const { return d->source_ == Source_Stream || d->source_ == Source_Tidal || d->source_ == Source_Subsonic || d->source_ == Source_Qobuz; }
|
||||
bool Song::is_cdda() const { return d->source_ == Source_CDDA; }
|
||||
bool Song::is_compilation() const { return (d->compilation_ || d->compilation_detected_ || d->compilation_on_) && !d->compilation_off_; }
|
||||
|
||||
bool Song::art_automatic_is_valid() const {
|
||||
return (
|
||||
@@ -420,15 +427,7 @@ void Song::set_bitdepth(int v) { d->bitdepth_ = v; }
|
||||
|
||||
void Song::set_source(Source v) { d->source_ = v; }
|
||||
void Song::set_directory_id(int v) { d->directory_id_ = v; }
|
||||
void Song::set_url(const QUrl &v) {
|
||||
if (Application::kIsPortable) {
|
||||
QUrl base = QUrl::fromLocalFile(QCoreApplication::applicationDirPath() + "/");
|
||||
d->url_ = base.resolved(v);
|
||||
}
|
||||
else {
|
||||
d->url_ = v;
|
||||
}
|
||||
}
|
||||
void Song::set_url(const QUrl &v) { d->url_ = v; }
|
||||
void Song::set_basefilename(const QString &v) { d->basefilename_ = v; }
|
||||
void Song::set_filetype(FileType v) { d->filetype_ = v; }
|
||||
void Song::set_filesize(int v) { d->filesize_ = v; }
|
||||
@@ -488,8 +487,8 @@ QIcon Song::IconForSource(Source source) {
|
||||
|
||||
switch (source) {
|
||||
case Song::Source_LocalFile: return IconLoader::Load("folder-sound");
|
||||
case Song::Source_Collection: return IconLoader::Load("vinyl");
|
||||
case Song::Source_CDDA: return IconLoader::Load("cd");
|
||||
case Song::Source_Collection: return IconLoader::Load("library-music");
|
||||
case Song::Source_CDDA: return IconLoader::Load("media-optical");
|
||||
case Song::Source_Device: return IconLoader::Load("device");
|
||||
case Song::Source_Stream: return IconLoader::Load("applications-internet");
|
||||
case Song::Source_Tidal: return IconLoader::Load("tidal");
|
||||
@@ -943,7 +942,7 @@ void Song::InitFromQuery(const SqlRow &q, bool reliable_metadata, int col) {
|
||||
set_art_automatic(QUrl::fromEncoded(art_automatic.toUtf8()));
|
||||
}
|
||||
else {
|
||||
set_art_automatic(QUrl::fromLocalFile(art_automatic.toUtf8()));
|
||||
set_art_automatic(QUrl::fromLocalFile(art_automatic));
|
||||
}
|
||||
}
|
||||
else if (Song::kColumns.value(i) == "art_manual") {
|
||||
@@ -952,7 +951,7 @@ void Song::InitFromQuery(const SqlRow &q, bool reliable_metadata, int col) {
|
||||
set_art_manual(QUrl::fromEncoded(art_manual.toUtf8()));
|
||||
}
|
||||
else {
|
||||
set_art_manual(QUrl::fromLocalFile(art_manual.toUtf8()));
|
||||
set_art_manual(QUrl::fromLocalFile(art_manual));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1281,18 +1280,7 @@ void Song::BindToQuery(QSqlQuery *query) const {
|
||||
|
||||
query->bindValue(":source", d->source_);
|
||||
query->bindValue(":directory_id", notnullintval(d->directory_id_));
|
||||
|
||||
QString url;
|
||||
if (d->url_.isValid()) {
|
||||
if (Application::kIsPortable && Utilities::UrlOnSameDriveAsStrawberry(d->url_)) {
|
||||
url = Utilities::GetRelativePathToStrawberryBin(d->url_).toEncoded();
|
||||
}
|
||||
else {
|
||||
url = d->url_.toEncoded();
|
||||
}
|
||||
}
|
||||
query->bindValue(":url", url);
|
||||
|
||||
query->bindValue(":url", d->url_.toString(QUrl::FullyEncoded));
|
||||
query->bindValue(":filetype", d->filetype_);
|
||||
query->bindValue(":filesize", notnullintval(d->filesize_));
|
||||
query->bindValue(":mtime", notnullintval(d->mtime_));
|
||||
@@ -1308,8 +1296,8 @@ void Song::BindToQuery(QSqlQuery *query) const {
|
||||
query->bindValue(":compilation_off", d->compilation_off_ ? 1 : 0);
|
||||
query->bindValue(":compilation_effective", is_compilation() ? 1 : 0);
|
||||
|
||||
query->bindValue(":art_automatic", d->art_automatic_);
|
||||
query->bindValue(":art_manual", d->art_manual_);
|
||||
query->bindValue(":art_automatic", d->art_automatic_.toString(QUrl::FullyEncoded));
|
||||
query->bindValue(":art_manual", d->art_manual_.toString(QUrl::FullyEncoded));
|
||||
|
||||
query->bindValue(":effective_albumartist", this->effective_albumartist());
|
||||
query->bindValue(":effective_originalyear", intval(this->effective_originalyear()));
|
||||
|
||||
@@ -126,6 +126,8 @@ class Song {
|
||||
static const QRegExp kTitleRemoveMisc;
|
||||
static const QRegExp kFilenameRemoveNonFatChars;
|
||||
|
||||
static const QString kVariousArtists;
|
||||
|
||||
static const QStringList kArticles;
|
||||
|
||||
static QString JoinSpec(const QString &table);
|
||||
@@ -200,7 +202,7 @@ class Song {
|
||||
int year() const;
|
||||
int originalyear() const;
|
||||
const QString &genre() const;
|
||||
bool is_compilation() const;
|
||||
bool compilation() const;
|
||||
const QString &composer() const;
|
||||
const QString &performer() const;
|
||||
const QString &grouping() const;
|
||||
@@ -232,6 +234,10 @@ class Song {
|
||||
int skipcount() const;
|
||||
int lastplayed() const;
|
||||
|
||||
bool compilation_detected() const;
|
||||
bool compilation_off() const;
|
||||
bool compilation_on() const;
|
||||
|
||||
const QUrl &art_automatic() const;
|
||||
const QUrl &art_manual() const;
|
||||
|
||||
@@ -249,9 +255,11 @@ class Song {
|
||||
bool is_metadata_good() const;
|
||||
bool art_automatic_is_valid() const;
|
||||
bool art_manual_is_valid() const;
|
||||
bool is_compilation() const;
|
||||
|
||||
// Playlist views are special because you don't want to fill in album artists automatically for compilations, but you do for normal albums:
|
||||
const QString &playlist_albumartist() const;
|
||||
const QString &playlist_albumartist_sortable() const;
|
||||
|
||||
// Returns true if this Song had it's cover manually unset by user.
|
||||
bool has_manually_unset_cover() const;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Strawberry Music Player
|
||||
* This file was part of Clementine.
|
||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -167,7 +168,7 @@ SongLoader::Result SongLoader::LoadLocalPartial(const QString &filename) {
|
||||
LoadLocalDirectory(filename);
|
||||
return Success;
|
||||
}
|
||||
Song song;
|
||||
Song song(Song::Source_LocalFile);
|
||||
song.InitFromFilePartial(filename);
|
||||
if (song.is_valid()) {
|
||||
songs_ << song;
|
||||
@@ -228,7 +229,7 @@ SongLoader::Result SongLoader::LoadLocal(const QString &filename) {
|
||||
if (collection_->ExecQuery(&query) && query.Next()) {
|
||||
// We may have many results when the file has many sections
|
||||
do {
|
||||
Song song;
|
||||
Song song(Song::Source_Collection);
|
||||
song.InitFromQuery(query, true);
|
||||
|
||||
if (song.is_valid()) {
|
||||
@@ -289,7 +290,7 @@ SongLoader::Result SongLoader::LoadLocalAsync(const QString &filename) {
|
||||
}
|
||||
|
||||
// Assume it's just a normal file
|
||||
Song song;
|
||||
Song song(Song::Source_LocalFile);
|
||||
song.InitFromFilePartial(filename);
|
||||
if (song.is_valid()) {
|
||||
songs_ << song;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Strawberry Music Player
|
||||
* This file was part of Clementine.
|
||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2018-2019, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -46,8 +46,9 @@ TagReaderClient::TagReaderClient(QObject *parent) : QObject(parent), worker_pool
|
||||
original_thread_ = thread();
|
||||
|
||||
worker_pool_->SetExecutableName(kWorkerExecutableName);
|
||||
worker_pool_->SetWorkerCount(QThread::idealThreadCount());
|
||||
worker_pool_->SetWorkerCount(qBound(1, QThread::idealThreadCount() / 2, 4));
|
||||
connect(worker_pool_, SIGNAL(WorkerFailedToStart()), SLOT(WorkerFailedToStart()));
|
||||
|
||||
}
|
||||
|
||||
void TagReaderClient::Start() { worker_pool_->Start(); }
|
||||
|
||||
@@ -514,6 +514,26 @@ bool ParseUntilElement(QXmlStreamReader *reader, const QString &name) {
|
||||
|
||||
}
|
||||
|
||||
bool ParseUntilElementCI(QXmlStreamReader *reader, const QString &name) {
|
||||
|
||||
while (!reader->atEnd()) {
|
||||
QXmlStreamReader::TokenType type = reader->readNext();
|
||||
switch (type) {
|
||||
case QXmlStreamReader::StartElement:{
|
||||
QString element = reader->name().toString().toLower();
|
||||
if (element == name) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
QDateTime ParseRFC822DateTime(const QString &text) {
|
||||
|
||||
QRegExp regexp("(\\d{1,2}) (\\w{3,12}) (\\d+) (\\d{1,2}):(\\d{1,2}):(\\d{1,2})");
|
||||
@@ -716,19 +736,6 @@ void IncreaseFDLimit() {
|
||||
|
||||
}
|
||||
|
||||
void CheckPortable() {
|
||||
|
||||
QFile f(QApplication::applicationDirPath() + QDir::separator() + "data");
|
||||
if (f.exists()) {
|
||||
// We are portable. Set the bool and change the qsettings path
|
||||
Application::kIsPortable = true;
|
||||
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, f.fileName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QString GetRandomStringWithChars(const int len) {
|
||||
const QString UseCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
|
||||
return GetRandomString(len, UseCharacters);
|
||||
|
||||
@@ -96,6 +96,7 @@ void ConsumeCurrentElement(QXmlStreamReader *reader);
|
||||
// Advances the stream reader until it finds an element with the given name.
|
||||
// Returns false if the end of the document was reached before finding a matching element.
|
||||
bool ParseUntilElement(QXmlStreamReader *reader, const QString &name);
|
||||
bool ParseUntilElementCI(QXmlStreamReader *reader, const QString &name);
|
||||
|
||||
// Parses a string containing an RFC822 time and date.
|
||||
QDateTime ParseRFC822DateTime(const QString &text);
|
||||
@@ -123,7 +124,6 @@ QString FiddleFileExtension(const QString &filename, const QString &new_extensio
|
||||
QString GetEnv(const QString &key);
|
||||
void SetEnv(const char *key, const QString &value);
|
||||
void IncreaseFDLimit();
|
||||
void CheckPortable();
|
||||
|
||||
// Borrowed from schedutils
|
||||
enum IoPriority {
|
||||
|
||||
@@ -131,7 +131,7 @@ void AlbumCoverChoiceController::ReloadSettings() {
|
||||
}
|
||||
|
||||
QList<QAction*> AlbumCoverChoiceController::GetAllActions() {
|
||||
return QList<QAction*>() << cover_from_file_ << cover_to_file_ << separator_ << cover_from_url_ << search_for_cover_ << unset_cover_ << show_cover_;
|
||||
return QList<QAction*>() << cover_from_file_ << cover_to_file_ << separator_ << cover_from_url_ << search_for_cover_ << unset_cover_ << separator_ << show_cover_;
|
||||
}
|
||||
|
||||
QUrl AlbumCoverChoiceController::LoadCoverFromFile(Song *song) {
|
||||
|
||||
@@ -95,8 +95,8 @@ AlbumCoverManager::AlbumCoverManager(Application *app, CollectionBackend *collec
|
||||
cover_searcher_(nullptr),
|
||||
cover_export_(nullptr),
|
||||
cover_exporter_(new AlbumCoverExporter(this)),
|
||||
artist_icon_(IconLoader::Load("folder-sound" )),
|
||||
all_artists_icon_(IconLoader::Load("vinyl" )),
|
||||
artist_icon_(IconLoader::Load("folder-sound")),
|
||||
all_artists_icon_(IconLoader::Load("library-music")),
|
||||
no_cover_icon_(":/pictures/cdcase.png"),
|
||||
no_cover_image_(GenerateNoCoverImage(no_cover_icon_)),
|
||||
no_cover_item_icon_(QPixmap::fromImage(no_cover_image_)),
|
||||
@@ -110,12 +110,12 @@ AlbumCoverManager::AlbumCoverManager(Application *app, CollectionBackend *collec
|
||||
ui_->albums->set_cover_manager(this);
|
||||
|
||||
// Icons
|
||||
ui_->action_fetch->setIcon(IconLoader::Load("download" ));
|
||||
ui_->export_covers->setIcon(IconLoader::Load("document-save" ));
|
||||
ui_->view->setIcon(IconLoader::Load("view-choose" ));
|
||||
ui_->button_fetch->setIcon(IconLoader::Load("download" ));
|
||||
ui_->action_add_to_playlist->setIcon(IconLoader::Load("media-play" ));
|
||||
ui_->action_load->setIcon(IconLoader::Load("media-play" ));
|
||||
ui_->action_fetch->setIcon(IconLoader::Load("download"));
|
||||
ui_->export_covers->setIcon(IconLoader::Load("document-save"));
|
||||
ui_->view->setIcon(IconLoader::Load("view-choose"));
|
||||
ui_->button_fetch->setIcon(IconLoader::Load("download"));
|
||||
ui_->action_add_to_playlist->setIcon(IconLoader::Load("media-playback-start"));
|
||||
ui_->action_load->setIcon(IconLoader::Load("media-playback-start"));
|
||||
|
||||
album_cover_choice_controller_->Init(app_);
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ QStringList CddaLister::DeviceUniqueIDs() { return devices_list_; }
|
||||
|
||||
QVariantList CddaLister::DeviceIcons(const QString &) {
|
||||
QVariantList icons;
|
||||
icons << QString("cd");
|
||||
icons << QString("media-optical");
|
||||
return icons;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,10 +107,9 @@ void CddaSongLoader::LoadSongs() {
|
||||
SongList songs;
|
||||
for (int track_number = 1; track_number <= num_tracks; track_number++) {
|
||||
// Init song
|
||||
Song song;
|
||||
Song song(Song::Source_CDDA);
|
||||
song.set_id(track_number);
|
||||
song.set_valid(true);
|
||||
song.set_source(Song::Source_CDDA);
|
||||
song.set_filetype(Song::FileType_CDDA);
|
||||
song.set_url(GetUrlFromTrack(track_number));
|
||||
song.set_title(QString("Track %1").arg(track_number));
|
||||
@@ -150,7 +149,7 @@ void CddaSongLoader::LoadSongs() {
|
||||
gst_message_parse_toc (msg_toc, &toc, nullptr);
|
||||
if (toc) {
|
||||
GList *entries = gst_toc_get_entries(toc);
|
||||
if (entries && songs.size() <= g_list_length (entries)) {
|
||||
if (entries && (guint)songs.size() <= g_list_length(entries)) {
|
||||
int i = 0;
|
||||
for (GList *node = entries; node != nullptr; node = node->next) {
|
||||
GstTocEntry *entry = static_cast<GstTocEntry*>(node->data);
|
||||
@@ -200,7 +199,7 @@ void CddaSongLoader::AudioCDTagsLoaded(const QString &artist, const QString &alb
|
||||
if (results.empty()) return;
|
||||
int track_number = 1;
|
||||
for (const MusicBrainzClient::Result &ret : results) {
|
||||
Song song;
|
||||
Song song(Song::Source_CDDA);
|
||||
song.set_artist(artist);
|
||||
song.set_album(album);
|
||||
song.set_title(ret.title_);
|
||||
@@ -208,7 +207,6 @@ void CddaSongLoader::AudioCDTagsLoaded(const QString &artist, const QString &alb
|
||||
song.set_track(track_number);
|
||||
song.set_year(ret.year_);
|
||||
song.set_id(track_number);
|
||||
song.set_source(Song::Source_CDDA);
|
||||
song.set_filetype(Song::FileType_CDDA);
|
||||
song.set_valid(true);
|
||||
// We need to set url: that's how playlist will find the correct item to update
|
||||
|
||||
@@ -252,6 +252,8 @@ QStringList DeviceLister::GuessIconForPath(const QString &path) {
|
||||
ret << model_icon.arg(model);
|
||||
}
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(path)
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
|
||||