Compare commits

...

62 Commits
0.6.4 ... 0.6.6

Author SHA1 Message Date
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
134 changed files with 2657 additions and 2347 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

View File

@@ -7,7 +7,6 @@ services:
- docker
compiler:
- gcc
- clang
before_install:
- if ! [ "$DEPLOY_KEY_ENC" == "" ]; then

View File

@@ -327,7 +327,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,33 @@ Strawberry Music Player
=======================
ChangeLog
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

@@ -25,8 +25,11 @@ Strawberry is a music player and music collection organizer. It is a fork of Cle
* 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 @@
set(STRAWBERRY_VERSION_MAJOR 0)
set(STRAWBERRY_VERSION_MINOR 6)
set(STRAWBERRY_VERSION_PATCH 4)
set(STRAWBERRY_VERSION_PATCH 6)
#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

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

@@ -199,7 +199,7 @@ Section "Strawberry" Strawberry
File "libpcre-1.dll"
File "libpcre2-16-0.dll"
File "libpng16-16.dll"
File "libprotobuf-20.dll"
File "libprotobuf-21.dll"
File "libsoup-2.4-1.dll"
File "libspeex-1.dll"
File "libsqlite3-0.dll"
@@ -318,6 +318,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"
@@ -475,7 +476,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-21.dll"
Delete "$INSTDIR\libsoup-2.4-1.dll"
Delete "$INSTDIR\libspeex-1.dll"
Delete "$INSTDIR\libsqlite3-0.dll"
@@ -545,6 +546,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"

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);
local_server_name_ = qApp->applicationName().toLower();
if (local_server_name_.isEmpty())
local_server_name_ = "workerpool";
}
template <typename HandlerType>

View File

@@ -1,5 +1,5 @@
name: strawberry
version: '0.6.4+git'
version: '0.6.6+git'
summary: music player and collection organizer
description: |
Strawberry is a music player and collection organizer.

View File

@@ -121,7 +121,7 @@ set(SOURCES
engine/enginetype.cpp
engine/enginebase.cpp
engine/enginedevice.cpp
engine/devicefinders.cpp
engine/devicefinder.cpp
analyzer/fht.cpp
@@ -315,7 +315,7 @@ set(HEADERS
core/mimedata.h
engine/enginebase.h
engine/enginedevice.h
engine/devicefinders.h
analyzer/analyzerbase.h
analyzer/analyzercontainer.h
@@ -877,6 +877,7 @@ endif()
optional_source(WIN32
SOURCES
engine/directsounddevicefinder.cpp
engine/mmdevicefinder.cpp
widgets/osd_win.cpp
core/windows7thumbbar.cpp
HEADERS

View File

@@ -904,28 +904,30 @@ 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|QUrl::StripTrailingSlash);
CompilationInfo &info = compilation_info[album];
CompilationInfo &info = compilation_info[directory + album];
info.urls << url;
info.directory = directory;
info.album = 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;
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_));
find_songs.prepare(QString("SELECT ROWID, " + Song::kColumnSpec + " FROM %1 WHERE url = :url AND compilation_detected = :compilation_detected AND unavailable = 0").arg(songs_table_));
QSqlQuery update_songs(db);
update_songs.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 = :url AND unavailable = 0").arg(songs_table_));
SongList deleted_songs;
SongList added_songs;
@@ -935,17 +937,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 (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_songs, update_songs, deleted_songs, added_songs, url, true);
}
else {
if (info.has_compilation_detected > 0)
UpdateCompilations(find_songs, update_songs, deleted_songs, added_songs, url, false);
}
}
}
@@ -955,27 +958,28 @@ 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_songs, QSqlQuery &update_songs, 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);
// Get song, so we can tell the model its updated
find_songs.bindValue(":url", url.toString());
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);
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_songs.bindValue(":compilation_detected", int(compilation_detected));
update_songs.bindValue(":url", url);
update_songs.exec();
db_->CheckErrors(update_songs);
}

View File

@@ -225,16 +225,18 @@ 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) {}
QString directory;
QString album;
QList<QUrl> urls;
QSet<QString> artists;
QSet<QString> directories;
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_songs, QSqlQuery &update_songs, 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

@@ -449,7 +449,6 @@ void CollectionModel::SongsDeleted(const SongList &songs) {
break;
}
}
beginRemoveRows(idx, node->row, node->row);
node->parent->Delete(node->row);
song_nodes_.remove(song.id());

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

@@ -355,8 +355,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

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

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
@@ -105,7 +105,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
@@ -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;
@@ -78,7 +78,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

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

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

@@ -296,14 +296,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 +332,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; }
@@ -349,6 +354,7 @@ 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_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 (
@@ -488,8 +494,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");

View File

@@ -200,7 +200,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 +232,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 +253,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

@@ -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, 2));
connect(worker_pool_, SIGNAL(WorkerFailedToStart()), SLOT(WorkerFailedToStart()));
}
void TagReaderClient::Start() { worker_pool_->Start(); }

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

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

View File

