Compare commits

..

118 Commits
0.6.4 ... 0.6.7

Author SHA1 Message Date
Jonas Kvinge
cd490ca946 Release 0.6.7 2019-11-27 23:09:49 +01:00
Jonas Kvinge
793f6b00e6 Allow 4 tagreader workers 2019-11-27 22:57:51 +01:00
Strawbs Bot
c1ec568fda Update translations 2019-11-27 01:03:22 +01:00
Jonas Kvinge
4e2b52975e Remove require for sqlite on centos since we use customized sqlite 2019-11-26 23:43:34 +01:00
Jonas Kvinge
c141df6b86 Remove low-latency setting for wasapisink 2019-11-26 22:30:56 +01:00
Jonas Kvinge
63b781765a Update copyrights 2019-11-26 22:30:14 +01:00
Jonas Kvinge
c121e141e7 Remove duplicate entries in Changelog 2019-11-26 22:29:13 +01:00
Jonas Kvinge
7544c9a9f5 Update nsi with libprotobuf-22.dll 2019-11-26 19:42:38 +01:00
Jonas Kvinge
722a088515 Only remove pixmap cache when removing parents in collection model 2019-11-26 19:42:05 +01:00
Jonas Kvinge
0ce75bff58 Remove unused code in context albums 2019-11-26 19:41:32 +01:00
Strawbs Bot
3744b6d3de Update translations 2019-11-26 01:02:03 +01:00
Jonas Kvinge
a4ebd91e8d Make sure QSqlQuery::exec() was successful 2019-11-25 22:43:09 +01:00
Jonas Kvinge
3bb0ee916d Update Changelog 2019-11-25 22:31:42 +01:00
Jonas Kvinge
fd6afdf5f3 Extend url test 2019-11-25 22:30:33 +01:00
Jonas Kvinge
47c13a840e Handle different urls in collection backend for backward compatibility 2019-11-25 22:29:12 +01:00
Jonas Kvinge
5b61992b3c Save cover urls encoded 2019-11-25 22:28:48 +01:00
Jonas Kvinge
36331dc253 Fix removing nodes from pending art 2019-11-25 22:25:29 +01:00
Strawbs Bot
4265cf31b2 Update translations 2019-11-25 01:05:00 +01:00
Jonas Kvinge
337e47269f Remove portable, we dont use it 2019-11-25 00:35:48 +01:00
Jonas Kvinge
7039234471 Fix compile collection model test 2019-11-25 00:35:16 +01:00
Jonas Kvinge
f7f9333d91 Add collection backend url tests 2019-11-25 00:34:59 +01:00
Jonas Kvinge
bf35665932 Update all songs for the same directory+album when updating compilations
- Fixes a bug where the songs are stuck in various artists, because the
album has child songs, it will be stuck with various artists as the
parent node.
2019-11-25 00:28:49 +01:00
Jonas Kvinge
089a2271c2 Add GitHub Actions 2019-11-24 20:04:05 +01:00
Jonas Kvinge
f8e83e3631 Fix loading replay gain setting
Fixes #311
2019-11-24 19:34:05 +01:00
Strawbs Bot
46fd329913 Update translations 2019-11-23 01:07:52 +01:00
Jonas Kvinge
6b9ba96e77 Revert "Tidal: Add explicit to album titles"
This reverts commit b7d360d850.
2019-11-21 22:55:39 +01:00
Jonas Kvinge
b7d360d850 Tidal: Add explicit to album titles 2019-11-20 22:13:28 +01:00
Jonas Kvinge
8e226302ab Allow scrobbling songs without album
Fixes #309
2019-11-20 21:30:41 +01:00
Jonas Kvinge
7795b9edaf Dont replace metadata when loading playlists 2019-11-20 19:34:57 +01:00
Jonas Kvinge
9375d9699a No 2019-11-19 21:51:15 +01:00
Jonas Kvinge
cf0442d5b8 Fix setting pixmap cache limit 2019-11-19 21:49:46 +01:00
Jonas Kvinge
b386ca14df Show fullsize cover on doubleclick 2019-11-19 21:20:36 +01:00
Jonas Kvinge
ea47fae31e Add seperator between "unset cover" and "show fullsize" 2019-11-19 21:19:44 +01:00
Jonas Kvinge
e0fed07b10 Change pixmap cache limit 2019-11-19 21:03:06 +01:00
Jonas Kvinge
779d5ff7b6 Dont reset pixmap cache on model reset 2019-11-19 20:56:03 +01:00
Jonas Kvinge
eb6fbd03ec Update Changelog 2019-11-19 20:49:54 +01:00
Jonas Kvinge
95409d1b0e Remove unused variables 2019-11-19 20:47:06 +01:00
Jonas Kvinge
49599c8731 Add back ChartLyrics
This reverts commit c992768efe.
2019-11-19 20:45:22 +01:00
Jonas Kvinge
572f94e000 Update Changelog 2019-11-18 17:25:57 +01:00
Jonas Kvinge
c0a2ad5f50 Change comment 2019-11-18 17:16:58 +01:00
Jonas Kvinge
71fa5acc74 Fix previous player and doubleclick playlist song behaviour settings 2019-11-17 23:46:10 +01:00
Jonas Kvinge
bac5b7679d Use killproc.exe instead in nsi 2019-11-17 16:34:30 +01:00
Strawbs Bot
93ade821a5 Update translations 2019-11-17 01:10:32 +01:00
Jonas Kvinge
a718e19979 Use KillProc in nsi 2019-11-15 23:25:12 +01:00
Jonas Kvinge
8ac83a46f5 Remove clang compiler flag 2019-11-15 23:24:37 +01:00
Jonas Kvinge
1b65dcd7df Fix comparison between signed/unsigned 2019-11-15 00:23:06 +01:00
Jonas Kvinge
bbad45f1e7 Minor cmake fixes 2019-11-15 00:22:41 +01:00
Jonas Kvinge
331b9cca18 Remove sudo 2019-11-14 21:23:50 +01:00
Jonas Kvinge
a9accb7d85 Refactor scrobbler authentication code
Fix a crash when authentication is cancelled
2019-11-14 21:07:30 +01:00
Jonas Kvinge
1862e70628 Declare song using source 2019-11-14 00:09:35 +01:00
Jonas Kvinge
c4f7054ca6 Use QUrl::FullyEncoded in update compilations 2019-11-13 23:51:04 +01:00
Jonas Kvinge
175e568a28 Minor improvements to update compilations 2019-11-13 21:27:04 +01:00
Jonas Kvinge
c8d580e7de No need to delete pixmap cache when deleting empty parents 2019-11-13 21:16:48 +01:00
Jonas Kvinge
bc0c50ee65 Remove commented code 2019-11-13 21:12:50 +01:00
Jonas Kvinge
45e9dd96d1 Remove left click on analyzer to popup menu
Fixes #294
2019-11-11 00:01:39 +01:00
Jonas Kvinge
1cc73562a3 Turn back git revision 2019-11-10 15:35:36 +01:00
Jonas Kvinge
d870ef0bd5 Release 0.6.6 2019-11-09 17:21:08 +01:00
Jonas Kvinge
53d308dac5 Exclude .github dir in maketarball.sh 2019-11-09 17:16:18 +01:00
Jonas Kvinge
89b06ae7c7 Mulitply samples by channels, dont hardcode to 2 2019-11-09 16:34:17 +01:00
Jonas Kvinge
d38485a8ad Update Changelog 2019-11-09 16:30:23 +01:00
Jonas Kvinge
834877c503 Refactor gstreamer engine code, equalizer and fix stereo balancer 2019-11-08 23:07:21 +01:00
Jonas Kvinge
d033b79af4 Remove exclusive for wasapisink
Fixes #283
2019-11-07 20:26:25 +01:00
Jonas Kvinge
daec2cc203 Remove g_type_init 2019-11-06 21:53:27 +01:00
Jonas Kvinge
4e593cebab Add const 2019-11-06 21:53:09 +01:00
Jonas Kvinge
73d7701e94 Update FUNDING.yml 2019-11-05 19:38:46 +01:00
Strawbs Bot
24f1d7a72f Update translations 2019-11-04 01:07:14 +01:00
Jonas Kvinge
6387a01d7b Fix updating compilations
Fixes #288
2019-11-03 23:23:04 +01:00
Jonas Kvinge
e838840548 Remove duplicate check 2019-11-03 19:56:10 +01:00
Jonas Kvinge
6a430b441e Remove debug line 2019-11-03 19:56:01 +01:00
Jonas Kvinge
7b977ea839 Rename EngineDevice --> DeviceFinders, Add MMDeviceFinder 2019-11-03 19:53:08 +01:00
Jonas Kvinge
62b8521cbe Update Changelog 2019-10-29 19:27:03 +01:00
Martin Delille
308244d901 Change email (#287)
I didn't noticed you mention me in the *About...* section. Thank you for that even if it is an oversized thank you for the contributions made! : sweat_smile:

I just update it to my personal address.
2019-10-29 19:12:29 +01:00
Jonas Kvinge
6f521183f9 Fix spelling 2019-10-28 20:20:13 +01:00
Jonas Kvinge
76c6f7e733 Update README.md 2019-10-28 20:06:22 +01:00
Strawbs Bot
80ebfbeb6b Update translations 2019-10-28 01:02:39 +01:00
Jonas Kvinge
793901b319 Revert accidental change to flac test file 2019-10-28 00:05:29 +01:00
Jonas Kvinge
3950df8ec9 Add libgstwasapi.dll to nsi 2019-10-27 23:55:03 +01:00
Jonas Kvinge
e800b236aa Simplify the pipeline
Fix issue where bitrate is updated incorrectly by stream discoverer
Fixes issue #282
Also make it possible to enable stereo balancer without enabling the
equalizer
2019-10-27 23:48:54 +01:00
Jonas Kvinge
4ab7871106 Add wasapisink to directsound devicefinder 2019-10-27 23:47:28 +01:00
Jonas Kvinge
3de85549b6 Add option to automatically select current playing track 2019-10-27 02:11:51 +01:00
Jonas Kvinge
73164f7182 Update scrobble point when song is restarted 2019-10-27 02:09:34 +01:00
Strawbs Bot
004b000890 Update translations 2019-10-21 01:23:16 +02:00
Jonas Kvinge
d9c703d944 Add gst/audio/audio.h include 2019-10-20 20:04:23 +02:00
Jonas Kvinge
364b650033 Convert S32LE to S16LE for analyzer 2019-10-20 18:52:58 +02:00
Jonas Kvinge
156eb874db Fix analyzer and cleanup old pipeline code
- Move HandoffCallback to audio queue
- Add new callback for detecting source format
- Remove old decodebin stuff
2019-10-20 02:56:47 +02:00
Strawbs Bot
1a28dd0311 Update translations 2019-10-20 01:24:47 +02:00
Jonas Kvinge
e29b4b8609 Add more alternative icon names 2019-10-20 01:11:40 +02:00
Jonas Kvinge
c02997e6d9 More icon fixes 2019-10-20 00:59:22 +02:00
Jonas Kvinge
7c9fc91af9 Enable system theme icons, add iconmapper and rename some icon names 2019-10-20 00:17:28 +02:00
Jonas Kvinge
cf5198ac64 Limit tagreader workers to 2 2019-10-19 15:09:18 +02:00
Strawbs Bot
e76ddd6dd2 Update translations 2019-10-19 14:56:24 +02:00
Jonas Kvinge
e3a4cf1cf5 Add option to prefer album artist when sending scrobbles
Fixes #274
2019-10-19 02:56:23 +02:00
Jonas Kvinge
5844616ea8 Only ignore closeEvent when minimizing to system tray
Fixes #277
2019-10-19 02:21:20 +02:00
Jonas Kvinge
abeb580228 Disable analyzer for other bit depths than 16
This removes the splitting of the pipeline with the tee.
Move HandoffCallback to the source, which makes it possible to convert the audio buffer in HandoffCallback later.
Until then just disable analyzer for other formats.

Removes tee and probe queue converter and sink
2019-10-19 01:45:24 +02:00
Ike Devolder
4d888dfce8 subsonic: change disc to discNumber (#278)
As found in the v1.13.0 xsd, the disc is named discNumber in the api,
currently there is a check for disc which will never be found in the
response.

@see http://www.subsonic.org/pages/inc/api/schema/subsonic-rest-api-1.13.0.xsd

Signed-off-by: BlackEagle <ike.devolder@gmail.com>
2019-10-17 17:06:30 +02:00
Jonas Kvinge
08ff6f0ede Only use gcc 2019-10-13 00:17:01 +02:00
Jonas Kvinge
c458c27231 Switch to opensuse leap 15.1 2019-10-12 23:49:41 +02:00
Jonas Kvinge
9821b70c38 Dont use gst_caps_to_string as it causes hang with some formats 2019-10-12 01:58:01 +02:00
Jonas Kvinge
8ab8401110 Update libprotobuf in nsi 2019-10-06 17:53:00 +02:00
Strawbs Bot
4f798c85cf Update translations 2019-10-05 01:01:44 +02:00
Jonas Kvinge
1949bdb43f Merge branch 'master' of github.com:jonaski/strawberry 2019-10-04 17:09:08 +02:00
Jonas Kvinge
8cf2e6b31b Remove all lines in settings 2019-10-04 17:08:35 +02:00
Jonas Kvinge
b1069f9f18 Disable use system icons option 2019-10-04 17:08:12 +02:00
Strawbs Bot
fb8dfa9ae9 Update translations 2019-10-04 01:07:02 +02:00
Jonas Kvinge
4402a56e94 Fix compile with optional components disabled 2019-10-03 23:29:52 +02:00
Jonas Kvinge
f449808ba3 Fix: imobiledevice depends on libgpod enabled 2019-10-03 22:54:40 +02:00
Jonas Kvinge
5599739433 Fix lowercased playlist album artist column
Fixes #275
2019-10-03 18:25:50 +02:00
Jonas Kvinge
197cf85f56 Turn back git revision 2019-10-01 21:42:08 +02:00
Jonas Kvinge
8c039c9c8b Release 0.6.5 2019-09-30 22:05:42 +02:00
Jonas Kvinge
c1d9bc046d Change context default 2019-09-30 22:05:03 +02:00
Jonas Kvinge
cd99fac7ed Fix OSD Pretty upper left (0,0) position and positioning on Windows
Fixes #269
2019-09-30 20:32:34 +02:00
Jonas Kvinge
f4489e6807 No need to initialize SimpleMetaBundle here 2019-09-30 20:31:18 +02:00
Jonas Kvinge
f2078271b6 Only update scrobble point in SetStreamMetadata when length is changed 2019-09-30 18:58:55 +02:00
Jonas Kvinge
a3ae9acebb Listenbrainz: don't send "various artists" as artist 2019-09-29 13:50:24 +02:00
Jonas Kvinge
b0580265ca Listenbrainz: don't send "various artists" as album artist
Fixes #273
2019-09-29 13:31:46 +02:00
Jonas Kvinge
b4f012392a Fix full validation of appdata file
Fixes #271
2019-09-29 13:29:52 +02:00
Jonas Kvinge
1598809f55 Fix OSD reposition image 2019-09-25 19:01:55 +02:00
Jonas Kvinge
6d4f7aa61f Turn back git revision 2019-09-25 18:54:22 +02:00
185 changed files with 3618 additions and 3037 deletions

2
.github/FUNDING.yml vendored
View File

@@ -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
View 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

View File

@@ -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

View File

@@ -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)

View File

@@ -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");

View File

@@ -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");

View File

@@ -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"

View File

@@ -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

View File

@@ -1,4 +1,4 @@
from jonaski/opensuse:tumbleweed
from jonaski/opensuse:lp151
run mkdir -p /usr/src/app
workdir /usr/src/app

View File

@@ -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.

View File

@@ -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}
)