@@ -97,7 +97,7 @@ void DeviceProperties::ShowDevice(QModelIndex idx) {
<< "device"
<< "device-usb-drive"
<< "device-usb-flash"
<< "cd"
<< "media-optical"
<< "device-ipod"
<< "device-ipod-nano"
<< "device-phone";

View File

@@ -225,8 +225,8 @@ void DeviceView::contextMenuEvent(QContextMenuEvent *e) {
properties_action_ = device_menu_->addAction(IconLoader::Load("configure"), tr("Device properties..."), this, SLOT(Properties()));
// Collection menu
add_to_playlist_action_ = collection_menu_->addAction(IconLoader::Load("media-play"), tr("Append to current playlist"), this, SLOT(AddToPlaylist()));
load_action_ = collection_menu_->addAction(IconLoader::Load("media-play"), tr("Replace current playlist"), this, SLOT(Load()));
add_to_playlist_action_ = collection_menu_->addAction(IconLoader::Load("media-playback-start"), tr("Append to current playlist"), this, SLOT(AddToPlaylist()));
load_action_ = collection_menu_->addAction(IconLoader::Load("media-playback-start"), tr("Replace current playlist"), this, SLOT(Load()));
open_in_new_playlist_ = collection_menu_->addAction(IconLoader::Load("document-new"), tr("Open in new playlist"), this, SLOT(OpenInNewPlaylist()));
collection_menu_->addSeparator();

View File

@@ -755,7 +755,7 @@ QVariantList MacOsDeviceLister::DeviceIcons(const QString& serial) {
}
if (IsCDDevice(serial)) {
return QVariantList() << "cd";
return QVariantList() << "media-optical";
}
QString bsd_name = current_devices_[serial];

View File

@@ -35,7 +35,7 @@
#include "core/song.h"
class MtpConnection : public QObject, public std::enable_shared_from_this<MtpConnection> {
public:
public:
MtpConnection(const QUrl &url);
~MtpConnection();
@@ -43,7 +43,7 @@ public:
LIBMTP_mtpdevice_t *device() const { return device_; }
bool GetSupportedFiletypes(QList<Song::FileType> *ret);
private:
private:
Q_DISABLE_COPY(MtpConnection)
LIBMTP_mtpdevice_t *device_;

View File

@@ -46,7 +46,7 @@ About::About(QWidget *parent):QDialog(parent) {
strawberry_contributors_ \
<< Person("Gavin D. Howard", "yzena.tech@gmail.com")
<< Person("Martin Delille", "martin@lylo.tv");
<< Person("Martin Delille", "martin@delille.org");
strawberry_thanks_ \
<< Person("Robert-André Mauchin", "eclipseo@fedoraproject.org")

View File

@@ -841,9 +841,10 @@ void EditTagDialog::ResetPlayCounts() {
UpdateStatisticsTab(*song);
}
#if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
void EditTagDialog::FetchTag() {
#if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
const QModelIndexList sel = ui_->song_list->selectionModel()->selectedIndexes();
SongList songs;
@@ -864,10 +865,14 @@ void EditTagDialog::FetchTag() {
results_dialog_->show();
#endif
}
void EditTagDialog::FetchTagSongChosen(const Song &original_song, const Song &new_metadata) {
#if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
const QString filename = original_song.url().toLocalFile();
// Find the song with this filename
@@ -893,9 +898,13 @@ void EditTagDialog::FetchTagSongChosen(const Song &original_song, const Song &ne
UpdateUI(sel);
}
}
#else
Q_UNUSED(original_song)
Q_UNUSED(new_metadata)
#endif
}
void EditTagDialog::SongSaveComplete(TagReaderReply *reply, const QString &filename, const Song &song) {
pending_--;
@@ -905,9 +914,7 @@ void EditTagDialog::SongSaveComplete(TagReaderReply *reply, const QString &filen
emit Error(message);
}
else if (song.directory_id() != -1) {
SongList songs;
songs << song;
app_->collection_backend()->AddOrUpdateSongs(songs);
app_->collection_backend()->AddOrUpdateSongs(SongList() << song);
}
if (pending_ <= 0) AcceptFinished();

View File

@@ -109,10 +109,8 @@ class EditTagDialog : public QDialog {
void ResetField();
void ButtonClicked(QAbstractButton *button);
void ResetPlayCounts();
#if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
void FetchTag();
void FetchTagSongChosen(const Song &original_song, const Song &new_metadata);
#endif
void AlbumCoverLoaded(const quint64 id, const QUrl &cover_url, const QImage &scaled, const QImage &original);

View File

@@ -26,8 +26,8 @@
#include <QtDebug>
#include "core/logging.h"
#include "devicefinders.h"
#include "devicefinder.h"
#include "enginedevice.h"
#ifdef HAVE_ALSA
# include "alsadevicefinder.h"
@@ -43,16 +43,16 @@
#ifdef Q_OS_WIN32
# include "directsounddevicefinder.h"
# include "mmdevicefinder.h"
#endif
EngineDevice::EngineDevice(QObject *parent) : QObject(parent) {
}
DeviceFinders::DeviceFinders(QObject *parent) : QObject(parent) {}
EngineDevice::~EngineDevice() {
DeviceFinders::~DeviceFinders() {
qDeleteAll(device_finders_);
}
void EngineDevice::Init() {
void DeviceFinders::Init() {
QList<DeviceFinder*> device_finders;
@@ -67,6 +67,7 @@ void EngineDevice::Init() {
#endif
#ifdef Q_OS_WIN32
device_finders.append(new DirectSoundDeviceFinder);
device_finders.append(new MMDeviceFinder);
#endif
for (DeviceFinder *finder : device_finders) {

View File

@@ -17,8 +17,8 @@
*
*/
#ifndef ENGINEDEVICE_H
#define ENGINEDEVICE_H
#ifndef DEVICEFINDERS_H
#define DEVICEFINDERS_H
#include "config.h"
@@ -28,21 +28,19 @@
class DeviceFinder;
class EngineDevice : public QObject {
class DeviceFinders : public QObject {
Q_OBJECT
public:
explicit EngineDevice(QObject *parent = nullptr);
~EngineDevice();
explicit DeviceFinders(QObject *parent = nullptr);
~DeviceFinders();
void Init();
QList<DeviceFinder*> device_finders_;
QList<DeviceFinder*> ListFinders() { return device_finders_; }
private:
QString output_;
QList<DeviceFinder*> device_finders_;
};
#endif // ENGINEDEVICE_H
#endif // DEVICEFINDERS_H

View File

@@ -52,9 +52,7 @@ BOOL DirectSoundDeviceFinder::EnumerateCallback(LPGUID guid, LPCSTR description,
Device dev;
dev.description = QString::fromLatin1(description);
//if (guid) dev.value = QUuid(*guid).toByteArray();
if (guid) dev.value = QUuid(*guid).toString();
else dev.value = QVariant();
dev.iconname = GuessIconName(dev.description);
state->devices.append(dev);

View File

@@ -82,7 +82,7 @@ bool Engine::Base::Play(const QUrl &stream_url, const QUrl &original_url, TrackC
}
void Engine::Base::SetVolume(uint value) {
void Engine::Base::SetVolume(const uint value) {
volume_ = value;
SetVolumeSW(MakeVolumeLogarithmic(value));

View File

@@ -41,7 +41,7 @@
#include "engine_fwd.h"
#include "enginetype.h"
#include "enginedevice.h"
#include "devicefinders.h"
#include "core/song.h"
namespace Engine {
@@ -102,13 +102,13 @@ public:
void SetVolume(const uint value);
static uint MakeVolumeLogarithmic(const uint volume);
public slots:
public slots:
virtual void ReloadSettings();
protected:
protected:
void EmitAboutToEnd();
public:
public:
// Simple accessors
EngineType type() const { return type_; }
@@ -126,9 +126,10 @@ public:
QVariant device() { return device_; }
public slots:
virtual void SetStereoBalancerEnabled(const bool) {}
virtual void SetStereoBalance(const float) {}
virtual void SetEqualizerEnabled(const bool) {}
virtual void SetEqualizerParameters(const int preamp, const QList<int> &bandGains) { Q_UNUSED(preamp); Q_UNUSED(bandGains); }
virtual void SetStereoBalance(float value) { Q_UNUSED(value); }
virtual void SetEqualizerParameters(const int, const QList<int>&) {}
signals:
// Emitted when crossfading is enabled and the track is crossfade_duration_ away from finishing
@@ -199,7 +200,7 @@ public:
qint64 fadeout_pause_duration_;
qint64 fadeout_pause_duration_nanosec_;
private:
private:
bool about_to_end_emitted_;
Q_DISABLE_COPY(Base)
@@ -214,13 +215,13 @@ struct SimpleMetaBundle {
QString album;
QString comment;
QString genre;
qlonglong length;
qint64 length;
int year;
int track;
Song::FileType filetype;
int samplerate;
int bitdepth;
qlonglong bitrate;
qint64 bitrate;
QString lyrics;
};

View File

@@ -25,6 +25,8 @@
#include <gst/gstbuffer.h>
#include <QString>
class GstEnginePipeline;
class GstBufferConsumer {
@@ -33,7 +35,7 @@ public:
// This is called in some unspecified GStreamer thread.
// Ownership of the buffer is transferred to the BufferConsumer and it should gst_buffer_unref it.
virtual void ConsumeBuffer(GstBuffer *buffer, int pipeline_id) = 0;
virtual void ConsumeBuffer(GstBuffer *buffer, const int pipeline_id, const QString &format) = 0;
};
#endif // GSTBUFFERCONSUMER_H

View File

@@ -83,7 +83,10 @@ GstEngine::GstEngine(TaskManager *task_manager)
task_manager_(task_manager),
buffering_task_id_(-1),
latest_buffer_(nullptr),
stereo_balancer_enabled_(false),
stereo_balance_(0.0f),
equalizer_enabled_(false),
equalizer_preamp_(0),
seek_timer_(new QTimer(this)),
timer_id_(-1),
next_element_id_(0),
@@ -102,8 +105,15 @@ GstEngine::GstEngine(TaskManager *task_manager)
}
GstEngine::~GstEngine() {
EnsureInitialised();
current_pipeline_.reset();
if (latest_buffer_) {
gst_buffer_unref(latest_buffer_);
latest_buffer_ = nullptr;
}
}
bool GstEngine::Init() {
@@ -411,20 +421,34 @@ GstElement *GstEngine::CreateElement(const QString &factoryName, GstElement *bin
return element;
}
void GstEngine::ConsumeBuffer(GstBuffer *buffer, const int pipeline_id) {
void GstEngine::ConsumeBuffer(GstBuffer *buffer, const int pipeline_id, const QString &format) {
// Schedule this to run in the GUI thread. The buffer gets added to the queue and unreffed by UpdateScope.
if (!QMetaObject::invokeMethod(this, "AddBufferToScope", Q_ARG(GstBuffer*, buffer), Q_ARG(int, pipeline_id))) {
if (!QMetaObject::invokeMethod(this, "AddBufferToScope", Q_ARG(GstBuffer*, buffer), Q_ARG(int, pipeline_id), Q_ARG(QString, format))) {
qLog(Warning) << "Failed to invoke AddBufferToScope on GstEngine";
}
}
void GstEngine::SetStereoBalancerEnabled(const bool enabled) {
stereo_balancer_enabled_ = enabled;
if (current_pipeline_) current_pipeline_->set_stereo_balancer_enabled(enabled);
}
void GstEngine::SetStereoBalance(const float value) {
stereo_balance_ = value;
if (current_pipeline_) current_pipeline_->SetStereoBalance(value);
}
void GstEngine::SetEqualizerEnabled(const bool enabled) {
equalizer_enabled_ = enabled;
if (current_pipeline_) current_pipeline_->set_equalizer_enabled(enabled);
if (current_pipeline_) current_pipeline_->SetEqualizerEnabled(enabled);
}
void GstEngine::SetEqualizerParameters(const int preamp, const QList<int> &band_gains) {
@@ -432,27 +456,22 @@ void GstEngine::SetEqualizerParameters(const int preamp, const QList<int> &band_
equalizer_preamp_ = preamp;
equalizer_gains_ = band_gains;
if (current_pipeline_)
current_pipeline_->SetEqualizerParams(preamp, band_gains);
}
void GstEngine::SetStereoBalance(const float value) {
stereo_balance_ = value;
if (current_pipeline_) current_pipeline_->SetStereoBalance(value);
if (current_pipeline_) current_pipeline_->SetEqualizerParams(preamp, band_gains);
}
void GstEngine::AddBufferConsumer(GstBufferConsumer *consumer) {
buffer_consumers_ << consumer;
if (current_pipeline_) current_pipeline_->AddBufferConsumer(consumer);
}
void GstEngine::RemoveBufferConsumer(GstBufferConsumer *consumer) {
buffer_consumers_.removeAll(consumer);
if (current_pipeline_) current_pipeline_->RemoveBufferConsumer(consumer);
}
void GstEngine::timerEvent(QTimerEvent *e) {
@@ -520,7 +539,7 @@ void GstEngine::NewMetaData(const int pipeline_id, const Engine::SimpleMetaBundl
}
void GstEngine::AddBufferToScope(GstBuffer *buf, const int pipeline_id) {
void GstEngine::AddBufferToScope(GstBuffer *buf, const int pipeline_id, const QString &format) {
if (!current_pipeline_ || current_pipeline_->id() != pipeline_id) {
gst_buffer_unref(buf);
@@ -531,6 +550,7 @@ void GstEngine::AddBufferToScope(GstBuffer *buf, const int pipeline_id) {
gst_buffer_unref(latest_buffer_);
}
buffer_format_ = format;
latest_buffer_ = buf;
have_new_buffer_ = true;
@@ -739,11 +759,12 @@ shared_ptr<GstEnginePipeline> GstEngine::CreatePipeline() {
shared_ptr<GstEnginePipeline> ret(new GstEnginePipeline(this));
ret->set_output_device(output_, device_);
ret->set_volume_control(volume_control_);
ret->set_volume_enabled(volume_control_);
ret->set_stereo_balancer_enabled(stereo_balancer_enabled_);
ret->set_equalizer_enabled(equalizer_enabled_);
ret->set_replaygain(rg_enabled_, rg_mode_, rg_preamp_, rg_compression_);
ret->set_buffer_duration_nanosec(buffer_duration_nanosec_);
ret->set_buffer_min_fill(buffer_min_fill_);
ret->SetEqualizerEnabled(equalizer_enabled_);
ret->AddBufferConsumer(this);
for (GstBufferConsumer *consumer : buffer_consumers_) {
@@ -806,13 +827,22 @@ void GstEngine::UpdateScope(const int chunk_length) {
}
scope_chunk_++;
memcpy(dest, source, bytes);
if (buffer_format_.startsWith("S16") ||
buffer_format_.startsWith("U16") ||
buffer_format_.startsWith("S32")) {
memcpy(dest, source, bytes);
}
else {
memset(dest, 0, bytes);
}
gst_buffer_unmap(latest_buffer_, &map);
if (scope_chunk_ == scope_chunks_) {
gst_buffer_unref(latest_buffer_);
latest_buffer_ = nullptr;
buffer_format_.clear();
}
}

View File

@@ -50,11 +50,6 @@
class TaskManager;
class GstEnginePipeline;
#ifdef Q_OS_MACOS
struct _GTlsDatabase;
typedef struct _GTlsDatabase GTlsDatabase;
#endif
/**
* @class GstEngine
* @short GStreamer engine plugin
@@ -95,28 +90,26 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
void EnsureInitialised() { gst_startup_->EnsureInitialised(); }
GstElement *CreateElement(const QString &factoryName, GstElement *bin = nullptr, const bool showerror = true);
void ConsumeBuffer(GstBuffer *buffer, int pipeline_id);
void ConsumeBuffer(GstBuffer *buffer, const int pipeline_id, const QString &format);
public slots:
void ReloadSettings();
/** Set whether equalizer is enabled */
// Set whether stereo balancer is enabled
void SetStereoBalancerEnabled(const bool enabled);
// Set Stereo balance, range -1.0f..1.0f
void SetStereoBalance(const float value);
// Set whether equalizer is enabled
void SetEqualizerEnabled(const bool);
/** Set equalizer preamp and gains, range -100..100. Gains are 10 values. */
// Set equalizer preamp and gains, range -100..100. Gains are 10 values.
void SetEqualizerParameters(const int preamp, const QList<int> &bandGains);
/** Set Stereo balance, range -1.0f..1.0f */
void SetStereoBalance(const float value);
void AddBufferConsumer(GstBufferConsumer *consumer);
void RemoveBufferConsumer(GstBufferConsumer *consumer);
#ifdef Q_OS_MACOS
GTlsDatabase *tls_database() const { return tls_database_; }
#endif
protected:
void timerEvent(QTimerEvent*);
@@ -124,7 +117,7 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
void EndOfStreamReached(const int pipeline_id, const bool has_next_track);
void HandlePipelineError(const int pipeline_id, const QString &message, const int domain, const int error_code);
void NewMetaData(const int pipeline_id, const Engine::SimpleMetaBundle &bundle);
void AddBufferToScope(GstBuffer *buf, const int pipeline_id);
void AddBufferToScope(GstBuffer *buf, const int pipeline_id, const QString &format);
void FadeoutFinished();
void FadeoutPauseFinished();
void SeekNow();
@@ -180,9 +173,12 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
GstBuffer *latest_buffer_;
bool stereo_balancer_enabled_;
float stereo_balance_;
bool equalizer_enabled_;
int equalizer_preamp_;
QList<int> equalizer_gains_;
float stereo_balance_;
mutable bool can_decode_success_;
mutable bool can_decode_last_;
@@ -201,10 +197,7 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
int scope_chunk_;
bool have_new_buffer_;
int scope_chunks_;
#ifdef Q_OS_MACOS
GTlsDatabase* tls_database_;
#endif
QString buffer_format_;
};

File diff suppressed because it is too large Load Diff

View File

@@ -69,14 +69,15 @@ class GstEnginePipeline : public QObject {
// Call these setters before Init
void set_output_device(const QString &sink, const QVariant &device);
void set_volume_control(const bool volume_control);
void set_volume_enabled(const bool enabled);
void set_stereo_balancer_enabled(const bool enabled);
void set_equalizer_enabled(const bool enabled);
void set_replaygain(const bool enabled, const int mode, const float preamp, const bool compression);
void set_buffer_duration_nanosec(qint64 duration_nanosec);
void set_buffer_min_fill(int percent);
// Creates the pipeline, returns false on error
bool InitFromUrl(const QByteArray &stream_url, const QUrl original_url, const qint64 end_nanosec);
bool InitFromString(const QString &pipeline);
// GstBufferConsumers get fed audio data. Thread-safe.
void AddBufferConsumer(GstBufferConsumer *consumer);
@@ -86,10 +87,10 @@ class GstEnginePipeline : public QObject {
// Control the music playback
QFuture<GstStateChangeReturn> SetState(const GstState state);
Q_INVOKABLE bool Seek(const qint64 nanosec);
void SetEqualizerEnabled(const bool enabled);
void SetEqualizerParams(const int preamp, const QList<int> &band_gains);
void SetVolume(const int percent);
void SetStereoBalance(const float value);
void SetEqualizerParams(const int preamp, const QList<int> &band_gains);
void StartFader(const qint64 duration_nanosec, const QTimeLine::Direction direction = QTimeLine::Forward, const QTimeLine::CurveShape shape = QTimeLine::LinearCurve, const bool use_fudge_timer = true);
// If this is set then it will be loaded automatically when playback finishes for gapless playback
@@ -102,6 +103,7 @@ class GstEnginePipeline : public QObject {
QByteArray stream_url() const { return stream_url_; }
QUrl original_url() const { return original_url_; }
bool is_valid() const { return valid_; }
// Please note that this method (unlike GstEngine's.position()) is multiple-section media unaware.
qint64 position() const;
// Please note that this method (unlike GstEngine's.length()) is multiple-section media unaware.
@@ -120,7 +122,7 @@ class GstEnginePipeline : public QObject {
public slots:
void SetVolumeModifier(qreal mod);
signals:
signals:
void EndOfStreamReached(const int pipeline_id, const bool has_next_track);
void MetadataFound(const int pipeline_id, const Engine::SimpleMetaBundle &bundle);
// This indicates an error, delegated from GStreamer, in the pipeline.
@@ -136,16 +138,21 @@ signals:
void timerEvent(QTimerEvent*);
private:
bool InitAudioBin();
// Static callbacks. The GstEnginePipeline instance is passed in the last argument.
static GstPadProbeReturn EventHandoffCallback(GstPad*, GstPadProbeInfo*, gpointer);
static void SourceSetupCallback(GstPlayBin*, GParamSpec* pspec, gpointer);
static void NewPadCallback(GstElement*, GstPad*, gpointer);
static GstPadProbeReturn PlaybinProbe(GstPad*, GstPadProbeInfo*, gpointer);
static GstPadProbeReturn HandoffCallback(GstPad*, GstPadProbeInfo*, gpointer);
static void AboutToFinishCallback(GstPlayBin*, gpointer);
static GstBusSyncReply BusCallbackSync(GstBus*, GstMessage*, gpointer);
static gboolean BusCallback(GstBus*, GstMessage*, gpointer);
static void NewPadCallback(GstElement*, GstPad*, gpointer);
static GstPadProbeReturn HandoffCallback(GstPad*, GstPadProbeInfo*, gpointer);
static GstPadProbeReturn EventHandoffCallback(GstPad*, GstPadProbeInfo*, gpointer);
static void AboutToFinishCallback(GstPlayBin*, gpointer);
static GstPadProbeReturn DecodebinProbe(GstPad*, GstPadProbeInfo*, gpointer);
static void SourceSetupCallback(GstPlayBin*, GParamSpec* pspec, gpointer);
static void TaskEnterCallback(GstTask*, GThread*, gpointer);
static void StreamDiscovered(GstDiscoverer *discoverer, GstDiscovererInfo *info, GError *err, gpointer instance);
static void StreamDiscoveryFinished(GstDiscoverer *discoverer, gpointer instance);
static QString GSTdiscovererErrorMessage(GstDiscovererResult result);
void TagMessageReceived(GstMessage*);
void ErrorMessageReceived(GstMessage*);
@@ -158,17 +165,9 @@ signals:
QString ParseStrTag(GstTagList *list, const char *tag) const;
guint ParseUIntTag(GstTagList *list, const char *tag) const;
bool InitDecodeBin(GstElement *new_bin);
bool InitAudioBin();
GstElement *CreateDecodeBinFromString(const char *pipeline);
void UpdateVolume();
void UpdateEqualizer();
void UpdateStereoBalance();
static void StreamDiscovered(GstDiscoverer *discoverer, GstDiscovererInfo *info, GError *err, gpointer instance);
static void StreamDiscoveryFinished(GstDiscoverer *discoverer, gpointer instance);
static QString GSTdiscovererErrorMessage(GstDiscovererResult result);
void UpdateEqualizer();
private slots:
void FaderTimelineFinished();
@@ -193,20 +192,21 @@ signals:
bool valid_;
QString output_;
QVariant device_;
bool volume_control_;
// Equalizer
bool volume_enabled_;
bool stereo_balancer_enabled_;
bool eq_enabled_;
int eq_preamp_;
QList<int> eq_band_gains_;
bool rg_enabled_;
// Stereo balance.
// Stereo balance:
// From -1.0 - 1.0
// -1.0 is left, 1.0 is right.
float stereo_balance_;
// Equalizer
int eq_preamp_;
QList<int> eq_band_gains_;
// ReplayGain
bool rg_enabled_;
int rg_mode_;
float rg_preamp_;
bool rg_compression_;
@@ -247,7 +247,8 @@ signals:
// When we need to specify the device to use as source (for CD device)
QString source_device_;
// Seeking while the pipeline is in the READY state doesn't work, so we have to wait until it goes to PAUSED or PLAYING. Also we have to wait for the decodebin to be connected.
// Seeking while the pipeline is in the READY state doesn't work, so we have to wait until it goes to PAUSED or PLAYING.
// Also we have to wait for the playbin to be connected.
bool pipeline_is_initialised_;
bool pipeline_is_connected_;
qint64 pending_seek_nanosec_;
@@ -268,34 +269,24 @@ signals:
bool use_fudge_timer_;
GstElement *pipeline_;
// The audiobin is either linked with a decodebin or set as sink of the playbin pipeline.
GstElement *audiobin_;
// Elements in the audiobin. See comments in Init()'s definition.
GstElement *queue_;
GstElement *audioconvert_;
GstElement *audioconvert2_;
GstElement *audioscale_;
GstElement *audiosink_;
GstElement *audioqueue_;
GstElement *volume_;
GstElement *audio_panorama_;
GstElement *equalizer_preamp_;
GstElement *audiopanorama_;
GstElement *equalizer_;
GstElement *rgvolume_;
GstElement *rglimiter_;
GstElement *equalizer_preamp_;
GstDiscoverer *discoverer_;
int about_to_finish_cb_id_;
int pad_added_cb_id_;
int notify_source_cb_id_;
int about_to_finish_cb_id_;
int bus_cb_id_;
int discovery_finished_cb_id_;
int discovery_discovered_cb_id_;
QThreadPool set_state_threadpool_;
GstSegment last_decodebin_segment_;
GstSegment last_playbin_segment_;
};

View File

@@ -0,0 +1,115 @@
/*
* 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 <initguid.h>
#include <devpkey.h>
#include <functiondiscoverykeys_devpkey.h>
#include <mmdeviceapi.h>
#include <QList>
#include <QVariant>
#include <QString>
#include "mmdevicefinder.h"
#include "core/logging.h"
MMDeviceFinder::MMDeviceFinder() : DeviceFinder("mmdevice", { "wasapisink" }) {}
QList<DeviceFinder::Device> MMDeviceFinder::ListDevices() {
HRESULT hr = S_OK;
IMMDeviceEnumerator *enumerator = nullptr;
hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&enumerator);
if (FAILED(hr)) {
return QList<Device>();
}
IMMDeviceCollection *collection = nullptr;
hr = enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &collection);
if (FAILED(hr)) {
enumerator->Release();
return QList<Device>();
}
UINT count;
hr = collection->GetCount(&count);
if (FAILED(hr)) {
collection->Release();
enumerator->Release();
return QList<Device>();
}
QList<Device> devices;
Device default_device;
default_device.description = "Default device";
default_device.iconname = GuessIconName(default_device.description);
devices.append(default_device);
for (ULONG i = 0 ; i < count ; i++) {
IMMDevice *endpoint = nullptr;
hr = collection->Item(i, &endpoint);
if (FAILED(hr)) { return devices; }
LPWSTR pwszid = nullptr;
hr = endpoint->GetId(&pwszid);
if (FAILED(hr)) {
endpoint->Release();
continue;
}
IPropertyStore *props = nullptr;
hr = endpoint->OpenPropertyStore(STGM_READ, &props);
if (FAILED(hr)) {
CoTaskMemFree(pwszid);
endpoint->Release();
continue;
}
PROPVARIANT var_name;
PropVariantInit(&var_name);
hr = props->GetValue(PKEY_Device_FriendlyName, &var_name);
if (FAILED(hr)) {
props->Release();
CoTaskMemFree(pwszid);
endpoint->Release();
continue;
}
Device device;
device.description = QString::fromWCharArray(var_name.pwszVal);
device.iconname = GuessIconName(device.description);
device.value = QString::fromStdWString(pwszid);
devices.append(device);
PropVariantClear(&var_name);
props->Release();
CoTaskMemFree(pwszid);
endpoint->Release();
}
collection->Release();
enumerator->Release();
return devices;
}

View File

@@ -0,0 +1,34 @@
/*
* 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/>.
*
*/
#ifndef MMDEVICEFINDER_H
#define MMDEVICEFINDER_H
#include "config.h"
#include "devicefinder.h"
class MMDeviceFinder : public DeviceFinder {
public:
MMDeviceFinder();
virtual bool Initialise() { return true; }
virtual QList<Device> ListDevices();
};
#endif // MMDEVICEFINDER_H

View File

@@ -74,13 +74,14 @@ Equalizer::Equalizer(QWidget *parent)
// Must be done before the signals are connected
ReloadSettings();
connect(ui_->enable, SIGNAL(toggled(bool)), SIGNAL(EnabledChanged(bool)));
connect(ui_->enable, SIGNAL(toggled(bool)), ui_->slider_container, SLOT(setEnabled(bool)));
connect(ui_->enable, SIGNAL(toggled(bool)), SLOT(Save()));
connect(ui_->enable_equalizer, SIGNAL(toggled(bool)), SLOT(EqualizerEnabledChangedSlot(bool)));
connect(ui_->preset, SIGNAL(currentIndexChanged(int)), SLOT(PresetChanged(int)));
connect(ui_->preset_save, SIGNAL(clicked()), SLOT(SavePreset()));
connect(ui_->preset_del, SIGNAL(clicked()), SLOT(DelPreset()));
connect(ui_->balance_slider, SIGNAL(valueChanged(int)), SLOT(StereoSliderChanged(int)));
connect(ui_->enable_stereo_balancer, SIGNAL(toggled(bool)), SLOT(StereoBalancerEnabledChangedSlot(bool)));
connect(ui_->stereo_balance_slider, SIGNAL(valueChanged(int)), SLOT(StereoBalanceSliderChanged(int)));
QShortcut *close = new QShortcut(QKeySequence::Close, this);
connect(close, SIGNAL(activated()), SLOT(close()));
@@ -116,12 +117,16 @@ void Equalizer::ReloadSettings() {
if (selected_index != -1) ui_->preset->setCurrentIndex(selected_index);
// Enabled?
ui_->enable->setChecked(s.value("enabled", false).toBool());
ui_->slider_container->setEnabled(ui_->enable->isChecked());
ui_->enable_equalizer->setChecked(s.value("enabled", false).toBool());
ui_->slider_container->setEnabled(ui_->enable_equalizer->isChecked());
ui_->enable_stereo_balancer->setChecked(s.value("enable_stereo_balancer", false).toBool());
ui_->slider_label_layout->setEnabled(ui_->enable_stereo_balancer->isChecked());
ui_->stereo_balance_slider->setEnabled(ui_->enable_stereo_balancer->isChecked());
int stereo_balance = s.value("stereo_balance", 0).toInt();
ui_->balance_slider->setValue(stereo_balance);
StereoSliderChanged(stereo_balance);
ui_->stereo_balance_slider->setValue(stereo_balance);
StereoBalanceSliderChanged(stereo_balance);
PresetChanged(selected_preset);
@@ -184,7 +189,7 @@ void Equalizer::PresetChanged(const QString& name) {
for (int i = 0; i < kBands; ++i) gain_[i]->set_value(p.gain[i]);
loading_ = false;
ParametersChanged();
EqualizerParametersChangedSlot();
Save();
}
@@ -234,14 +239,18 @@ EqualizerSlider *Equalizer::AddSlider(const QString &label) {
EqualizerSlider *ret = new EqualizerSlider(label, ui_->slider_container);
ui_->slider_container->layout()->addWidget(ret);
connect(ret, SIGNAL(ValueChanged(int)), SLOT(ParametersChanged()));
connect(ret, SIGNAL(ValueChanged(int)), SLOT(EqualizerParametersChangedSlot()));
return ret;
}
bool Equalizer::is_enabled() const {
return ui_->enable->isChecked();
bool Equalizer::is_stereo_balancer_enabled() const {
return ui_->enable_stereo_balancer->isChecked();
}
bool Equalizer::is_equalizer_enabled() const {
return ui_->enable_equalizer->isChecked();
}
int Equalizer::preamp_value() const {
@@ -268,13 +277,41 @@ Equalizer::Params Equalizer::current_params() const {
}
float Equalizer::stereo_balance() const {
return qBound(-1.0f, ui_->balance_slider->value() / 100.0f, 1.0f);
return qBound(-1.0f, ui_->stereo_balance_slider->value() / 100.0f, 1.0f);
}
void Equalizer::ParametersChanged() {
if (loading_) return;
void Equalizer::StereoBalancerEnabledChangedSlot(const bool enabled) {
if (!enabled) {
ui_->stereo_balance_slider->setValue(0);
emit StereoBalanceChanged(stereo_balance());
}
ui_->stereo_balance_slider->setEnabled(enabled);
emit StereoBalancerEnabledChanged(enabled);
Save();
}
void Equalizer::StereoBalanceSliderChanged(int) {
emit StereoBalanceChanged(stereo_balance());
Save();
}
void Equalizer::EqualizerEnabledChangedSlot(const bool enabled) {
emit EqualizerEnabledChanged(enabled);
ui_->slider_container->setEnabled(enabled);
Save();
}
void Equalizer::EqualizerParametersChangedSlot() {
if (loading_) return;
emit EqualizerParametersChanged(preamp_value(), gain_values());
emit ParametersChanged(preamp_value(), gain_values());
}
void Equalizer::Save() {
@@ -296,15 +333,14 @@ void Equalizer::Save() {
s.setValue("selected_preset", ui_->preset->itemData(ui_->preset->currentIndex()).toString());
// Enabled?
s.setValue("enabled", ui_->enable->isChecked());
s.setValue("enabled", ui_->enable_equalizer->isChecked());
s.setValue("stereo_balance", ui_->balance_slider->value());
s.setValue("enable_stereo_balancer", ui_->enable_stereo_balancer->isChecked());
s.setValue("stereo_balance", ui_->stereo_balance_slider->value());
}
void Equalizer::closeEvent(QCloseEvent *e) {
Q_UNUSED(e);
void Equalizer::closeEvent(QCloseEvent*) {
QString name = ui_->preset->currentText();
if (!presets_.contains(name)) return;
@@ -319,8 +355,7 @@ Equalizer::Params::Params() : preamp(0) {
for (int i = 0; i < Equalizer::kBands; ++i) gain[i] = 0;
}
Equalizer::Params::Params(int g0, int g1, int g2, int g3, int g4, int g5, int g6, int g7, int g8, int g9, int pre)
: preamp(pre) {
Equalizer::Params::Params(int g0, int g1, int g2, int g3, int g4, int g5, int g6, int g7, int g8, int g9, int pre) : preamp(pre) {
gain[0] = g0;
gain[1] = g1;
gain[2] = g2;
@@ -345,12 +380,6 @@ bool Equalizer::Params::operator !=(const Equalizer::Params& other) const {
return ! (*this == other);
}
void Equalizer::StereoSliderChanged(int value) {
Q_UNUSED(value);
emit StereoBalanceChanged(stereo_balance());
Save();
}
QDataStream &operator<<(QDataStream& s, const Equalizer::Params& p) {
s << p.preamp;
for (int i = 0; i < Equalizer::kBands; ++i) s << p.gain[i];

View File

@@ -61,28 +61,32 @@ class Equalizer : public QDialog {
int gain[kBands];
};
bool is_enabled() const;
bool is_equalizer_enabled() const;
bool is_stereo_balancer_enabled() const;
int preamp_value() const;
QList<int> gain_values() const;
Params current_params() const;
float stereo_balance() const;
signals:
void EnabledChanged(bool enabled);
void ParametersChanged(int preamp, const QList<int> &band_gains);
void StereoBalanceChanged(float balance);
void StereoBalancerEnabledChanged(const bool enabled);
void StereoBalanceChanged(const float balance);
void EqualizerEnabledChanged(const bool enabled);
void EqualizerParametersChanged(const int preamp, const QList<int> &band_gains);
protected:
void closeEvent(QCloseEvent *);
void closeEvent(QCloseEvent*);
private slots:
void ParametersChanged();
void StereoBalancerEnabledChangedSlot(const bool enabled);
void StereoBalanceSliderChanged(const int value);
void EqualizerEnabledChangedSlot(const bool enabled);
void EqualizerParametersChangedSlot();
void PresetChanged(const QString &name);
void PresetChanged(int index);
void SavePreset();
void DelPreset();
void Save();
void StereoSliderChanged(int value);
private:
EqualizerSlider *AddSlider(const QString &label);

View File

@@ -61,7 +61,7 @@
</widget>
</item>
<item>
<widget class="QCheckBox" name="enable">
<widget class="QCheckBox" name="enable_equalizer">
<property name="text">
<string>Enable equalizer</string>
</property>
@@ -81,6 +81,13 @@
<layout class="QHBoxLayout" name="horizontalLayout_2"/>
</widget>
</item>
<item>
<widget class="QCheckBox" name="enable_stereo_balancer">
<property name="text">
<string>Enable stereo balancer</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="slider_label_layout">
<item>
@@ -126,7 +133,7 @@
</layout>
</item>
<item>
<widget class="QSlider" name="balance_slider">
<widget class="QSlider" name="stereo_balance_slider">
<property name="minimum">
<number>-100</number>
</property>

View File

@@ -299,8 +299,8 @@ void InternetCollectionView::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

@@ -430,8 +430,8 @@ bool InternetSearchView::SearchKeyEvent(QKeyEvent *event) {
bool InternetSearchView::ResultsContextMenuEvent(QContextMenuEvent *event) {
context_menu_ = new QMenu(this);
context_actions_ << context_menu_->addAction( IconLoader::Load("media-play"), tr("Append to current playlist"), this, SLOT(AddSelectedToPlaylist()));
context_actions_ << context_menu_->addAction( IconLoader::Load("media-play"), tr("Replace current playlist"), this, SLOT(LoadSelected()));
context_actions_ << context_menu_->addAction( IconLoader::Load("media-playback-start"), tr("Append to current playlist"), this, SLOT(AddSelectedToPlaylist()));
context_actions_ << context_menu_->addAction( IconLoader::Load("media-playback-start"), tr("Replace current playlist"), this, SLOT(LoadSelected()));
context_actions_ << context_menu_->addAction( IconLoader::Load("document-new"), tr("Open in new playlist"), this, SLOT(OpenSelectedInNewPlaylist()));
context_menu_->addSeparator();

View File

@@ -120,10 +120,7 @@ int main(int argc, char* argv[]) {
QCoreApplication::setApplicationVersion(STRAWBERRY_VERSION_DISPLAY);
QCoreApplication::setOrganizationDomain("strawberrymusicplayer.org");
// This makes us show up nicely in gnome-volume-control
#if !GLIB_CHECK_VERSION(2, 36, 0) // Deprecated in glib 2.36.0
g_type_init();
#endif
// This makes us show up nicely in gnome-volume-control
g_set_application_name(QCoreApplication::applicationName().toLocal8Bit());
RegisterMetaTypes();

View File

@@ -330,7 +330,6 @@ void Organise::UpdateProgress() {
}
#ifdef HAVE_GSTREAMER
void Organise::FileTranscoded(const QString &input, const QString &output, bool success) {
Q_UNUSED(output);
@@ -348,7 +347,6 @@ void Organise::FileTranscoded(const QString &input, const QString &output, bool
QTimer::singleShot(0, this, SLOT(ProcessSomeFiles()));
}
#endif
void Organise::timerEvent(QTimerEvent *e) {

View File

@@ -81,9 +81,7 @@ class Organise : public QObject {
private slots:
void ProcessSomeFiles();
#ifdef HAVE_GSTREAMER
void FileTranscoded(const QString &input, const QString &output, bool success);
#endif
void LogLine(const QString message);
private:
@@ -125,14 +123,9 @@ class Organise : public QObject {
int task_count_;
const QString playlist_;
#ifdef HAVE_GSTREAMER
QBasicTimer transcode_progress_timer_;
#endif
QList<Task> tasks_pending_;
#ifdef HAVE_GSTREAMER
QMap<QString, Task> tasks_transcoding_;
#endif
int tasks_complete_;
bool started_;

View File

@@ -600,7 +600,11 @@ void Playlist::set_current_row(int i, bool is_stopping) {
queue_->TakeNext();
}
if (current_item_index_ == old_current_item_index) return;
if (current_item_index_ == old_current_item_index) {
UpdateScrobblePoint();
nowplaying_ = false;
return;
}
if (old_current_item_index.isValid()) {
emit dataChanged(old_current_item_index, old_current_item_index.sibling(old_current_item_index.row(), ColumnCount - 1));
@@ -1121,7 +1125,7 @@ bool Playlist::CompareItems(int column, Qt::SortOrder order, shared_ptr<Playlist
case Column_Year: cmp(year);
case Column_OriginalYear: cmp(originalyear);
case Column_Genre: strcmp(genre);
case Column_AlbumArtist: strcmp(playlist_albumartist);
case Column_AlbumArtist: strcmp(playlist_albumartist_sortable);
case Column_Composer: strcmp(composer);
case Column_Performer: strcmp(performer);
case Column_Grouping: strcmp(grouping);
@@ -1496,6 +1500,8 @@ void Playlist::SetStreamMetadata(const QUrl &url, const Song &song, const bool m
//qLog(Debug) << "Setting temporary metadata for" << url;
bool length_changed = song.length_nanosec() != current_item_metadata().length_nanosec();
current_item()->SetTemporaryMetadata(song);
if (minor) {
@@ -1510,7 +1516,7 @@ void Playlist::SetStreamMetadata(const QUrl &url, const Song &song, const bool m
InformOfCurrentSongChange();
}
UpdateScrobblePoint();
if (length_changed) UpdateScrobblePoint();
}
@@ -1977,7 +1983,7 @@ void Playlist::SkipTracks(const QModelIndexList &source_indexes) {
}
void Playlist::UpdateScrobblePoint(qint64 seek_point_nanosec) {
void Playlist::UpdateScrobblePoint(const qint64 seek_point_nanosec) {
const qint64 length = current_item_metadata().length_nanosec();

View File

@@ -222,7 +222,7 @@ class Playlist : public QAbstractListModel {
void set_scrobbled(bool state) { scrobbled_ = state; }
void set_nowplaying(bool state) { nowplaying_ = state; }
qint64 scrobble_point_nanosec() const { return scrobble_point_; }
void UpdateScrobblePoint(qint64 seek_point_nanosec = 0);
void UpdateScrobblePoint(const qint64 seek_point_nanosec = 0);
// Changing the playlist
void InsertItems (const PlaylistItemList &items, int pos = -1, bool play_now = false, bool enqueue = false, bool enqueue_next = false);

View File

@@ -161,6 +161,7 @@ PlaylistView::PlaylistView(QWidget *parent)
previous_background_image_x_(0),
previous_background_image_y_(0),
glow_enabled_(true),
select_track_(false),
currently_glowing_(false),
glow_intensity_step_(0),
inhibit_autoscroll_timer_(new QTimer(this)),
@@ -1004,6 +1005,7 @@ void PlaylistView::ReloadSettings() {
#endif
glow_enabled_ = s.value("glow_effect", glow_effect).toBool();
bool editmetadatainline = s.value("editmetadatainline", false).toBool();
select_track_ = s.value("select_track", false).toBool();
s.endGroup();
s.beginGroup(Playlist::kSettingsGroup);
@@ -1228,7 +1230,15 @@ void PlaylistView::CopyCurrentSongToClipboard() const {
}
void PlaylistView::SongChanged(const Song &song) {
song_playing_ = song;
if (select_track_ && playlist_) {
clearSelection();
QItemSelection selection(playlist_->index(playlist_->current_row(), 0), playlist_->index(playlist_->current_row(), playlist_->ColumnCount - 1));
selectionModel()->select(selection, QItemSelectionModel::Select);
}
}
void PlaylistView::Playing() {}

View File

@@ -240,6 +240,8 @@ class PlaylistView : public QTreeView {
int previous_background_image_y_;
bool glow_enabled_;
bool select_track_;
bool currently_glowing_;
QBasicTimer glow_timer_;
int glow_intensity_step_;

View File

@@ -72,6 +72,7 @@ void AudioScrobbler::ReloadSettings() {
scrobble_button_ = s.value("scrobble_button", false).toBool();
love_button_ = s.value("love_button", false).toBool();
submit_delay_ = s.value("submit", 0).toInt();
prefer_albumartist_ = s.value("albumartist", false).toBool();
s.endGroup();
emit ScrobblingEnabledChanged(enabled_);

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