View File

@@ -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)

View File

@@ -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>

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 908 B

After

Width:  |  Height:  |  Size: 908 B

View File

Before

Width:  |  Height:  |  Size: 921 B

After

Width:  |  Height:  |  Size: 921 B

View File

Before

Width:  |  Height:  |  Size: 921 B

After

Width:  |  Height:  |  Size: 921 B

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 162 KiB

After

Width:  |  Height:  |  Size: 162 KiB

BIN
data/icons/full/love.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

2
debian/control vendored
View File

@@ -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
View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
View 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

View 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>

View File

@@ -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"

View File

@@ -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})

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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})

View File

@@ -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.

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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());
}

View File

@@ -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_;

View File

@@ -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_);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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));

View File

@@ -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;

View File

@@ -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,

View File

@@ -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();

View File

@@ -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:

View File

@@ -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_;

View File

@@ -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();

View File

@@ -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_;

View File

@@ -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()) {

View File

@@ -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

View File

@@ -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

View File

@@ -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
View 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

View File

@@ -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) {

View File

@@ -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_;

View File

@@ -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) : "";
}

View File

@@ -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) {

View File

@@ -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_;

View File

@@ -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);

View File

@@ -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()));

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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(); }

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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_);

View File

@@ -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;
}

View File

@@ -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

View File

@@ -252,6 +252,8 @@ QStringList DeviceLister::GuessIconForPath(const QString &path) {
ret << model_icon.arg(model);
}
}
#else
Q_UNUSED(path)
#endif
return ret;

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