Compare commits

...

476 Commits

Author SHA1 Message Date
Jonas Kvinge
3b72a12540 Release 1.0.13 2023-01-09 22:46:59 +01:00
Strawbs Bot
38a1b7765a Update translations 2023-01-09 01:09:50 +01:00
Jonas Kvinge
02f2b8b6f0 CueParser: Detect encoding 2023-01-08 23:40:56 +01:00
Jonas Kvinge
7bfa75102c Remove QRegularExpressionMatch include 2023-01-08 23:24:25 +01:00
Jonas Kvinge
b0f3e7351c Update Changelog 2023-01-08 18:36:32 +01:00
Jonas Kvinge
b5fa401db9 Collection: Make sure RunQuery does not access collection items
- Rename `QueryOptions` to `CollectionFilterOptions`.
- Create new class `CollectionQueryOptions` for passing options from model to `CollectionQuery`.
- Rename `Directory` to `CollectionDirectory`.

Fixes #1095
2023-01-08 18:16:16 +01:00
Jonas Kvinge
41f2710dea GstEnginePipeline: Use linear volume 2023-01-08 15:25:24 +01:00
Jonas Kvinge
f19dda57f0 gstfastspectrum: Use static_cast 2023-01-08 06:21:34 +01:00
Jonas Kvinge
cc4a99ad80 CollectionModel: Close database with same mutex 2023-01-07 23:57:23 +01:00
Jonas Kvinge
1c1a3fc417 ResizableTextEdit: Don't delete setText 2023-01-07 23:38:59 +01:00
Jonas Kvinge
e97be5850b CollectionModel: Change while to for loop 2023-01-07 23:26:36 +01:00
Jonas Kvinge
2c302654b7 CollectionBackendInterface: Initialize filetype 2023-01-07 23:19:37 +01:00
Jonas Kvinge
3ee4dc77b2 Update Changelog 2023-01-06 23:14:28 +01:00
Jonas Kvinge
db55f314c9 Settings: Require tab icons to be minimum 32 2023-01-04 21:24:57 +01:00
Jonas Kvinge
0b536b287f MainWindow: Require tab icons to be minimum 32
Fixes #1084
2023-01-04 21:24:39 +01:00
Jonas Kvinge
6f298a9917 Use system icons for tabbar
Fixes #1093
2023-01-04 17:53:28 +01:00
Jonas Kvinge
70f829a2e5 PlaylistParser: Fix saving relative playlists to new files
Fixes #1092
2023-01-04 17:40:54 +01:00
Jonas Kvinge
1dfe07003f GstEnginePipeline: Set and notify volume only when changed
Another fix for #1089
2023-01-03 21:32:20 +01:00
Jonas Kvinge
286b908062 SliderSlider: Rename `value to new_value` 2023-01-03 19:53:53 +01:00
Jonas Kvinge
4ec028e736 GstEnginePipeline: Change callback ID's to long 2023-01-03 19:51:23 +01:00
Strawbs Bot
35a6d1437a Update translations 2023-01-03 01:01:50 +01:00
Jonas Kvinge
7e3cb3de89 OrganizeFormat: Parse the file path as a single block to avoid splitting brackets
Fixes #1091
2023-01-02 22:23:49 +01:00
Jonas Kvinge
bd945039f1 Turn on git revision 2023-01-02 22:10:13 +01:00
Jonas Kvinge
46743c8f15 Release 1.0.12 2023-01-02 18:56:51 +01:00
Jonas Kvinge
9b75284447 Update Changelog 2023-01-02 18:56:51 +01:00
Strawbs Bot
dca3b0052a Update translations 2023-01-02 01:02:18 +01:00
Jonas Kvinge
6d05bb2de5 GstEnginePipeline: Remove upstream events and buffer probes
Also rename some variables and callback functions

Possible fix for #1090
2023-01-02 00:06:18 +01:00
Jonas Kvinge
8b2e8d3804 OSDPretty: Change pensize back to 2
Removes workaround from commit 91eee99bab
2023-01-01 22:51:49 +01:00
Jonas Kvinge
1a2ab19ab4 GstEnginePipeline: Ignore core error when next song is set
Fixes #958
2023-01-01 20:25:57 +01:00
Jonas Kvinge
04f010aa7b Move SliderSlider and PrettySlider into own files 2023-01-01 18:45:21 +01:00
Jonas Kvinge
25323b4a3a VolumeSlider: Fix infinite loop when adjusting volume using mouse wheel
Fixes #1089
2023-01-01 17:46:26 +01:00
Jonas Kvinge
f353c022f6 LocalRedirectServer: Cast sizeof to int 2023-01-01 16:02:56 +01:00
Jonas Kvinge
9d8b3d3428 ContextView: Fix parameters for `IconLoader::Load()` 2023-01-01 16:02:17 +01:00
Strawbs Bot
e4b06772c0 Update translations 2023-01-01 01:08:45 +01:00
Jonas Kvinge
a2b5c3ea08 Remove settings for changing palette colors
Fixes #1087
2022-12-31 18:20:28 +01:00
Jonas Kvinge
f632e95600 Turn on git revision 2022-12-30 22:47:49 +01:00
Jonas Kvinge
4b5da8c6d4 Release 1.0.11 2022-12-30 18:52:59 +01:00
Jonas Kvinge
77d7ffd10a Update Changelog 2022-12-30 18:52:34 +01:00
Jonas Kvinge
d2f720011a macdeployqt: Disable libgstgme 2022-12-29 22:26:21 +01:00
Jonas Kvinge
6329a7711d Fix includes 2022-12-29 21:39:03 +01:00
Jonas Kvinge
fd14d044e3 CI: Bump macOS version to 11 2022-12-29 20:32:54 +01:00
Strawbs Bot
6368d507e1 Update translations 2022-12-29 01:06:59 +01:00
Jonas Kvinge
205b7f2401 Split utilities functions into separate files 2022-12-28 22:53:59 +01:00
Strawbs Bot
f7d10f9530 Update translations 2022-12-28 01:19:59 +01:00
Jonas Kvinge
66154bb51e Song: Add xesam:userRating in Song::ToXesam 2022-12-27 21:18:40 +01:00
Jonas Kvinge
fac4ad5313 Scrobbler: Allow album artists to be "Various Artists"
Fixes #1082
2022-12-27 21:15:20 +01:00
Jonas Kvinge
fee63891ac FilesystemMusicStorage: QFile::moveToTrash recursively moves files to trash 2022-12-27 20:59:09 +01:00
Strawbs Bot
efa979ee03 Update translations 2022-12-27 01:01:39 +01:00
Jonas Kvinge
c756346357 GstEnginePipeline: Add audio converter for sink 2022-12-11 01:14:17 +01:00
Strawbs Bot
cc95db25cc Update translations 2022-12-11 01:05:26 +01:00
Jonas Kvinge
44970c3321 GstEnginePipeline: Use converter for event probe 2022-12-11 00:21:16 +01:00
Jonas Kvinge
43c7934af7 Mpris2: Use art manual or automatic directly when available
Fixes #1079
2022-12-10 23:22:46 +01:00
Jonas Kvinge
3e7b51163c Don't use system icons for tabbar
Fixes #1084
2022-12-10 18:49:01 +01:00
Jonas Kvinge
4d5f8a53f0 CI: Remove unneeded "shell: bash" 2022-12-05 18:14:40 +01:00
Jonas Kvinge
0b73ca8318 CI: Add Remove Fedora 35 and add 38 2022-12-05 18:07:27 +01:00
Jonas Kvinge
754cfc3bfd Mpris2: Rename function parameter variable 2022-12-04 21:42:36 +01:00
Jonas Kvinge
2ed1a5c06a Add keywords to desktop file 2022-12-04 21:36:45 +01:00
Jonas Kvinge
b2073df3c3 GstEnginePipeline: Detect if autoaudiosink has volume
Fixes #1037
2022-12-04 08:37:33 +01:00
Jonas Kvinge
6267edaa81 Update Changelog 2022-12-04 03:18:04 +01:00
Jonas Kvinge
292f2de3e6 GstEnginePipeline: Add more info when ignoring error 2022-12-04 03:18:04 +01:00
Strawbs Bot
7803dc8be3 Update translations 2022-12-04 02:44:03 +01:00
Jonas Kvinge
2a1260b79e PlaylistParser: Resolve symbolic links when creating relative paths
Fixes #1071
2022-12-04 00:18:55 +01:00
Jonas Kvinge
f9ec438b7f Don't remove disc from album title when creating cover hash
Fixes #1069
2022-12-03 23:23:18 +01:00
Jonas Kvinge
de544c4856 CI: Fix Fedora 37 build 2022-12-03 13:06:21 +01:00
Jonas Kvinge
55e04dd520 Player: Fix volume adjustment 2022-12-03 05:29:39 +01:00
Jonas Kvinge
b2d06f900b GstEnginePipeline: Correct parameter name for SetFaderVolume function 2022-12-03 04:47:41 +01:00
Jonas Kvinge
b92ec71810 Use system volume when possible
Fixes #1037
2022-12-03 04:33:22 +01:00
Jonas Kvinge
3a4199240e Change constexpr to const 2022-11-27 03:27:40 +01:00
Jonas Kvinge
157de12bdf Improve Tidal and Qobuz request 2022-11-27 01:28:29 +01:00
Jonas Kvinge
7c0c9fccdb Organize: Don't allow organizing files without unique tags
Fixes #1077
2022-11-26 23:37:41 +01:00
Jonas Kvinge
2cb29d06b3 EditTagDialog: Disable fields for unsupported tags 2022-11-23 22:06:45 +01:00
Jonas Kvinge
1fdeb50d93 TagReaderTagLib: Don't use TPE1 as performer for ID3 tags
Fixes #1076
2022-11-23 00:03:23 +01:00
Jonas Kvinge
f59632ae59 TagReaderTest: Add tests for reading and writing compilation tag 2022-11-22 21:27:26 +01:00
Jonas Kvinge
67b503da44 TagReaderTagLib: Fix compilation tag read/write for MP4
Partial fix for #1076
2022-11-22 21:09:18 +01:00
Jonas Kvinge
a351de6904 TagReaderTagLib: Fix saving FMPS_Playcount
Fixes #1074
2022-11-22 19:34:11 +01:00
Jonas Kvinge
f94742abd5 EditTagDialog: Fix tab order
Fixes #1075
2022-11-22 19:06:40 +01:00
Jonas Kvinge
891182637e Update README.md 2022-11-21 23:40:30 +01:00
bhrgunatha
086681c915 Add spacefm support to core/utilities.cpp OpenInFileManager 2022-11-19 12:36:21 +01:00
Strawbs Bot
3970d2d02b Update translations 2022-11-17 01:01:49 +01:00
Jonas Kvinge
2b3fddd015 main: Set PULSE_PROP_media.role 2022-11-17 00:59:22 +01:00
Jonas Kvinge
30fa0480a3 main: Set PULSE_PROP_application.icon_name
Fixes #1066
2022-11-17 00:57:10 +01:00
Jonas Kvinge
320a81ce69 main: Use capitalized name in g_set_application_name()
Partial fix for #1066
2022-11-16 23:53:53 +01:00
Jonas Kvinge
950411ef56 ResizableTextEdit: Force updating geometry
Possible fix for
2022-11-16 21:10:30 +01:00
Strawbs Bot
cb9cf084c0 Update translations 2022-11-12 01:01:38 +01:00
Strawbs Bot
bb18af09ae Update translations 2022-11-11 01:12:18 +01:00
Jonas Kvinge
049bf0c7f9 TrackSlider: Remove extra parentheses 2022-11-10 19:19:33 +01:00
Jonas Kvinge
ebc73ef775 CI: Move macOS remove problematic files step 2022-11-10 01:03:50 +01:00
Strawbs Bot
1bd6f59355 Update translations 2022-11-10 01:01:50 +01:00
Jonas Kvinge
c16396a690 GstEnginePipeline: Log pipeline initialized 2022-11-09 22:42:43 +01:00
Strawbs Bot
32a9fe3e9c Update translations 2022-10-30 01:01:54 +02:00
Jonas Kvinge
f48d133bc6 TidalRequest: Fix returning empty results 2022-10-30 00:17:38 +02:00
Jonas Kvinge
0678526d7d CI: Build on FreeBSD with Qt 6 2022-10-29 22:16:15 +02:00
Jonas Kvinge
26d3e8371f CollectionWatcher: Only run periodic scan when monitoring is on 2022-10-29 19:12:04 +02:00
Jonas Kvinge
6768f614c7 GstEngine: Call SetState right before setFuture 2022-10-29 18:45:09 +02:00
Jonas Kvinge
171dc84df1 GstEngine: Use QUrl::clear() 2022-10-29 18:43:49 +02:00
Jonas Kvinge
5ca6513c04 TidalRequest: Only return error when no songs are received
Fixes #1061
2022-10-28 21:46:14 +02:00
Strawbs Bot
41aeb0ac80 Update translations 2022-10-27 01:01:24 +02:00
Strawbs Bot
f871c4adef Update translations 2022-10-25 01:01:27 +02:00
Jonas Kvinge
ad4d0e89b1 Turn off git revision 2022-10-22 10:14:20 +02:00
Jonas Kvinge
0d0c49caa1 Release 1.0.10 2022-10-21 23:39:59 +02:00
Jonas Kvinge
7cbc7bdcfb Update Changelog 2022-10-21 23:38:29 +02:00
Jonas Kvinge
6b46c8ed4a CI: Fix macOS build 2022-10-21 22:14:38 +02:00
Jonas Kvinge
e33ffd1c8a MusixmatchLyricsProvider: Fix error message 2022-10-21 20:54:16 +02:00
Strawbs Bot
8dce9cc938 Update translations 2022-10-21 01:02:47 +02:00
Jonas Kvinge
f06218f8e3 Qobuz: Add option for base64 app secret 2022-10-20 20:47:06 +02:00
Strawbs Bot
5711eef2be Update translations 2022-10-20 01:20:20 +02:00
Jonas Kvinge
db6aac603c nsi: Bump icu 2022-10-19 19:23:54 +02:00
Jonas Kvinge
f10e928106 Organize: Only load embedded cover if the destination is a device 2022-10-19 18:37:49 +02:00
Jonas Kvinge
99d963b99c MusicStorage: Add source 2022-10-19 18:36:33 +02:00
Jonas Kvinge
5d35c22238 OrganizeDialog: Use QUrl::isLocalFile 2022-10-19 18:34:30 +02:00
Jonas Kvinge
54fc11a235 CollectionBackend: Rename source accessor 2022-10-19 17:11:56 +02:00
Jonas Kvinge
ec99df3144 Create common class for Musixmatch 2022-10-18 22:49:15 +02:00
Jonas Kvinge
d722035883 VLCEngine: Only emit stopped when still playing
VLC sends the stopped signal too late, the player has already moved on based on the end reached signal. Emitting Stopped afterwards will interrupt the player in the middle of the song change.

Fixes #1054
2022-10-18 20:12:21 +02:00
Jonas Kvinge
52139fbaa0 Player: Reverse if 2022-10-18 20:09:38 +02:00
Jonas Kvinge
88854eb558 nsi: Bump libunistring 2022-10-17 21:41:14 +02:00
Jonas Kvinge
c82bba01ee MusixmatchLyricsProvider: Remove unused declaration 2022-10-17 20:34:51 +02:00
Jonas Kvinge
eaa33a03d7 MusixmatchLyricsProvider: Use API for lyrics search when possible 2022-10-17 20:29:44 +02:00
Jonas Kvinge
89e8518f31 GeniusLyricsProvider: Make private 2022-10-17 20:28:51 +02:00
Jonas Kvinge
c7bf2e1da8 LyricsProvider: Add missing newline 2022-10-16 22:52:06 +02:00
Jonas Kvinge
bf904a6afa LyricsProvider: Parse multiple sections of the same tag 2022-10-16 01:27:54 +02:00
Jonas Kvinge
43c14ae71b Replace pragma once with header guards for consistency
Only 2 headers have this.
2022-10-15 19:54:09 +02:00
Jonas Kvinge
4abb8ef3c9 Update Changelog 2022-10-15 14:39:49 +02:00
Jonas Kvinge
e46b92dd7d GeniusLyricsProvider: Use new function for parsing HTML 2022-10-15 14:34:09 +02:00
Jonas Kvinge
1a25faa5b9 LyricsProvider: Add function for parsing lyrics from HTML 2022-10-15 14:33:35 +02:00
Strawbs Bot
3f4bf5f512 Update translations 2022-10-14 01:18:29 +02:00
Jonas Kvinge
ae7dbf15ed nsi: Remove avresample-4.dll 2022-10-14 00:10:30 +02:00
Jonas Kvinge
b22320c48f Replace typedef with using 2022-10-13 22:39:31 +02:00
Jonas Kvinge
61204e8d35 CMakeLists: cmake_minimum_required before project 2022-10-13 21:41:46 +02:00
Jonas Kvinge
b0704c654c utilities_test: Fix QByteArray conversion 2022-10-13 21:37:11 +02:00
Strawbs Bot
f40f8a8873 Update translations 2022-10-13 01:01:31 +02:00
Jonas Kvinge
560a7db506 Update .clang-format 2022-10-12 21:28:14 +02:00
Strawbs Bot
15baa8f70e Update translations 2022-10-12 01:01:48 +02:00
Jonas Kvinge
97a7637294 FileView: Use QFileIconProvider instead of QAbstractFileIconProvider
Fixes compile with Qt 5
2022-10-12 00:36:16 +02:00
Jonas Kvinge
3454656207 PlaylistContainer: Fix search field crash on macOS
Fixes #1053
2022-10-12 00:11:12 +02:00
Iridias
7dff6f26bc FileView: Create new file icon provider if icons are missing 2022-10-11 23:52:00 +02:00
Jonas Kvinge
9e835a23fd Rename QSearchField 2022-10-11 23:34:22 +02:00
Jonas Kvinge
c0259fb6ce CI: Remove unused macOS brew packages 2022-10-11 00:27:26 +02:00
Jonas Kvinge
acf106220b CI: Upgrade packages for macOS 2022-10-10 22:31:35 +02:00
Strawbs Bot
5d4dc9c907 Update translations 2022-10-10 01:02:17 +02:00
Jonas Kvinge
2b9a56af7f Update Changelog 2022-10-09 22:18:20 +02:00
Jonas Kvinge
f1e3ac65ac TidalRequest: Simplify no results
Fixes #1047
2022-10-09 22:07:59 +02:00
Jonas Kvinge
143f72cf6b PlaylistView: Fix scaling mid bar for currently playing track
Fixes #1051
2022-10-09 21:41:16 +02:00
Jonas Kvinge
5c8e49296c CI: Add Fedora 37 2022-10-05 00:08:09 +02:00
Jonas Kvinge
b2558b703c nsi: Add jpeg62.dll for MSVC 2022-10-02 22:33:36 +02:00
Jonas Kvinge
bf9d87106e CI: Build Jammy with Qt 6 2022-10-02 19:38:22 +02:00
Jonas Kvinge
5b7f507d9b Windows7ThumbBar: Use QString length instead of count 2022-10-01 14:03:28 +02:00
Jonas Kvinge
59a7835ace CI: Fix if lines 2022-10-01 01:40:32 +02:00
Jonas Kvinge
2495838fe3 CI: Use matrix 2022-09-30 23:58:25 +02:00
Jonas Kvinge
bab687bedf Add USE_RPATH option 2022-09-30 01:00:29 +02:00
Jonas Kvinge
6467c3c8ee Update CMakeLists.txt 2022-09-30 01:00:15 +02:00
Jonas Kvinge
66c2b7aaa6 Update Version.cmake 2022-09-30 00:59:33 +02:00
Jonas Kvinge
ab72c52661 CI: Remove custom libsoup step for macOS 2022-09-29 22:33:47 +02:00
Jonas Kvinge
f0bf1b8a54 Rename CI 2022-09-29 22:32:04 +02:00
Strawbs Bot
119251719f Update translations 2022-09-24 01:01:45 +02:00
Jonas Kvinge
0348400132 ContextView: Remove use of fixed font
Fixes #1040
2022-09-23 18:10:01 +02:00
Jonas Kvinge
813473805b CI: Get latest MSVC dependencies 2022-09-17 01:45:42 +02:00
Strawbs Bot
fe6368561b Update translations 2022-09-17 01:01:19 +02:00
Strawbs Bot
7ff06f424d Update translations 2022-09-15 01:01:21 +02:00
Jonas Kvinge
31958592c7 main: Always create initial style settings 2022-09-13 22:44:24 +02:00
Jonas Kvinge
adc21f4f75 Remove subdir for generated dbus files 2022-09-13 17:53:57 +02:00
Strawbs Bot
9cecd89d6f Update translations 2022-09-13 01:26:32 +02:00
Jonas Kvinge
d866b9b4d4 Update definitions i CMakeLists 2022-09-12 23:20:07 +02:00
Jonas Kvinge
93f12baf51 Fix narrowing conversions in connects 2022-09-12 23:18:54 +02:00
Jonas Kvinge
78d6fd634b Fix casts from QByteArray 2022-09-12 22:39:08 +02:00
Strawbs Bot
b5fc19f08a Update translations 2022-09-12 01:01:20 +02:00
Jonas Kvinge
2dae6a6546 nsi: Update flac dll version 2022-09-10 23:52:27 +02:00
Jonas Kvinge
b6bba46391 CI: Update vmactions/freebsd-vm 2022-09-09 23:02:28 +02:00
Jonas Kvinge
b791d97116 CI: Use variable for workspace 2022-09-09 22:40:37 +02:00
Strawbs Bot
6aa8255f34 Update translations 2022-09-08 01:01:22 +02:00
Jonas Kvinge
98e2140761 Turn on git revision 2022-09-04 00:48:35 +02:00
Jonas Kvinge
a59e064778 Release 1.0.9 2022-09-03 20:40:14 +02:00
Jonas Kvinge
655c4c66a7 Update Changelog 2022-09-03 20:34:25 +02:00
Jonas Kvinge
407c128f65 GstStartup: Set LIBSOUP3_LIBRARY_PATH for macOS 2022-09-03 00:19:25 +02:00
Jonas Kvinge
59a261a5be main: Add Frameworks to library paths for macOS 2022-09-03 00:19:25 +02:00
Jonas Kvinge
ba4e1afefe CI: Compile entire gstreamer from source for macOS 2022-09-02 23:55:25 +02:00
Jonas Kvinge
98b53b81d8 Update Changelog 2022-09-01 22:06:00 +02:00
Jonas Kvinge
8270cc0aa2 macdeploycheck: Fail on parse error 2022-09-01 21:58:11 +02:00
Jonas Kvinge
74207b1a87 Update ISSUE_TEMPLATE.md 2022-09-01 21:35:33 +02:00
Jonas Kvinge
77983445ce debian: Fix icu dependency 2022-09-01 19:18:40 +02:00
Ondrej Mosnáček
162190bcb8 Mark collectionmodel_test as not requiring GUI
The test doesn't seem to acually need gui_required = true, so set it to
false.
2022-08-31 12:40:46 -07:00
Jonas Kvinge
86b92b20b7 macdeployqt: Add back extra changeInstallName 2022-08-30 21:35:11 +02:00
Jonas Kvinge
2f5b60d548 macdeployqt: Fix deploying libgcc
Fixes #1025
2022-08-30 19:33:59 +02:00
Jonas Kvinge
c19661c977 macdeploycheck: Fix check for libgcc 2022-08-30 19:32:59 +02:00
Jonas Kvinge
82d101ca27 macdeployqt: Merge changes from upstream 2022-08-30 17:48:16 +02:00
Jonas Kvinge
32f9c4e670 GstEnginePipeline: Parse album from stream title tag
Fixes #1023
2022-08-30 16:56:08 +02:00
Jonas Kvinge
34c7225ab7 Turn back git revision 2022-08-29 22:05:07 +02:00
Jonas Kvinge
b02eb502e4 Release 1.0.8 2022-08-29 17:54:05 +02:00
Jonas Kvinge
7d6b3dfd20 Update maketarball.sh.in 2022-08-29 17:53:49 +02:00
Strawbs Bot
3ac39968d2 Update translations 2022-08-29 01:16:24 +02:00
Jonas Kvinge
2b24ac54a0 Remove unused includes 2022-08-28 03:09:33 +02:00
Jonas Kvinge
6da6b794c7 VolumeSlider: Remove unused Background and Foreground 2022-08-28 02:52:40 +02:00
Jonas Kvinge
ed689e27c9 Transcoder: Change return type for QueuedJobsCount to qint64 2022-08-28 02:51:10 +02:00
Jonas Kvinge
186f9c3f18 SmartPlaylistWizard: Add missing override 2022-08-28 02:50:33 +02:00
Jonas Kvinge
42cdde3203 SmartPlaylistsViewContainer: Add missing override 2022-08-28 02:50:17 +02:00
Jonas Kvinge
b9091702e9 SmartPlaylistSearchTermWidget: Add missing override 2022-08-28 02:50:02 +02:00
Jonas Kvinge
d42ecbe74e SmartPlaylistQueryWizardPlugin: Add missing override 2022-08-28 02:49:45 +02:00
Jonas Kvinge
e6c5446d63 PlaylistQueryGenerator: Add missing override 2022-08-28 02:49:30 +02:00
Jonas Kvinge
cc277211b3 LibreFMScrobbler: Call base class for ReloadSettings 2022-08-28 02:48:47 +02:00
Jonas Kvinge
6703c15c52 RadioPlaylistItem: Fix header guard comment 2022-08-28 02:48:22 +02:00
Jonas Kvinge
4ecdaf573e MoodbarRenderer: Remove unused kNumHues 2022-08-28 02:47:45 +02:00
Jonas Kvinge
71ec3e61be signalchecker: Remove useless return 2022-08-28 02:46:23 +02:00
Jonas Kvinge
216fdb2393 FileSystemWatcherInterface: Change signal to non const 2022-08-28 02:45:56 +02:00
Jonas Kvinge
c39acc6e3c Database: Remove useless return 2022-08-28 02:45:34 +02:00
Jonas Kvinge
d97b0478a7 Fix typos 2022-08-28 02:44:37 +02:00
Jonas Kvinge
d15d64eb67 nsi: Add nghttp2.dll for MSVC 2022-08-27 23:43:39 +02:00
Jonas Kvinge
3acd2656ee Update Changelog 2022-08-27 23:14:56 +02:00
Jonas Kvinge
a4b003534a CI: Switch to libsoup 3 2022-08-27 19:36:29 +02:00
Jonas Kvinge
8752538a02 nsi: Switch to libsoup 3 2022-08-27 19:36:29 +02:00
Strawbs Bot
bde435753a Update translations 2022-08-25 01:02:52 +02:00
Jonas Kvinge
d347e6fc5f Add setting for turning off HTTP/2 2022-08-24 20:34:10 +02:00
Jonas Kvinge
27b01d3642 Analyzer::Base: Set Qt::WA_OpaquePaintEvent 2022-08-24 20:32:08 +02:00
Jonas Kvinge
b78677e285 nsi: Use libsoup 2 2022-08-22 23:19:49 +02:00
Jonas Kvinge
f8f6c74bcb CI: Use libsoup 2 2022-08-22 23:19:40 +02:00
Strawbs Bot
7ce123939b Update translations 2022-08-21 01:19:35 +02:00
Jonas Kvinge
e7b02cfb15 TagReaderGME: Use UTF-16 2022-08-21 00:36:06 +02:00
Jonas Kvinge
5931077b08 macdeployqt: Add GStreamer GME plugin 2022-08-20 19:52:32 +02:00
Jonas Kvinge
a521bdc0e3 TagReaderGME: Compare file extension case-insensitive 2022-08-20 19:08:58 +02:00
Eoin O'Neill
80da565609 Initial support for GME's VGM/SPC playback and tag management.
Co-Authored-By: Jonas Kvinge <jonas@jkvinge.net>
2022-08-20 18:33:13 +02:00
Jonas Kvinge
6bc46e4598 CollectionModel: Make separate_albums_by_grouping optional 2022-08-20 16:47:09 +02:00
Jonas Kvinge
6562258db5 CollectionModel: Make separating albums by grouping optional
Fixes #1018
2022-08-20 14:51:19 +02:00
Jonas Kvinge
c219995218 Update .gitignore 2022-08-19 21:15:08 +02:00
Jonas Kvinge
62035431ed Install Visual C++ runtime 2022-08-18 22:47:34 +02:00
Jonas Kvinge
fa1fbca7dc DirectSoundDeviceFinder: Remove __attribute__((stdcall)) 2022-08-15 19:55:55 +02:00
Strawbs Bot
391b7476b3 Update translations 2022-08-15 01:01:37 +02:00
Jonas Kvinge
9c04ce665f DirectSoundDeviceFinder: Add CALLBACK to EnumerateCallback 2022-08-14 10:37:31 +02:00
Jonas Kvinge
dd87268197 CI: Build Windows x86 2022-08-14 10:37:31 +02:00
Jonas Kvinge
8d9af59db2 MainWindow: Use different Sparkle URL for x86 2022-08-14 10:37:31 +02:00
Strawbs Bot
1b754a35ff Update translations 2022-08-14 01:01:17 +02:00
Jonas Kvinge
7230f91f61 CI: Update actions 2022-08-10 21:32:18 +02:00
Strawbs Bot
93edfc315c Update translations 2022-08-10 01:01:34 +02:00
Strawbs Bot
74c8269531 Update translations 2022-08-09 18:02:04 +02:00
Jonas Kvinge
acb6c0fc83 Use PlaylistFilter directly 2022-08-09 17:23:46 +02:00
Jonas Kvinge
553d4cce93 PlaylistContainer: Translate Undo/Redo
Fixes #1017
2022-08-09 17:04:59 +02:00
Jonas Kvinge
ca81f144e6 README: Add ICU to dependencies 2022-08-08 00:37:37 +02:00
Jonas Kvinge
ec84960347 nsi: Move icu to common files 2022-08-08 00:37:19 +02:00
Jonas Kvinge
38db0764af Require ICU 2022-08-07 20:23:23 +02:00
Jonas Kvinge
a647f63bb0 CI: Add macOS 2022-08-07 17:35:53 +02:00
Jonas Kvinge
5b7087cc9e nsi: Add files for MSVC 2022-08-07 12:32:31 +02:00
Jonas Kvinge
1a6fcd5da6 QSearchField: Replace use of C-style cast 2022-08-07 05:14:38 +02:00
Jonas Kvinge
e31dd9f553 MacSystemTrayIcon: Replace use of C-style cast 2022-08-07 05:14:05 +02:00
Jonas Kvinge
22844716d1 RadioView: Remove duplicate double clicked
Already done in AutoExpandingTreeView::ItemDoubleClicked

Fixes #1015
2022-08-07 02:40:09 +02:00
Jonas Kvinge
6abed76f70 nsi: Add gme 2022-08-06 17:02:00 +02:00
Jonas Kvinge
72ff502e0f OSDDBus: Set timeout 2022-07-31 03:28:13 +02:00
Jonas Kvinge
2b781df32b CI: Use openSUSE Leap 15.4 for source builder 2022-07-29 16:27:21 +02:00
Strawbs Bot
bf601c3906 Update translations 2022-07-29 01:25:43 +02:00
Jonas Kvinge
b753e0ebb0 CI: Remove macOS 2022-07-28 16:56:35 +02:00
Jonas Kvinge
564211aceb Prefer ICU to transliterate characters when available
Fixes #1008
2022-07-28 16:31:16 +02:00
Strawbs Bot
538c759fef Update translations 2022-07-28 01:02:19 +02:00
Jonas Kvinge
95edc34100 Update README and issue template 2022-07-27 20:43:03 +02:00
Jonas Kvinge
98682a2da9 Use C++17 fallthrough 2022-07-26 20:37:06 +02:00
Jonas Kvinge
33581fa61d PlaylistContainer: Fix filter text when switching playlist
Fixes #1005
2022-07-26 07:35:43 +02:00
Jonas Kvinge
b02e0aae98 PlaylistListSortFilterModel: Add header guard 2022-07-26 07:33:11 +02:00
Jonas Kvinge
6fa4e1cb6d Turn on git revision 2022-07-25 23:37:33 +02:00
Jonas Kvinge
9f2ec22e95 Release 1.0.7 2022-07-25 21:45:27 +02:00
Jonas Kvinge
65b2e506b1 CI: Remove Ubuntu Impish 2022-07-25 17:29:35 +02:00
Jonas Kvinge
8bc07b5286 nsi: Add libgpg-error-0.dll 2022-07-25 15:51:05 +02:00
Jonas Kvinge
fe0af63795 Update Changelog 2022-07-25 15:28:25 +02:00
Jonas Kvinge
44ce7f4c67 CI: Disable audio cd for Windows MinGW build 2022-07-25 15:27:17 +02:00
Jonas Kvinge
252936134b nsi: Remove gstwinrt-1.0-0.dll 2022-07-25 04:25:08 +02:00
Jonas Kvinge
e255b06945 macdeployqt: Update gstreamer plugins 2022-07-25 03:56:38 +02:00
Jonas Kvinge
d726568a23 nsi: Add gstwavenc 2022-07-25 03:55:38 +02:00
Jonas Kvinge
66880a6de7 nsi: Update gstreamer plugins 2022-07-25 03:23:34 +02:00
Jonas Kvinge
fda622a0c0 Update Changelog 2022-07-24 23:44:54 +02:00
Jonas Kvinge
efa7d10f40 nsi: Add twolame 2022-07-21 03:04:48 +02:00
Strawbs Bot
348a3fabab Update translations 2022-07-21 01:09:44 +02:00
Jonas Kvinge
1bbaee605c PlaylistParser: Check file extension case-insensitive 2022-07-20 14:56:55 +02:00
Jonas Kvinge
22edf7a2b3 TagReaderTagParser: Fix reading and writing rating 2022-07-20 11:44:46 +02:00
Jonas Kvinge
3ffcc29249 Add back save all playlists action 2022-07-20 01:09:00 +02:00
Jonas Kvinge
21f1fe52c0 Remove save all playlists action
It's hard-coded to m3u, needs a new select directory dialog with option to select different playlist formats.

Fixes #987
2022-07-18 22:56:32 +02:00
Jonas Kvinge
99840c9e4f Turn on git revision 2022-07-18 00:40:00 +02:00
Jonas Kvinge
3194fe7d8e Release 1.0.6 2022-07-17 23:36:45 +02:00
Jonas Kvinge
81df72b0cb Update debian/copyright 2022-07-17 21:47:35 +02:00
Jonas Kvinge
57b056ac43 WorkerPool: Search for tagreader in libexec 2022-07-17 17:21:11 +02:00
Jonas Kvinge
c5876d0d48 Update Changelog 2022-07-17 01:53:39 +02:00
Jonas Kvinge
b5e65401b6 Update Changelog 2022-07-17 01:52:21 +02:00
Jonas Kvinge
ebea5b48ea Update Changelog 2022-07-17 01:50:58 +02:00
Jonas Kvinge
7d081e581a CI: Remove extra Qt 6 repo 2022-07-17 01:16:06 +02:00
Jonas Kvinge
5e819cf04b Remove defining _WIN32_WINNT 2022-07-17 01:16:10 +02:00
Jonas Kvinge
fd9ab43681 Windows7ThumbBar: Create taskbar list once 2022-07-17 00:13:37 +02:00
Jonas Kvinge
4935cdc722 Transcoder: Formatting 2022-07-16 16:31:04 +02:00
Jonas Kvinge
26a3c7ad6a Transcoder: Fix caps leak 2022-07-16 16:10:49 +02:00
Strawbs Bot
c358216ad9 Update translations 2022-07-16 01:01:40 +02:00
Yaroslav Chvanov
bb9302143c Send the media player name and version to ListenBrainz 2022-07-15 20:50:00 +02:00
Yaroslav Chvanov
3a73553aac Send more information to ListenBrainz
- Track duration and number.
- Player name and version.
2022-07-15 20:50:00 +02:00
Strawbs Bot
6447a17e3e Update translations 2022-07-15 01:01:45 +02:00
Jonas Kvinge
4bd5c8ffb3 EditTagDialog: Remove useless HTML 2022-07-14 23:56:00 +02:00
Jonas Kvinge
89f137b211 SmartPlaylistSearchTermWidget: Remove tr from Strawberry 2022-07-14 23:41:38 +02:00
Strawbs Bot
3425572c66 Update translations
Fixes #994
2022-07-14 22:09:06 +02:00
Jonas Kvinge
ad50875f9c SnapDialog: Remove HTML tag from tr text 2022-07-14 22:04:23 +02:00
Strawbs Bot
34e5645dab Update translations 2022-07-14 20:54:57 +02:00
Jonas Kvinge
e8ae91c230 nsi: Add pcre2-8 2022-07-13 17:25:14 +02:00
Jonas Kvinge
44b83994fa Remove libpcre-1.dll 2022-07-13 16:58:28 +02:00
Jonas Kvinge
201f585350 CI: Use official Qt 6 repo for Leap 15.3 and 15.4 2022-07-11 23:12:26 +02:00
Strawbs Bot
e4d2f1925e Update translations 2022-07-11 01:04:46 +02:00
Jonas Kvinge
658c116eac Utilities: Remove unnecessary constData() in Sha1CoverHash 2022-07-10 19:14:05 +02:00
Jonas Kvinge
dbbedee77f CollectionBackendTest: Remove invalid song test 2022-07-10 19:09:09 +02:00
Jonas Kvinge
16ac9ea061 TagReaderTest: Remove use of deprecated QCryptographicHash constructor 2022-07-10 19:08:43 +02:00
Jonas Kvinge
6afbc71b4a Remove old schemas 2022-07-10 18:57:00 +02:00
Jonas Kvinge
71263863ad Allow invalid ctime/mtime
Possible fix for #815 and #947
2022-07-10 03:24:02 +02:00
Jonas Kvinge
05232065f8 schema: Remove DEFAULT for TEXT 2022-07-10 01:56:39 +02:00
Jonas Kvinge
f289ae4143 Add Ubuntu Kinetic 2022-07-08 19:36:43 +02:00
Jonas Kvinge
91703ecec4 macdeployqt: Add hls plugin 2022-07-07 21:47:05 +02:00
Strawbs Bot
6fb0858b87 Update translations 2022-07-04 01:01:17 +02:00
Jonas Kvinge
f1c6620df9 Add Wiki link to README 2022-07-02 22:38:55 +02:00
Jonas Kvinge
08fed9a5ee CI: Update libsoup dll 2022-07-02 10:21:15 +02:00
Jonas Kvinge
eb28b3b05b Update libsoup in nsi 2022-07-01 23:33:19 +02:00
Strawbs Bot
f0c354b0c9 Update translations 2022-07-01 01:01:44 +02:00
Yaroslav Chvanov
07d88e86a2 Add support for prefer album artist option to ListenBrainz 2022-06-30 21:59:30 +02:00
Jonas Kvinge
f41a3b9bb2 CommandlineOptions: Change quint64 to quint32 to match operator>>
Fixes #986
2022-06-24 17:18:54 +02:00
Jonas Kvinge
bfd9e76f40 Remove capture of ‘this’ via ‘[=]’ 2022-06-20 23:52:18 +02:00
Strawbs Bot
38ce208a43 Update translations 2022-06-18 01:01:29 +02:00
Jonas Kvinge
fcd148b8d5 Playlist: Fix "Stop after this track" greys out next track in dynamic mode
Fixes #912
2022-06-16 17:53:07 +02:00
Ondrej Mosnacek
fc6c3774b0 README: Exclude unsupported repos in the repology badge
Showing them provides little value, as they are no longer maintained
and thus expected to contain outdated packages.

Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
2022-06-15 17:12:43 +02:00
Chongo Bong
18023d2e18 Update desktop file action, use play/pause instead of play and pause
Condenses it a bit. looks cleaner, yet provides the same functionality as before.
2022-06-15 17:08:15 +02:00
Strawbs Bot
467e834ad6 Update translations 2022-06-15 01:01:41 +02:00
Jonas Kvinge
629d9e7ae0 FileViewList: Sort files with QCollator in numeric mode
Fixes #977
2022-06-14 17:21:59 +02:00
Jonas Kvinge
4487d292e8 Set C standard to C99 for MSVC 2022-06-14 16:16:49 +02:00
Jonas Kvinge
76711b9a66 Set C standard to C17 2022-06-13 21:20:41 +02:00
Jonas Kvinge
b54c749e43 Replace use of C-style casts 2022-06-13 00:40:31 +02:00
Jonas Kvinge
d82fd421ed Replace use of C-style casts 2022-06-13 00:23:42 +02:00
Jonas Kvinge
abdcadb5fa Flush correct queue 2022-06-12 02:28:02 +02:00
Jonas Kvinge
fa3891e383 Use list instead of map for songs in internet search
Fixes issues with sorting
2022-06-12 01:59:46 +02:00
Strawbs Bot
f1dc0f95c8 Update translations 2022-06-12 01:28:33 +02:00
Jonas Kvinge
5c721d243a Turn on git revision 2022-06-11 00:27:38 +02:00
Jonas Kvinge
2770384f1f Release 1.0.5 2022-06-10 21:50:35 +02:00
Jonas Kvinge
f4e5b83039 Replace use of C-style casts 2022-06-10 02:30:39 +02:00
Jonas Kvinge
124681605b Change -Wno-old-style-cast to -Wold-style-cast 2022-06-10 01:23:55 +02:00
Jonas Kvinge
a217faae7c OSDPretty: Remove use of C-style cast 2022-06-10 00:47:11 +02:00
Jonas Kvinge
184c39bbb7 Update Changelog 2022-06-10 00:01:21 +02:00
Jonas Kvinge
508e2a70bb Update Changelog 2022-06-09 23:38:25 +02:00
Jonas Kvinge
5aac56fe96 ContextView: Cleanup spacers 2022-06-09 23:09:41 +02:00
Strawbs Bot
dab7dad966 Update translations 2022-06-09 01:02:32 +02:00
Jonas Kvinge
25e48d6cae Add option for disabling bars on currently playing track
Fixes #972
2022-06-09 00:50:21 +02:00
Jonas Kvinge
9b743e55d1 ContextView: Update album width from context 2022-06-09 00:46:39 +02:00
Jonas Kvinge
dc1f9edfaf Organize: Only notify song path changed for collection and device songs 2022-06-07 22:43:39 +02:00
Strawbs Bot
b6b68edf1e Update translations 2022-06-07 01:01:51 +02:00
Jonas Kvinge
a2320b99ae ContextView: Use fixed size to avoid scrollbar issues 2022-06-06 20:54:15 +02:00
Jonas Kvinge
be01e28068 ContextAlbum: Use sizeHint() 2022-06-06 18:24:00 +02:00
Jonas Kvinge
d6084083a5 Update data/style/strawberry.css 2022-06-06 18:23:34 +02:00
Jonas Kvinge
019bf5102c ResizableTextEdit: Add Q_OBJECT macro 2022-06-06 18:23:12 +02:00
Jonas Kvinge
a1633224d1 CI: Add g++ for debian/ubuntu 2022-06-06 18:22:06 +02:00
Strawbs Bot
e62bd26cb9 Update translations 2022-06-06 01:26:37 +02:00
Jonas Kvinge
c29f517292 Update debian/control.in 2022-06-05 23:47:04 +02:00
Jonas Kvinge
d80144f80c Remove -fpermissive 2022-06-05 23:19:40 +02:00
Jonas Kvinge
4733c84a86 ContextAlbum: Move rescaling back to paintevent 2022-06-05 19:02:34 +02:00
Jonas Kvinge
23f3d2095b ContextAlbum: Improve album cover fading 2022-06-05 18:20:44 +02:00
Jonas Kvinge
4f1f2b6fc6 ContextView: Change condition for showing context menu 2022-06-05 18:19:14 +02:00
Jonas Kvinge
1ea70b085f Context: Remove albums 2022-06-05 11:58:53 +02:00
Jonas Kvinge
6c0b395f4a Add option for overwriting playcounts
Fixes #962
2022-06-05 04:59:50 +02:00
Jonas Kvinge
0ee67f186f Remove widgets/resizabletextedit.h from CMakeLists.txt 2022-06-05 04:57:58 +02:00
Jonas Kvinge
d133addbaa Context: Use custom textedits instead of labels
Also improve album cover scaling

Fixes #965
2022-06-05 04:41:36 +02:00
Jonas Kvinge
683991b1c9 Add ResizableTextEdit 2022-06-05 04:41:36 +02:00
Strawbs Bot
32ac02007b Update translations 2022-06-05 01:01:44 +02:00
Jonas Kvinge
d716617ae0 FancyTabWidget: Make sure context menu does not popup outside of tabbar 2022-06-05 00:25:48 +02:00
Jonas Kvinge
26e1f015d2 Add streaming to description in CMakeLists.txt 2022-06-04 16:16:19 +02:00
Jonas Kvinge
1c94093a4b Update debian/copyright 2022-06-04 16:16:19 +02:00
Strawbs Bot
27eccd456a Update translations 2022-06-04 01:02:03 +02:00
Jonas Kvinge
eed4447560 Update protobuf in nsi 2022-05-31 19:02:31 +02:00
Jonas Kvinge
3c8d0ebd52 CollectionModel: Use grouping in all album groupings 2022-05-31 00:53:47 +02:00
Jonas Kvinge
7ec0d2f2cc Update fftw3 in nsi 2022-05-22 02:14:07 +02:00
Strawbs Bot
35da91a997 Update translations 2022-05-22 01:02:14 +02:00
Jonas Kvinge
788747c071 MainWindow: Remove unnecessary hide() 2022-05-21 19:12:53 +02:00
Jonas Kvinge
36eb131289 MainWindow: Remove QEvent::spontaneous() check in close event
Fixes #964
2022-05-21 19:12:53 +02:00
Jonas Kvinge
f231f28818 Move QGuiApplication::setQuitOnLastWindowClosed before QApplication 2022-05-21 19:12:53 +02:00
Strawbs Bot
aebdc89f77 Update translations 2022-05-20 01:04:44 +02:00
Jonas Kvinge
4a3a379871 Increase icons to include 128x128 and set global application icon
Fixes #954
2022-05-19 22:02:35 +02:00
Jonas Kvinge
a7f27add2d Combine definitions 2022-05-17 23:40:53 +02:00
Strawbs Bot
cd1d4247cf Update translations 2022-05-16 01:01:29 +02:00
Strawbs Bot
6d618c4b78 Update translations 2022-05-14 01:11:35 +02:00
Jonas Kvinge
ad469531ff SPFParser: Use percent-encoding for image too 2022-05-13 23:36:38 +02:00
Jonas Kvinge
cf9b4b1246 XSPFParser: Use percent-encoding when loading and saving playlists
Fixes #821
2022-05-13 23:32:35 +02:00
Jonas Kvinge
18a2692dc1 PlaylistParser: Refactor code and exclude CUE from save playlist filters
Fixes #953
2022-05-13 23:14:56 +02:00
Jonas Kvinge
a2dad982f8 Move sqlrow to core 2022-05-13 18:15:04 +02:00
Jonas Kvinge
8f27b6a4c9 CI: Update Fedora 2022-05-10 01:06:04 +02:00
Jonas Kvinge
21c4022fca PlaylistView: Fix invalidating cached pixmap on scroll
Fixes #952
2022-05-09 23:46:33 +02:00
Jonas Kvinge
237933855a Remove unused PKGBUILD file 2022-05-06 18:31:32 +02:00
Jonas Kvinge
dff7068a03 Move debian configuration to separate CMakeLists.txt 2022-05-06 18:26:46 +02:00
Jonas Kvinge
8f28a85a6d RadioParadiseService: Change URLs to https 2022-05-06 18:07:20 +02:00
Jonas Kvinge
2414eb2598 GstEnginePipeline: Replace char with int8_t in HandoffCallback 2022-05-06 17:42:08 +02:00
Strawbs Bot
4851f6bffd Update translations 2022-05-06 01:01:57 +02:00
Jonas Kvinge
948be36d3c SmartPlaylistSearchTerm: Move value assigment
Mistake done in commit 3f3ae7c38f
2022-05-05 20:41:30 +02:00
Jonas Kvinge
edd088927d macdeployqt: List missing gstreamer plugins instead of failing
Fixes #936
2022-05-04 23:11:53 +02:00
Jonas Kvinge
4cfe8dd95e nsi: Fix pcre2 dll for debug 2022-05-03 20:08:40 +02:00
Jonas Kvinge
e1ce81c5bf Update pcre2 filename in nsi 2022-04-30 21:03:09 +02:00
Jonas Kvinge
0f40b5f022 VLCEngine: Fix track progress
Fixes #941
2022-04-29 00:09:29 +02:00
FireFragment
94c5ffa92e Allow setting blur amount of background image up to 100px 2022-04-27 20:53:29 +02:00
FireFragment
3c9bf56767 Improve CMake error message in case of missing libvlc
When running CMake with VLC installed, but without libvlc there pops out following error message:
 > You need to have eithoer GStreamer or VLC to compile!

This may be confusing for some users, because they might have VLC already installed, but not libvlc. This commit fixes it.
2022-04-26 17:39:07 +02:00
Jonas Kvinge
9024acb16e debian: Add qt6-qpa-plugins to depends
Fixes #937
2022-04-23 23:48:16 +02:00
Jonas Kvinge
7732402122 Add ffmpeg to MSVC 2022-04-23 18:06:38 +02:00
Jonas Kvinge
2059bce6a7 Add Qt 6 support to debian files 2022-04-23 02:15:22 +02:00
Jonas Kvinge
499c86a8b8 Add safe git directory 2022-04-20 01:23:02 +02:00
Strawbs Bot
ef084eb145 Update translations 2022-04-20 01:02:20 +02:00
Jonas Kvinge
3f3ae7c38f SmartPlaylistSearchTerm: Fix filetype search 2022-04-19 23:11:13 +02:00
Strawbs Bot
83d762287f Update translations 2022-04-18 01:01:58 +02:00
Strawbs Bot
5af0acf147 Update translations 2022-04-16 01:05:16 +02:00
Jonas Kvinge
907dfee6f7 Utilities: Use inconv with MSVC 2022-04-15 17:44:04 +02:00
Strawbs Bot
d587d24603 Update translations 2022-04-15 01:03:02 +02:00
Jonas Kvinge
c246b8f164 GstEngine: Show debug information in error dialog 2022-04-14 20:56:57 +02:00
Strawbs Bot
deecafa053 Update translations 2022-04-11 01:02:28 +02:00
Jonas Kvinge
f8810106a2 Turn on git revision 2022-04-10 17:34:26 +02:00
Jonas Kvinge
8e35fbe532 Release 1.0.4 2022-04-10 14:08:25 +02:00
Jonas Kvinge
b1fdccde6e ContextView: Specify alternative fonts for no song playing 2022-04-10 14:05:51 +02:00
Jonas Kvinge
6741f100a1 Update Changelog 2022-04-10 12:19:23 +02:00
Jonas Kvinge
e05e9ea1b2 timeconstants: Use constexpr 2022-04-08 17:35:44 +02:00
Jonas Kvinge
197341de5e Update debian/copyright-scan-patterns.yml 2022-04-08 17:35:31 +02:00
Jonas Kvinge
2933482be3 Update debian/copyright 2022-04-08 17:35:23 +02:00
Jonas Kvinge
c7ce23239f Disable gstwasapi2 in nsi 2022-04-07 23:18:08 +02:00
Jonas Kvinge
79115f7439 Update README and issue template 2022-04-07 01:22:21 +02:00
Jonas Kvinge
4457103672 Add pcre2 to nsi for MSVC 2022-04-06 23:23:20 +02:00
Jonas Kvinge
d204875f72 globalshortcut-x11: Fix minor code issues 2022-04-06 21:22:10 +02:00
Strawbs Bot
c690e73b1a Update translations 2022-04-05 01:02:10 +02:00
Jonas Kvinge
b5d39c5f21 Context: Remove use of custom font
Fixes #932
2022-04-04 20:26:38 +02:00
Strawbs Bot
7f8834cb04 Update translations 2022-04-04 01:02:50 +02:00
Jonas Kvinge
0dab7e293c GstEngine: Append "2" to wasapi2sink output description 2022-04-02 01:37:43 +02:00
Jonas Kvinge
8f016880af globalshortcut-win: Register 0-9 as num keys too 2022-04-02 00:43:41 +02:00
Jonas Kvinge
f471462a84 AnalyzerBase: Refactor code 2022-04-01 22:30:22 +02:00
Strawbs Bot
58eec8df1e Update translations 2022-03-30 01:02:21 +02:00
Jonas Kvinge
2655b8b43a TagReaderTagLib: Replace use of QByteArray::count() 2022-03-29 01:43:07 +02:00
Jonas Kvinge
ea86c043a4 AlsaPCMDeviceFinder: Fix use of deleted memory 2022-03-29 01:23:35 +02:00
Strawbs Bot
c1faa616bc Update translations 2022-03-29 01:04:21 +02:00
Strawbs Bot
a68bf5a30d Update translations 2022-03-28 01:02:14 +02:00
Jonas Kvinge
9568b8e0e5 Add hls to nsi 2022-03-28 00:34:20 +02:00
Jonas Kvinge
b34321ef87 GlobalShortcutsManager: Translate shortcuts
Fixes #928
2022-03-27 14:31:58 +02:00
Strawbs Bot
4971f1c5bf Update translations 2022-03-27 01:04:49 +01:00
Maxime Haselbauer
962b52bd5b Add save all playlists action 2022-03-26 22:38:21 +01:00
Jonas Kvinge
9449bfa414 Update protobuf in nsi 2022-03-26 21:02:56 +01:00
Strawbs Bot
5b8e9066c6 Update translations 2022-03-26 01:03:00 +01:00
Jonas Kvinge
8690be7fd2 Use separate sparkle feed for mingw and msvc 2022-03-25 21:38:37 +01:00
Jonas Kvinge
497267016b Turn on git revision 2022-03-25 01:22:31 +01:00
Jonas Kvinge
0468f850c2 Release 1.0.3 2022-03-24 21:23:36 +01:00
Jonas Kvinge
b9e7d4e30c Update Changelog 2022-03-24 21:21:24 +01:00
Jonas Kvinge
0e7734b555 Update README.md 2022-03-24 20:32:50 +01:00
Jonas Kvinge
e81dcce5b3 Update nsi for msvc dependencies 2022-03-23 19:13:40 +01:00
Strawbs Bot
38bd1f7e1c Update translations 2022-03-23 01:16:48 +01:00
Jonas Kvinge
36ad9704a2 Update libspeex for msvc in nsi 2022-03-22 21:24:54 +01:00
Jonas Kvinge
a6c05df362 Formatting 2022-03-22 21:19:59 +01:00
Jonas Kvinge
f6b70fda71 Formatting 2022-03-22 21:09:05 +01:00
Jonas Kvinge
8cb4e75f70 Update nsi for msvc dependencies 2022-03-22 17:32:49 +01:00
Jonas Kvinge
da1815ac2b Qobuz: Fix albums request limited to 50 albums
Fixes #922
2022-03-21 21:54:27 +01:00
Jonas Kvinge
f7357f2d10 Add libbrotlienc.dll to nsi 2022-03-21 21:30:33 +01:00
Jonas Kvinge
d9c92c5ddd CI: Use new MSVC dependencies 2022-03-21 18:37:31 +01:00
Jonas Kvinge
c82bdb6405 Add musepack, bs2b, faac and faad to nsi for msvc 2022-03-19 20:15:56 +01:00
Jonas Kvinge
eec8ee5830 Add qtsparkle for msvc in nsi 2022-03-17 14:46:12 +01:00
Strawbs Bot
e67eb3c0d8 Update translations 2022-03-17 01:02:02 +01:00
Jonas Kvinge
9c101759f6 CI: Update CI for MSVC dependencies 2022-03-17 00:06:18 +01:00
Jonas Kvinge
a55ee92590 Update nsi for MSVC library changes 2022-03-17 00:05:27 +01:00
Jonas Kvinge
5ccfc97dab Database: Fix schema update with Windows line-endings 2022-03-17 00:04:12 +01:00
Jonas Kvinge
d6dd88ec3d Add registry inetc plugin to nsi 2022-03-14 22:13:14 +01:00
Strawbs Bot
8557d83599 Update translations 2022-03-13 01:02:01 +01:00
Jonas Kvinge
94cf1f8698 macdeployqt: Remove optional plugins 2022-03-11 20:45:15 +01:00
Strawbs Bot
9ada35c3a3 Update translations 2022-03-11 01:03:01 +01:00
Jonas Kvinge
79b0c906fa CI: Fix path to gst-plugin-scanner for macOS 2022-03-10 22:14:51 +01:00
Jonas Kvinge
a0688f1dba CI: Fix path to gst-plugin-scanner for macOS 2022-03-10 21:09:12 +01:00
Jonas Kvinge
f91e8fecee CI: Reduce installed macports packages 2022-03-10 16:24:01 +01:00
Jonas Kvinge
1b363babe2 Use our own macOS dependencies 2022-03-10 15:51:07 +01:00
Jonas Kvinge
73843cb54d Switch back to libsoup 2 in nsi
libsoup 3.0 currently has issues with gstreamer
2022-03-08 21:53:10 +01:00
Jonas Kvinge
a2ccfc2116 Add libgioopenssl.dll to nsi 2022-03-07 22:32:50 +01:00
Jonas Kvinge
fe104e2bad Update gstreamer plugins in nsi 2022-03-07 19:28:38 +01:00
Jonas Kvinge
35e3e9f4ff RPM spec: Update release for OpenMandriva 2022-03-06 14:05:07 +01:00
Jonas Kvinge
b2a1cd9716 CI: Add openSUSE Leap 15.4 2022-03-05 21:26:51 +01:00
Jonas Kvinge
14f58eae4b CI: Add Fedora 36 2022-03-05 21:26:24 +01:00
Jonas Kvinge
5cec000618 Add fdk-aac to nsi 2022-03-05 12:15:48 +01:00
Jonas Kvinge
4805a5287d CI: Remove Ubuntu Hirsute 2022-03-05 03:27:09 +01:00
Jonas Kvinge
4789dc5b30 Add bs2b to nsi 2022-03-05 01:55:05 +01:00
Jonas Kvinge
5a35099043 Add support for bs2b
Improve headphone listening of stereo audio records
2022-03-05 01:30:49 +01:00
Strawbs Bot
4cd0128919 Update translations 2022-03-02 01:02:32 +01:00
Jonas Kvinge
61e9b80f67 Song: Remove playlists from accepted file extensions
Fixes #909
2022-03-01 21:26:08 +01:00
Strawbs Bot
dcd881ba6c Update translations 2022-02-23 01:02:20 +01:00
Strawbs Bot
d40a67ce68 Update translations 2022-02-22 01:02:35 +01:00
Jonas Kvinge
1c1e7ca62a nsi: Move libmpg123-0.dll to common files 2022-02-21 20:47:11 +01:00
Jonas Kvinge
d3831d511b nsi: Move libmpg123-0.dll to common files 2022-02-21 20:45:26 +01:00
Jonas Kvinge
0942e93144 Add mpg123 plugin to nsi 2022-02-21 20:33:10 +01:00
Jonas Kvinge
98d3eba8e8 AlbumCoverLoader: Use char for QString::remove() 2022-02-21 20:22:47 +01:00
Jonas Kvinge
ff3db03696 AlbumCoverLoader: Remove slash and backslash from cover filename
Fixes #903
2022-02-21 20:21:06 +01:00
Strawbs Bot
3608c31d22 Update translations 2022-02-21 01:03:09 +01:00
Jonas Kvinge
8d504d9cee Turn on git revision 2022-02-20 21:47:24 +01:00
605 changed files with 38560 additions and 36381 deletions

View File

@@ -1,105 +1,216 @@
BasedOnStyle: Chromium
Language: Cpp
Standard: Cpp11
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -1
AlignAfterOpenBracket: false
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignConsecutiveMacros: true
AlignEscapedNewlines: true
AlignOperands: false
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignEscapedNewlines: Left
AlignOperands: DontAlign
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
AllowShortLambdasOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: No
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BreakBeforeBraces: false
BreakBeforeBinaryOperators: false
BreakBeforeBraces: Stroustrup
BreakBeforeTernaryOperators: false
BreakConstructorInitializers: BeforeColon
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 0
ColumnLimit: 0
CommentPragmas: '^ IWYU pragma:'
QualifierAlignment: Leave
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 2
Cpp11BracedListStyle: false
DeriveLineEnding: true
DerivePointerAlignment: true
DisableFormat: false
ExperimentalAutoDetectBinPacking: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: BinPack
BasedOnStyle: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: false
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: true
IncludeBlocks: Preserve
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: true
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: AfterHash
IndentWidth: 2
IndentExternBlock: AfterExternBlock
IndentRequiresClause: true
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertBraces: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
LambdaBodyIndentation: Signature
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 100
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 0
PenaltyBreakBeforeFirstCallParameter: 0
PenaltyBreakComment: 0
PenaltyBreakFirstLessLess: 0
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 0
PenaltyBreakTemplateDeclaration: 0
PenaltyExcessCharacter: 0
PenaltyReturnTypeOnItsOwnLine: 0
PenaltyIndentedWhitespace: 0
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
PPIndentWidth: -1
ReferenceAlignment: Pointer
ReflowComments: false
RemoveBracesLLVM: false
RequiresClausePosition: OwnLine
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: false
SortJavaStaticImport: Before
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
UseCRLF: false
UseTab: Never
BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: false
AfterCaseLabel: false
AfterStruct: false
AfterClass: false
AfterEnum: false
AfterUnion: false
AfterControlStatement: Never
AfterNamespace: false
AfterObjCDeclaration: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: true
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...

View File

@@ -7,12 +7,9 @@ assignees: ''
---
For technical issues, questions and feature suggestions/requests please use the forum on https://forum.strawberrymusicplayer.org/
Check the Changelog to see if the issue is already fixed:
https://github.com/strawberrymusicplayer/strawberry/blob/master/Changelog
If it's fixed, try the latest development build from: https://builds.strawberrymusicplayer.org/
- [ ] I have checked the [FAQ](https://wiki.strawberrymusicplayer.org/wiki/FAQ) for answers.
- [ ] I have checked the [Changelog](https://github.com/strawberrymusicplayer/strawberry/blob/master/Changelog) that the issue is not already fixed.
- [ ] I believe this issue is a bug, and not a general technical issue, question or feature requests that can be discussed on the [forum](https://forum.strawberrymusicplayer.org/).
**Describe the bug**
A clear and concise description of what the bug is.

1054
.github/workflows/build.yml vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

40
.gitignore vendored
View File

@@ -65,19 +65,6 @@ ui_*.h
*.moc
*.qm
# QtCreator
CMakeLists.txt.user*
*.pro.user
*.pro.user.*
*creator.user*
target_wrapper.*
compile_commands.json
*.kdev4
*.vscode
*.code-workspace
*.sublime-workspace
# Temporary files
*~
*.autosave
@@ -105,22 +92,29 @@ Thumbs.db
# Stuff in dist
maketarball.sh
changelog
PKGBUILD
# Translations
translations.pot
zanata.xml
.zanata-cache/
# Snap
parts/
prime/
stage/
*.snap
/snap/.snapcraft/
/*_source.tar.bz2
# QtCreator
CMakeLists.txt.user*
*.pro.user
*.pro.user.*
*creator.user*
target_wrapper.*
compile_commands.json
*.kdev4
*.vscode
*.code-workspace
*.sublime-workspace
# MSVC
CMakeSettings.json
/.vs/
/out/
/.vs
/out
# CLion
/.idea

View File

@@ -40,6 +40,8 @@
#include <QDir>
#include <QSet>
#include <QList>
#include <QVariant>
#include <QVariantMap>
#include <QStack>
#include <QDirIterator>
#include <QLibraryInfo>
@@ -187,9 +189,7 @@ OtoolInfo findDependencyInfo(const QString &binaryPath)
return info;
}
static const QRegularExpression regexp(QStringLiteral(
"^\\t(.+) \\(compatibility version (\\d+\\.\\d+\\.\\d+), "
"current version (\\d+\\.\\d+\\.\\d+)(, weak)?\\)$"));
static const QRegularExpression regexp(QStringLiteral("^\\t(.+) \\(compatibility version (\\d+\\.\\d+\\.\\d+), current version (\\d+\\.\\d+\\.\\d+)(, weak|, reexport)?\\)$"));
QString output = otool.readAllStandardOutput();
QStringList outputLines = output.split("\n", Qt::SkipEmptyParts);
@@ -220,6 +220,8 @@ OtoolInfo findDependencyInfo(const QString &binaryPath)
for (const QString &outputLine : outputLines) {
const auto match = regexp.match(outputLine);
if (match.hasMatch()) {
if (match.captured(1) == info.installName)
continue; // Another arch reference to the same binary
DylibInfo dylib;
dylib.binaryPath = match.captured(1);
dylib.compatibilityVersion = QVersionNumber::fromString(match.captured(2));
@@ -300,11 +302,11 @@ FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundl
if (state == QtPath) {
// Check for library name part
if (part < parts.count() && parts.at(part).contains(".dylib")) {
info.frameworkDirectory += "/" + (qtPath + currentPart + "/").simplified();
info.frameworkDirectory += "/" + QString(qtPath + currentPart + "/").simplified();
state = DylibName;
continue;
} else if (part < parts.count() && parts.at(part).endsWith(".framework")) {
info.frameworkDirectory += "/" + (qtPath + "lib/").simplified();
info.frameworkDirectory += "/" + QString(qtPath + "lib/").simplified();
state = FrameworkName;
continue;
} else if (trimmed.startsWith("/") == false) { // If the line does not contain a full path, the app is using a binary Qt package.
@@ -865,6 +867,18 @@ void changeInstallName(const QString &bundlePath, const FrameworkInfo &framework
if (!framework.installName.isEmpty() && framework.installName != framework.sourceFilePath) {
changeInstallName(framework.installName, deployedInstallName, binary);
}
// Workaround for the case when the library ID name is a symlink, while the dependencies
// specified using the canonical path to the library (QTBUG-56814)
QFileInfo fileInfo= QFileInfo(framework.installName);
QString canonicalInstallName = fileInfo.canonicalFilePath();
if (!canonicalInstallName.isEmpty() && canonicalInstallName != framework.installName) {
changeInstallName(canonicalInstallName, deployedInstallName, binary);
// some libraries' inner dependencies (such as ffmpeg, nettle) use symbol link (QTBUG-100093)
QString innerDependency = fileInfo.canonicalPath() + "/" + fileInfo.fileName();
if (innerDependency != canonicalInstallName && innerDependency != framework.installName) {
changeInstallName(innerDependency, deployedInstallName, binary);
}
}
}
}
@@ -1078,7 +1092,7 @@ QString getLibInfix(const QStringList &deployedFrameworks)
{
QString libInfix;
for (const QString &framework : deployedFrameworks) {
if (framework.startsWith(QStringLiteral("QtCore")) && framework.endsWith(QStringLiteral(".framework"))) {
if (framework.startsWith(QStringLiteral("QtCore")) && framework.endsWith(QStringLiteral(".framework")) && !framework.contains(QStringLiteral("5Compat"))) {
Q_ASSERT(framework.length() >= 16);
// 16 == "QtCore" + ".framework"
const int lengthOfLibInfix = framework.length() - 16;
@@ -1214,28 +1228,42 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
// GIO modules
{
QString sourcePath = qgetenv("GIO_EXTRA_MODULES");
if (sourcePath.isEmpty()) {
if (QFileInfo::exists("/usr/local/lib/gio/modules/libgiognutls.so")) {
sourcePath = "/usr/local/lib/gio/modules/libgiognutls.so";
QString giomodule_path = qgetenv("GIO_EXTRA_MODULES");
if (giomodule_path.isEmpty()) {
if (QDir().exists("/usr/local/lib/gio/modules")) {
giomodule_path = "/usr/local/lib/gio/modules";
}
else if (QFileInfo::exists("/opt/local/lib/gio/modules/libgiognutls.so")) {
sourcePath = "/opt/local/lib/gio/modules/libgiognutls.so";
else if (QDir().exists("/opt/local/lib/gio/modules")) {
giomodule_path = "/opt/local/lib/gio/modules";
}
else {
qFatal("Missing GIO_EXTRA_MODULES");
}
}
else {
sourcePath = sourcePath + "/libgiognutls.so";
const QStringList giomodules = QStringList() << "libgiognutls.so" << "libgioopenssl.so";
bool have_giomodule = false;
for (const QString &giomodule : giomodules) {
const QString sourcePath = giomodule_path + "/" + giomodule;
QFileInfo fileinfo(sourcePath);
if (!fileinfo.exists()) {
LogError() << "Missing GIO module" << fileinfo.baseName();
continue;
}
have_giomodule = true;
const QString destinationPath = appBundleInfo.path + "/Contents/PlugIns/gio-modules/" + giomodule;
QDir dir;
if (dir.mkpath(QFileInfo(destinationPath).path()) && copyFilePrintStatus(sourcePath, destinationPath)) {
runStrip(destinationPath);
QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath, appBundleInfo.path, deploymentInfo.rpathsUsed, useDebugLibs);
deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
}
}
const QString destinationPath = appBundleInfo.path + "/Contents/PlugIns/gio-modules/libgiognutls.so";
QDir dir;
if (dir.mkpath(QFileInfo(destinationPath).path()) && copyFilePrintStatus(sourcePath, destinationPath)) {
runStrip(destinationPath);
QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath, appBundleInfo.path, deploymentInfo.rpathsUsed, useDebugLibs);
deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
if (!have_giomodule) {
qFatal("Missing GIO modules.");
}
}
// gst-plugin-scanner
@@ -1262,8 +1290,13 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
}
// GStreamer plugins.
QStringList gstreamer_plugins = QStringList() << "libgstapetag.dylib"
QStringList gstreamer_plugins = QStringList()
<< "libgstaes.dylib"
<< "libgstaiff.dylib"
<< "libgstapetag.dylib"
<< "libgstapp.dylib"
<< "libgstasf.dylib"
<< "libgstasfmux.dylib"
<< "libgstaudioconvert.dylib"
<< "libgstaudiofx.dylib"
<< "libgstaudiomixer.dylib"
@@ -1271,48 +1304,51 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
<< "libgstaudiorate.dylib"
<< "libgstaudioresample.dylib"
<< "libgstaudiotestsrc.dylib"
<< "libgstaudiovisualizers.dylib"
<< "libgstauparse.dylib"
<< "libgstautoconvert.dylib"
<< "libgstautodetect.dylib"
<< "libgstbs2b.dylib"
<< "libgstcdio.dylib"
<< "libgstcoreelements.dylib"
<< "libgstdash.dylib"
<< "libgstequalizer.dylib"
<< "libgstfaac.dylib"
<< "libgstfaad.dylib"
<< "libgstfdkaac.dylib"
<< "libgstflac.dylib"
<< "libgstgio.dylib"
//<< "libgstgme.dylib"
<< "libgsthls.dylib"
<< "libgsticydemux.dylib"
<< "libgstid3demux.dylib"
<< "libgstlevel.dylib"
<< "libgstid3tag.dylib"
<< "libgstisomp4.dylib"
<< "libgstlame.dylib"
<< "libgstlibav.dylib"
<< "libgstmpg123.dylib"
<< "libgstmusepack.dylib"
<< "libgstogg.dylib"
<< "libgstopenmpt.dylib"
<< "libgstopus.dylib"
<< "libgstopusparse.dylib"
<< "libgstosxaudio.dylib"
<< "libgstplayback.dylib"
<< "libgstrawparse.dylib"
<< "libgstreplaygain.dylib"
<< "libgstsoup.dylib"
<< "libgstspectrum.dylib"
<< "libgsttypefindfunctions.dylib"
<< "libgstvolume.dylib"
<< "libgstxingmux.dylib"
<< "libgsttcp.dylib"
<< "libgstudp.dylib"
<< "libgstpbtypes.dylib"
<< "libgstplayback.dylib"
<< "libgstreplaygain.dylib"
<< "libgstrtp.dylib"
<< "libgstrtsp.dylib"
<< "libgstflac.dylib"
<< "libgstwavparse.dylib"
<< "libgstfaad.dylib"
<< "libgstogg.dylib"
<< "libgstopus.dylib"
<< "libgstasf.dylib"
<< "libgstsoup.dylib"
<< "libgstspectrum.dylib"
<< "libgstspeex.dylib"
<< "libgsttaglib.dylib"
<< "libgsttcp.dylib"
<< "libgsttwolame.dylib"
<< "libgsttypefindfunctions.dylib"
<< "libgstudp.dylib"
<< "libgstvolume.dylib"
<< "libgstvorbis.dylib"
<< "libgstisomp4.dylib"
<< "libgstlibav.dylib"
<< "libgstaiff.dylib"
<< "libgstlame.dylib";
// macports does not have these.
QStringList gstreamer_plugins_optional = QStringList() << "libgstopusparse.dylib"
<< "libgstfaac.dylib"
<< "libgstmusepack.dylib";
<< "libgstwavenc.dylib"
<< "libgstwavpack.dylib"
<< "libgstwavparse.dylib"
<< "libgstxingmux.dylib";
QString gstreamer_plugins_dir = qgetenv("GST_PLUGIN_PATH");
if (gstreamer_plugins_dir.isEmpty()) {
@@ -1327,13 +1363,16 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
}
}
QStringList missing_gst_plugins;
for (const QString &plugin : gstreamer_plugins) {
QFileInfo info(gstreamer_plugins_dir + "/" + plugin);
if (!info.exists()) {
info.setFile(gstreamer_plugins_dir + "/" + info.baseName() + QString(".so"));
if (!info.exists()) {
LogError() << "Missing gstreamer plugin" << info.baseName();
qFatal("Missing %s", info.baseName().toUtf8().constData());
missing_gst_plugins << info.baseName();
continue;
}
}
const QString &sourcePath = info.filePath();
@@ -1345,22 +1384,8 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
}
}
for (const QString &plugin : gstreamer_plugins_optional) {
QFileInfo info(gstreamer_plugins_dir + "/" + plugin);
if (!info.exists()) {
info.setFile(gstreamer_plugins_dir + "/" + info.baseName() + QString(".so"));
if (!info.exists()) {
LogWarning() << "Skip missing gstreamer plugin" << info.baseName();
continue;
}
}
const QString &sourcePath = info.filePath();
const QString destinationPath = appBundleInfo.path + "/Contents/PlugIns/gstreamer/" + info.fileName();
if (QDir().mkpath(QFileInfo(destinationPath).path()) && copyFilePrintStatus(sourcePath, destinationPath)) {
runStrip(destinationPath);
QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath, appBundleInfo.path, deploymentInfo.rpathsUsed, useDebugLibs);
deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
}
if (!missing_gst_plugins.isEmpty()) {
LogError() << "Missing gstreamer plugins" << missing_gst_plugins;
}
}
@@ -1463,9 +1488,9 @@ bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInf
for (const QString &importPath : qmlImportPaths)
argumentList << "-importPath" << importPath;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QString qmlImportsPath = QLibraryInfo::path(QLibraryInfo::Qml2ImportsPath);
QString qmlImportsPath = QLibraryInfo::path(QLibraryInfo::QmlImportsPath);
#else
QString qmlImportsPath = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
QString qmlImportsPath = QLibraryInfo::location(QLibraryInfo::QmlImportsPath);
#endif
argumentList.append( "-importPath");
argumentList.append(qmlImportsPath);
@@ -1477,7 +1502,7 @@ bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInf
LogError() << "Could not start qmlimpoortscanner. Process error is" << qmlImportScanner.errorString();
return false;
}
qmlImportScanner.waitForFinished();
qmlImportScanner.waitForFinished(-1);
// log qmlimportscanner errors
qmlImportScanner.setReadChannel(QProcess::StandardError);

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.7)
include(CheckIncludeFiles)
include(CheckFunctionExists)

View File

@@ -1,7 +1,11 @@
cmake_minimum_required(VERSION 3.7)
project(strawberry)
cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0054 NEW)
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
cmake_policy(SET CMP0074 NEW)
endif()
include(CheckCXXCompilerFlag)
include(CheckCXXSourceRuns)
@@ -12,13 +16,13 @@ include(cmake/Summary.cmake)
include(cmake/OptionalSource.cmake)
include(cmake/ParseArguments.cmake)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(LINUX ON)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
set(FREEBSD ON)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
set(OPENBSD ON)
endif()
@@ -32,14 +36,22 @@ endif()
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
if(MSVC)
set(CMAKE_C_STANDARD 99)
else()
set(CMAKE_C_STANDARD 11)
endif()
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(MSVC)
list(APPEND COMPILE_OPTIONS /std:c++17 /MP)
list(APPEND COMPILE_OPTIONS /MP)
else()
list(APPEND COMPILE_OPTIONS
$<$<COMPILE_LANGUAGE:C>:-std=c99>
$<$<COMPILE_LANGUAGE:C>:-std=c11>
$<$<COMPILE_LANGUAGE:CXX>:-std=c++17>
-Wall
-Wextra
@@ -58,26 +70,24 @@ else()
-Wformat=2
-Wdisabled-optimization
$<$<COMPILE_LANGUAGE:CXX>:-Woverloaded-virtual>
$<$<COMPILE_LANGUAGE:CXX>:-Wno-old-style-cast>
$<$<COMPILE_LANGUAGE:CXX>:-fpermissive>
$<$<COMPILE_LANGUAGE:CXX>:-Wold-style-cast>
)
endif()
option(BUILD_WERROR "Build with -Werror" OFF)
if(BUILD_WERROR)
list(APPEND COMPILE_OPTIONS -Werror)
option(BUILD_WERROR "Build with -Werror" OFF)
if(BUILD_WERROR)
list(APPEND COMPILE_OPTIONS -Werror)
endif()
endif()
add_compile_options(${COMPILE_OPTIONS})
if(${CMAKE_BUILD_TYPE} MATCHES "Release")
if(CMAKE_BUILD_TYPE MATCHES "Release")
add_definitions(-DNDEBUG)
add_definitions(-DQT_NO_DEBUG_OUTPUT)
endif()
if(APPLE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks")
option(USE_RPATH "Use RPATH" APPLE)
if(USE_RPATH)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
endif()
find_program(CCACHE_EXECUTABLE NAMES ccache)
@@ -87,6 +97,8 @@ if(CCACHE_EXECUTABLE)
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_EXECUTABLE})
endif()
option(USE_ICU "Use ICU" ON)
find_package(PkgConfig REQUIRED)
find_package(Boost REQUIRED)
find_package(Threads)
@@ -94,7 +106,14 @@ find_package(Backtrace)
if(Backtrace_FOUND)
set(HAVE_BACKTRACE ON)
endif()
find_package(Iconv)
if(USE_ICU)
find_package(ICU COMPONENTS uc i18n REQUIRED)
if(ICU_FOUND)
set(HAVE_ICU ON)
endif()
else()
find_package(Iconv)
endif()
find_package(GnuTLS REQUIRED)
find_package(Protobuf REQUIRED)
if(NOT Protobuf_PROTOC_EXECUTABLE)
@@ -427,9 +446,9 @@ endif()
option(INSTALL_TRANSLATIONS "Install translations" OFF)
optional_component(SUBSONIC ON "Subsonic support")
optional_component(TIDAL ON "Tidal support")
optional_component(QOBUZ ON "Qobuz support")
optional_component(SUBSONIC ON "Streaming: Subsonic")
optional_component(TIDAL ON "Streaming: Tidal")
optional_component(QOBUZ ON "Streaming: Qobuz")
optional_component(MOODBAR ON "Moodbar"
DEPENDS "fftw3" FFTW3_FOUND
@@ -490,12 +509,16 @@ endif()
# Set up definitions
add_definitions(-DBOOST_BIND_NO_PLACEHOLDERS)
add_definitions(${QT_DEFINITIONS})
add_definitions(-DQT_STRICT_ITERATORS)
add_definitions(-DQT_USE_QSTRINGBUILDER)
add_definitions(-DQT_NO_URL_CAST_FROM_STRING)
add_definitions(-DQT_NO_CAST_TO_ASCII)
add_definitions(
-DBOOST_BIND_NO_PLACEHOLDERS
-DQT_STRICT_ITERATORS
-DQT_NO_CAST_FROM_BYTEARRAY
-DQT_USE_QSTRINGBUILDER
-DQT_NO_URL_CAST_FROM_STRING
-DQT_NO_CAST_TO_ASCII
-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT
-DQT_NO_FOREACH
)
if(WIN32)
add_definitions(-DUNICODE)
@@ -518,6 +541,10 @@ if(GTest_FOUND AND GMOCK_LIBRARY AND QtTest_LIBRARIES)
add_subdirectory(tests)
endif()
if(LINUX AND LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
add_subdirectory(debian)
endif()
# Uninstall support
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
@@ -526,7 +553,7 @@ add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/c
# Show a summary of what we have enabled
summary_show()
if(NOT HAVE_GSTREAMER AND NOT HAVE_VLC)
message(FATAL_ERROR "You need to have either GStreamer or VLC to compile!")
message(FATAL_ERROR "You need to have either GStreamer or libvlc to compile!")
elseif(NOT HAVE_GSTREAMER)
message(WARNING "GStreamer is the only engine that is fully implemented. Using other engines is possible but not recommended.")
endif()

171
Changelog
View File

@@ -2,6 +2,169 @@ Strawberry Music Player
=======================
ChangeLog
Version 1.0.13 (2023.01.09):
Bugfixes:
* Fixed volume synchronization leading to infinite loop resulting in crash when adjusting volume while playing (#1089).
* Fixed incorrect volume.
* Fixed collection organizing incorrectly handling slashes inside {} brackets for variables (#1091).
* Fixed saving relative playlists to non-existing playlist files (#1092).
* Fixed intermittent crash on collection model query (#1095).
* Require system icons for fancy tabbar and settings sidebar to be larger than 22x22 (#1084).
Version 1.0.12 (2023.01.02):
Bugfixes:
* Fixed crash when adjusting volume with mouse wheel (#1089).
* Fixed playback stopping in certain cases where the next track was unavailable (#958).
* (Windows) Apply patch for fonts too large on High DPI screen (QTBUG-108593).
Removed features:
* Removed appearance settings for changing palette colors, it was never properly implemented.
Version 1.0.11 (2022.12.30):
Bugfixes:
* Capitalize GLib application name so it appears nicely in GNOME and PulseAudio Volume Control (#1066).
* Fixed missing application icon for PulseAudio Volume Control (#1066).
* Ignore errors for missing albums when updating Tidal collection if there are results (#1061).
* Only run periodic collection scan when moitoring collection setting is on.
* Fixed an edge case where the context headline text was being cut short (#1067).
* Made "Show in file browser" support SpaceFM filemanager (#1073).
* Fixed incorrect tab order in edit tag dialog (#1075).
* Changed "FMPS_PlayCount" to "FMPS_Playcount" when saving tag (#1074).
* Fixed compilation tag read and write for MP4 (#1076).
* Removed incorrect use of "TPE1" for performer when reading ID3 tags (#1076).
* Disable tag fields for unsupported tags in tag editor.
* Don't allow organizing files without unique tags (track or title) for filename (#1077).
* Don't remove disc from album title when creating cover hash to allow different covers for each disc on an album (#1069).
* Fixed incorrect relative paths for song filenames when saving playlists if the saved playlist location is a symablic link to the song filename (#1071).
* Scrobble "Various Artists" as album artist (#1082).
Enhancements:
* Use system volume instead of own software volume when available (#1037).
* Improved Tidal and Qobuz support with timed requests.
* Support MPRIS2 xesam:userRating.
Version 1.0.10 (2022.10.21):
Bugfixes:
* Fixed "Could not open settings file for writing: No such file or directory" error before settings file is created.
* Fixed visual glitch on currently playing track (#1051).
* Fixed "Unknown error" on Tidal search (#1047).
* Fixed incomplete lyrics from Genius.
* Fixed icons not showing in the file view on some systems (#1024).
* Fixed issues with context and playing widget stopping when using VLC (#1054).
* (macOS) Fixed search field related crash when playlist toolbar is turned off.
Enhancements:
* Fixed narrowing conversions in connects.
* Fixed casts from QByteArray.
* Removed subdir for generated dbus files
* Removed use of fixed font in context (#1040).
* Improve Musixmatch lyrics search.
Version 1.0.9 (2022.09.03):
Bugfixes:
* Fixed parsing album title from radio stream metadata (#1023).
* (macOS) Fixed Strawberry not starting, incorrect rpath for libgcc_s.1.1.dylib (#1025).
* (macOS) Fixed HTTP streaming.
Version 1.0.8 (2022.08.29):
Bugfixes:
* Fixed backslash being appended to filter text when switching playlist (#1005).
* Fixed OSD notifications service registering taking too long to timeout when not available.
* Fixed radio stream added twice when double-clicked (#1015).
* Fixed translating undo and redo buttons (#1017).
Enhancements:
* Use ICU instead of iconv to transliterate characters for filenames.
* Make separating albums by grouping tag optional in collection group by album.
* Added support for video game music formats VGM and SPC.
* Added setting for explicitly turning on HTTP/2 for streaming. Strawberry will set the
libsoup SOUP_FORCE_HTTP1 environment variable when the HTTP/2 is not checked (#1016).
* (Windows|MSVC) Install Visual C++ runtime redistributable automatically in installer.
Version 1.0.7 (2022.07.25)
Bugfixes:
* Fixed checking file extension case-insensitive when loading and saving playlists.
* Fixed reading and saving rating with TagParser.
* (macOS/Windows) Fixed playlist column alignment. Applied patch for Qt bug QTBUG-103576 (#999).
* (Windows|MinGW) Fixed HLS streaming.
* (Windows|MSVC) Fixed MP3 encoding.
Enhancements
* Added option for selecting file extension when saving all playlists.
Version 1.0.6 (2022.07.17)
Bugfixes:
* Fixed certain albums not added to playlist in correct track order from search for Tidal and QObuz.
* Fixed songs not added to playlist in numeric order when added from file view with right click (#977).
* Fixed "Stop after this track" graying out next track in dynamic mode (#912).
* Fixed a gstreamer caps leak when transcoding songs.
* Fixed errors in translation files (#994).
Enhancements
* Add songs to the collection even when they have invalid ctime or mtime.
* Made ListenBrainz scrobbler respect "Prefer album artist" option (#989).
* Send track duration, number, player name and version when scrobbling to ListenBrainz (#995).
* (macOS) Added missing HLS streaming plugin.
Version 1.0.5 (2022.06.10)
Bugfixes:
* Fixed smart playlist filetype search.
* Fixed Radio Paradise URLs to use HTTPS instead of HTTP.
* Fixed horizontal scrolling not affecting currently playing track (#952).
* Fixed keep running in the background when window is closed with Wayland (#964).
* Fixed percent-encoding of URLs when loading and saving XSPF playlists (#821).
* Fixed fancy tabbar context menu showing on right clicks outside of tabbar when a song is playing.
* Fixed possible duplicating songs in the database when moving songs to the collection using the organize feature.
* (Windows|MSVC) Fixed moodbar fftw3 crash with (older) CPU's that does not support AVX2 (#944).
* (Windows|MSVC) Fixed using libiconv for converting characters when organizing files like with MinGW.
Enhancements
* Show more details in error dialog on GStreamer errors (#958).
* Allow setting blur amount of playlist background image up to 100px (#939).
* Include 128x128 icon sizes (#954).
* Show right click copy context menu in context view on top text and lyrics (#965).
* Improve fading between album covers in context view.
* Added option for overwriting database playcounts in collection settings (#962).
* Added option for disabling bar on currently playing track (#972).
* (Debian) Added Qt 6 support to debian files and build with Qt 6 for Debian Bookworm, Ubuntu Jammy and newer.
* (Windows|MSVC) Added libav/ffmpeg plugin.
Version 1.0.4 (2022.04.10)
Bugfixes:
* Fixed use-after-free memory in ALSA PCM device finder.
* Translate global shortcuts.
* (Windows) Fixed registering 0-9 numpad keys in global shortcuts.
Enhancements
* Added save all playlists action.
* (Windows) Made updater support both MSVC and MinGW.
* (Windows) Added HLS support.
Other:
* Removed use of custom font in context.
Version 1.0.3 (2022.03.24)
Bugfixes:
* Remove slash and backslash from filenames when saving album covers using album directory cover filenames (#903).
* Remove playlist file-extensions from accepted audio file extensions (#909).
* Fixed Qobuz requests only receiving the first 50 albums (#922).
* (Windows|MinGW) Fixed streaming stopping at the end of each track. libsoup downgraded from 3.0 to 2.74.
* (Windows|MSVC) Fixed initial database schema failure caused by CRLF line-endings in schema files.
New features
* Added support for bs2b (Improved headphone listening of stereo audio records using Bauer stereophonic-to-binaural DSP) (#249).
Version 1.0.2 (2022.02.20)
Bugfixes:
@@ -131,7 +294,7 @@ Version 0.9.3 (2021.04.18)
Bugfixes:
* Fix "Show in file browser" to work with thunar.
* Check that the clicked rating position is to the right or left of the rectangle.
* Fix rescan when collection directory is removed and readded.
* Fix rescan when collection directory is removed and re-added.
* Create GLib main event loop on non-glib systems to fix stream discoverer.
* (macOS) Fix intermittent abort on startup.
* (macOS) Fix Tidal and Qobuz search field not showing.
@@ -468,7 +631,7 @@ Version 0.6.10 (2020.05.01)
* Made font and font sizes in context configurable.
* Splitting artist and song title to the relevant metadata when artist and song title is sent as title separated by a dash in streams.
* Added label to show collection pixmap disk cache used in settings.
* Icreased default collection pixmap disk cache to 360.
* Increased default collection pixmap disk cache to 360.
New features:
* Added back Tidal streaming support.
@@ -536,7 +699,7 @@ Version 0.6.7 (2019.11.27)
* Fixed "Pressing Previous in player" behaviour setting
* Fixed updating compilations where there are spaces or special characters in filenames
* Fixed cases where songs were stuck in "Various Artists" because not all songs in
the same compilation was removed from the model before readded with actual artist.
the same compilation was removed from the model before re-added with actual artist.
* Fixed a bug when importing playlists where metadata was reset
* Fixed scrobbler to also scrobble songs without album title
* Fixed text for replay gain setting not loading in backend setting
@@ -889,7 +1052,7 @@ Version 0.1.5 (2018.05.16)
Version 0.1.4 (2018.05.14)
* Fixed compliation with clang compiler
* Fixed compilation with clang compiler
* This release is mainly to get it working on openbsd and freebsd.

View File

@@ -1,4 +1,4 @@
:strawberry: Strawberry Music Player [![Build Status](https://github.com/strawberrymusicplayer/strawberry/workflows/C/C++%20CI/badge.svg)](https://github.com/strawberrymusicplayer/strawberry/actions)
:strawberry: Strawberry Music Player [![Build Status](https://github.com/strawberrymusicplayer/strawberry/workflows/build/badge.svg)](https://github.com/strawberrymusicplayer/strawberry/actions)
=======================
[![Sponsor](https://img.shields.io/badge/-Sponsor-green?logo=github)](https://github.com/sponsors/jonaski)
[![Patreon](https://img.shields.io/badge/patreon-donate-green.svg)](https://patreon.com/jonaskvinge)
@@ -11,6 +11,7 @@ Strawberry is a music player and music collection organizer. It is a fork of Cle
Resources:
* Website: https://www.strawberrymusicplayer.org/
* Wiki: https://wiki.strawberrymusicplayer.org/
* Forum: https://forum.strawberrymusicplayer.org/
* Github: https://github.com/strawberrymusicplayer/strawberry
* Buildbot: https://buildbot.strawberrymusicplayer.org/
@@ -22,8 +23,10 @@ Resources:
### :bangbang: Opening an issue:
* Read the FAQ: https://wiki.strawberrymusicplayer.org/wiki/FAQ
* Search for the issue to see if it is already solved, or if there is an open issue for it already. If there is an open issue already, you can comment on it if you have additional information that could be useful to us.
* For technical problems, questions and feature requests please use our forum on https://forum.strawberrymusicplayer.org/ that is better suited for discussion. It also better allows answers from the community instead of just the developers on GitHub.
* For technical problems, discussion, questions and feature suggestions use the forum (https://forum.strawberrymusicplayer.org/) instead. The forum is better suited for discussion.
* We do not take feature requests from users on GitHub. Any issues related to feature requests will be closed. This does not necessarily mean that we won't add new features, but we don't have time to take feature requests or answer questions about new features from users. It is still possible to suggest or discuss new features on the forum (https://forum.strawberrymusicplayer.org/).
### :moneybag: Sponsoring:
@@ -66,18 +69,19 @@ It has so far been tested to work on Linux, OpenBSD, FreeBSD, macOS and Windows.
To build Strawberry from source you need the following installed on your system with the additional development packages/headers:
* [CMake](https://cmake.org/)
* [GNU Make](https://www.gnu.org/software/make/)
* [GCC](https://gcc.gnu.org/) or [clang](https://clang.llvm.org/) compiler
* C/C++ compiler ([GCC](https://gcc.gnu.org/), [Clang](https://clang.llvm.org/) or [MSVC](https://visualstudio.microsoft.com/vs/features/cplusplus/))
* [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) or [pkgconf](https://github.com/pkgconf/pkgconf)
* [Boost](https://www.boost.org/)
* [GLib](https://developer.gnome.org/glib/)
* [Protobuf](https://developers.google.com/protocol-buffers/)
* [Qt 5.9 or higher (or Qt 6) with components Core, Gui, Widgets, Concurrent, Network and Sql](https://www.qt.io/)
* [Qt 6 or Qt 5.9 or higher with components Core, Gui, Widgets, Concurrent, Network and Sql](https://www.qt.io/)
* [SQLite 3.9 or newer with FTS5](https://www.sqlite.org)
* [ALSA (Linux required)](https://www.alsa-project.org/)
* [D-Bus (Linux required)](https://www.freedesktop.org/wiki/Software/dbus/)
* [Protobuf](https://developers.google.com/protocol-buffers/)
* [ALSA (Required on Linux)](https://www.alsa-project.org/)
* [D-Bus (Required on Linux)](https://www.freedesktop.org/wiki/Software/dbus/)
* [GStreamer](https://gstreamer.freedesktop.org/) or [VLC](https://www.videolan.org)
* [GnuTLS](https://www.gnutls.org/)
* [TagLib 1.11.1 or higher](https://www.taglib.org/) or [TagParser](https://github.com/Martchus/tagparser)
* [ICU](https://unicode-org.github.io/icu/)
Optional dependencies:
@@ -88,8 +92,7 @@ Optional dependencies:
* MTP devices: [libmtp](http://libmtp.sourceforge.net/)
* iPod Classic devices: [libgpod](http://www.gtkpod.org/libgpod/)
Either GStreamer or VLC engine is required, but only GStreamer is fully implemented, and works best, it is therefore recommended to use GStreamer.
You should also install the gstreamer plugins base and good, and optionally bad, ugly and libav.
You should also install the gstreamer plugins base and good, and optionally bad, ugly and libav to support all audio formats.
### :wrench: Compiling from source
@@ -100,16 +103,19 @@ You should also install the gstreamer plugins base and good, and optionally bad,
### Compile and install:
cd strawberry
mkdir build && cd build
cmake ..
make -j$(nproc)
sudo make install
To compile with Qt 6 use:
mkdir build
cd build
cmake .. -DBUILD_WITH_QT6=ON
make -j $(nproc)
sudo make install
Strawberry is backwards compatible with Qt 5, to compile with Qt 5 use:
cmake .. -DBUILD_WITH_QT5=ON
To compile on Windows with Visual Studio 2019 or 2022, see https://github.com/strawberrymusicplayer/strawberry-msvc
### :penguin: Packaging status
[![Packaging status](https://repology.org/badge/vertical-allrepos/strawberry.svg)](https://repology.org/metapackage/strawberry/versions)
[![Packaging status](https://repology.org/badge/vertical-allrepos/strawberry.svg?exclude_unsupported=1)](https://repology.org/metapackage/strawberry/versions)

View File

@@ -2,18 +2,5 @@ find_program(LSB_RELEASE_EXEC lsb_release)
find_program(DPKG_BUILDPACKAGE dpkg-buildpackage)
if (LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
execute_process(COMMAND env LC_ALL=C date "+%a, %-d %b %Y %H:%M:%S %z" OUTPUT_VARIABLE DEB_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -cs"
OUTPUT_VARIABLE DEB_CODENAME
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (DEB_CODENAME AND DEB_DATE)
add_custom_target(deb
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMAND ${DPKG_BUILDPACKAGE} -b -d -uc -us
)
endif()
add_custom_target(deb WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${DPKG_BUILDPACKAGE} -b -d -uc -us)
endif()

View File

@@ -21,10 +21,7 @@ if(MACDEPLOYQT_EXECUTABLE)
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/strawberry.app/Contents/{Frameworks,Resources}
COMMAND cp -v ${CMAKE_SOURCE_DIR}/dist/macos/Info.plist ${CMAKE_BINARY_DIR}/strawberry.app/Contents/
COMMAND cp -v ${CMAKE_SOURCE_DIR}/dist/macos/strawberry.icns ${CMAKE_BINARY_DIR}/strawberry.app/Contents/Resources/
COMMAND ${MACDEPLOYQT_EXECUTABLE} strawberry.app -verbose=3
-executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/strawberry-tagreader
-executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/gio-modules/libgiognutls.so
#-executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/gst-plugin-scanner
COMMAND ${MACDEPLOYQT_EXECUTABLE} strawberry.app -verbose=3 -executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/strawberry-tagreader
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS strawberry strawberry-tagreader copy_gstreamer_plugins macdeployqt
)

View File

@@ -1,6 +1,6 @@
set(STRAWBERRY_VERSION_MAJOR 1)
set(STRAWBERRY_VERSION_MINOR 0)
set(STRAWBERRY_VERSION_PATCH 2)
set(STRAWBERRY_VERSION_PATCH 13)
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
set(INCLUDE_GIT_REVISION OFF)
@@ -14,10 +14,6 @@ set(STRAWBERRY_VERSION_RPM_R "1")
set(STRAWBERRY_VERSION_PAC_V "${majorminorpatch}")
set(STRAWBERRY_VERSION_PAC_R "1")
if(${STRAWBERRY_VERSION_PATCH} EQUAL "0")
set(STRAWBERRY_VERSION_DISPLAY "${STRAWBERRY_VERSION_MAJOR}.${STRAWBERRY_VERSION_MINOR}")
endif(${STRAWBERRY_VERSION_PATCH} EQUAL "0")
if(STRAWBERRY_VERSION_PRERELEASE)
set(STRAWBERRY_VERSION_DISPLAY "${STRAWBERRY_VERSION_DISPLAY} ${STRAWBERRY_VERSION_PRERELEASE}")
set(STRAWBERRY_VERSION_RPM_R "0.${STRAWBERRY_VERSION_PRERELEASE}")

View File

@@ -1,15 +1,6 @@
<RCC>
<qresource prefix="/">
<file>schema/schema.sql</file>
<file>schema/schema-1.sql</file>
<file>schema/schema-2.sql</file>
<file>schema/schema-3.sql</file>
<file>schema/schema-4.sql</file>
<file>schema/schema-5.sql</file>
<file>schema/schema-6.sql</file>
<file>schema/schema-7.sql</file>
<file>schema/schema-8.sql</file>
<file>schema/schema-9.sql</file>
<file>schema/schema-10.sql</file>
<file>schema/schema-11.sql</file>
<file>schema/schema-12.sql</file>
@@ -46,7 +37,6 @@
<file>pictures/rainbowdash.png</file>
<file>pictures/star-on.png</file>
<file>pictures/star-off.png</file>
<file>fonts/HumongousofEternitySt.ttf</file>
<file>mood/sample.mood</file>
<file>text/ghosts.txt</file>
</qresource>

Binary file not shown.

View File

@@ -24,6 +24,7 @@
<file>icons/128x128/document-open-folder.png</file>
<file>icons/128x128/document-open.png</file>
<file>icons/128x128/document-save.png</file>
<file>icons/128x128/document-save-all.png</file>
<file>icons/128x128/document-search.png</file>
<file>icons/128x128/download.png</file>
<file>icons/128x128/edit-clear-list.png</file>
@@ -120,6 +121,7 @@
<file>icons/64x64/document-open-folder.png</file>
<file>icons/64x64/document-open.png</file>
<file>icons/64x64/document-save.png</file>
<file>icons/64x64/document-save-all.png</file>
<file>icons/64x64/document-search.png</file>
<file>icons/64x64/download.png</file>
<file>icons/64x64/edit-clear-list.png</file>
@@ -218,6 +220,7 @@
<file>icons/48x48/document-open-remote.png</file>
<file>icons/48x48/document-open.png</file>
<file>icons/48x48/document-save.png</file>
<file>icons/48x48/document-save-all.png</file>
<file>icons/48x48/document-search.png</file>
<file>icons/48x48/download.png</file>
<file>icons/48x48/edit-clear-list.png</file>
@@ -319,6 +322,7 @@
<file>icons/32x32/document-open-remote.png</file>
<file>icons/32x32/document-open.png</file>
<file>icons/32x32/document-save.png</file>
<file>icons/32x32/document-save-all.png</file>
<file>icons/32x32/document-search.png</file>
<file>icons/32x32/download.png</file>
<file>icons/32x32/edit-clear-list.png</file>
@@ -420,6 +424,7 @@
<file>icons/22x22/document-open-remote.png</file>
<file>icons/22x22/document-open.png</file>
<file>icons/22x22/document-save.png</file>
<file>icons/22x22/document-save-all.png</file>
<file>icons/22x22/document-search.png</file>
<file>icons/22x22/download.png</file>
<file>icons/22x22/edit-clear-list.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

View File

@@ -1,35 +1,35 @@
CREATE TABLE device_%deviceid_directories (
path TEXT NOT NULL DEFAULT '',
path TEXT NOT NULL,
subdirs INTEGER NOT NULL
);
CREATE TABLE device_%deviceid_subdirectories (
directory_id INTEGER NOT NULL,
path TEXT NOT NULL DEFAULT '',
path TEXT NOT NULL,
mtime INTEGER NOT NULL
);
CREATE TABLE device_%deviceid_songs (
title TEXT DEFAULT '',
album TEXT DEFAULT '',
artist TEXT DEFAULT '',
albumartist TEXT DEFAULT '',
title TEXT,
album TEXT,
artist TEXT,
albumartist TEXT,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT DEFAULT '',
genre TEXT,
compilation INTEGER NOT NULL DEFAULT 0,
composer TEXT DEFAULT '',
performer TEXT DEFAULT '',
grouping TEXT DEFAULT '',
comment TEXT DEFAULT '',
lyrics TEXT DEFAULT '',
composer TEXT,
performer TEXT,
grouping TEXT,
comment TEXT,
lyrics TEXT,
artist_id TEXT DEFAULT '',
album_id TEXT DEFAULT '',
song_id TEXT DEFAULT '',
artist_id TEXT,
album_id TEXT,
song_id TEXT,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -40,14 +40,14 @@ CREATE TABLE device_%deviceid_songs (
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL DEFAULT '',
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT DEFAULT '',
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
@@ -59,13 +59,13 @@ CREATE TABLE device_%deviceid_songs (
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT DEFAULT '',
art_manual TEXT DEFAULT '',
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT DEFAULT '',
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT DEFAULT '',
cue_path TEXT,
rating INTEGER DEFAULT -1

View File

@@ -1,3 +0,0 @@
ALTER TABLE playlist_items ADD COLUMN internet_service TEXT;
UPDATE schema_version SET version=1;

View File

@@ -1,4 +1,4 @@
ALTER TABLE %allsongstables ADD COLUMN fingerprint TEXT DEFAULT '';
ALTER TABLE %allsongstables ADD COLUMN fingerprint TEXT;
ALTER TABLE %allsongstables ADD COLUMN lastseen INTEGER NOT NULL DEFAULT -1;

View File

@@ -1,8 +1,8 @@
CREATE TABLE IF NOT EXISTS radio_channels (
source INTEGER NOT NULL DEFAULT 0,
name TEXT DEFAULT '',
url TEXT DEFAULT '',
thumbnail_url TEXT DEFAULT ''
name TEXT NOT NULL,
url TEXT NOT NULL,
thumbnail_url TEXT
);
UPDATE schema_version SET version=15;

View File

@@ -1,5 +0,0 @@
ALTER TABLE songs ADD COLUMN lyrics TEXT;
ALTER TABLE playlist_items ADD COLUMN lyrics TEXT;
UPDATE schema_version SET version=2;

View File

@@ -1,65 +0,0 @@
ALTER TABLE songs ADD COLUMN source INTEGER NOT NULL DEFAULT 0;
UPDATE songs SET source = 2 WHERE source = 0;
DROP TABLE playlist_items;
CREATE TABLE IF NOT EXISTS playlist_items (
playlist INTEGER NOT NULL,
type INTEGER NOT NULL DEFAULT 0,
collection_id INTEGER,
url TEXT,
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT 0,
samplerate INTEGER NOT NULL DEFAULT 0,
bitdepth INTEGER NOT NULL DEFAULT 0,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER,
filename TEXT,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER,
mtime INTEGER,
ctime INTEGER,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT 0,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
UPDATE schema_version SET version=3;

View File

@@ -1,205 +0,0 @@
CREATE TABLE IF NOT EXISTS tidal_artists_songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT 0,
samplerate INTEGER NOT NULL DEFAULT 0,
bitdepth INTEGER NOT NULL DEFAULT 0,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL,
filename TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT 0,
mtime INTEGER NOT NULL DEFAULT 0,
ctime INTEGER NOT NULL DEFAULT 0,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT 0,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE TABLE IF NOT EXISTS tidal_albums_songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT 0,
samplerate INTEGER NOT NULL DEFAULT 0,
bitdepth INTEGER NOT NULL DEFAULT 0,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL,
filename TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT 0,
mtime INTEGER NOT NULL DEFAULT 0,
ctime INTEGER NOT NULL DEFAULT 0,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT 0,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE TABLE IF NOT EXISTS tidal_songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT 0,
samplerate INTEGER NOT NULL DEFAULT 0,
bitdepth INTEGER NOT NULL DEFAULT 0,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL,
filename TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT 0,
mtime INTEGER NOT NULL DEFAULT 0,
ctime INTEGER NOT NULL DEFAULT 0,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT 0,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE VIRTUAL TABLE IF NOT EXISTS tidal_artists_songs_fts USING fts3(
ftstitle,
ftsalbum,
ftsartist,
ftsalbumartist,
ftscomposer,
ftsperformer,
ftsgrouping,
ftsgenre,
ftscomment,
tokenize=unicode
);
CREATE VIRTUAL TABLE IF NOT EXISTS tidal_albums_songs_fts USING fts3(
ftstitle,
ftsalbum,
ftsartist,
ftsalbumartist,
ftscomposer,
ftsperformer,
ftsgrouping,
ftsgenre,
ftscomment,
tokenize=unicode
);
CREATE VIRTUAL TABLE IF NOT EXISTS tidal_songs_fts USING fts3(
ftstitle,
ftsalbum,
ftsartist,
ftsalbumartist,
ftscomposer,
ftsperformer,
ftsgrouping,
ftsgenre,
ftscomment,
tokenize=unicode
);
UPDATE schema_version SET version=4;

View File

@@ -1,31 +0,0 @@
ALTER TABLE songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
ALTER TABLE songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
ALTER TABLE songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
ALTER TABLE tidal_artists_songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
ALTER TABLE tidal_artists_songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
ALTER TABLE tidal_artists_songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
ALTER TABLE tidal_albums_songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
ALTER TABLE tidal_albums_songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
ALTER TABLE tidal_albums_songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
ALTER TABLE tidal_songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
ALTER TABLE tidal_songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
ALTER TABLE tidal_songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
ALTER TABLE playlist_items ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
ALTER TABLE playlist_items ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
ALTER TABLE playlist_items ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
UPDATE schema_version SET version=5;

View File

@@ -1,73 +0,0 @@
CREATE TABLE IF NOT EXISTS subsonic_songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
artist_id INTEGER NOT NULL DEFAULT -1,
album_id INTEGER NOT NULL DEFAULT -1,
song_id INTEGER NOT NULL DEFAULT -1,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT 0,
samplerate INTEGER NOT NULL DEFAULT 0,
bitdepth INTEGER NOT NULL DEFAULT 0,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL,
filename TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT 0,
mtime INTEGER NOT NULL DEFAULT 0,
ctime INTEGER NOT NULL DEFAULT 0,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT 0,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE VIRTUAL TABLE IF NOT EXISTS subsonic_songs_fts USING fts3(
ftstitle,
ftsalbum,
ftsartist,
ftsalbumartist,
ftscomposer,
ftsperformer,
ftsgrouping,
ftsgenre,
ftscomment,
tokenize=unicode
);
UPDATE schema_version SET version=6;

View File

@@ -1,217 +0,0 @@
CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
artist_id INTEGER NOT NULL DEFAULT -1,
album_id INTEGER NOT NULL DEFAULT -1,
song_id INTEGER NOT NULL DEFAULT -1,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT 0,
samplerate INTEGER NOT NULL DEFAULT 0,
bitdepth INTEGER NOT NULL DEFAULT 0,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL,
filename TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT 0,
mtime INTEGER NOT NULL DEFAULT 0,
ctime INTEGER NOT NULL DEFAULT 0,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT 0,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
artist_id INTEGER NOT NULL DEFAULT -1,
album_id INTEGER NOT NULL DEFAULT -1,
song_id INTEGER NOT NULL DEFAULT -1,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT 0,
samplerate INTEGER NOT NULL DEFAULT 0,
bitdepth INTEGER NOT NULL DEFAULT 0,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL,
filename TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT 0,
mtime INTEGER NOT NULL DEFAULT 0,
ctime INTEGER NOT NULL DEFAULT 0,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT 0,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE TABLE IF NOT EXISTS qobuz_songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
artist_id INTEGER NOT NULL DEFAULT -1,
album_id INTEGER NOT NULL DEFAULT -1,
song_id INTEGER NOT NULL DEFAULT -1,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT 0,
samplerate INTEGER NOT NULL DEFAULT 0,
bitdepth INTEGER NOT NULL DEFAULT 0,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL,
filename TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT 0,
mtime INTEGER NOT NULL DEFAULT 0,
ctime INTEGER NOT NULL DEFAULT 0,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT 0,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE VIRTUAL TABLE IF NOT EXISTS qobuz_artists_songs_fts USING fts3(
ftstitle,
ftsalbum,
ftsartist,
ftsalbumartist,
ftscomposer,
ftsperformer,
ftsgrouping,
ftsgenre,
ftscomment,
tokenize=unicode
);
CREATE VIRTUAL TABLE IF NOT EXISTS qobuz_albums_songs_fts USING fts3(
ftstitle,
ftsalbum,
ftsartist,
ftsalbumartist,
ftscomposer,
ftsperformer,
ftsgrouping,
ftsgenre,
ftscomment,
tokenize=unicode
);
CREATE VIRTUAL TABLE IF NOT EXISTS qobuz_songs_fts USING fts3(
ftstitle,
ftsalbum,
ftsartist,
ftsalbumartist,
ftscomposer,
ftsperformer,
ftsgrouping,
ftsgenre,
ftscomment,
tokenize=unicode
);
UPDATE schema_version SET version=7;

View File

@@ -1,595 +0,0 @@
ALTER TABLE songs RENAME TO songs_old;
ALTER TABLE playlist_items RENAME TO playlist_items_old;
ALTER TABLE tidal_artists_songs RENAME TO tidal_artists_songs_old;
ALTER TABLE tidal_albums_songs RENAME TO tidal_albums_songs_old;
ALTER TABLE tidal_songs RENAME TO tidal_songs_old;
ALTER TABLE qobuz_artists_songs RENAME TO qobuz_artists_songs_old;
ALTER TABLE qobuz_albums_songs RENAME TO qobuz_albums_songs_old;
ALTER TABLE qobuz_songs RENAME TO qobuz_songs_old;
ALTER TABLE subsonic_songs RENAME TO subsonic_songs_old;
DROP INDEX idx_filename;
CREATE TABLE songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
artist_id INTEGER NOT NULL DEFAULT -1,
album_id TEXT NOT NULL,
song_id INTEGER NOT NULL DEFAULT -1,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT -1,
samplerate INTEGER NOT NULL DEFAULT -1,
bitdepth INTEGER NOT NULL DEFAULT -1,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE TABLE tidal_artists_songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
artist_id INTEGER NOT NULL DEFAULT -1,
album_id TEXT NOT NULL,
song_id INTEGER NOT NULL DEFAULT -1,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT -1,
samplerate INTEGER NOT NULL DEFAULT -1,
bitdepth INTEGER NOT NULL DEFAULT -1,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE TABLE tidal_albums_songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
artist_id INTEGER NOT NULL DEFAULT -1,
album_id TEXT NOT NULL,
song_id INTEGER NOT NULL DEFAULT -1,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT -1,
samplerate INTEGER NOT NULL DEFAULT -1,
bitdepth INTEGER NOT NULL DEFAULT -1,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE TABLE tidal_songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
artist_id INTEGER NOT NULL DEFAULT -1,
album_id TEXT NOT NULL,
song_id INTEGER NOT NULL DEFAULT -1,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT -1,
samplerate INTEGER NOT NULL DEFAULT -1,
bitdepth INTEGER NOT NULL DEFAULT -1,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE TABLE subsonic_songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
artist_id INTEGER NOT NULL DEFAULT -1,
album_id TEXT NOT NULL,
song_id INTEGER NOT NULL DEFAULT -1,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT -1,
samplerate INTEGER NOT NULL DEFAULT -1,
bitdepth INTEGER NOT NULL DEFAULT -1,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE TABLE qobuz_artists_songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
artist_id INTEGER NOT NULL DEFAULT -1,
album_id TEXT NOT NULL,
song_id INTEGER NOT NULL DEFAULT -1,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT -1,
samplerate INTEGER NOT NULL DEFAULT -1,
bitdepth INTEGER NOT NULL DEFAULT -1,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE TABLE qobuz_albums_songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
artist_id INTEGER NOT NULL DEFAULT -1,
album_id TEXT NOT NULL,
song_id INTEGER NOT NULL DEFAULT -1,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT -1,
samplerate INTEGER NOT NULL DEFAULT -1,
bitdepth INTEGER NOT NULL DEFAULT -1,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE TABLE qobuz_songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
artist_id INTEGER NOT NULL DEFAULT -1,
album_id TEXT NOT NULL,
song_id INTEGER NOT NULL DEFAULT -1,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT -1,
samplerate INTEGER NOT NULL DEFAULT -1,
bitdepth INTEGER NOT NULL DEFAULT -1,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE TABLE playlist_items (
playlist INTEGER NOT NULL,
type INTEGER NOT NULL DEFAULT 0,
collection_id INTEGER,
playlist_url TEXT,
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
artist_id INTEGER NOT NULL DEFAULT -1,
album_id TEXT NOT NULL,
song_id INTEGER NOT NULL DEFAULT -1,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT -1,
samplerate INTEGER NOT NULL DEFAULT -1,
bitdepth INTEGER NOT NULL DEFAULT -1,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER,
url TEXT,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER,
mtime INTEGER,
ctime INTEGER,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
INSERT INTO songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
FROM songs_old;
DROP TABLE songs_old;
INSERT INTO tidal_artists_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
FROM tidal_artists_songs_old;
DROP TABLE tidal_artists_songs_old;
INSERT INTO tidal_albums_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
FROM tidal_albums_songs_old;
DROP TABLE tidal_albums_songs_old;
INSERT INTO tidal_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
FROM tidal_songs_old;
DROP TABLE tidal_songs_old;
INSERT INTO qobuz_artists_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
FROM qobuz_artists_songs_old;
DROP TABLE qobuz_artists_songs_old;
INSERT INTO qobuz_albums_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
FROM qobuz_albums_songs_old;
DROP TABLE qobuz_albums_songs_old;
INSERT INTO qobuz_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
FROM qobuz_songs_old;
DROP TABLE qobuz_songs_old;
INSERT INTO subsonic_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
FROM subsonic_songs_old;
DROP TABLE subsonic_songs_old;
INSERT INTO playlist_items (playlist, type, collection_id, playlist_url, title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
SELECT playlist, type, collection_id, url, title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
FROM playlist_items_old;
DROP TABLE playlist_items_old;
CREATE INDEX idx_url ON songs (url);
UPDATE schema_version SET version=8;

View File

@@ -1,41 +0,0 @@
DROP TABLE %allsongstables_fts;
DROP TABLE playlist_items_fts_;
CREATE VIRTUAL TABLE %allsongstables_fts USING fts5(
ftstitle,
ftsalbum,
ftsartist,
ftsalbumartist,
ftscomposer,
ftsperformer,
ftsgrouping,
ftsgenre,
ftscomment,
tokenize = "unicode61 remove_diacritics 1"
);
CREATE VIRTUAL TABLE playlist_items_fts_ USING fts5(
ftstitle,
ftsalbum,
ftsartist,
ftsalbumartist,
ftscomposer,
ftsperformer,
ftsgrouping,
ftsgenre,
ftscomment,
tokenize = "unicode61 remove_diacritics 1"
);
INSERT INTO %allsongstables_fts (ROWID, ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment)
SELECT ROWID, title, album, artist, albumartist, composer, performer, grouping, genre, comment FROM %allsongstables;
INSERT INTO playlist_items_fts_ (ROWID, ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment)
SELECT ROWID, title, album, artist, albumartist, composer, performer, grouping, genre, comment FROM playlist_items;
UPDATE schema_version SET version=9;

View File

@@ -7,37 +7,37 @@ DELETE FROM schema_version;
INSERT INTO schema_version (version) VALUES (15);
CREATE TABLE IF NOT EXISTS directories (
path TEXT NOT NULL DEFAULT '',
path TEXT NOT NULL,
subdirs INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS subdirectories (
directory_id INTEGER NOT NULL,
path TEXT NOT NULL DEFAULT '',
path TEXT NOT NULL,
mtime INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS songs (
title TEXT DEFAULT '',
album TEXT DEFAULT '',
artist TEXT DEFAULT '',
albumartist TEXT DEFAULT '',
title TEXT,
album TEXT,
artist TEXT,
albumartist TEXT,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT -1,
genre TEXT DEFAULT '',
genre TEXT,
compilation INTEGER NOT NULL DEFAULT 0,
composer TEXT DEFAULT '',
performer TEXT DEFAULT '',
grouping TEXT DEFAULT '',
comment TEXT DEFAULT '',
lyrics TEXT DEFAULT '',
composer TEXT,
performer TEXT,
grouping TEXT,
comment TEXT,
lyrics TEXT,
artist_id TEXT DEFAULT '',
album_id TEXT DEFAULT '',
song_id TEXT DEFAULT '',
artist_id TEXT,
album_id TEXT,
song_id TEXT,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -48,14 +48,14 @@ CREATE TABLE IF NOT EXISTS songs (
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL DEFAULT '',
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT DEFAULT '',
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
@@ -67,13 +67,13 @@ CREATE TABLE IF NOT EXISTS songs (
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT DEFAULT '',
art_manual TEXT DEFAULT '',
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT DEFAULT '',
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT DEFAULT '',
cue_path TEXT,
rating INTEGER DEFAULT -1
@@ -81,25 +81,25 @@ CREATE TABLE IF NOT EXISTS songs (
CREATE TABLE IF NOT EXISTS subsonic_songs (
title TEXT DEFAULT '',
album TEXT DEFAULT '',
artist TEXT DEFAULT '',
albumartist TEXT DEFAULT '',
title TEXT,
album TEXT,
artist TEXT,
albumartist TEXT,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT -1,
genre TEXT DEFAULT '',
genre TEXT,
compilation INTEGER NOT NULL DEFAULT 0,
composer TEXT DEFAULT '',
performer TEXT DEFAULT '',
grouping TEXT DEFAULT '',
comment TEXT DEFAULT '',
lyrics TEXT DEFAULT '',
composer TEXT,
performer TEXT,
grouping TEXT,
comment TEXT,
lyrics TEXT,
artist_id TEXT DEFAULT '',
album_id TEXT DEFAULT '',
song_id TEXT DEFAULT '',
artist_id TEXT,
album_id TEXT,
song_id TEXT,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -110,14 +110,14 @@ CREATE TABLE IF NOT EXISTS subsonic_songs (
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL DEFAULT '',
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT DEFAULT '',
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
@@ -129,13 +129,13 @@ CREATE TABLE IF NOT EXISTS subsonic_songs (
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT DEFAULT '',
art_manual TEXT DEFAULT '',
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT DEFAULT '',
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT DEFAULT '',
cue_path TEXT,
rating INTEGER DEFAULT -1
@@ -143,25 +143,25 @@ CREATE TABLE IF NOT EXISTS subsonic_songs (
CREATE TABLE IF NOT EXISTS tidal_artists_songs (
title TEXT DEFAULT '',
album TEXT DEFAULT '',
artist TEXT DEFAULT '',
albumartist TEXT DEFAULT '',
title TEXT,
album TEXT,
artist TEXT,
albumartist TEXT,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT -1,
genre TEXT DEFAULT '',
genre TEXT,
compilation INTEGER NOT NULL DEFAULT 0,
composer TEXT DEFAULT '',
performer TEXT DEFAULT '',
grouping TEXT DEFAULT '',
comment TEXT DEFAULT '',
lyrics TEXT DEFAULT '',
composer TEXT,
performer TEXT,
grouping TEXT,
comment TEXT,
lyrics TEXT,
artist_id TEXT DEFAULT '',
album_id TEXT DEFAULT '',
song_id TEXT DEFAULT '',
artist_id TEXT,
album_id TEXT,
song_id TEXT,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -172,14 +172,14 @@ CREATE TABLE IF NOT EXISTS tidal_artists_songs (
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL DEFAULT '',
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT DEFAULT '',
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
@@ -191,13 +191,13 @@ CREATE TABLE IF NOT EXISTS tidal_artists_songs (
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT DEFAULT '',
art_manual TEXT DEFAULT '',
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT DEFAULT '',
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT DEFAULT '',
cue_path TEXT,
rating INTEGER DEFAULT -1
@@ -205,25 +205,25 @@ CREATE TABLE IF NOT EXISTS tidal_artists_songs (
CREATE TABLE IF NOT EXISTS tidal_albums_songs (
title TEXT DEFAULT '',
album TEXT DEFAULT '',
artist TEXT DEFAULT '',
albumartist TEXT DEFAULT '',
title TEXT,
album TEXT,
artist TEXT,
albumartist TEXT,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT -1,
genre TEXT DEFAULT '',
genre TEXT,
compilation INTEGER NOT NULL DEFAULT 0,
composer TEXT DEFAULT '',
performer TEXT DEFAULT '',
grouping TEXT DEFAULT '',
comment TEXT DEFAULT '',
lyrics TEXT DEFAULT '',
composer TEXT,
performer TEXT,
grouping TEXT,
comment TEXT,
lyrics TEXT,
artist_id TEXT DEFAULT '',
album_id TEXT DEFAULT '',
song_id TEXT DEFAULT '',
artist_id TEXT,
album_id TEXT,
song_id TEXT,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -234,14 +234,14 @@ CREATE TABLE IF NOT EXISTS tidal_albums_songs (
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL DEFAULT '',
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT DEFAULT '',
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
@@ -253,13 +253,13 @@ CREATE TABLE IF NOT EXISTS tidal_albums_songs (
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT DEFAULT '',
art_manual TEXT DEFAULT '',
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT DEFAULT '',
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT DEFAULT '',
cue_path TEXT,
rating INTEGER DEFAULT -1
@@ -267,25 +267,25 @@ CREATE TABLE IF NOT EXISTS tidal_albums_songs (
CREATE TABLE IF NOT EXISTS tidal_songs (
title TEXT DEFAULT '',
album TEXT DEFAULT '',
artist TEXT DEFAULT '',
albumartist TEXT DEFAULT '',
title TEXT,
album TEXT,
artist TEXT,
albumartist TEXT,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT -1,
genre TEXT DEFAULT '',
genre TEXT,
compilation INTEGER NOT NULL DEFAULT 0,
composer TEXT DEFAULT '',
performer TEXT DEFAULT '',
grouping TEXT DEFAULT '',
comment TEXT DEFAULT '',
lyrics TEXT DEFAULT '',
composer TEXT,
performer TEXT,
grouping TEXT,
comment TEXT,
lyrics TEXT,
artist_id TEXT DEFAULT '',
album_id TEXT DEFAULT '',
song_id TEXT DEFAULT '',
artist_id TEXT,
album_id TEXT,
song_id TEXT,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -296,14 +296,14 @@ CREATE TABLE IF NOT EXISTS tidal_songs (
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL DEFAULT '',
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT DEFAULT '',
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
@@ -315,13 +315,13 @@ CREATE TABLE IF NOT EXISTS tidal_songs (
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT DEFAULT '',
art_manual TEXT DEFAULT '',
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT DEFAULT '',
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT DEFAULT '',
cue_path TEXT,
rating INTEGER DEFAULT -1
@@ -329,25 +329,25 @@ CREATE TABLE IF NOT EXISTS tidal_songs (
CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
title TEXT DEFAULT '',
album TEXT DEFAULT '',
artist TEXT DEFAULT '',
albumartist TEXT DEFAULT '',
title TEXT,
album TEXT,
artist TEXT,
albumartist TEXT,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT -1,
genre TEXT DEFAULT '',
genre TEXT,
compilation INTEGER NOT NULL DEFAULT 0,
composer TEXT DEFAULT '',
performer TEXT DEFAULT '',
grouping TEXT DEFAULT '',
comment TEXT DEFAULT '',
lyrics TEXT DEFAULT '',
composer TEXT,
performer TEXT,
grouping TEXT,
comment TEXT,
lyrics TEXT,
artist_id TEXT DEFAULT '',
album_id TEXT DEFAULT '',
song_id TEXT DEFAULT '',
artist_id TEXT,
album_id TEXT,
song_id TEXT,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -358,14 +358,14 @@ CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL DEFAULT '',
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT DEFAULT '',
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
@@ -377,13 +377,13 @@ CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT DEFAULT '',
art_manual TEXT DEFAULT '',
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT DEFAULT '',
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT DEFAULT '',
cue_path TEXT,
rating INTEGER DEFAULT -1
@@ -391,25 +391,25 @@ CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
title TEXT DEFAULT '',
album TEXT DEFAULT '',
artist TEXT DEFAULT '',
albumartist TEXT DEFAULT '',
title TEXT,
album TEXT,
artist TEXT,
albumartist TEXT,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT -1,
genre TEXT DEFAULT '',
genre TEXT,
compilation INTEGER NOT NULL DEFAULT 0,
composer TEXT DEFAULT '',
performer TEXT DEFAULT '',
grouping TEXT DEFAULT '',
comment TEXT DEFAULT '',
lyrics TEXT DEFAULT '',
composer TEXT,
performer TEXT,
grouping TEXT,
comment TEXT,
lyrics TEXT,
artist_id TEXT DEFAULT '',
album_id TEXT DEFAULT '',
song_id TEXT DEFAULT '',
artist_id TEXT,
album_id TEXT,
song_id TEXT,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -420,14 +420,14 @@ CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL DEFAULT '',
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT DEFAULT '',
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
@@ -439,13 +439,13 @@ CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT DEFAULT '',
art_manual TEXT DEFAULT '',
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT DEFAULT '',
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT DEFAULT '',
cue_path TEXT,
rating INTEGER DEFAULT -1
@@ -453,25 +453,25 @@ CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
CREATE TABLE IF NOT EXISTS qobuz_songs (
title TEXT DEFAULT '',
album TEXT DEFAULT '',
artist TEXT DEFAULT '',
albumartist TEXT DEFAULT '',
title TEXT,
album TEXT,
artist TEXT,
albumartist TEXT,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT -1,
genre TEXT DEFAULT '',
genre TEXT,
compilation INTEGER NOT NULL DEFAULT 0,
composer TEXT DEFAULT '',
performer TEXT DEFAULT '',
grouping TEXT DEFAULT '',
comment TEXT DEFAULT '',
lyrics TEXT DEFAULT '',
composer TEXT,
performer TEXT,
grouping TEXT,
comment TEXT,
lyrics TEXT,
artist_id TEXT DEFAULT '',
album_id TEXT DEFAULT '',
song_id TEXT DEFAULT '',
artist_id TEXT,
album_id TEXT,
song_id TEXT,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -482,14 +482,14 @@ CREATE TABLE IF NOT EXISTS qobuz_songs (
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL DEFAULT -1,
url TEXT NOT NULL DEFAULT '',
url TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER NOT NULL DEFAULT -1,
mtime INTEGER NOT NULL DEFAULT -1,
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT DEFAULT '',
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
@@ -501,13 +501,13 @@ CREATE TABLE IF NOT EXISTS qobuz_songs (
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT DEFAULT '',
art_manual TEXT DEFAULT '',
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT DEFAULT '',
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT DEFAULT '',
cue_path TEXT,
rating INTEGER DEFAULT -1
@@ -515,15 +515,15 @@ CREATE TABLE IF NOT EXISTS qobuz_songs (
CREATE TABLE IF NOT EXISTS playlists (
name TEXT NOT NULL DEFAULT '',
name TEXT NOT NULL,
last_played INTEGER NOT NULL DEFAULT -1,
ui_order INTEGER NOT NULL DEFAULT 0,
special_type TEXT DEFAULT '',
ui_path TEXT DEFAULT '',
special_type TEXT,
ui_path TEXT,
is_favorite INTEGER NOT NULL DEFAULT 0,
dynamic_playlist_type INTEGER,
dynamic_playlist_backend TEXT DEFAULT '',
dynamic_playlist_backend TEXT,
dynamic_playlist_data BLOB
);
@@ -533,27 +533,27 @@ CREATE TABLE IF NOT EXISTS playlist_items (
playlist INTEGER NOT NULL,
type INTEGER NOT NULL DEFAULT 0,
collection_id INTEGER,
playlist_url TEXT DEFAULT '',
playlist_url TEXT,
title TEXT DEFAULT '',
album TEXT DEFAULT '',
artist TEXT DEFAULT '',
albumartist TEXT DEFAULT '',
title TEXT,
album TEXT,
artist TEXT,
albumartist TEXT,
track INTEGER,
disc INTEGER,
year INTEGER,
originalyear INTEGER,
genre TEXT DEFAULT '',
genre TEXT,
compilation INTEGER DEFAULT 0,
composer TEXT DEFAULT '',
performer TEXT DEFAULT '',
grouping TEXT DEFAULT '',
comment TEXT DEFAULT '',
lyrics TEXT DEFAULT '',
composer TEXT,
performer TEXT,
grouping TEXT,
comment TEXT,
lyrics TEXT,
artist_id TEXT DEFAULT '',
album_id TEXT DEFAULT '',
song_id TEXT DEFAULT '',
artist_id TEXT,
album_id TEXT,
song_id TEXT,
beginning INTEGER,
length INTEGER,
@@ -564,14 +564,14 @@ CREATE TABLE IF NOT EXISTS playlist_items (
source INTEGER,
directory_id INTEGER,
url TEXT DEFAULT '',
url TEXT NOT NULL,
filetype INTEGER,
filesize INTEGER,
mtime INTEGER,
ctime INTEGER,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT DEFAULT '',
fingerprint TEXT,
playcount INTEGER DEFAULT 0,
skipcount INTEGER DEFAULT 0,
@@ -583,23 +583,23 @@ CREATE TABLE IF NOT EXISTS playlist_items (
compilation_off INTEGER DEFAULT 0,
compilation_effective INTEGER DEFAULT 0,
art_automatic TEXT DEFAULT '',
art_manual TEXT DEFAULT '',
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT DEFAULT '',
effective_albumartist TEXT,
effective_originalyear INTEGER,
cue_path TEXT DEFAULT '',
cue_path TEXT,
rating INTEGER DEFAULT -1
);
CREATE TABLE IF NOT EXISTS devices (
unique_id TEXT NOT NULL DEFAULT '',
friendly_name TEXT DEFAULT '',
unique_id TEXT NOT NULL,
friendly_name TEXT,
size INTEGER,
icon TEXT DEFAULT '',
icon TEXT,
schema_version INTEGER NOT NULL DEFAULT 0,
transcode_mode NOT NULL DEFAULT 3,
transcode_format NOT NULL DEFAULT 5
@@ -607,9 +607,9 @@ CREATE TABLE IF NOT EXISTS devices (
CREATE TABLE IF NOT EXISTS radio_channels (
source INTEGER NOT NULL DEFAULT 0,
name TEXT DEFAULT '',
url TEXT DEFAULT '',
thumbnail_url TEXT DEFAULT ''
name TEXT,
url TEXT NOT NULL,
thumbnail_url TEXT
);
CREATE INDEX IF NOT EXISTS idx_url ON songs (url);

View File

@@ -31,6 +31,10 @@
background-color: %palette-base;
}
#context-scrollarea {
background-color: %palette-base;
}
QToolButton {
border: 2px solid transparent;
border-radius: 3px;

22
debian/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,22 @@
if(LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
execute_process(COMMAND env LC_ALL=C date "+%a, %-d %b %Y %H:%M:%S %z" OUTPUT_VARIABLE DEB_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -cs" OUTPUT_VARIABLE DEB_CODENAME OUTPUT_STRIP_TRAILING_WHITESPACE)
if(DEB_CODENAME AND DEB_DATE)
if(BUILD_WITH_QT5)
set(DEBIAN_BUILD_DEPENDS_QT_PACKAGES qtbase5-dev,qtbase5-dev-tools,qttools5-dev,qttools5-dev-tools,libqt5x11extras5-dev)
set(DEBIAN_DEPENDS_QT_PACKAGES libqt5sql5-sqlite)
endif()
if(BUILD_WITH_QT6)
set(DEBIAN_BUILD_DEPENDS_QT_PACKAGES qt6-base-dev,qt6-base-dev-tools,qt6-tools-dev,qt6-tools-dev-tools,qt6-l10n-tools)
set(DEBIAN_DEPENDS_QT_PACKAGES libqt6sql6-sqlite,qt6-qpa-plugins)
endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/control.in ${CMAKE_CURRENT_SOURCE_DIR}/control @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/changelog.in ${CMAKE_CURRENT_SOURCE_DIR}/changelog)
endif()
endif()

View File

@@ -6,6 +6,7 @@ Build-Depends: debhelper (>= 11),
make,
cmake,
gcc,
g++,
protobuf-compiler,
libglib2.0-dev,
libdbus-1-dev,
@@ -16,11 +17,8 @@ Build-Depends: debhelper (>= 11),
libasound2-dev,
libpulse-dev,
libtag1-dev,
qtbase5-dev,
qtbase5-private-dev,
qtbase5-dev-tools,
qttools5-dev,
libqt5x11extras5-dev,
libicu-dev,
@DEBIAN_BUILD_DEPENDS_QT_PACKAGES@,
libgstreamer1.0-dev,
libgstreamer-plugins-base1.0-dev,
libcdio-dev,
@@ -28,20 +26,19 @@ Build-Depends: debhelper (>= 11),
libmtp-dev,
libchromaprint-dev,
libfftw3-dev
Standards-Version: 4.2.1
Standards-Version: 4.6.1
Package: strawberry
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
libsqlite3-0,
libqt5sql5-sqlite,
@DEBIAN_DEPENDS_QT_PACKAGES@,
gstreamer1.0-plugins-base,
gstreamer1.0-plugins-good,
gstreamer1.0-alsa,
gstreamer1.0-pulseaudio
Homepage: http://www.strawberrymusicplayer.org/
Description: Audio player and music collection organizer
Description: music player and music collection organizer
Strawberry is a music player aimed at music collectors and audiophiles.
.
Features:
@@ -49,14 +46,13 @@ Description: Audio player and music collection organizer
- Supports WAV, FLAC, WavPack, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF
- Audio CD playback
- Native desktop notifications
- Playlist management
- Playlists in multiple formats
- Playlist management and playlists in multiple formats
- Smart and dynamic playlists
- Advanced audio output and device configuration for bit-perfect playback on Linux
- Edit tags on audio files
- Automatically retrieve tags from MusicBrainz
- Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
- Song lyrics from AudD, Genius, Musixmatch, ChartLyrics, lyrics.ovh and lololyrics.com
- Support for multiple backends
- Audio analyzer
- Audio equalizer
- Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic

197
debian/copyright vendored
View File

@@ -1,26 +1,26 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: strawberry
Upstream-Contact: Jonas Kvinge <jonas@jkvinge.net>
Source: https://www.strawberrymusicplayer.org/
Source: https://github.com/strawberrymusicplayer/strawberry
Files: *
Copyright: 2010-2015, David Sansome <me@davidsansome.com>
2012-2014, 2017-2023 Jonas Kvinge <jonas@jkvinge.net>
License: GPL-3+
Files: src/core/timeconstants.h
Files: src/utilities/timeconstants.h
ext/libstrawberry-common/core/logging.cpp
ext/libstrawberry-common/core/logging.h
ext/libstrawberry-common/core/messagehandler.cpp
ext/libstrawberry-common/core/messagehandler.h
Copyright: 2011, 2012, David Sansome <me@davidsansome.com>
2018-2022, Jonas Kvinge <jonas@jkvinge.net>
License: Apache-2.0
Files: src/core/main.h
src/core/iconloader.cpp
src/core/iconloader.h
src/core/iconmapper.h
src/config.h.in
src/version.h.in
src/context/contextview.cpp
src/context/contextview.h
src/context/contextalbum.cpp
@@ -29,6 +29,8 @@ Files: src/core/main.h
src/engine/enginetype.h
src/engine/alsadevicefinder.cpp
src/engine/alsadevicefinder.h
src/engine/alsapcmdevicefinder.cpp
src/engine/alsapcmdevicefinder.h
src/engine/mmdevicefinder.cpp
src/engine/mmdevicefinder.h
src/engine/devicefinder.cpp
@@ -69,11 +71,17 @@ Files: src/core/main.h
src/covermanager/spotifycoverprovider.h
src/covermanager/musixmatchcoverprovider.cpp
src/covermanager/musixmatchcoverprovider.h
src/globalshortcuts/globalshortcutsbackend-system.cpp
src/globalshortcuts/globalshortcutsbackend-system.h
src/globalshortcuts/globalshortcutsbackend-kde.cpp
src/globalshortcuts/globalshortcutsbackend-kde.h
src/globalshortcuts/globalshortcutsbackend-mate.cpp
src/globalshortcuts/globalshortcutsbackend-mate.h
src/globalshortcuts/globalshortcutsbackend-x11.cpp
src/globalshortcuts/globalshortcutsbackend-x11.h
src/globalshortcuts/globalshortcutsbackend-win.cpp
src/globalshortcuts/globalshortcutsbackend-win.h
src/globalshortcuts/globalshortcut.cpp
src/globalshortcuts/globalshortcut.h
src/globalshortcuts/globalshortcut-X11.cpp
src/globalshortcuts/globalshortcut-x11.cpp
src/globalshortcuts/globalshortcut-win.cpp
src/globalshortcuts/keymapper_x11.h
src/globalshortcuts/keymapper_win.h
@@ -81,132 +89,21 @@ Files: src/core/main.h
src/scrobbler/*
src/subsonic/*
src/tidal/*
src/qobuz/*
src/radios/*
src/transcoder/transcoderoptionswavpack.cpp
src/transcoder/transcoderoptionswavpack.h
Copyright: 2012-2014, 2017-2020, Jonas Kvinge <jonas@jkvinge.net>
License: GPL-3+
Files: src/core/main.cpp
src/core/mainwindow.cpp
src/core/mainwindow.h
src/core/player.cpp
src/core/player.h
src/core/song.cpp
src/core/song.h
src/core/songloader.cpp
src/core/songloader.h
src/core/urlhandler.cpp
src/core/urlhandler.h
src/core/utilities.cpp
src/core/utilities.h
src/core/networkaccessmanager.cpp
src/core/networkaccessmanager.h
src/core/threadsafenetworkdiskcache.cpp
src/core/threadsafenetworkdiskcache.h
src/core/filesystemmusicstorage.cpp
src/core/filesystemmusicstorage.h
src/core/stylesheetloader.cpp
src/core/stylesheetloader.h
src/engine/gstenginepipeline.cpp
src/engine/gstenginepipeline.h
src/engine/vlcengine.cpp
src/engine/vlcengine.h
src/collection/collectionwatcher.cpp
src/collection/collectionwatcher.h
src/collection/collectionbackend.cpp
src/collection/collectionbackend.h
src/collection/collectionmodel.cpp
src/collection/collectionmodel.h
src/context/contextalbumsmodel.cpp
src/context/contextalbumsview.cpp
src/context/contextalbumsmodel.h
src/context/contextalbumsview.h
src/widgets/playingwidget.cpp
src/widgets/playingwidget.h
src/osd/osdbase.cpp
src/osd/osdbase.h
src/osd/osdpretty.cpp
src/osd/osdpretty.h
src/osd/osddbus.cpp
src/osd/osddbus.h
src/osd/osdmac.cpp
src/osd/osdmac.h
src/dialogs/about.cpp
src/dialogs/about.h
src/playlist/playlist.cpp
src/playlist/playlist.h
src/playlist/playlistitem.cpp
src/playlist/playlistitem.h
src/playlist/playlistdelegates.cpp
src/playlist/playlistdelegates.h
src/playlist/playlistbackend.cpp
src/playlist/playlistbackend.h
src/playlist/playlistview.cpp
src/playlist/playlistview.h
src/playlist/songplaylistitem.cpp
src/playlist/songplaylistitem.h
src/internet/internetplaylistitem.cpp
src/internet/internetsearch.cpp
src/internet/internetsearch.h
src/internet/internetsearchview.cpp
src/internet/internetsearchview.h
src/internet/internetservices.cpp
src/internet/internetservices.h
src/internet/internetsongsview.cpp
src/internet/internetsongsview.h
src/internet/internetcollectionview.cpp
src/internet/internetcollectionview.h
ext/libstrawberry-tagreader/tagreader.cpp
ext/libstrawberry-tagreader/tagreader.h
src/device/devicemanager.cpp
src/device/devicemanager.h
src/device/deviceinfo.cpp
src/device/deviceinfo.h
src/device/deviceproperties.cpp
src/device/deviceproperties.h
src/device/deviceview.cpp
src/device/deviceview.h
src/device/connecteddevice.cpp
src/device/connecteddevice.h
src/device/mtpconnection.cpp
src/device/mtpconnection.h
src/device/mtpdevice.cpp
src/device/mtpdevice.h
src/globalshortcuts/globalshortcutsmanager.cpp
src/globalshortcuts/globalshortcutsmanager.h
src/settings/shortcutssettingspage.cpp
src/settings/shortcutssettingspage.h
src/settings/appearancesettingspage.cpp
src/settings/appearancesettingspage.h
src/organize/organize.cpp
src/organize/organize.h
src/organize/organizedialog.cpp
src/organize/organizedialog.h
src/organize/organizeerrordialog.cpp
src/organize/organizeerrordialog.h
src/transcoder/transcoder.cpp
src/transcoder/transcoder.h
src/musicbrainz/musicbrainzclient.cpp
src/musicbrainz/musicbrainzclient.h
src/covermanager/albumcoverloader.cpp
src/covermanager/albumcoverloader.h
src/covermanager/currentalbumcoverloader.cpp
src/covermanager/currentalbumcoverloader.h
src/covermanager/albumcoverchoicecontroller.cpp
src/covermanager/albumcoverchoicecontroller.h
src/covermanager/albumcoverfetchersearch.cpp
src/covermanager/albumcoverfetchersearch.h
src/covermanager/coverproviders.cpp
src/covermanager/coverproviders.h
src/covermanager/coverprovider.cpp
src/covermanager/coverprovider.h
Copyright: 2010, 2012-2014 David Sansome <me@davidsansome.com>
2012-2014, 2017-2020 Jonas Kvinge <jonas@jkvinge.net>
ext/libstrawberry-tagreader/tagreadertagparser.cpp
ext/libstrawberry-tagreader/tagreadertagparser.h
ext/macdeploycheck/*
src/widgets/resizabletextedit.cpp
src/widgets/resizabletextedit.h
Copyright: 2012-2014, 2017-2023, Jonas Kvinge <jonas@jkvinge.net>
License: GPL-3+
Files: src/engine/enginebase.cpp
src/engine/enginebase.h
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
Copyright: 2017-2021, Jonas Kvinge <jonas@jkvinge.net>
2010, David Sansome <me@davidsansome.com>
2004, 2005, Max Howell, <max.howell@methylblue.com>
2003, Mark Kretschmann <markey@web.de>
@@ -214,7 +111,7 @@ License: GPL-3+
Files: src/engine/gstengine.cpp
src/engine/gstengine.h
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
Copyright: 2017-2021, Jonas Kvinge <jonas@jkvinge.net>
2006, Paul Cifarelli <paul@cifarelli.net>
2005, Jakub Stachowski <qbast@go2.pl>
2003-2005, Mark Kretschmann <markey@web.de>
@@ -230,12 +127,7 @@ Files: src/core/application.cpp
src/core/application.h
Copyright: 2012, David Sansome <me@davidsansome.com>
2012, 2014, John Maguire <john.maguire@gmail.com>
2018, Jonas Kvinge <jonas@jkvinge.net>
License: GPL-3+
Files: src/core/appearance.cpp
src/core/appearance.h
Copyright: 2012, Arnaud Bienner <arnaud.bienner@gmail.com>
2018-2021, Jonas Kvinge <jonas@jkvinge.net>
License: GPL-3+
Files: src/covermanager/discogscoverprovider.cpp
@@ -244,13 +136,7 @@ Copyright: 2012, Martin Björklund <mbj4668@gmail.com>
2016, Jonas Kvinge <jonas@jkvinge.net>
License: GPL-3+
Files: ext/libstrawberry-common/core/arraysize.h
ext/libstrawberry-common/core/scoped_nsautorelease_pool.h
ext/libstrawberry-common/core/scoped_nsautorelease_pool.mm
Copyright: 2010, 2011, 2014, The Chromium Authors.
License: BSD-style
Files: ext/libstrawberry-common/core/lazy.h
Files: src/core/lazy.h
Copyright: 2016, John Maguire <john.maguire@gmail.com>
License: GPL-3+
@@ -298,12 +184,16 @@ Copyright: 2011, Tyler Rhodes <tyler.s.rhodes@gmail.com>
2015, Arun Narayanankutty <n.arun.lifescience@gmail.com>
License: GPL-2+
Files: src/collection/savedgroupingmanager.h
Files: src/collection/savedgroupingmanager.*
Copyright: 2015, Nick Lanham <nick@afternight.org>
2019-2021 Jonas Kvinge <jonas@jkvinge.net>
License: GPL-3+
Files: src/core/scoped_cftyperef.h
Files: src/core/arraysize.h
src/core/scoped_cftyperef.h
src/core/scoped_nsobject.h
src/core/scoped_nsautorelease_pool.h
src/core/scoped_nsautorelease_pool.mm
Copyright: 2010, 2011, 2014, The Chromium Authors.
License: BSD-style
@@ -322,7 +212,7 @@ Files: src/internet/localredirectserver.cpp
src/internet/localredirectserver.h
Copyright: 2012, 2014, John Maguire <john.maguire@gmail.com>
2014, Krzysztof Sobiecki <sobkas@gmail.com>
2018-2019, Jonas Kvinge <jonas@jkvinge.net>
2018-2021, Jonas Kvinge <jonas@jkvinge.net>
License: GPL-3+
Files: src/transcoder/transcoderoptionsopus.cpp
@@ -337,12 +227,22 @@ Files: src/widgets/clickablelabel.cpp
Copyright: 2010, 2011, Andrea Decorte <adecorte@gmail.com>
License: GPL-3+
Files: src/widgets/sliderwidget.cpp
src/widgets/sliderwidget.h
Copyright: 2005, Gábor Lehel
Files: src/widgets/sliderslider.cpp
src/widgets/sliderslider.h
src/widgets/prettyslider.cpp
src/widgets/prettyslider.h
src/widgets/volumeslider.cpp
src/widgets/volumeslider.h
Copyright: 2018-2023, Jonas Kvinge <jonas@jkvinge.net>
2005, Gábor Lehel
2003, Mark Kretschmann <markey@web.de>
License: GPL-2+
Files: src/scrobbler/subsonicscrobbler.*
Copyright: 2018-2021 Jonas Kvinge <jonas@jkvinge.net>
2020 Pascal Below <spezifisch@below.fr>
License: GPL-3+
Files: src/core/stylehelper.cpp
src/core/stylehelper.h
Copyright: 2016 The Qt Company Ltd.
@@ -358,6 +258,7 @@ License: GPL-2+
Files: src/widgets/qsearchfield_nonmac.cpp
src/widgets/qsearchfield_mac.mm
src/widgets/qsearchfield.h
src/widgets/qocoa_mac.h
Copyright: 2011, Mike McQuaid <mike@mikemcquaid.com>
License: Expat
@@ -367,7 +268,7 @@ Copyright: 2010, Spotify AB
License: BSD-3-clause
Files: 3rdparty/singleapplication/*
Copyright: 2015-2018, Itay Grudev
Copyright: 2015-2022, Itay Grudev
License: MIT

View File

@@ -4,14 +4,14 @@ ignore:
- Changelog
- COPYING
- CMakeLists.txt
- Dockerfile
- cmake_uninstall.cmake.in
- .clang-format
- .gitignore
- .travis.yml
- .github
- /debian/
- /cmake/
- /data/
- /dist/
- /snap/
suffixes:
- jpg

1
debian/rules vendored
View File

@@ -5,7 +5,6 @@
override_dh_auto_clean:
rm -f dist/macos/Info.plist
rm -f dist/unix/PKGBUILD
rm -f dist/unix/strawberry.spec
rm -f dist/scripts/maketarball.sh
rm -f dist/windows/strawberry.nsi

4
dist/CMakeLists.txt vendored
View File

@@ -2,10 +2,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/maketarball.sh.in ${CMAKE_CUR
if(RPM_DISTRO AND RPM_DATE)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec @ONLY)
endif(RPM_DISTRO AND RPM_DATE)
if(DEB_CODENAME AND DEB_DATE)
configure_file(${CMAKE_SOURCE_DIR}/debian/changelog.in ${CMAKE_SOURCE_DIR}/debian/changelog)
endif(DEB_CODENAME AND DEB_DATE)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unix/PKGBUILD.in ${CMAKE_CURRENT_SOURCE_DIR}/unix/PKGBUILD @ONLY)
if(APPLE)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist.in ${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist)

View File

@@ -39,8 +39,12 @@ fi
cp -v -f "${GST_PLUGIN_SCANNER}" "${bundledir}/Contents/PlugIns/" || exit 1
gst_plugins="
libgstaes.dylib
libgstaiff.dylib
libgstapetag.dylib
libgstapp.dylib
libgstasf.dylib
libgstasfmux.dylib
libgstaudioconvert.dylib
libgstaudiofx.dylib
libgstaudiomixer.dylib
@@ -48,46 +52,46 @@ libgstaudioparsers.dylib
libgstaudiorate.dylib
libgstaudioresample.dylib
libgstaudiotestsrc.dylib
libgstaudiovisualizers.dylib
libgstauparse.dylib
libgstautoconvert.dylib
libgstautodetect.dylib
libgstbs2b.dylib
libgstcdio.dylib
libgstcoreelements.dylib
libgstdash.dylib
libgstequalizer.dylib
libgstflac.dylib
libgstfaac.dylib
libgstfaad.dylib
libgstfdkaac.dylib
libgstgio.dylib
libgsticydemux.dylib
libgstid3demux.dylib
libgstlevel.dylib
libgstisomp4.dylib
libgstlame.dylib
libgstlibav.dylib
libgstmpg123.dylib
libgstmusepack.dylib
libgstogg.dylib
libgstopenmpt.dylib
libgstopus.dylib
libgstopusparse.dylib
libgstosxaudio.dylib
libgstplayback.dylib
libgstrawparse.dylib
libgstreplaygain.dylib
libgstsoup.dylib
libgstspectrum.dylib
libgsttypefindfunctions.dylib
libgstvolume.dylib
libgstxingmux.dylib
libgsttcp.dylib
libgstudp.dylib
libgstpbtypes.dylib
libgstplayback.dylib
libgstreplaygain.dylib
libgstrtp.dylib
libgstrtsp.dylib
libgstflac.dylib
libgstwavparse.dylib
libgstfaad.dylib
libgstogg.dylib
libgstopus.dylib
libgstasf.dylib
libgstsoup.dylib
libgstspectrum.dylib
libgstspeex.dylib
libgsttaglib.dylib
libgsttcp.dylib
libgsttypefindfunctions.dylib
libgstudp.dylib
libgstvolume.dylib
libgstvorbis.dylib
libgstisomp4.dylib
libgstlibav.dylib
libgstaiff.dylib
libgstlame.dylib
libgstopusparse.dylib
libgstfaac.dylib
libgstmusepack.dylib
libgstwavpack.dylib
libgstwavparse.dylib
libgstxingmux.dylib;
"
gst_plugins=$(echo "$gst_plugins" | tr '\n' ' ' | sed -e 's/^ //g' | sed -e 's/ / /g')

View File

@@ -49,6 +49,7 @@ ${TAR} -cJf $name-$version.tar.xz \
--exclude="*.nsi" \
--exclude="*.kdev4" \
--exclude=".vscode" \
--exclude=".idea" \
--exclude="$root/.github" \
--exclude="$root/.travis.yml" \
--exclude="$root/.circleci" \
@@ -56,11 +57,11 @@ ${TAR} -cJf $name-$version.tar.xz \
--exclude="$root/CMakeLists.txt.user" \
--exclude="$root/.clang-format" \
--exclude="$root/build" \
--exclude="$root/cmake-build-debug" \
--exclude="$root/zanata.xml" \
--exclude="$root/.zanata-cache" \
--exclude="$root/debian/changelog" \
--exclude="$root/dist/scripts/maketarball.sh" \
--exclude="$root/dist/unix/PKGBUILD" \
--exclude="$root/dist/macos/Info.plist" \
--exclude="$root/dist/windows/windres.rc" \
--exclude="$root/src/translations/translations.pot" \

56
dist/unix/PKGBUILD.in vendored
View File

@@ -1,56 +0,0 @@
# Maintainer: Jonas Kvinge <jonas@jkvinge.net>
pkgname=strawberry
pkgver=@STRAWBERRY_VERSION_PAC_V@
pkgrel=@STRAWBERRY_VERSION_PAC_R@
pkgdesc="A music player aimed at audio enthusiasts and music collectors"
arch=(x86_64)
url="https://www.strawberrymusicplayer.org/"
license=(GPL3)
makedepends=(git cmake make gcc boost gettext qt5-tools)
depends=(
desktop-file-utils
hicolor-icon-theme
gnutls
udisks2
protobuf
qt5-base
qt5-x11extras
sqlite3
alsa-lib
libpulse
dbus
taglib
gstreamer
gst-plugins-base
gst-plugins-good
vlc
chromaprint
libgpod
libcdio
libmtp
fftw
)
optdepends=(
gst-plugins-bad
gst-plugins-ugly
gst-libav
)
provides=(strawberry)
conflicts=(strawberry)
source=("strawberry-@STRAWBERRY_VERSION_PACKAGE@.tar.xz")
sha256sums=('SKIP')
prepare() {
mkdir -p build
}
build() {
cd build
cmake ../${pkgname}-@STRAWBERRY_VERSION_PACKAGE@ -DCMAKE_INSTALL_PREFIX=/usr
make -j$(nproc)
}
package() {
cd build
make DESTDIR="${pkgdir}" install
}

View File

@@ -9,18 +9,15 @@ TryExec=strawberry
Icon=strawberry
Terminal=false
Categories=AudioVideo;Player;Qt;Audio;
Keywords=Audio;Player;
StartupNotify=false
MimeType=x-content/audio-player;application/ogg;application/x-ogg;application/x-ogm-audio;audio/flac;audio/ogg;audio/vorbis;audio/aac;audio/mp4;audio/mpeg;audio/mpegurl;audio/vnd.rn-realaudio;audio/x-flac;audio/x-oggflac;audio/x-vorbis;audio/x-vorbis+ogg;audio/x-speex;audio/x-wav;audio/x-wavpack;audio/x-ape;audio/x-mp3;audio/x-mpeg;audio/x-mpegurl;audio/x-ms-wma;audio/x-musepack;audio/x-pn-realaudio;audio/x-scpls;video/x-ms-asf;x-scheme-handler/tidal;
StartupWMClass=strawberry
Actions=Play;Pause;Stop;StopAfterCurrent;Previous;Next;
Actions=Play-Pause;Stop;StopAfterCurrent;Previous;Next;
[Desktop Action Play]
Name=Play
Exec=strawberry --play
[Desktop Action Pause]
Name=Pause
Exec=strawberry --pause
[Desktop Action Play-Pause]
Name=Play/Pause
Exec=strawberry --play-pause
[Desktop Action Stop]
Name=Stop

View File

@@ -1,6 +1,6 @@
Name: strawberry
Version: @STRAWBERRY_VERSION_RPM_V@
%if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos}
%if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos} || "%{?_vendor}" == "openmandriva"
Release: @STRAWBERRY_VERSION_RPM_R@%{?dist}
%else
Release: @STRAWBERRY_VERSION_RPM_R@.@RPM_DISTRO@
@@ -49,6 +49,8 @@ BuildRequires: pkgconfig(sqlite3) >= 3.9
BuildRequires: pkgconfig(taglib)
%endif
BuildRequires: pkgconfig(fftw3)
BuildRequires: pkgconfig(icu-uc)
BuildRequires: pkgconfig(icu-i18n)
%if "@QT_VERSION_MAJOR@" == "5" && ( 0%{?fedora} || 0%{?rhel_version} || 0%{?centos} )
BuildRequires: pkgconfig(Qt@QT_VERSION_MAJOR@Core)
BuildRequires: pkgconfig(Qt@QT_VERSION_MAJOR@Gui)

186
dist/windows/Registry.nsh vendored Normal file
View File

@@ -0,0 +1,186 @@
!define registry::Open `!insertmacro registry::Open`
!macro registry::Open _PATH _OPTIONS _HANDLE
registry::_Open /NOUNLOAD `${_PATH}` `${_OPTIONS}`
Pop ${_HANDLE}
!macroend
!define registry::Find `!insertmacro registry::Find`
!macro registry::Find _HANDLE _PATH _VALUEORKEY _STRING _TYPE
registry::_Find /NOUNLOAD `${_HANDLE}`
Pop ${_PATH}
Pop ${_VALUEORKEY}
Pop ${_STRING}
Pop ${_TYPE}
!macroend
!define registry::Close `!insertmacro registry::Close`
!macro registry::Close _HANDLE
registry::_Close /NOUNLOAD `${_HANDLE}`
!macroend
!define registry::KeyExists `!insertmacro registry::KeyExists`
!macro registry::KeyExists _PATH _ERR
registry::_KeyExists /NOUNLOAD `${_PATH}`
Pop ${_ERR}
!macroend
!define registry::Read `!insertmacro registry::Read`
!macro registry::Read _PATH _VALUE _STRING _TYPE
registry::_Read /NOUNLOAD `${_PATH}` `${_VALUE}`
Pop ${_STRING}
Pop ${_TYPE}
!macroend
!define registry::Write `!insertmacro registry::Write`
!macro registry::Write _PATH _VALUE _STRING _TYPE _ERR
registry::_Write /NOUNLOAD `${_PATH}` `${_VALUE}` `${_STRING}` `${_TYPE}`
Pop ${_ERR}
!macroend
!define registry::ReadExtra `!insertmacro registry::ReadExtra`
!macro registry::ReadExtra _PATH _VALUE _NUMBER _STRING _TYPE
registry::_ReadExtra /NOUNLOAD `${_PATH}` `${_VALUE}` `${_NUMBER}`
Pop ${_STRING}
Pop ${_TYPE}
!macroend
!define registry::WriteExtra `!insertmacro registry::WriteExtra`
!macro registry::WriteExtra _PATH _VALUE _STRING _ERR
registry::_WriteExtra /NOUNLOAD `${_PATH}` `${_VALUE}` `${_STRING}`
Pop ${_ERR}
!macroend
!define registry::CreateKey `!insertmacro registry::CreateKey`
!macro registry::CreateKey _PATH _ERR
registry::_CreateKey /NOUNLOAD `${_PATH}`
Pop ${_ERR}
!macroend
!define registry::DeleteValue `!insertmacro registry::DeleteValue`
!macro registry::DeleteValue _PATH _VALUE _ERR
registry::_DeleteValue /NOUNLOAD `${_PATH}` `${_VALUE}`
Pop ${_ERR}
!macroend
!define registry::DeleteKey `!insertmacro registry::DeleteKey`
!macro registry::DeleteKey _PATH _ERR
registry::_DeleteKey /NOUNLOAD `${_PATH}`
Pop ${_ERR}
!macroend
!define registry::DeleteKeyEmpty `!insertmacro registry::DeleteKeyEmpty`
!macro registry::DeleteKeyEmpty _PATH _ERR
registry::_DeleteKeyEmpty /NOUNLOAD `${_PATH}`
Pop ${_ERR}
!macroend
!define registry::CopyValue `!insertmacro registry::CopyValue`
!macro registry::CopyValue _PATH_SOURCE _VALUE_SOURCE _PATH_TARGET _VALUE_TARGET _ERR
registry::_CopyValue /NOUNLOAD `${_PATH_SOURCE}` `${_VALUE_SOURCE}` `${_PATH_TARGET}` `${_VALUE_TARGET}`
Pop ${_ERR}
!macroend
!define registry::MoveValue `!insertmacro registry::MoveValue`
!macro registry::MoveValue _PATH_SOURCE _VALUE_SOURCE _PATH_TARGET _VALUE_TARGET _ERR
registry::_MoveValue /NOUNLOAD `${_PATH_SOURCE}` `${_VALUE_SOURCE}` `${_PATH_TARGET}` `${_VALUE_TARGET}`
Pop ${_ERR}
!macroend
!define registry::CopyKey `!insertmacro registry::CopyKey`
!macro registry::CopyKey _PATH_SOURCE _PATH_TARGET _ERR
registry::_CopyKey /NOUNLOAD `${_PATH_SOURCE}` `${_PATH_TARGET}`
Pop ${_ERR}
!macroend
!define registry::MoveKey `!insertmacro registry::MoveKey`
!macro registry::MoveKey _PATH_SOURCE _PATH_TARGET _ERR
registry::_MoveKey /NOUNLOAD `${_PATH_SOURCE}` `${_PATH_TARGET}`
Pop ${_ERR}
!macroend
!define registry::SaveKey `!insertmacro registry::SaveKey`
!macro registry::SaveKey _PATH _FILE _OPTIONS _ERR
registry::_SaveKey /NOUNLOAD `${_PATH}` `${_FILE}` `${_OPTIONS}`
Pop ${_ERR}
!macroend
!define registry::RestoreKey `!insertmacro registry::RestoreKey`
!macro registry::RestoreKey _FILE _ERR
registry::_RestoreKey /NOUNLOAD `${_FILE}`
Pop ${_ERR}
!macroend
!define registry::StrToHex `!insertmacro registry::StrToHexA`
!define registry::StrToHexA `!insertmacro registry::StrToHexA`
!macro registry::StrToHexA _STRING _HEX_STRING
registry::_StrToHexA /NOUNLOAD `${_STRING}`
Pop ${_HEX_STRING}
!macroend
!define registry::StrToHexW `!insertmacro registry::StrToHexW`
!macro registry::StrToHexW _STRING _HEX_STRING
registry::_StrToHexW /NOUNLOAD `${_STRING}`
Pop ${_HEX_STRING}
!macroend
!define registry::HexToStr `!insertmacro registry::HexToStrA`
!define registry::HexToStrA `!insertmacro registry::HexToStrA`
!macro registry::HexToStrA _HEX_STRING _STRING
registry::_HexToStrA /NOUNLOAD `${_HEX_STRING}`
Pop ${_STRING}
!macroend
!define registry::HexToStrW `!insertmacro registry::HexToStrW`
!macro registry::HexToStrW _HEX_STRING _STRING
registry::_HexToStrW /NOUNLOAD `${_HEX_STRING}`
Pop ${_STRING}
!macroend
!define registry::Unload `!insertmacro registry::Unload`
!macro registry::Unload
registry::_Unload
!macroend

View File

@@ -38,6 +38,14 @@
!define compiler "msvc"
!endif
!if "@CMAKE_BUILD_TYPE@" == "Release"
!define release
!endif
!if "@CMAKE_BUILD_TYPE@" == "RelWithDebInfo"
!define release
!endif
!if "@CMAKE_BUILD_TYPE@" == "Debug"
!define debug
!undef build_type
@@ -96,6 +104,7 @@ SetCompressor /SOLID lzma
!include "FileAssociation.nsh"
!include "Capabilities.nsh"
!include LogicLib.nsh
!include Registry.nsh
!include x64.nsh
!define MUI_ICON "strawberry.ico"
@@ -105,11 +114,15 @@ SetCompressor /SOLID lzma
!ifdef mingw
ReserveFile "${NSISDIR}/Plugins/x86-unicode/LockedList.dll"
ReserveFile "${NSISDIR}/Plugins/LockedList64.dll"
ReserveFile "${NSISDIR}/Plugins/registry.dll"
ReserveFile "${NSISDIR}/Plugins/x86-unicode/INetC.dll"
!endif
!ifdef msvc
ReserveFile "${NSISDIR}\Plugins\x86-unicode\LockedList.dll"
ReserveFile "${NSISDIR}\Plugins\LockedList64.dll"
ReserveFile "${NSISDIR}\Plugins\registry.dll"
ReserveFile "${NSISDIR}\Plugins\x86-unicode\INetC.dll"
!endif
!define LockedListPATH $InstallDir
@@ -119,6 +132,9 @@ SetCompressor /SOLID lzma
!insertmacro MUI_PAGE_LICENSE COPYING
Page Custom LockedListPageShow
!insertmacro MUI_PAGE_DIRECTORY
!ifdef msvc
Page Custom InstallMSVCRuntime
!endif
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
@@ -173,6 +189,20 @@ done:
FunctionEnd
!ifdef msvc
!define vc_redist_file "vc_redist.${arch}.exe"
Function InstallMSVCRuntime
${registry::Read} "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\${arch}" "Version" $R0 $R1
${If} $R0 == ""
SetDetailsView hide
inetc::get /caption "Downloading..." "https://aka.ms/vs/17/release/${vc_redist_file}" "$TEMP\${vc_redist_file}" /end
ExecWait '"$TEMP\${vc_redist_file}" /install /passive'
Delete "$TEMP\${vc_redist_file}"
SetDetailsView show
${EndIf}
FunctionEnd
!endif
Function .onInit
!insertmacro MUI_LANGDLL_DISPLAY
@@ -192,9 +222,7 @@ Section "Strawberry" Strawberry
File "strawberry.exe"
File "strawberry-tagreader.exe"
File "strawberry.ico"
!ifdef mingw
File "sqlite3.exe"
!endif
File "gst-launch-1.0.exe"
File "gst-discoverer-1.0.exe"
@@ -217,22 +245,28 @@ Section "Strawberry" Strawberry
File "avfilter-8.dll"
File "avformat-59.dll"
File "avutil-57.dll"
File "libFLAC-12.dll"
File "libbrotlicommon.dll"
File "libbrotlidec.dll"
File "libbrotlienc.dll"
File "libbs2b-0.dll"
File "libbz2.dll"
File "libcdio-19.dll"
File "libchromaprint.dll"
File "libdl.dll"
File "libfaac-0.dll"
File "libfaad-2.dll"
File "libfdk-aac-2.dll"
File "libffi-8.dll"
File "libfreetype-6.dll"
File "libgcrypt-20.dll"
File "libgio-2.0-0.dll"
File "libglib-2.0-0.dll"
File "libgme.dll"
File "libgmodule-2.0-0.dll"
File "libgmp-10.dll"
File "libgnutls-30.dll"
File "libgobject-2.0-0.dll"
File "libgpg-error-0.dll"
File "libgstadaptivedemux-1.0-0.dll"
File "libgstapp-1.0-0.dll"
File "libgstaudio-1.0-0.dll"
@@ -252,30 +286,39 @@ Section "Strawberry" Strawberry
File "libgstvideo-1.0-0.dll"
File "libharfbuzz-0.dll"
File "libhogweed-6.dll"
File "libiconv-2.dll"
File "libidn2-0.dll"
File "libintl-8.dll"
File "libjpeg-9.dll"
File "liblzma-5.dll"
File "libmp3lame-0.dll"
File "libmpcdec.dll"
File "libmpg123-0.dll"
File "libnettle-8.dll"
File "libnghttp2.dll"
File "libogg-0.dll"
File "libopenmpt-0.dll"
File "libopus-0.dll"
File "liborc-0.4-0.dll"
File "libpcre-1.dll"
File "libpcre2-16-0.dll"
File "libpng16-16.dll"
File "libprotobuf-30.dll"
File "libprotobuf-32.dll"
File "libpsl-5.dll"
File "libqtsparkle-qt6.dll"
File "libsoup-3.0-0.dll"
File "libspeex-1.dll"
File "libsqlite3-0.dll"
File "libssp-0.dll"
File "libstdc++-6.dll"
File "libtag.dll"
File "libtasn1-6.dll"
File "libunistring-2.dll"
File "libtwolame-0.dll"
File "libunistring-5.dll"
File "libvorbis-0.dll"
File "libvorbisenc-2.dll"
File "libvorbisfile-3.dll"
File "libwavpack-1.dll"
File "libwinpthread-1.dll"
File "libxml2-2.dll"
File "libzstd.dll"
File "postproc-56.dll"
File "swresample-4.dll"
@@ -287,8 +330,13 @@ Section "Strawberry" Strawberry
File "libexpat-1.dll"
File "libmman.dll"
File "libmpfr-6.dll"
File "libpcre2-8d.dll"
File "libpcre2-16d.dll"
File "libreadline8.dll"
File "libtermcap.dll"
!else
File "libpcre2-8.dll"
File "libpcre2-16.dll"
!endif
!endif ; MinGW
@@ -298,29 +346,35 @@ Section "Strawberry" Strawberry
!ifdef msvc
!ifdef arch_x86
File "libcrypto-1_1.dll"
File "libssl-1_1.dll"
File "libcrypto-3.dll"
File "libssl-3.dll"
!endif
!ifdef arch_x64
File "libcrypto-1_1-x64.dll"
File "libssl-1_1-x64.dll"
File "libcrypto-3-x64.dll"
File "libssl-3-x64.dll"
!endif
File "FLAC.dll"
File "avcodec-58.dll"
File "avfilter-7.dll"
File "avformat-58.dll"
File "avutil-56.dll"
File "bz2.dll"
File "brotlicommon.dll"
File "brotlidec.dll"
File "chromaprint.dll"
File "faad.dll"
File "fdk-aac.dll"
File "ffi-7.dll"
File "gio-2.0-0.dll"
File "glib-2.0-0.dll"
File "gme.dll"
File "gmodule-2.0-0.dll"
File "gnutls.dll"
File "gobject-2.0-0.dll"
File "gstadaptivedemux-1.0-0.dll"
File "gstapp-1.0-0.dll"
File "gstaudio-1.0-0.dll"
File "gstbadaudio-1.0-0.dll"
File "gstbase-1.0-0.dll"
File "gstfft-1.0-0.dll"
File "gstisoff-1.0-0.dll"
@@ -334,38 +388,80 @@ Section "Strawberry" Strawberry
File "gsttag-1.0-0.dll"
File "gsturidownloader-1.0-0.dll"
File "gstvideo-1.0-0.dll"
File "gstwinrt-1.0-0.dll"
File "harfbuzz.dll"
File "intl-8.dll"
File "libprotobuf.dll"
File "opus-0.dll"
File "jpeg62.dll"
File "libbs2b.dll"
File "libfaac_dll.dll"
File "libiconv.dll"
File "liblzma.dll"
File "libmp3lame.dll"
File "libopenmpt.dll"
File "libspeex.dll"
File "mpcdec.dll"
File "mpg123.dll"
File "nghttp2.dll"
File "ogg.dll"
File "opus.dll"
File "orc-0.4-0.dll"
File "postproc-55.dll"
File "psl-5.dll"
File "soup-2.4-1.dll"
File "sqlite3-0.dll"
File "qtsparkle-qt6.dll"
File "soup-3.0-0.dll"
File "sqlite3.dll"
File "swresample-3.dll"
File "swscale-5.dll"
File "tag.dll"
File "z-1.dll"
File "vorbis.dll"
File "vorbisfile.dll"
File "wavpackdll.dll"
!ifdef release
File "freetype.dll"
File "libpng16.dll"
File "libprotobuf.dll"
File "libxml2.dll"
File "pcre2-8.dll"
File "pcre2-16.dll"
File "twolame.dll"
File "zlib.dll"
!endif
!ifdef debug
File "freetyped.dll"
File "libpng16d.dll"
File "libprotobufd.dll"
File "libxml2d.dll"
File "pcre2-8d.dll"
File "pcre2-16d.dll"
File "twolamed.dll"
File "zlibd.dll"
!endif
!endif ; MSVC
; Common files
File "icudt72.dll"
File "libfftw3-3.dll"
File "libFLAC-8.dll"
File "libiconv-2.dll"
File "libmp3lame-0.dll"
File "libogg-0.dll"
File "libspeex-1.dll"
File "libvorbis-0.dll"
File "libvorbisenc-2.dll"
File "libwinpthread-1.dll"
File "libxml2-2.dll"
!ifdef msvc && debug
File "icuin72d.dll"
File "icuuc72d.dll"
File "Qt6Concurrentd.dll"
File "Qt6Cored.dll"
File "Qt6Guid.dll"
File "Qt6Networkd.dll"
File "Qt6Sqld.dll"
File "Qt6Widgetsd.dll"
!else
File "icuin72.dll"
File "icuuc72.dll"
File "Qt6Concurrent.dll"
File "Qt6Core.dll"
File "Qt6Gui.dll"
File "Qt6Network.dll"
File "Qt6Sql.dll"
File "Qt6Widgets.dll"
!endif
; Register Strawberry with Default Programs
Var /GLOBAL AppIcon
@@ -403,43 +499,70 @@ Section "GIO modules" gio-modules
SetOutPath "$INSTDIR\gio-modules"
!ifdef mingw
File "/oname=libgiognutls.dll" "gio-modules\libgiognutls.dll"
File "/oname=libgioopenssl.dll" "gio-modules\libgioopenssl.dll"
!endif
!ifdef msvc
File "/oname=giognutls.dll" "gio-modules\giognutls.dll"
File "/oname=gioopenssl.dll" "gio-modules\gioopenssl.dll"
!endif
SectionEnd
Section "Qt Platform plugins" platforms
SetOutPath "$INSTDIR\platforms"
!ifdef msvc && debug
File "/oname=qwindowsd.dll" "platforms\qwindowsd.dll"
!else
File "/oname=qwindows.dll" "platforms\qwindows.dll"
!endif
SectionEnd
Section "Qt styles" styles
SetOutPath "$INSTDIR\styles"
!ifdef msvc && debug
File "/oname=qwindowsvistastyled.dll" "styles\qwindowsvistastyled.dll"
!else
File "/oname=qwindowsvistastyle.dll" "styles\qwindowsvistastyle.dll"
!endif
SectionEnd
Section "Qt TLS plugins" tls
SetOutPath "$INSTDIR\tls"
!ifdef msvc && debug
File "/oname=qschannelbackendd.dll" "tls\qschannelbackendd.dll"
File "/oname=qopensslbackendd.dll" "tls\qopensslbackendd.dll"
!else
File "/oname=qschannelbackend.dll" "tls\qschannelbackend.dll"
File "/oname=qopensslbackend.dll" "tls\qopensslbackend.dll"
!endif
SectionEnd
Section "Qt SQL Drivers" sqldrivers
SetOutPath "$INSTDIR\sqldrivers"
!ifdef msvc && debug
File "/oname=qsqlited.dll" "sqldrivers\qsqlited.dll"
!else
File "/oname=qsqlite.dll" "sqldrivers\qsqlite.dll"
!endif
SectionEnd
Section "Qt imageformats" imageformats
SetOutPath "$INSTDIR\imageformats"
!ifdef msvc && debug
File "/oname=qgifd.dll" "imageformats\qgifd.dll"
File "/oname=qicod.dll" "imageformats\qicod.dll"
File "/oname=qjpegd.dll" "imageformats\qjpegd.dll"
!else
File "/oname=qgif.dll" "imageformats\qgif.dll"
File "/oname=qico.dll" "imageformats\qico.dll"
File "/oname=qjpeg.dll" "imageformats\qjpeg.dll"
!endif
SectionEnd
Section "Gstreamer plugins" gstreamer-plugins
SetOutPath "$INSTDIR\gstreamer-plugins"
!ifdef mingw
File "/oname=libgstaes.dll" "gstreamer-plugins\libgstaes.dll"
File "/oname=libgstaiff.dll" "gstreamer-plugins\libgstaiff.dll"
File "/oname=libgstapetag.dll" "gstreamer-plugins\libgstapetag.dll"
File "/oname=libgstapp.dll" "gstreamer-plugins\libgstapp.dll"
@@ -453,20 +576,26 @@ Section "Gstreamer plugins" gstreamer-plugins
File "/oname=libgstaudioresample.dll" "gstreamer-plugins\libgstaudioresample.dll"
File "/oname=libgstaudiotestsrc.dll" "gstreamer-plugins\libgstaudiotestsrc.dll"
File "/oname=libgstautodetect.dll" "gstreamer-plugins\libgstautodetect.dll"
File "/oname=libgstcdio.dll" "gstreamer-plugins\libgstcdio.dll"
File "/oname=libgstbs2b.dll" "gstreamer-plugins\libgstbs2b.dll"
File "/oname=libgstcoreelements.dll" "gstreamer-plugins\libgstcoreelements.dll"
File "/oname=libgstdash.dll" "gstreamer-plugins\libgstdash.dll"
File "/oname=libgstdirectsound.dll" "gstreamer-plugins\libgstdirectsound.dll"
File "/oname=libgstequalizer.dll" "gstreamer-plugins\libgstequalizer.dll"
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
File "/oname=libgstfaac.dll" "gstreamer-plugins\libgstfaac.dll"
File "/oname=libgstfaad.dll" "gstreamer-plugins\libgstfaad.dll"
File "/oname=libgstfdkaac.dll" "gstreamer-plugins\libgstfdkaac.dll"
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
File "/oname=libgstgio.dll" "gstreamer-plugins\libgstgio.dll"
File "/oname=libgstgme.dll" "gstreamer-plugins\libgstgme.dll"
File "/oname=libgsthls.dll" "gstreamer-plugins\libgsthls.dll"
File "/oname=libgsticydemux.dll" "gstreamer-plugins\libgsticydemux.dll"
File "/oname=libgstid3demux.dll" "gstreamer-plugins\libgstid3demux.dll"
File "/oname=libgstid3tag.dll" "gstreamer-plugins\libgstid3tag.dll"
File "/oname=libgstisomp4.dll" "gstreamer-plugins\libgstisomp4.dll"
File "/oname=libgstlame.dll" "gstreamer-plugins\libgstlame.dll"
File "/oname=libgstlibav.dll" "gstreamer-plugins\libgstlibav.dll"
File "/oname=libgstmpg123.dll" "gstreamer-plugins\libgstmpg123.dll"
File "/oname=libgstmusepack.dll" "gstreamer-plugins\libgstmusepack.dll"
File "/oname=libgstogg.dll" "gstreamer-plugins\libgstogg.dll"
File "/oname=libgstopenmpt.dll" "gstreamer-plugins\libgstopenmpt.dll"
File "/oname=libgstopus.dll" "gstreamer-plugins\libgstopus.dll"
@@ -481,17 +610,20 @@ Section "Gstreamer plugins" gstreamer-plugins
File "/oname=libgstspeex.dll" "gstreamer-plugins\libgstspeex.dll"
File "/oname=libgsttaglib.dll" "gstreamer-plugins\libgsttaglib.dll"
File "/oname=libgsttcp.dll" "gstreamer-plugins\libgsttcp.dll"
File "/oname=libgsttwolame.dll" "gstreamer-plugins\libgsttwolame.dll"
File "/oname=libgsttypefindfunctions.dll" "gstreamer-plugins\libgsttypefindfunctions.dll"
File "/oname=libgstudp.dll" "gstreamer-plugins\libgstudp.dll"
File "/oname=libgstvolume.dll" "gstreamer-plugins\libgstvolume.dll"
File "/oname=libgstvorbis.dll" "gstreamer-plugins\libgstvorbis.dll"
File "/oname=libgstwasapi.dll" "gstreamer-plugins\libgstwasapi.dll"
File "/oname=libgstwavenc.dll" "gstreamer-plugins\libgstwavenc.dll"
File "/oname=libgstwavpack.dll" "gstreamer-plugins\libgstwavpack.dll"
File "/oname=libgstwavparse.dll" "gstreamer-plugins\libgstwavparse.dll"
File "/oname=libgstxingmux.dll" "gstreamer-plugins\libgstxingmux.dll"
!endif ; MinGW
!ifdef msvc
File "/oname=gstaes.dll" "gstreamer-plugins\gstaes.dll"
File "/oname=gstaiff.dll" "gstreamer-plugins\gstaiff.dll"
File "/oname=gstapetag.dll" "gstreamer-plugins\gstapetag.dll"
File "/oname=gstapp.dll" "gstreamer-plugins\gstapp.dll"
@@ -505,20 +637,31 @@ Section "Gstreamer plugins" gstreamer-plugins
File "/oname=gstaudioresample.dll" "gstreamer-plugins\gstaudioresample.dll"
File "/oname=gstaudiotestsrc.dll" "gstreamer-plugins\gstaudiotestsrc.dll"
File "/oname=gstautodetect.dll" "gstreamer-plugins\gstautodetect.dll"
File "/oname=gstbs2b.dll" "gstreamer-plugins\gstbs2b.dll"
File "/oname=gstcoreelements.dll" "gstreamer-plugins\gstcoreelements.dll"
File "/oname=gstdash.dll" "gstreamer-plugins\gstdash.dll"
File "/oname=gstdirectsound.dll" "gstreamer-plugins\gstdirectsound.dll"
File "/oname=gstequalizer.dll" "gstreamer-plugins\gstequalizer.dll"
File "/oname=gstfaac.dll" "gstreamer-plugins\gstfaac.dll"
File "/oname=gstfaad.dll" "gstreamer-plugins\gstfaad.dll"
File "/oname=gstfdkaac.dll" "gstreamer-plugins\gstfdkaac.dll"
File "/oname=gstflac.dll" "gstreamer-plugins\gstflac.dll"
File "/oname=gstgio.dll" "gstreamer-plugins\gstgio.dll"
File "/oname=gstgme.dll" "gstreamer-plugins\gstgme.dll"
File "/oname=gsthls.dll" "gstreamer-plugins\gsthls.dll"
File "/oname=gsticydemux.dll" "gstreamer-plugins\gsticydemux.dll"
File "/oname=gstid3demux.dll" "gstreamer-plugins\gstid3demux.dll"
File "/oname=gstid3tag.dll" "gstreamer-plugins\gstid3tag.dll"
File "/oname=gstisomp4.dll" "gstreamer-plugins\gstisomp4.dll"
File "/oname=gstlame.dll" "gstreamer-plugins\gstlame.dll"
File "/oname=gstlibav.dll" "gstreamer-plugins\gstlibav.dll"
File "/oname=gstmpg123.dll" "gstreamer-plugins\gstmpg123.dll"
File "/oname=gstmusepack.dll" "gstreamer-plugins\gstmusepack.dll"
File "/oname=gstogg.dll" "gstreamer-plugins\gstogg.dll"
File "/oname=gstopenmpt.dll" "gstreamer-plugins\gstopenmpt.dll"
File "/oname=gstopus.dll" "gstreamer-plugins\gstopus.dll"
File "/oname=gstopusparse.dll" "gstreamer-plugins\gstopusparse.dll"
File "/oname=gstpbtypes.dll" "gstreamer-plugins\gstpbtypes.dll"
File "/oname=gstplayback.dll" "gstreamer-plugins\gstplayback.dll"
File "/oname=gstreplaygain.dll" "gstreamer-plugins\gstreplaygain.dll"
File "/oname=gstrtp.dll" "gstreamer-plugins\gstrtp.dll"
@@ -526,13 +669,15 @@ Section "Gstreamer plugins" gstreamer-plugins
File "/oname=gstsoup.dll" "gstreamer-plugins\gstsoup.dll"
File "/oname=gstspectrum.dll" "gstreamer-plugins\gstspectrum.dll"
File "/oname=gstspeex.dll" "gstreamer-plugins\gstspeex.dll"
File "/oname=gsttaglib.dll" "gstreamer-plugins\gsttaglib.dll"
File "/oname=gsttcp.dll" "gstreamer-plugins\gsttcp.dll"
File "/oname=gsttwolame.dll" "gstreamer-plugins\gsttwolame.dll"
File "/oname=gsttypefindfunctions.dll" "gstreamer-plugins\gsttypefindfunctions.dll"
File "/oname=gstudp.dll" "gstreamer-plugins\gstudp.dll"
File "/oname=gstvolume.dll" "gstreamer-plugins\gstvolume.dll"
File "/oname=gstvorbis.dll" "gstreamer-plugins\gstvorbis.dll"
File "/oname=gstwasapi.dll" "gstreamer-plugins\gstwasapi.dll"
File "/oname=gstwasapi2.dll" "gstreamer-plugins\gstwasapi2.dll"
File "/oname=gstwavenc.dll" "gstreamer-plugins\gstwavenc.dll"
File "/oname=gstwavpack.dll" "gstreamer-plugins\gstwavpack.dll"
File "/oname=gstwavparse.dll" "gstreamer-plugins\gstwavparse.dll"
File "/oname=gstxingmux.dll" "gstreamer-plugins\gstxingmux.dll"
@@ -578,9 +723,7 @@ Section "Uninstall"
Delete "$INSTDIR\strawberry.exe"
Delete "$INSTDIR\strawberry-tagreader.exe"
Delete "$INSTDIR\strawberry.ico"
!ifdef mingw
Delete "$INSTDIR\sqlite3.exe"
!endif
Delete "$INSTDIR\gst-launch-1.0.exe"
Delete "$INSTDIR\gst-discoverer-1.0.exe"
@@ -604,22 +747,28 @@ Section "Uninstall"
Delete "$INSTDIR\avfilter-8.dll"
Delete "$INSTDIR\avformat-59.dll"
Delete "$INSTDIR\avutil-57.dll"
Delete "$INSTDIR\libFLAC-12.dll"
Delete "$INSTDIR\libbrotlicommon.dll"
Delete "$INSTDIR\libbrotlidec.dll"
Delete "$INSTDIR\libbrotlienc.dll"
Delete "$INSTDIR\libbs2b-0.dll"
Delete "$INSTDIR\libbz2.dll"
Delete "$INSTDIR\libcdio-19.dll"
Delete "$INSTDIR\libchromaprint.dll"
Delete "$INSTDIR\libdl.dll"
Delete "$INSTDIR\libfaac-0.dll"
Delete "$INSTDIR\libfaad-2.dll"
Delete "$INSTDIR\libfdk-aac-2.dll"
Delete "$INSTDIR\libffi-8.dll"
Delete "$INSTDIR\libfreetype-6.dll"
Delete "$INSTDIR\libgcrypt-20.dll"
Delete "$INSTDIR\libgio-2.0-0.dll"
Delete "$INSTDIR\libglib-2.0-0.dll"
Delete "$INSTDIR\libgme.dll"
Delete "$INSTDIR\libgmodule-2.0-0.dll"
Delete "$INSTDIR\libgmp-10.dll"
Delete "$INSTDIR\libgnutls-30.dll"
Delete "$INSTDIR\libgobject-2.0-0.dll"
Delete "$INSTDIR\libgpg-error-0.dll"
Delete "$INSTDIR\libgstadaptivedemux-1.0-0.dll"
Delete "$INSTDIR\libgstapp-1.0-0.dll"
Delete "$INSTDIR\libgstaudio-1.0-0.dll"
@@ -639,30 +788,39 @@ Section "Uninstall"
Delete "$INSTDIR\libgstvideo-1.0-0.dll"
Delete "$INSTDIR\libharfbuzz-0.dll"
Delete "$INSTDIR\libhogweed-6.dll"
Delete "$INSTDIR\libiconv-2.dll"
Delete "$INSTDIR\libidn2-0.dll"
Delete "$INSTDIR\libintl-8.dll"
Delete "$INSTDIR\libjpeg-9.dll"
Delete "$INSTDIR\liblzma-5.dll"
Delete "$INSTDIR\libmp3lame-0.dll"
Delete "$INSTDIR\libmpcdec.dll"
Delete "$INSTDIR\libmpg123-0.dll"
Delete "$INSTDIR\libnettle-8.dll"
Delete "$INSTDIR\libnghttp2.dll"
Delete "$INSTDIR\libogg-0.dll"
Delete "$INSTDIR\libopenmpt-0.dll"
Delete "$INSTDIR\libopus-0.dll"
Delete "$INSTDIR\liborc-0.4-0.dll"
Delete "$INSTDIR\libpcre-1.dll"
Delete "$INSTDIR\libpcre2-16-0.dll"
Delete "$INSTDIR\libpng16-16.dll"
Delete "$INSTDIR\libprotobuf-30.dll"
Delete "$INSTDIR\libprotobuf-32.dll"
Delete "$INSTDIR\libpsl-5.dll"
Delete "$INSTDIR\libqtsparkle-qt6.dll"
Delete "$INSTDIR\libsoup-3.0-0.dll"
Delete "$INSTDIR\libspeex-1.dll"
Delete "$INSTDIR\libsqlite3-0.dll"
Delete "$INSTDIR\libssp-0.dll"
Delete "$INSTDIR\libstdc++-6.dll"
Delete "$INSTDIR\libtag.dll"
Delete "$INSTDIR\libtasn1-6.dll"
Delete "$INSTDIR\libunistring-2.dll"
Delete "$INSTDIR\libtwolame-0.dll"
Delete "$INSTDIR\libunistring-5.dll"
Delete "$INSTDIR\libvorbis-0.dll"
Delete "$INSTDIR\libvorbisenc-2.dll"
Delete "$INSTDIR\libvorbisfile-3.dll"
Delete "$INSTDIR\libwavpack-1.dll"
Delete "$INSTDIR\libwinpthread-1.dll"
Delete "$INSTDIR\libxml2-2.dll"
Delete "$INSTDIR\libzstd.dll"
Delete "$INSTDIR\postproc-56.dll"
Delete "$INSTDIR\swresample-4.dll"
@@ -674,8 +832,13 @@ Section "Uninstall"
Delete "$INSTDIR\libexpat-1.dll"
Delete "$INSTDIR\libmman.dll"
Delete "$INSTDIR\libmpfr-6.dll"
Delete "$INSTDIR\libpcre2-8d.dll"
Delete "$INSTDIR\libpcre2-16d.dll"
Delete "$INSTDIR\libreadline8.dll"
Delete "$INSTDIR\libtermcap.dll"
!else
Delete "$INSTDIR\libpcre2-8.dll"
Delete "$INSTDIR\libpcre2-16.dll"
!endif
!endif ; MinGW
@@ -685,29 +848,35 @@ Section "Uninstall"
!ifdef msvc
!ifdef arch_x86
Delete "$INSTDIR\libcrypto-1_1.dll"
Delete "$INSTDIR\libssl-1_1.dll"
Delete "$INSTDIR\libcrypto-3.dll"
Delete "$INSTDIR\libssl-3.dll"
!endif
!ifdef arch_x64
Delete "$INSTDIR\libcrypto-1_1-x64.dll"
Delete "$INSTDIR\libssl-1_1-x64.dll"
Delete "$INSTDIR\libcrypto-3-x64.dll"
Delete "$INSTDIR\libssl-3-x64.dll"
!endif
Delete "$INSTDIR\FLAC.dll"
Delete "$INSTDIR\avcodec-58.dll"
Delete "$INSTDIR\avfilter-7.dll"
Delete "$INSTDIR\avformat-58.dll"
Delete "$INSTDIR\avutil-56.dll"
Delete "$INSTDIR\bz2.dll"
Delete "$INSTDIR\brotlicommon.dll"
Delete "$INSTDIR\brotlidec.dll"
Delete "$INSTDIR\chromaprint.dll"
Delete "$INSTDIR\faad.dll"
Delete "$INSTDIR\fdk-aac.dll"
Delete "$INSTDIR\ffi-7.dll"
Delete "$INSTDIR\gio-2.0-0.dll"
Delete "$INSTDIR\glib-2.0-0.dll"
Delete "$INSTDIR\gme.dll"
Delete "$INSTDIR\gmodule-2.0-0.dll"
Delete "$INSTDIR\gnutls.dll"
Delete "$INSTDIR\gobject-2.0-0.dll"
Delete "$INSTDIR\gstadaptivedemux-1.0-0.dll"
Delete "$INSTDIR\gstapp-1.0-0.dll"
Delete "$INSTDIR\gstaudio-1.0-0.dll"
Delete "$INSTDIR\gstbadaudio-1.0-0.dll"
Delete "$INSTDIR\gstbase-1.0-0.dll"
Delete "$INSTDIR\gstfft-1.0-0.dll"
Delete "$INSTDIR\gstisoff-1.0-0.dll"
@@ -721,58 +890,114 @@ Section "Uninstall"
Delete "$INSTDIR\gsttag-1.0-0.dll"
Delete "$INSTDIR\gsturidownloader-1.0-0.dll"
Delete "$INSTDIR\gstvideo-1.0-0.dll"
Delete "$INSTDIR\gstwinrt-1.0-0.dll"
Delete "$INSTDIR\harfbuzz.dll"
Delete "$INSTDIR\intl-8.dll"
Delete "$INSTDIR\libprotobuf.dll"
Delete "$INSTDIR\opus-0.dll"
Delete "$INSTDIR\jpeg62.dll"
Delete "$INSTDIR\libbs2b.dll"
Delete "$INSTDIR\libfaac_dll.dll"
Delete "$INSTDIR\libiconv.dll"
Delete "$INSTDIR\liblzma.dll"
Delete "$INSTDIR\libmp3lame.dll"
Delete "$INSTDIR\libopenmpt.dll"
Delete "$INSTDIR\libspeex.dll"
Delete "$INSTDIR\mpcdec.dll"
Delete "$INSTDIR\mpg123.dll"
Delete "$INSTDIR\nghttp2.dll"
Delete "$INSTDIR\ogg.dll"
Delete "$INSTDIR\opus.dll"
Delete "$INSTDIR\orc-0.4-0.dll"
Delete "$INSTDIR\postproc-55.dll"
Delete "$INSTDIR\psl-5.dll"
Delete "$INSTDIR\soup-2.4-1.dll"
Delete "$INSTDIR\sqlite3-0.dll"
Delete "$INSTDIR\qtsparkle-qt6.dll"
Delete "$INSTDIR\soup-3.0-0.dll"
Delete "$INSTDIR\sqlite3.dll"
Delete "$INSTDIR\swresample-3.dll"
Delete "$INSTDIR\swscale-5.dll"
Delete "$INSTDIR\tag.dll"
Delete "$INSTDIR\z-1.dll"
Delete "$INSTDIR\vorbis.dll"
Delete "$INSTDIR\vorbisfile.dll"
Delete "$INSTDIR\wavpackdll.dll"
!ifdef release
Delete "$INSTDIR\freetype.dll"
Delete "$INSTDIR\libpng16.dll"
Delete "$INSTDIR\libprotobuf.dll"
Delete "$INSTDIR\libxml2.dll"
Delete "$INSTDIR\pcre2-8.dll"
Delete "$INSTDIR\pcre2-16.dll"
Delete "$INSTDIR\twolame.dll"
Delete "$INSTDIR\zlib.dll"
!endif
!ifdef debug
Delete "$INSTDIR\freetyped.dll"
Delete "$INSTDIR\libpng16d.dll"
Delete "$INSTDIR\libprotobufd.dll"
Delete "$INSTDIR\libxml2d.dll"
Delete "$INSTDIR\pcre2-8d.dll"
Delete "$INSTDIR\pcre2-16d.dll"
Delete "$INSTDIR\twolamed.dll"
Delete "$INSTDIR\zlibd.dll"
!endif
!endif ; MSVC
; Common files
Delete "$INSTDIR\icudt72.dll"
Delete "$INSTDIR\libfftw3-3.dll"
Delete "$INSTDIR\libFLAC-8.dll"
Delete "$INSTDIR\libiconv-2.dll"
Delete "$INSTDIR\libmp3lame-0.dll"
Delete "$INSTDIR\libogg-0.dll"
Delete "$INSTDIR\libspeex-1.dll"
Delete "$INSTDIR\libvorbis-0.dll"
Delete "$INSTDIR\libvorbisenc-2.dll"
Delete "$INSTDIR\libwinpthread-1.dll"
Delete "$INSTDIR\libxml2-2.dll"
!ifdef msvc && debug
Delete "$INSTDIR\icuin72d.dll"
Delete "$INSTDIR\icuuc72d.dll"
Delete "$INSTDIR\Qt6Concurrentd.dll"
Delete "$INSTDIR\Qt6Cored.dll"
Delete "$INSTDIR\Qt6Guid.dll"
Delete "$INSTDIR\Qt6Networkd.dll"
Delete "$INSTDIR\Qt6Sqld.dll"
Delete "$INSTDIR\Qt6Widgetsd.dll"
!else
Delete "$INSTDIR\icuin72.dll"
Delete "$INSTDIR\icuuc72.dll"
Delete "$INSTDIR\Qt6Concurrent.dll"
Delete "$INSTDIR\Qt6Core.dll"
Delete "$INSTDIR\Qt6Gui.dll"
Delete "$INSTDIR\Qt6Network.dll"
Delete "$INSTDIR\Qt6Sql.dll"
Delete "$INSTDIR\Qt6Widgets.dll"
!endif
!ifdef mingw
Delete "$INSTDIR\gio-modules\libgiognutls.dll"
Delete "$INSTDIR\gio-modules\libgioopenssl.dll"
!endif
!ifdef msvc
Delete "$INSTDIR\gio-modules\giognutls.dll"
Delete "$INSTDIR\gio-modules\gioopenssl.dll"
!endif
!ifdef msvc && debug
Delete "$INSTDIR\platforms\qwindowsd.dll"
Delete "$INSTDIR\styles\qwindowsvistastyled.dll"
Delete "$INSTDIR\tls\qschannelbackendd.dll"
Delete "$INSTDIR\tls\qopensslbackendd.dll"
Delete "$INSTDIR\sqldrivers\qsqlited.dll"
Delete "$INSTDIR\imageformats\qgifd.dll"
Delete "$INSTDIR\imageformats\qicod.dll"
Delete "$INSTDIR\imageformats\qjpegd.dll"
!else
Delete "$INSTDIR\platforms\qwindows.dll"
Delete "$INSTDIR\styles\qwindowsvistastyle.dll"
Delete "$INSTDIR\tls\qschannelbackend.dll"
Delete "$INSTDIR\tls\qopensslbackend.dll"
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
Delete "$INSTDIR\imageformats\qgif.dll"
Delete "$INSTDIR\imageformats\qico.dll"
Delete "$INSTDIR\imageformats\qjpeg.dll"
!endif
; MinGW GStreamer plugins
!ifdef mingw
Delete "$INSTDIR\gstreamer-plugins\libgstaes.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaiff.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstapetag.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstapp.dll"
@@ -786,20 +1011,26 @@ Section "Uninstall"
Delete "$INSTDIR\gstreamer-plugins\libgstaudioresample.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudiotestsrc.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstautodetect.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstcdio.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstbs2b.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstcoreelements.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstdash.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstequalizer.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstflac.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstfaac.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstfaad.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstfdkaac.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstflac.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstgio.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstgme.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsthls.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsticydemux.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstid3demux.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstid3tag.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstisomp4.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstlame.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstlibav.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstmpg123.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstmusepack.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstogg.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstopenmpt.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstopus.dll"
@@ -814,11 +1045,13 @@ Section "Uninstall"
Delete "$INSTDIR\gstreamer-plugins\libgstspeex.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsttaglib.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsttcp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsttwolame.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsttypefindfunctions.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstudp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstvolume.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstvorbis.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstwasapi.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstwavenc.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstwavpack.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstwavparse.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstxingmux.dll"
@@ -827,6 +1060,7 @@ Section "Uninstall"
; MSVC GStreamer plugins
!ifdef msvc
Delete "$INSTDIR\gstreamer-plugins\gstaes.dll"
Delete "$INSTDIR\gstreamer-plugins\gstaiff.dll"
Delete "$INSTDIR\gstreamer-plugins\gstapetag.dll"
Delete "$INSTDIR\gstreamer-plugins\gstapp.dll"
@@ -840,20 +1074,31 @@ Section "Uninstall"
Delete "$INSTDIR\gstreamer-plugins\gstaudioresample.dll"
Delete "$INSTDIR\gstreamer-plugins\gstaudiotestsrc.dll"
Delete "$INSTDIR\gstreamer-plugins\gstautodetect.dll"
Delete "$INSTDIR\gstreamer-plugins\gstbs2b.dll"
Delete "$INSTDIR\gstreamer-plugins\gstcoreelements.dll"
Delete "$INSTDIR\gstreamer-plugins\gstdash.dll"
Delete "$INSTDIR\gstreamer-plugins\gstdirectsound.dll"
Delete "$INSTDIR\gstreamer-plugins\gstequalizer.dll"
Delete "$INSTDIR\gstreamer-plugins\gstfaac.dll"
Delete "$INSTDIR\gstreamer-plugins\gstfaad.dll"
Delete "$INSTDIR\gstreamer-plugins\gstfdkaac.dll"
Delete "$INSTDIR\gstreamer-plugins\gstflac.dll"
Delete "$INSTDIR\gstreamer-plugins\gstgio.dll"
Delete "$INSTDIR\gstreamer-plugins\gstgme.dll"
Delete "$INSTDIR\gstreamer-plugins\gsthls.dll"
Delete "$INSTDIR\gstreamer-plugins\gsticydemux.dll"
Delete "$INSTDIR\gstreamer-plugins\gstid3demux.dll"
Delete "$INSTDIR\gstreamer-plugins\gstid3tag.dll"
Delete "$INSTDIR\gstreamer-plugins\gstisomp4.dll"
Delete "$INSTDIR\gstreamer-plugins\gstlame.dll"
Delete "$INSTDIR\gstreamer-plugins\gstlibav.dll"
Delete "$INSTDIR\gstreamer-plugins\gstmpg123.dll"
Delete "$INSTDIR\gstreamer-plugins\gstmusepack.dll"
Delete "$INSTDIR\gstreamer-plugins\gstogg.dll"
Delete "$INSTDIR\gstreamer-plugins\gstopenmpt.dll"
Delete "$INSTDIR\gstreamer-plugins\gstopus.dll"
Delete "$INSTDIR\gstreamer-plugins\gstopusparse.dll"
Delete "$INSTDIR\gstreamer-plugins\gstpbtypes.dll"
Delete "$INSTDIR\gstreamer-plugins\gstplayback.dll"
Delete "$INSTDIR\gstreamer-plugins\gstreplaygain.dll"
Delete "$INSTDIR\gstreamer-plugins\gstrtp.dll"
@@ -861,13 +1106,15 @@ Section "Uninstall"
Delete "$INSTDIR\gstreamer-plugins\gstsoup.dll"
Delete "$INSTDIR\gstreamer-plugins\gstspectrum.dll"
Delete "$INSTDIR\gstreamer-plugins\gstspeex.dll"
Delete "$INSTDIR\gstreamer-plugins\gsttaglib.dll"
Delete "$INSTDIR\gstreamer-plugins\gsttcp.dll"
Delete "$INSTDIR\gstreamer-plugins\gsttwolame.dll"
Delete "$INSTDIR\gstreamer-plugins\gsttypefindfunctions.dll"
Delete "$INSTDIR\gstreamer-plugins\gstudp.dll"
Delete "$INSTDIR\gstreamer-plugins\gstvolume.dll"
Delete "$INSTDIR\gstreamer-plugins\gstvorbis.dll"
Delete "$INSTDIR\gstreamer-plugins\gstwasapi.dll"
Delete "$INSTDIR\gstreamer-plugins\gstwasapi2.dll"
Delete "$INSTDIR\gstreamer-plugins\gstwavenc.dll"
Delete "$INSTDIR\gstreamer-plugins\gstwavpack.dll"
Delete "$INSTDIR\gstreamer-plugins\gstwavparse.dll"
Delete "$INSTDIR\gstreamer-plugins\gstxingmux.dll"

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.7)
set(SOURCES gstfastspectrum.cpp gstmoodbarplugin.cpp)

View File

@@ -50,7 +50,10 @@ enum {
} // namespace
#define gst_fastspectrum_parent_class parent_class
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
G_DEFINE_TYPE(GstFastSpectrum, gst_fastspectrum, GST_TYPE_AUDIO_FILTER)
#pragma GCC diagnostic pop
static void gst_fastspectrum_finalize(GObject *object);
static void gst_fastspectrum_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
@@ -79,9 +82,9 @@ static void gst_fastspectrum_class_init(GstFastSpectrumClass *klass) {
filter_class->setup = GST_DEBUG_FUNCPTR(gst_fastspectrum_setup);
g_object_class_install_property(gobject_class, PROP_INTERVAL, g_param_spec_uint64("interval", "Interval", "Interval of time between message posts (in nanoseconds)", 1, G_MAXUINT64, DEFAULT_INTERVAL, GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property(gobject_class, PROP_INTERVAL, g_param_spec_uint64("interval", "Interval", "Interval of time between message posts (in nanoseconds)", 1, G_MAXUINT64, DEFAULT_INTERVAL, static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property(gobject_class, PROP_BANDS, g_param_spec_uint("bands", "Bands", "Number of frequency bands", 0, G_MAXUINT, DEFAULT_BANDS, GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property(gobject_class, PROP_BANDS, g_param_spec_uint("bands", "Bands", "Number of frequency bands", 0, G_MAXUINT, DEFAULT_BANDS, static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
GST_DEBUG_CATEGORY_INIT(gst_fastspectrum_debug, "spectrum", 0, "audio spectrum analyser element");

View File

@@ -47,7 +47,7 @@ class QMutex;
typedef void (*GstFastSpectrumInputData)(const guint8 *in, double *out, guint len, double max_value, guint op, guint nfft);
typedef std::function<void(double *magnitudes, int size)> OutputCallback;
using OutputCallback = std::function<void(double *magnitudes, int size)>;
struct GstFastSpectrum {
GstAudioFilter parent;

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.7)
set(SOURCES
core/logging.cpp

View File

@@ -61,7 +61,7 @@ static const char *kMessageHandlerMagic = "__logging_message__";
static const size_t kMessageHandlerMagicLength = strlen(kMessageHandlerMagic);
static QtMessageHandler sOriginalMessageHandler = nullptr;
template <class T>
template<class T>
static T CreateLogger(Level level, const QString &class_name, int line, const char *category);
void GLog(const char *domain, int level, const char *message, void*) {
@@ -88,7 +88,7 @@ void GLog(const char *domain, int level, const char *message, void*) {
}
template <class T>
template<class T>
class DebugBase : public QDebug {
public:
DebugBase() : QDebug(sNullDevice) {}
@@ -126,7 +126,8 @@ class LoggedDebug : public DebugBase<LoggedDebug> {
static void MessageHandler(QtMsgType type, const QMessageLogContext&, const QString &message) {
if (message.startsWith(kMessageHandlerMagic)) {
fprintf(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout, "%s\n", message.toUtf8().data() + kMessageHandlerMagicLength);
QByteArray message_data = message.toUtf8();
fprintf(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout, "%s\n", message_data.constData() + kMessageHandlerMagicLength);
fflush(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout);
return;
}
@@ -314,11 +315,11 @@ QString LinuxDemangle(const QString &symbol) {
QString DarwinDemangle(const QString &symbol);
QString DarwinDemangle(const QString &symbol) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
# if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QStringList split = symbol.split(' ', Qt::SkipEmptyParts);
#else
# else
QStringList split = symbol.split(' ', QString::SkipEmptyParts);
#endif
# endif
QString mangled_function = split[3];
return CXXDemangle(mangled_function);
@@ -379,7 +380,7 @@ QDebug CreateLoggerError(int line, const char *pretty_function, const char *cate
namespace {
template <typename T>
template<typename T>
QString print_duration(T duration, const std::string &unit) {
return QString("%1%2").arg(duration.count()).arg(unit.c_str());
}

View File

@@ -98,7 +98,7 @@ void _MessageHandlerBase::DeviceReadyRead() {
void _MessageHandlerBase::WriteMessage(const QByteArray &data) {
QDataStream s(device_);
s << quint32(data.length());
s << static_cast<quint32>(data.length());
s.writeRawData(data.data(), static_cast<int>(data.length()));
// Sorry.

View File

@@ -35,9 +35,6 @@
class QIODevice;
#define QStringFromStdString(x) QString::fromUtf8((x).data(), (x).size())
#define DataCommaSizeFromQString(x) (x).toUtf8().constData(), (x).toUtf8().length()
// Reads and writes uint32 length encoded protobufs to a socket.
// This base QObject is separate from AbstractMessageHandler because moc can't handle templated classes.
// Use AbstractMessageHandler instead.
@@ -79,14 +76,14 @@ class _MessageHandlerBase : public QObject {
// Reads and writes uint32 length encoded MessageType messages to a socket.
// You should subclass this and implement the MessageArrived(MessageType) method.
template <typename MT>
template<typename MT>
class AbstractMessageHandler : public _MessageHandlerBase {
public:
AbstractMessageHandler(QIODevice *device, QObject *parent);
~AbstractMessageHandler() override { AbstractMessageHandler::AbortAll(); }
typedef MT MessageType;
typedef MessageReply<MT> ReplyType;
using MessageType = MT;
using ReplyType = MessageReply<MT>;
// Serialises the message and writes it to the socket.
// This version MUST be called from the thread in which the AbstractMessageHandler was created.
@@ -115,11 +112,11 @@ class AbstractMessageHandler : public _MessageHandlerBase {
QMap<int, ReplyType*> pending_replies_;
};
template <typename MT>
template<typename MT>
AbstractMessageHandler<MT>::AbstractMessageHandler(QIODevice *device, QObject *parent)
: _MessageHandlerBase(device, parent) {}
template <typename MT>
template<typename MT>
void AbstractMessageHandler<MT>::SendMessage(const MessageType &message) {
Q_ASSERT(QThread::currentThread() == thread());
@@ -127,7 +124,7 @@ void AbstractMessageHandler<MT>::SendMessage(const MessageType &message) {
WriteMessage(QByteArray(data.data(), data.size()));
}
template <typename MT>
template<typename MT>
void AbstractMessageHandler<MT>::SendMessageAsync(const MessageType &message) {
std::string data = message.SerializeAsString();
QMetaObject::invokeMethod(this, "WriteMessage", Qt::QueuedConnection, Q_ARG(QByteArray, QByteArray(data.data(), data.size())));

View File

@@ -56,7 +56,7 @@ class _MessageReplyBase : public QObject {
};
// A reply future class that is returned immediately for requests that will occur in the background. Similar to QNetworkReply.
template <typename MessageType>
template<typename MessageType>
class MessageReply : public _MessageReplyBase {
public:
explicit MessageReply(const MessageType &request_message, QObject *parent = nullptr);

View File

@@ -70,14 +70,14 @@ class _WorkerPoolBase : public QObject {
// A local socket server is started for each process, and the address is passed to the process as argv[1].
// The process is expected to connect back to the socket server, and when it does a HandlerType is created for it.
// Instances of HandlerType are created in the WorkerPool's thread.
template <typename HandlerType>
template<typename HandlerType>
class WorkerPool : public _WorkerPoolBase {
public:
explicit WorkerPool(QObject *parent = nullptr);
~WorkerPool() override;
typedef typename HandlerType::MessageType MessageType;
typedef typename HandlerType::ReplyType ReplyType;
using MessageType = typename HandlerType::MessageType;
using ReplyType = typename HandlerType::ReplyType;
// Sets the name of the worker executable. This is looked for first in the current directory, and then in $PATH.
// You must call this before calling Start().
@@ -121,9 +121,9 @@ class WorkerPool : public _WorkerPoolBase {
// Must only ever be called on my thread.
void StartOneWorker(Worker *worker);
template <typename T>
template<typename T>
Worker *FindWorker(T Worker::*member, T value) {
for (typename QList<Worker>::iterator it = workers_.begin() ; it != workers_.end() ; ++it) {
for (typename QList<Worker>::iterator it = workers_.begin(); it != workers_.end(); ++it) {
if ((*it).*member == value) {
return &(*it);
}
@@ -131,7 +131,7 @@ class WorkerPool : public _WorkerPoolBase {
return nullptr;
}
template <typename T>
template<typename T>
void DeleteQObjectPointerLater(T **p) {
if (*p) {
(*p)->deleteLater();
@@ -158,15 +158,15 @@ class WorkerPool : public _WorkerPoolBase {
QAtomicInt next_id_;
QMutex message_queue_mutex_;
QQueue<ReplyType*> message_queue_;
QQueue<ReplyType *> message_queue_;
};
template <typename HandlerType>
template<typename HandlerType>
WorkerPool<HandlerType>::WorkerPool(QObject *parent)
: _WorkerPoolBase(parent),
next_worker_(0),
next_id_(0) {
: _WorkerPoolBase(parent),
next_worker_(0),
next_id_(0) {
worker_count_ = qBound(1, QThread::idealThreadCount() / 2, 4);
local_server_name_ = qApp->applicationName().toLower();
@@ -177,7 +177,7 @@ WorkerPool<HandlerType>::WorkerPool(QObject *parent)
}
template <typename HandlerType>
template<typename HandlerType>
WorkerPool<HandlerType>::~WorkerPool() {
for (const Worker &worker : workers_) {
@@ -208,30 +208,30 @@ WorkerPool<HandlerType>::~WorkerPool() {
}
template <typename HandlerType>
template<typename HandlerType>
void WorkerPool<HandlerType>::SetWorkerCount(const int count) {
Q_ASSERT(workers_.isEmpty());
worker_count_ = count;
}
template <typename HandlerType>
template<typename HandlerType>
void WorkerPool<HandlerType>::SetLocalServerName(const QString &local_server_name) {
Q_ASSERT(workers_.isEmpty());
local_server_name_ = local_server_name;
}
template <typename HandlerType>
template<typename HandlerType>
void WorkerPool<HandlerType>::SetExecutableName(const QString &executable_name) {
Q_ASSERT(workers_.isEmpty());
executable_name_ = executable_name;
}
template <typename HandlerType>
template<typename HandlerType>
void WorkerPool<HandlerType>::Start() {
QMetaObject::invokeMethod(this, "DoStart");
}
template <typename HandlerType>
template<typename HandlerType>
void WorkerPool<HandlerType>::DoStart() {
Q_ASSERT(workers_.isEmpty());
@@ -243,6 +243,10 @@ void WorkerPool<HandlerType>::DoStart() {
QStringList search_path;
search_path << QCoreApplication::applicationDirPath();
#if defined(Q_OS_UNIX)
search_path << "/usr/libexec";
search_path << "/usr/local/libexec";
#endif
#if defined(Q_OS_MACOS) && defined(USE_BUNDLE)
search_path << QCoreApplication::applicationDirPath() + "/" + USE_BUNDLE_DIR;
#endif
@@ -270,7 +274,7 @@ void WorkerPool<HandlerType>::DoStart() {
}
template <typename HandlerType>
template<typename HandlerType>
void WorkerPool<HandlerType>::StartOneWorker(Worker *worker) {
Q_ASSERT(QThread::currentThread() == thread());
@@ -311,10 +315,9 @@ void WorkerPool<HandlerType>::StartOneWorker(Worker *worker) {
#endif
worker->process_->start(executable_path_, QStringList() << worker->local_server_->fullServerName());
}
template <typename HandlerType>
template<typename HandlerType>
void WorkerPool<HandlerType>::NewConnection() {
Q_ASSERT(QThread::currentThread() == thread());
@@ -342,7 +345,7 @@ void WorkerPool<HandlerType>::NewConnection() {
}
template <typename HandlerType>
template<typename HandlerType>
void WorkerPool<HandlerType>::ProcessError(QProcess::ProcessError error) {
Q_ASSERT(QThread::currentThread() == thread());
@@ -370,7 +373,7 @@ void WorkerPool<HandlerType>::ProcessError(QProcess::ProcessError error) {
}
template <typename HandlerType>
template<typename HandlerType>
void WorkerPool<HandlerType>::ProcessReadyReadStandardOutput() {
Q_ASSERT(QThread::currentThread() == thread());
@@ -383,7 +386,7 @@ void WorkerPool<HandlerType>::ProcessReadyReadStandardOutput() {
}
template <typename HandlerType>
template<typename HandlerType>
void WorkerPool<HandlerType>::ProcessReadyReadStandardError() {
Q_ASSERT(QThread::currentThread() == thread());
@@ -426,7 +429,7 @@ WorkerPool<HandlerType>::SendMessageWithReply(MessageType *message) {
}
template <typename HandlerType>
template<typename HandlerType>
void WorkerPool<HandlerType>::SendQueuedMessages() {
QMutexLocker l(&message_queue_mutex_);
@@ -448,7 +451,7 @@ void WorkerPool<HandlerType>::SendQueuedMessages() {
}
template <typename HandlerType>
template<typename HandlerType>
HandlerType *WorkerPool<HandlerType>::NextHandler() const {
for (int i = 0; i < workers_.count(); ++i) {

View File

@@ -1,10 +1,10 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.7)
set(MESSAGES tagreadermessages.proto)
set(SOURCES tagreaderbase.cpp)
if(USE_TAGLIB AND TAGLIB_FOUND)
list(APPEND SOURCES tagreadertaglib.cpp)
list(APPEND SOURCES tagreadertaglib.cpp tagreadergme.cpp)
endif()
if(USE_TAGPARSER AND TAGPARSER_FOUND)

View File

@@ -25,3 +25,33 @@ const std::string TagReaderBase::kEmbeddedCover = "(embedded)";
TagReaderBase::TagReaderBase() = default;
TagReaderBase::~TagReaderBase() = default;
void TagReaderBase::Decode(const QString &tag, std::string *output) {
output->assign(DataCommaSizeFromQString(tag));
}
float TagReaderBase::ConvertPOPMRating(const int POPM_rating) {
if (POPM_rating < 0x01) return 0.0F;
else if (POPM_rating < 0x40) return 0.20F;
else if (POPM_rating < 0x80) return 0.40F;
else if (POPM_rating < 0xC0) return 0.60F;
else if (POPM_rating < 0xFC) return 0.80F;
return 1.0F;
}
int TagReaderBase::ConvertToPOPMRating(const float rating) {
if (rating < 0.20) return 0x00;
else if (rating < 0.40) return 0x01;
else if (rating < 0.60) return 0x40;
else if (rating < 0.80) return 0x80;
else if (rating < 1.0) return 0xC0;
return 0xFF;
}

View File

@@ -27,6 +27,9 @@
#include "tagreadermessages.pb.h"
#define QStringFromStdString(x) QString::fromUtf8((x).data(), (x).size())
#define DataCommaSizeFromQString(x) (x).toUtf8().constData(), (x).toUtf8().length()
/*
* This class holds all useful methods to read and write tags from/to files.
* You should not use it directly in the main process but rather use a TagReaderWorker process (using TagReaderClient)
@@ -38,7 +41,7 @@ class TagReaderBase {
virtual bool IsMediaFile(const QString &filename) const = 0;
virtual void ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const = 0;
virtual bool ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const = 0;
virtual bool SaveFile(const QString &filename, const spb::tagreader::SongMetadata &song) const = 0;
virtual QByteArray LoadEmbeddedArt(const QString &filename) const = 0;
@@ -47,6 +50,11 @@ class TagReaderBase {
virtual bool SaveSongPlaycountToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const = 0;
virtual bool SaveSongRatingToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const = 0;
static void Decode(const QString &tag, std::string *output);
static float ConvertPOPMRating(const int POPM_rating);
static int ConvertToPOPMRating(const float rating);
protected:
static const std::string kEmbeddedCover;

View File

@@ -0,0 +1,299 @@
/*
* Strawberry Music Player
* Copyright 2022, Eoin O'Neill <eoinoneill1991@gmail.com>
*
* 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 "tagreadergme.h"
#include <tag.h>
#include <apefile.h>
#include <QByteArray>
#include <QString>
#include <QChar>
#include <QFileInfo>
#include <QFile>
#include <QTextStream>
#include "utilities/timeconstants.h"
#include "core/logging.h"
#include "core/messagehandler.h"
#include "tagreaderbase.h"
#include "tagreadertaglib.h"
bool GME::IsSupportedFormat(const QFileInfo &file_info) {
return file_info.exists() && (file_info.completeSuffix().endsWith("spc", Qt::CaseInsensitive) || file_info.completeSuffix().endsWith("vgm"), Qt::CaseInsensitive);
}
bool GME::ReadFile(const QFileInfo &file_info, spb::tagreader::SongMetadata *song_info) {
if (file_info.completeSuffix().endsWith("spc"), Qt::CaseInsensitive) {
SPC::Read(file_info, song_info);
return true;
}
if (file_info.completeSuffix().endsWith("vgm", Qt::CaseInsensitive)) {
VGM::Read(file_info, song_info);
return true;
}
return false;
}
quint32 GME::UnpackBytes32(const char *const bytes, size_t length) {
Q_ASSERT(length <= 4 && length > 0);
quint32 value = 0;
for (size_t i = 0; i < length; i++) {
value |= static_cast<unsigned char>(bytes[i]) << (8 * i);
}
return value;
}
void GME::SPC::Read(const QFileInfo &file_info, spb::tagreader::SongMetadata *song_info) {
QFile file(file_info.filePath());
if (!file.open(QIODevice::ReadOnly)) return;
qLog(Debug) << "Reading tags from SPC file" << file_info.fileName();
// Check for header -- more reliable than file name alone.
if (!file.read(33).startsWith(QString("SNES-SPC700").toLatin1())) return;
// First order of business -- get any tag values that exist within the core file information.
// These only allow for a certain number of bytes per field,
// so they will likely be overwritten either by the id666 standard or the APETAG format (as used by other players, such as foobar and winamp)
//
// Make sure to check id6 documentation before changing the read values!
file.seek(HAS_ID6_OFFSET);
bool has_id6 = (file.read(1)[0] == static_cast<char>(xID6_STATUS::ON));
file.seek(SONG_TITLE_OFFSET);
song_info->set_title(QString::fromLatin1(file.read(32)).toStdString());
file.seek(GAME_TITLE_OFFSET);
song_info->set_album(QString::fromLatin1(file.read(32)).toStdString());
file.seek(ARTIST_OFFSET);
song_info->set_artist(QString::fromLatin1(file.read(32)).toStdString());
file.seek(INTRO_LENGTH_OFFSET);
QByteArray length_bytes = file.read(INTRO_LENGTH_SIZE);
quint64 length_in_sec = 0;
if (length_bytes.size() >= INTRO_LENGTH_SIZE) {
length_in_sec = ConvertSPCStringToNum(length_bytes);
if (!length_in_sec || length_in_sec >= 0x1FFF) {
// This means that parsing the length as a string failed, so get value LE.
length_in_sec = length_bytes[0] | (length_bytes[1] << 8) | (length_bytes[2] << 16);
}
if (length_in_sec < 0x1FFF) {
song_info->set_length_nanosec(length_in_sec * kNsecPerSec);
}
}
file.seek(FADE_LENGTH_OFFSET);
QByteArray fade_bytes = file.read(FADE_LENGTH_SIZE);
if (fade_bytes.size() >= FADE_LENGTH_SIZE) {
quint64 fade_length_in_ms = ConvertSPCStringToNum(fade_bytes);
if (fade_length_in_ms > 0x7FFF) {
fade_length_in_ms = fade_bytes[0] | (fade_bytes[1] << 8) | (fade_bytes[2] << 16) | (fade_bytes[3] << 24);
}
}
// Check for XID6 data -- this is infrequently used, but being able to fill in data from this is ideal before trying to rely on APETAG values.
// XID6 format follows EA's binary file format standard named "IFF"
file.seek(XID6_OFFSET);
if (has_id6 && file.read(4) == QString("xid6").toLatin1()) {
QByteArray xid6_head_data = file.read(4);
if (xid6_head_data.size() >= 4) {
qint64 xid6_size = xid6_head_data[0] | (xid6_head_data[1] << 8) | (xid6_head_data[2] << 16) | xid6_head_data[3];
// This should be the size remaining for entire ID6 block, but it seems that most files treat this as the size of the remaining header space...
qLog(Debug) << file_info.fileName() << "has ID6 tag.";
while ((file.pos()) + 4 < XID6_OFFSET + xid6_size) {
QByteArray arr = file.read(4);
if (arr.size() < 4) break;
qint8 id = arr[0];
qint8 type = arr[1];
Q_UNUSED(id);
Q_UNUSED(type);
qint16 length = arr[2] | (arr[3] << 8);
file.read(GetNextMemAddressAlign32bit(length));
}
}
}
// Music Players that support SPC tend to support additional tagging data as
// an APETAG entry at the bottom of the file instead of writing into the xid6 tagging space.
// This is where a lot of the extra data for a file is stored, such as genre or replaygain data.
// This data is currently supported by TagLib, so we will simply use that for the remaining values.
TagLib::APE::File ape(file_info.filePath().toStdString().data());
if (ape.hasAPETag()) {
TagLib::Tag *tag = ape.tag();
if (!tag) return;
TagReaderTagLib::Decode(tag->artist(), song_info->mutable_artist());
TagReaderTagLib::Decode(tag->album(), song_info->mutable_album());
TagReaderTagLib::Decode(tag->title(), song_info->mutable_title());
TagReaderTagLib::Decode(tag->genre(), song_info->mutable_genre());
song_info->set_track(tag->track());
song_info->set_year(tag->year());
}
song_info->set_valid(true);
song_info->set_filetype(spb::tagreader::SongMetadata_FileType_SPC);
}
qint16 GME::SPC::GetNextMemAddressAlign32bit(qint16 input) {
return ((input + 0x3) & ~0x3);
// Plus 0x3 for rounding up (not down), AND NOT to flatten out on a 32 bit level.
}
quint64 GME::SPC::ConvertSPCStringToNum(const QByteArray &arr) {
quint64 result = 0;
for (auto it = arr.begin(); it != arr.end(); it++) {
unsigned int num = *it - '0';
if (num > 9) break;
result = (result * 10) + num; // Shift Left and add.
}
return result;
}
void GME::VGM::Read(const QFileInfo &file_info, spb::tagreader::SongMetadata *song_info) {
QFile file(file_info.filePath());
if (!file.open(QIODevice::ReadOnly)) return;
qLog(Debug) << "Reading tags from VGM file" << file_info.fileName();
if (!file.read(4).startsWith(QString("Vgm ").toLatin1())) return;
file.seek(GD3_TAG_PTR);
QByteArray gd3_head = file.read(4);
if (gd3_head.size() < 4) return;
quint64 pt = GME::UnpackBytes32(gd3_head.constData(), gd3_head.size());
file.seek(SAMPLE_COUNT);
QByteArray sample_count_bytes = file.read(4);
file.seek(LOOP_SAMPLE_COUNT);
QByteArray loop_count_bytes = file.read(4);
quint64 length = 0;
if (!GetPlaybackLength(sample_count_bytes, loop_count_bytes, length)) return;
file.seek(GD3_TAG_PTR + pt);
QByteArray gd3_version = file.read(4);
file.seek(file.pos() + 4);
QByteArray gd3_length_bytes = file.read(4);
quint32 gd3_length = GME::UnpackBytes32(gd3_length_bytes.constData(), gd3_length_bytes.size());
QByteArray gd3Data = file.read(gd3_length);
QTextStream fileTagStream(gd3Data, QIODevice::ReadOnly);
// Stored as 16 bit UTF string, two bytes per letter.
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
fileTagStream.setEncoding(QStringConverter::Utf16);
#else
fileTagStream.setCodec("UTF-16");
#endif
QStringList strings = fileTagStream.readLine(0).split(QChar('\0'));
if (strings.count() < 10) return;
// VGM standard dictates string tag data exist in specific order.
// Order alternates between English and Japanese version of data.
// Read GD3 tag standard for more details.
song_info->set_title(strings[0].toStdString());
song_info->set_album(strings[2].toStdString());
song_info->set_artist(strings[6].toStdString());
song_info->set_year(strings[8].left(4).toInt());
song_info->set_length_nanosec(length * kNsecPerMsec);
song_info->set_valid(true);
song_info->set_filetype(spb::tagreader::SongMetadata_FileType_VGM);
}
bool GME::VGM::GetPlaybackLength(const QByteArray &sample_count_bytes, const QByteArray &loop_count_bytes, quint64 &out_length) {
if (sample_count_bytes.size() != 4) return false;
if (loop_count_bytes.size() != 4) return false;
quint64 sample_count = GME::UnpackBytes32(sample_count_bytes.constData(), sample_count_bytes.size());
if (sample_count <= 0) return false;
quint64 loop_sample_count = GME::UnpackBytes32(loop_count_bytes.constData(), loop_count_bytes.size());
if (loop_sample_count <= 0) {
out_length = sample_count * 1000 / SAMPLE_TIMEBASE;
return true;
}
quint64 intro_length_ms = (sample_count - loop_sample_count) * 1000 / SAMPLE_TIMEBASE;
quint64 loop_length_ms = (loop_sample_count) * 1000 / SAMPLE_TIMEBASE;
out_length = intro_length_ms + (loop_length_ms * 2) + GST_GME_LOOP_TIME_MS;
return true;
}
TagReaderGME::TagReaderGME() = default;
TagReaderGME::~TagReaderGME() = default;
bool TagReaderGME::IsMediaFile(const QString &filename) const {
QFileInfo fileinfo(filename);
return GME::IsSupportedFormat(fileinfo);
}
bool TagReaderGME::ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const {
QFileInfo fileinfo(filename);
return GME::ReadFile(fileinfo, song);
}
bool TagReaderGME::SaveFile(const QString&, const spb::tagreader::SongMetadata&) const {
return false;
}
QByteArray TagReaderGME::LoadEmbeddedArt(const QString&) const {
return QByteArray();
}
bool TagReaderGME::SaveEmbeddedArt(const QString&, const QByteArray&) {
return false;
}
bool TagReaderGME::SaveSongPlaycountToFile(const QString&, const spb::tagreader::SongMetadata&) const {
return false;
}
bool TagReaderGME::SaveSongRatingToFile(const QString&, const spb::tagreader::SongMetadata&) const {
return false;
}

View File

@@ -0,0 +1,111 @@
/*
* Strawberry Music Player
* Copyright 2022, Eoin O'Neill <eoinoneill1991@gmail.com>
*
* 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 TAGREADERGME_H
#define TAGREADERGME_H
#include <taglib/tstring.h>
#include <QByteArray>
#include <QString>
#include <QFileInfo>
#include "tagreaderbase.h"
#include "tagreadermessages.pb.h"
namespace GME {
bool IsSupportedFormat(const QFileInfo &file_info);
bool ReadFile(const QFileInfo &file_info, spb::tagreader::SongMetadata *song_info);
uint32_t UnpackBytes32(const char *const arr, size_t length);
namespace SPC {
// SPC SPEC: http://vspcplay.raphnet.net/spc_file_format.txt
constexpr int HAS_ID6_OFFSET = 0x23;
constexpr int SONG_TITLE_OFFSET = 0x2E;
constexpr int GAME_TITLE_OFFSET = 0x4E;
constexpr int DUMPER_OFFSET = 0x6E;
constexpr int COMMENTS_OFFSET = 0x7E;
// It seems that intro length and fade length are inconsistent from file to file.
// It should be looked into within the GME source code to see how GStreamer gets its values for playback length.
constexpr int INTRO_LENGTH_OFFSET = 0xA9;
constexpr int INTRO_LENGTH_SIZE = 3;
constexpr int FADE_LENGTH_OFFSET = 0xAC;
constexpr int FADE_LENGTH_SIZE = 4;
constexpr int ARTIST_OFFSET = 0xB1;
constexpr int XID6_OFFSET = (0x101C0 + 64);
constexpr int NANO_PER_MS = 1000000;
enum xID6_STATUS {
ON = 0x26,
OFF = 0x27,
};
enum xID6_ID { SongName = 0x01, GameName = 0x02, ArtistName = 0x03 };
enum xID6_TYPE { Length = 0x0, String = 0x1, Integer = 0x4 };
void Read(const QFileInfo &file_info, spb::tagreader::SongMetadata *song_info);
qint16 GetNextMemAddressAlign32bit(qint16 input);
quint64 ConvertSPCStringToNum(const QByteArray &arr);
} // namespace SPC
namespace VGM {
// VGM SPEC:
// http://www.smspower.org/uploads/Music/vgmspec170.txt?sid=17c810c54633b6dd4982f92f718361c1
// GD3 TAG SPEC:
// http://www.smspower.org/uploads/Music/gd3spec100.txt
constexpr int GD3_TAG_PTR = 0x14;
constexpr int SAMPLE_COUNT = 0x18;
constexpr int LOOP_SAMPLE_COUNT = 0x20;
constexpr int SAMPLE_TIMEBASE = 44100;
constexpr int GST_GME_LOOP_TIME_MS = 8000;
void Read(const QFileInfo &file_info, spb::tagreader::SongMetadata *song_info);
// Takes in two QByteArrays, expected to be 4 bytes long. Desired length is returned via output parameter out_length. Returns false on error.
bool GetPlaybackLength(const QByteArray &sample_count_bytes, const QByteArray &loop_count_bytes, quint64 &out_length);
} // namespace VGM
} // namespace GME
// TagReaderGME
// Fulfills Strawberry's Intended interface for tag reading.
class TagReaderGME : public TagReaderBase {
public:
explicit TagReaderGME();
~TagReaderGME();
bool IsMediaFile(const QString &filename) const override;
bool ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override;
bool SaveFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
QByteArray LoadEmbeddedArt(const QString &filename) const override;
bool SaveEmbeddedArt(const QString &filename, const QByteArray &data) override;
bool SaveSongPlaycountToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
bool SaveSongRatingToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
};
#endif

View File

@@ -27,6 +27,8 @@ message SongMetadata {
S3M = 19;
XM = 20;
IT = 21;
SPC = 22;
VGM = 23;
CDDA = 90;
STREAM = 91;
}

View File

@@ -22,6 +22,7 @@
#include <string>
#include <memory>
#include <algorithm>
#include <sys/stat.h>
#include <taglib/taglib.h>
@@ -91,7 +92,7 @@
#include "core/logging.h"
#include "core/messagehandler.h"
#include "core/timeconstants.h"
#include "utilities/timeconstants.h"
class FileRefFactory {
public:
@@ -113,6 +114,7 @@ class TagLibFileRefFactory : public FileRefFactory {
return new TagLib::FileRef(QFile::encodeName(filename).constData());
#endif
}
private:
Q_DISABLE_COPY(TagLibFileRefFactory)
};
@@ -130,11 +132,11 @@ TagLib::String QStringToTaglibString(const QString &s) {
} // namespace
namespace {
const char *kMP4_OriginalYear_ID = "----:com.apple.iTunes:ORIGINAL YEAR";
const char *kMP4_OriginalYear_ID = "----:com.apple.iTunes:ORIGINAL YEAR";
const char *kMP4_FMPS_Playcount_ID = "----:com.apple.iTunes:FMPS_Playcount";
const char *kMP4_FMPS_Rating_ID = "----:com.apple.iTunes:FMPS_Rating";
const char *kASF_OriginalDate_ID = "WM/OriginalReleaseTime";
const char *kASF_OriginalYear_ID = "WM/OriginalReleaseYear";
const char *kMP4_FMPS_Rating_ID = "----:com.apple.iTunes:FMPS_Rating";
const char *kASF_OriginalDate_ID = "WM/OriginalReleaseTime";
const char *kASF_OriginalYear_ID = "WM/OriginalReleaseYear";
} // namespace
@@ -184,7 +186,7 @@ spb::tagreader::SongMetadata_FileType TagReaderTagLib::GuessFileType(TagLib::Fil
}
void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const {
bool TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const {
const QByteArray url(QUrl::fromLocalFile(filename).toEncoded());
const QFileInfo fileinfo(filename);
@@ -194,18 +196,23 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
song->set_basefilename(DataCommaSizeFromQString(fileinfo.fileName()));
song->set_url(url.constData(), url.size());
song->set_filesize(fileinfo.size());
song->set_mtime(fileinfo.lastModified().isValid() ? fileinfo.lastModified().toSecsSinceEpoch() : 0);
song->set_mtime(fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
song->set_ctime(fileinfo.birthTime().isValid() ? fileinfo.birthTime().toSecsSinceEpoch() : fileinfo.lastModified().isValid() ? fileinfo.lastModified().toSecsSinceEpoch() : 0);
song->set_ctime(fileinfo.birthTime().isValid() ? std::max(fileinfo.birthTime().toSecsSinceEpoch(), 0LL) : fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL);
#else
song->set_ctime(fileinfo.created().isValid() ? fileinfo.created().toSecsSinceEpoch() : fileinfo.lastModified().isValid() ? fileinfo.lastModified().toSecsSinceEpoch() : 0);
song->set_ctime(fileinfo.created().isValid() ? std::max(fileinfo.created().toSecsSinceEpoch(), 0LL) : fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL);
#endif
if (song->ctime() <= 0) {
song->set_ctime(song->mtime());
}
song->set_lastseen(QDateTime::currentDateTime().toSecsSinceEpoch());
std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename));
if (fileref->isNull()) {
qLog(Info) << "TagLib hasn't been able to read" << filename << "file";
return;
return false;
}
song->set_filetype(GuessFileType(fileref.get()));
@@ -247,9 +254,7 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
}
if (TagLib::FLAC::File *file_flac = dynamic_cast<TagLib::FLAC::File *>(fileref->file())) {
song->set_bitdepth(file_flac->audioProperties()->bitsPerSample());
if (file_flac->xiphComment()) {
ParseOggTag(file_flac->xiphComment()->fieldListMap(), &disc, &compilation, song);
TagLib::List<TagLib::FLAC::Picture*> pictures = file_flac->pictureList();
@@ -265,7 +270,7 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
if (tag) Decode(tag->comment(), song->mutable_comment());
}
else if (TagLib::WavPack::File *file_wavpack = dynamic_cast<TagLib::WavPack::File *>(fileref->file())) {
else if (TagLib::WavPack::File *file_wavpack = dynamic_cast<TagLib::WavPack::File*>(fileref->file())) {
song->set_bitdepth(file_wavpack->audioProperties()->bitsPerSample());
if (file_wavpack->APETag()) {
ParseAPETag(file_wavpack->APETag()->itemListMap(), &disc, &compilation, song);
@@ -292,21 +297,19 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
// content group
if (!map["TIT1"].isEmpty()) Decode(map["TIT1"].front()->toString(), song->mutable_grouping());
// ID3v2: lead performer/soloist
if (!map["TPE1"].isEmpty()) Decode(map["TPE1"].front()->toString(), song->mutable_performer());
// original artist/performer
if (!map["TOPE"].isEmpty()) Decode(map["TOPE"].front()->toString(), song->mutable_performer());
// Skip TPE1 (which is the artist) here because we already fetched it
// non-standard: Apple, Microsoft
if (!map["TPE2"].isEmpty()) Decode(map["TPE2"].front()->toString(), song->mutable_albumartist());
if (!map["TCMP"].isEmpty()) compilation = TStringToQString(map["TCMP"].front()->toString()).trimmed();
if (!map["TDOR"].isEmpty()) { song->set_originalyear(map["TDOR"].front()->toString().substr(0, 4).toInt()); }
if (!map["TDOR"].isEmpty()) {
song->set_originalyear(map["TDOR"].front()->toString().substr(0, 4).toInt());
}
else if (!map["TORY"].isEmpty()) {
song->set_originalyear(map["TORY"].front()->toString().substr(0, 4).toInt());
}
@@ -321,7 +324,7 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
if (!map["APIC"].isEmpty()) song->set_art_automatic(kEmbeddedCover);
// Find a suitable comment tag. For now we ignore iTunNORM comments.
for (uint i = 0 ; i < map["COMM"].size() ; ++i) {
for (uint i = 0; i < map["COMM"].size(); ++i) {
const TagLib::ID3v2::CommentsFrame *frame = dynamic_cast<const TagLib::ID3v2::CommentsFrame*>(map["COMM"][i]);
if (frame && TStringToQString(frame->description()) != "iTunNORM") {
@@ -393,6 +396,10 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
song->set_originalyear(TStringToQString(mp4_tag->item(kMP4_OriginalYear_ID).toStringList().toString('\n')).left(4).toInt());
}
if (mp4_tag->item("cpil").isValid()) {
song->set_compilation(mp4_tag->item("cpil").toBool());
}
{
TagLib::MP4::Item item = mp4_tag->item(kMP4_FMPS_Playcount_ID);
if (item.isValid()) {
@@ -450,7 +457,7 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
}
if (attributes_map.contains("FMPS/Rating")) {
const TagLib::ASF::AttributeList& attributes = attributes_map["FMPS/Rating"];
const TagLib::ASF::AttributeList &attributes = attributes_map["FMPS/Rating"];
if (!attributes.isEmpty()) {
float rating = TStringToQString(attributes.front().toString()).toFloat();
if (song->rating() <= 0 && rating > 0) {
@@ -508,6 +515,8 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
if (song->bitrate() <= 0) { song->set_bitrate(-1); }
if (song->lastplayed() <= 0) { song->set_lastplayed(-1); }
return song->filetype() != spb::tagreader::SongMetadata_FileType_UNKNOWN;
}
void TagReaderTagLib::Decode(const TagLib::String &tag, std::string *output) {
@@ -517,12 +526,6 @@ void TagReaderTagLib::Decode(const TagLib::String &tag, std::string *output) {
}
void TagReaderTagLib::Decode(const QString &tag, std::string *output) {
output->assign(DataCommaSizeFromQString(tag));
}
void TagReaderTagLib::ParseOggTag(const TagLib::Ogg::FieldListMap &map, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const {
if (!map["COMPOSER"].isEmpty()) Decode(map["COMPOSER"].front(), song->mutable_composer());
@@ -679,12 +682,12 @@ bool TagReaderTagLib::SaveFile(const QString &filename, const spb::tagreader::So
else if (TagLib::MP4::File *file_mp4 = dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
TagLib::MP4::Tag *tag = file_mp4->tag();
if (!tag) return false;
tag->setItem("disk", TagLib::MP4::Item(song.disc() <= 0 -1 ? 0 : song.disc(), 0));
tag->setItem("disk", TagLib::MP4::Item(song.disc() <= 0 - 1 ? 0 : song.disc(), 0));
tag->setItem("\251wrt", TagLib::StringList(TagLib::String(song.composer(), TagLib::String::UTF8)));
tag->setItem("\251grp", TagLib::StringList(TagLib::String(song.grouping(), TagLib::String::UTF8)));
tag->setItem("\251lyr", TagLib::StringList(TagLib::String(song.lyrics(), TagLib::String::UTF8)));
tag->setItem("aART", TagLib::StringList(TagLib::String(song.albumartist(), TagLib::String::UTF8)));
tag->setItem("cpil", TagLib::StringList(song.compilation() ? "1" : "0"));
tag->setItem("cpil", TagLib::MP4::Item(song.compilation()));
}
// Handle all the files which have VorbisComments (Ogg, OPUS, ...) in the same way;
@@ -743,7 +746,7 @@ void TagReaderTagLib::SetTextFrame(const char *id, const std::string &value, Tag
}
// Update and add the frames
for (int i = 0 ; i < frames_buffer.size() ; ++i) {
for (int i = 0; i < frames_buffer.size(); ++i) {
TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame(frames_buffer.at(i));
if (i == 0) {
frame->setText(StdStringToTaglibString(value));
@@ -799,7 +802,7 @@ void TagReaderTagLib::SetUnsyncLyricsFrame(const std::string &value, TagLib::ID3
}
// Update and add the frames
for (int i = 0 ; i < frames_buffer.size() ; ++i) {
for (int i = 0; i < frames_buffer.size(); ++i) {
TagLib::ID3v2::UnsynchronizedLyricsFrame *frame = new TagLib::ID3v2::UnsynchronizedLyricsFrame(frames_buffer.at(i));
if (i == 0) {
frame->setText(StdStringToTaglibString(value));
@@ -983,7 +986,7 @@ bool TagReaderTagLib::SaveEmbeddedArt(const QString &filename, const QByteArray
// Remove existing covers
TagLib::ID3v2::FrameList apiclist = tag->frameListMap()["APIC"];
for (TagLib::ID3v2::FrameList::ConstIterator it = apiclist.begin() ; it != apiclist.end() ; ++it ) {
for (TagLib::ID3v2::FrameList::ConstIterator it = apiclist.begin(); it != apiclist.end(); ++it) {
TagLib::ID3v2::AttachedPictureFrame *frame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(*it);
tag->removeFrame(frame, false);
}
@@ -994,7 +997,7 @@ bool TagReaderTagLib::SaveEmbeddedArt(const QString &filename, const QByteArray
frontcover = new TagLib::ID3v2::AttachedPictureFrame("APIC");
frontcover->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
frontcover->setMimeType("image/jpeg");
frontcover->setPicture(TagLib::ByteVector(data.constData(), data.count()));
frontcover->setPicture(TagLib::ByteVector(data.constData(), data.size()));
tag->addFrame(frontcover);
}
}
@@ -1008,7 +1011,7 @@ bool TagReaderTagLib::SaveEmbeddedArt(const QString &filename, const QByteArray
if (tag->contains("covr")) tag->removeItem("covr");
}
else {
covers.append(TagLib::MP4::CoverArt(TagLib::MP4::CoverArt::JPEG, TagLib::ByteVector(data.constData(), data.count())));
covers.append(TagLib::MP4::CoverArt(TagLib::MP4::CoverArt::JPEG, TagLib::ByteVector(data.constData(), data.size())));
tag->setItem("covr", covers);
}
}
@@ -1038,30 +1041,6 @@ TagLib::ID3v2::PopularimeterFrame *TagReaderTagLib::GetPOPMFrameFromTag(TagLib::
}
float TagReaderTagLib::ConvertPOPMRating(const int POPM_rating) {
if (POPM_rating < 0x01) return 0.0F;
else if (POPM_rating < 0x40) return 0.20F;
else if (POPM_rating < 0x80) return 0.40F;
else if (POPM_rating < 0xC0) return 0.60F;
else if (POPM_rating < 0xFC) return 0.80F;
return 1.0F;
}
int TagReaderTagLib::ConvertToPOPMRating(const float rating) {
if (rating < 0.20) return 0x00;
else if (rating < 0.40) return 0x01;
else if (rating < 0.60) return 0x40;
else if (rating < 0.80) return 0x80;
else if (rating < 1.0) return 0xC0;
return 0xFF;
}
bool TagReaderTagLib::SaveSongPlaycountToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const {
if (filename.isEmpty()) return false;
@@ -1085,14 +1064,14 @@ bool TagReaderTagLib::SaveSongPlaycountToFile(const QString &filename, const spb
TagLib::APE::Tag *tag = wavpack_file->APETag(true);
if (!tag) return false;
if (song.playcount() > 0) {
tag->setItem("FMPS_PlayCount", TagLib::APE::Item("FMPS_PlayCount", TagLib::String::number(static_cast<int>(song.playcount()))));
tag->setItem("FMPS_Playcount", TagLib::APE::Item("FMPS_Playcount", TagLib::String::number(static_cast<int>(song.playcount()))));
}
}
else if (TagLib::APE::File *ape_file = dynamic_cast<TagLib::APE::File*>(fileref->file())) {
TagLib::APE::Tag *tag = ape_file->APETag(true);
if (!tag) return false;
if (song.playcount() > 0) {
tag->setItem("FMPS_PlayCount", TagLib::APE::Item("FMPS_PlayCount", TagLib::String::number(static_cast<int>(song.playcount()))));
tag->setItem("FMPS_Playcount", TagLib::APE::Item("FMPS_Playcount", TagLib::String::number(static_cast<int>(song.playcount()))));
}
}
else if (TagLib::Ogg::XiphComment *xiph_comment = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
@@ -1107,7 +1086,7 @@ bool TagReaderTagLib::SaveSongPlaycountToFile(const QString &filename, const spb
TagLib::ID3v2::Tag *tag = mpeg_file->ID3v2Tag(true);
if (!tag) return false;
if (song.playcount() > 0) {
SetUserTextFrame("FMPS_PlayCount", QString::number(song.playcount()), tag);
SetUserTextFrame("FMPS_Playcount", QString::number(song.playcount()), tag);
TagLib::ID3v2::PopularimeterFrame *frame = GetPOPMFrameFromTag(tag);
if (frame) {
frame->setCounter(song.playcount());
@@ -1126,7 +1105,7 @@ bool TagReaderTagLib::SaveSongPlaycountToFile(const QString &filename, const spb
TagLib::APE::Tag *tag = mpc_file->APETag(true);
if (!tag) return false;
if (song.playcount() > 0) {
tag->setItem("FMPS_PlayCount", TagLib::APE::Item("FMPS_PlayCount", TagLib::String::number(static_cast<int>(song.playcount()))));
tag->setItem("FMPS_Playcount", TagLib::APE::Item("FMPS_Playcount", TagLib::String::number(static_cast<int>(song.playcount()))));
}
}
else if (TagLib::ASF::File *asf_file = dynamic_cast<TagLib::ASF::File*>(fileref->file())) {

View File

@@ -50,7 +50,7 @@ class TagReaderTagLib : public TagReaderBase {
bool IsMediaFile(const QString &filename) const override;
void ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override;
bool ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override;
bool SaveFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
QByteArray LoadEmbeddedArt(const QString &filename) const override;
@@ -59,12 +59,11 @@ class TagReaderTagLib : public TagReaderBase {
bool SaveSongPlaycountToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
bool SaveSongRatingToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
static void Decode(const TagLib::String &tag, std::string *output);
private:
spb::tagreader::SongMetadata_FileType GuessFileType(TagLib::FileRef *fileref) const;
static void Decode(const TagLib::String &tag, std::string *output);
static void Decode(const QString &tag, std::string *output);
void ParseOggTag(const TagLib::Ogg::FieldListMap &map, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const;
void ParseAPETag(const TagLib::APE::ItemListMap &map, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const;
@@ -75,13 +74,11 @@ class TagReaderTagLib : public TagReaderBase {
void SetTextFrame(const char *id, const std::string &value, TagLib::ID3v2::Tag *tag) const;
void SetUserTextFrame(const QString &description, const QString &value, TagLib::ID3v2::Tag *tag) const;
void SetUserTextFrame(const std::string &description, const std::string &value, TagLib::ID3v2::Tag *tag) const;
void SetUnsyncLyricsFrame(const std::string& value, TagLib::ID3v2::Tag* tag) const;
void SetUnsyncLyricsFrame(const std::string &value, TagLib::ID3v2::Tag *tag) const;
QByteArray LoadEmbeddedAPEArt(const TagLib::APE::ItemListMap &map) const;
static float ConvertPOPMRating(const int POPM_rating);
static int ConvertToPOPMRating(const float rating);
static TagLib::ID3v2::PopularimeterFrame *GetPOPMFrameFromTag(TagLib::ID3v2::Tag* tag);
static TagLib::ID3v2::PopularimeterFrame *GetPOPMFrameFromTag(TagLib::ID3v2::Tag *tag);
private:
FileRefFactory *factory_;

View File

@@ -93,25 +93,30 @@ bool TagReaderTagParser::IsMediaFile(const QString &filename) const {
}
void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const {
bool TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const {
qLog(Debug) << "Reading tags from" << filename;
const QFileInfo fileinfo(filename);
if (!fileinfo.exists() || fileinfo.suffix().compare("bak", Qt::CaseInsensitive) == 0) return;
if (!fileinfo.exists() || fileinfo.suffix().compare("bak", Qt::CaseInsensitive) == 0) return false;
const QByteArray url(QUrl::fromLocalFile(filename).toEncoded());
song->set_basefilename(DataCommaSizeFromQString(fileinfo.fileName()));
song->set_url(url.constData(), url.size());
song->set_filesize(fileinfo.size());
song->set_mtime(fileinfo.lastModified().isValid() ? fileinfo.lastModified().toSecsSinceEpoch() : 0);
song->set_mtime(fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
song->set_ctime(fileinfo.birthTime().isValid() ? fileinfo.birthTime().toSecsSinceEpoch() : fileinfo.lastModified().isValid() ? fileinfo.lastModified().toSecsSinceEpoch() : 0);
song->set_ctime(fileinfo.birthTime().isValid() ? std::max(fileinfo.birthTime().toSecsSinceEpoch(), 0LL) : fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL);
#else
song->set_ctime(fileinfo.created().isValid() ? fileinfo.created().toSecsSinceEpoch() : fileinfo.lastModified().isValid() ? fileinfo.lastModified().toSecsSinceEpoch() : 0);
song->set_ctime(fileinfo.created().isValid() ? std::max(fileinfo.created().toSecsSinceEpoch(), 0LL) : fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL);
#endif
if (song->ctime() <= 0) {
song->set_ctime(song->mtime());
}
song->set_lastseen(QDateTime::currentDateTime().toSecsSinceEpoch());
try {
@@ -130,19 +135,19 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
taginfo.parseContainerFormat(diag, progress);
if (progress.isAborted()) {
taginfo.close();
return;
return false;
}
taginfo.parseTracks(diag, progress);
if (progress.isAborted()) {
taginfo.close();
return;
return false;
}
taginfo.parseTags(diag, progress);
if (progress.isAborted()) {
taginfo.close();
return;
return false;
}
for (const TagParser::DiagMessage &msg : diag) {
@@ -151,7 +156,7 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
const auto tracks = taginfo.tracks();
for (const auto track : tracks) {
switch(track->format().general) {
switch (track->format().general) {
case TagParser::GeneralMediaFormat::Flac:
song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_FLAC);
break;
@@ -174,7 +179,7 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_OGGSPEEX);
break;
case TagParser::GeneralMediaFormat::Mpeg1Audio:
switch(track->format().sub) {
switch (track->format().sub) {
case TagParser::SubFormats::Mpeg1Layer3:
song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_MPEG);
break;
@@ -201,7 +206,7 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
if (song->filetype() == spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_UNKNOWN) {
taginfo.close();
return;
return false;
}
for (const auto tag : taginfo.tags()) {
@@ -222,6 +227,10 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
if (!tag->value(TagParser::KnownField::Cover).empty() && tag->value(TagParser::KnownField::Cover).dataSize() > 0) {
song->set_art_automatic(kEmbeddedCover);
}
const float rating = ConvertPOPMRating(tag->value(TagParser::KnownField::Rating));
if (song->rating() <= 0 && rating > 0.0 && rating <= 1.0) {
song->set_rating(rating);
}
}
// Set integer fields to -1 if they're not valid
@@ -238,8 +247,12 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
taginfo.close();
return true;
}
catch(...) {
return false;
}
catch(...) {}
}
@@ -464,7 +477,7 @@ bool TagReaderTagParser::SaveSongRatingToFile(const QString &filename, const spb
}
for (const auto tag : taginfo.tags()) {
tag->setValue(TagParser::KnownField::Rating, TagParser::TagValue(song.rating()));
tag->setValue(TagParser::KnownField::Rating, TagParser::TagValue(ConvertToPOPMRating(song.rating())));
}
taginfo.applyChanges(diag, progress);
taginfo.close();

View File

@@ -39,7 +39,7 @@ class TagReaderTagParser : public TagReaderBase {
bool IsMediaFile(const QString &filename) const override;
void ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override;
bool ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override;
bool SaveFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
QByteArray LoadEmbeddedArt(const QString &filename) const override;

View File

@@ -91,7 +91,7 @@ int main(int argc, char **argv) {
qLog(Error) << "First line" << first_line << "does not match" << filepath;
success = false;
}
QRegularExpression regexp(QStringLiteral("^\\t(.+) \\(compatibility version (\\d+\\.\\d+\\.\\d+), current version (\\d+\\.\\d+\\.\\d+)(, weak)?\\)$"));
QRegularExpression regexp(QStringLiteral("^\\t(.+) \\(compatibility version (\\d+\\.\\d+\\.\\d+), current version (\\d+\\.\\d+\\.\\d+)(, weak|, reexport)?\\)$"));
for (const QString &output_line : output_lines) {
//qDebug() << "Final check on" << filepath << output_line;
@@ -99,7 +99,7 @@ int main(int argc, char **argv) {
QRegularExpressionMatch match = regexp.match(output_line);
if (match.hasMatch()) {
QString library = match.captured(1);
if (QFileInfo(library).fileName() == QFileInfo(filepath).fileName()) { // It's this.
if (QFileInfo(library).fileName() == QFileInfo(filepath).fileName()) { // It's this.
continue;
}
else if (library.startsWith("@executable_path")) {
@@ -113,7 +113,7 @@ int main(int argc, char **argv) {
else if (library.startsWith("@rpath")) {
QString real_path = library;
real_path = real_path.replace("@rpath", bundle_path + "/Contents/Frameworks");
if (!QFile(real_path).exists() && !real_path.endsWith("QtSvg")) { // FIXME: Ignore broken svg image plugin.
if (!QFile(real_path).exists() && !real_path.endsWith("QtSvg")) { // FIXME: Ignore broken svg image plugin.
qLog(Error) << real_path << "does not exist for" << filepath;
success = false;
}
@@ -127,10 +127,7 @@ int main(int argc, char **argv) {
success = false;
}
}
else if (library.startsWith("/System/Library/") || library.startsWith("/usr/lib/")) { // System library
continue;
}
else if (library.endsWith("libgcc_s.1.dylib")) { // fftw points to it for some reason.
else if (library.startsWith("/System/Library/") || library.startsWith("/usr/lib/")) { // System library
continue;
}
else {

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.7)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})

View File

@@ -21,7 +21,7 @@
#include <QtGlobal>
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
#include <sys/time.h>
# include <sys/time.h>
#endif
#include <iostream>

View File

@@ -28,34 +28,17 @@
#include "tagreaderworker.h"
TagReaderWorker::TagReaderWorker(QIODevice *socket, QObject *parent)
: AbstractMessageHandler<spb::tagreader::Message>(socket, parent) {}
: AbstractMessageHandler<spb::tagreader::Message>(socket, parent) {}
void TagReaderWorker::MessageArrived(const spb::tagreader::Message &message) {
spb::tagreader::Message reply;
if (message.has_is_media_file_request()) {
reply.mutable_is_media_file_response()->set_success(tag_reader_.IsMediaFile(QStringFromStdString(message.is_media_file_request().filename())));
}
else if (message.has_read_file_request()) {
tag_reader_.ReadFile(QStringFromStdString(message.read_file_request().filename()), reply.mutable_read_file_response()->mutable_metadata());
}
else if (message.has_save_file_request()) {
reply.mutable_save_file_response()->set_success(tag_reader_.SaveFile(QStringFromStdString(message.save_file_request().filename()), message.save_file_request().metadata()));
}
else if (message.has_load_embedded_art_request()) {
QByteArray data = tag_reader_.LoadEmbeddedArt(QStringFromStdString(message.load_embedded_art_request().filename()));
reply.mutable_load_embedded_art_response()->set_data(data.constData(), data.size());
}
else if (message.has_save_embedded_art_request()) {
reply.mutable_save_embedded_art_response()->set_success(tag_reader_.SaveEmbeddedArt(QStringFromStdString(message.save_embedded_art_request().filename()), QByteArray(message.save_embedded_art_request().data().data(), static_cast<qint64>(message.save_embedded_art_request().data().size()))));
}
else if (message.has_save_song_playcount_to_file_request()) {
reply.mutable_save_song_playcount_to_file_response()->set_success(tag_reader_.SaveSongPlaycountToFile(QStringFromStdString(message.save_song_playcount_to_file_request().filename()), message.save_song_playcount_to_file_request().metadata()));
}
else if (message.has_save_song_rating_to_file_request()) {
reply.mutable_save_song_rating_to_file_response()->set_success(tag_reader_.SaveSongRatingToFile(QStringFromStdString(message.save_song_rating_to_file_request().filename()), message.save_song_rating_to_file_request().metadata()));
bool success = HandleMessage(message, reply, &tag_reader_);
if (!success) {
#if defined(USE_TAGLIB)
HandleMessage(message, reply, &tag_reader_gme_);
#endif
}
SendReply(message, &reply);
@@ -63,7 +46,50 @@ void TagReaderWorker::MessageArrived(const spb::tagreader::Message &message) {
}
void TagReaderWorker::DeviceClosed() {
AbstractMessageHandler<spb::tagreader::Message>::DeviceClosed();
QCoreApplication::exit();
}
bool TagReaderWorker::HandleMessage(const spb::tagreader::Message &message, spb::tagreader::Message &reply, TagReaderBase *reader) {
if (message.has_is_media_file_request()) {
bool success = reader->IsMediaFile(QStringFromStdString(message.is_media_file_request().filename()));
reply.mutable_is_media_file_response()->set_success(success);
return success;
}
else if (message.has_read_file_request()) {
bool success = reader->ReadFile(QStringFromStdString(message.read_file_request().filename()), reply.mutable_read_file_response()->mutable_metadata());
return success;
}
else if (message.has_save_file_request()) {
bool success = reader->SaveFile(QStringFromStdString(message.save_file_request().filename()), message.save_file_request().metadata());
reply.mutable_save_file_response()->set_success(success);
return success;
}
else if (message.has_load_embedded_art_request()) {
QByteArray data = reader->LoadEmbeddedArt(QStringFromStdString(message.load_embedded_art_request().filename()));
reply.mutable_load_embedded_art_response()->set_data(data.constData(), data.size());
return true;
}
else if (message.has_save_embedded_art_request()) {
bool success = reader->SaveEmbeddedArt(QStringFromStdString(message.save_embedded_art_request().filename()), QByteArray(message.save_embedded_art_request().data().data(), static_cast<qint64>(message.save_embedded_art_request().data().size())));
reply.mutable_save_embedded_art_response()->set_success(success);
return success;
}
else if (message.has_save_song_playcount_to_file_request()) {
bool success = reader->SaveSongPlaycountToFile(QStringFromStdString(message.save_song_playcount_to_file_request().filename()), message.save_song_playcount_to_file_request().metadata());
reply.mutable_save_song_playcount_to_file_response()->set_success(success);
return success;
}
else if (message.has_save_song_rating_to_file_request()) {
bool success = reader->SaveSongRatingToFile(QStringFromStdString(message.save_song_rating_to_file_request().filename()), message.save_song_rating_to_file_request().metadata());
reply.mutable_save_song_rating_to_file_response()->set_success(success);
return success;
}
return false;
}

View File

@@ -26,9 +26,11 @@
#include "core/messagehandler.h"
#if defined(USE_TAGLIB)
# include "tagreadertaglib.h"
# include "tagreadergme.h"
#elif defined(USE_TAGPARSER)
# include "tagreadertagparser.h"
#endif
#include "tagreadermessages.pb.h"
class QIODevice;
@@ -44,8 +46,12 @@ class TagReaderWorker : public AbstractMessageHandler<spb::tagreader::Message> {
void DeviceClosed() override;
private:
// Handle message using specific TagReaderBase implementation. Returns true on successful message handle.
bool HandleMessage(const spb::tagreader::Message &message, spb::tagreader::Message &reply, TagReaderBase* reader);
#if defined(USE_TAGLIB)
TagReaderTagLib tag_reader_;
TagReaderGME tag_reader_gme_;
#elif defined(USE_TAGPARSER)
TagReaderTagParser tag_reader_;
#endif

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.7)
if(HAVE_TRANSLATIONS)
include(../cmake/Translations.cmake)
@@ -7,11 +7,11 @@ endif()
set(SOURCES
core/mainwindow.cpp
core/application.cpp
core/appearance.cpp
core/player.cpp
core/commandlineoptions.cpp
core/database.cpp
core/sqlquery.cpp
core/sqlrow.cpp
core/metatypes.cpp
core/deletefiles.cpp
core/filesystemmusicstorage.cpp
@@ -34,14 +34,28 @@ set(SOURCES
core/taskmanager.cpp
core/thread.cpp
core/urlhandler.cpp
core/utilities.cpp
core/imageutils.cpp
core/iconloader.cpp
core/standarditemiconloader.cpp
core/scopedtransaction.cpp
core/translations.cpp
core/systemtrayicon.cpp
utilities/strutils.cpp
utilities/envutils.cpp
utilities/colorutils.cpp
utilities/cryptutils.cpp
utilities/fileutils.cpp
utilities/diskutils.cpp
utilities/imageutils.cpp
utilities/macaddrutils.cpp
utilities/mimeutils.cpp
utilities/randutils.cpp
utilities/threadutils.cpp
utilities/timeutils.cpp
utilities/transliterate.cpp
utilities/xmlutils.cpp
utilities/filemanagerutils.cpp
engine/enginetype.cpp
engine/enginebase.cpp
engine/devicefinders.cpp
@@ -59,8 +73,6 @@ set(SOURCES
context/contextview.cpp
context/contextalbum.cpp
context/contextalbumsmodel.cpp
context/contextalbumsview.cpp
collection/collection.cpp
collection/collectionmodel.cpp
@@ -70,10 +82,11 @@ set(SOURCES
collection/collectionitemdelegate.cpp
collection/collectionviewcontainer.cpp
collection/collectiondirectorymodel.cpp
collection/collectionfilteroptions.cpp
collection/collectionfilterwidget.cpp
collection/collectionplaylistitem.cpp
collection/collectionquery.cpp
collection/sqlrow.cpp
collection/collectionqueryoptions.cpp
collection/savedgroupingmanager.cpp
collection/groupbydialog.cpp
collection/collectiontask.cpp
@@ -164,6 +177,8 @@ set(SOURCES
lyrics/musixmatchlyricsprovider.cpp
lyrics/chartlyricsprovider.cpp
providers/musixmatchprovider.cpp
settings/settingsdialog.cpp
settings/settingspage.cpp
settings/behavioursettingspage.cpp
@@ -188,6 +203,7 @@ set(SOURCES
dialogs/deleteconfirmationdialog.cpp
dialogs/lastfmimportdialog.cpp
dialogs/snapdialog.cpp
dialogs/saveplaylistsdialog.cpp
widgets/autoexpandingtreeview.cpp
widgets/busyindicator.cpp
@@ -204,6 +220,8 @@ set(SOURCES
widgets/multiloadingindicator.cpp
widgets/playingwidget.cpp
widgets/renametablineedit.cpp
widgets/sliderslider.cpp
widgets/prettyslider.cpp
widgets/volumeslider.cpp
widgets/stickyslider.cpp
widgets/stretchheaderview.cpp
@@ -212,6 +230,7 @@ set(SOURCES
widgets/tracksliderslider.cpp
widgets/loginstatewidget.cpp
widgets/ratingwidget.cpp
widgets/resizabletextedit.cpp
osd/osdbase.cpp
osd/osdpretty.cpp
@@ -262,7 +281,6 @@ set(SOURCES
set(HEADERS
core/mainwindow.h
core/application.h
core/appearance.h
core/player.h
core/database.h
core/deletefiles.h
@@ -298,8 +316,6 @@ set(HEADERS
context/contextview.h
context/contextalbum.h
context/contextalbumsmodel.h
context/contextalbumsview.h
collection/collection.h
collection/collectionmodel.h
@@ -420,6 +436,7 @@ set(HEADERS
dialogs/deleteconfirmationdialog.h
dialogs/lastfmimportdialog.h
dialogs/snapdialog.h
dialogs/saveplaylistsdialog.h
widgets/autoexpandingtreeview.h
widgets/busyindicator.h
@@ -435,6 +452,8 @@ set(HEADERS
widgets/multiloadingindicator.h
widgets/playingwidget.h
widgets/renametablineedit.h
widgets/sliderslider.h
widgets/prettyslider.h
widgets/volumeslider.h
widgets/stickyslider.h
widgets/stretchheaderview.h
@@ -544,6 +563,7 @@ set(UI
dialogs/userpassdialog.ui
dialogs/lastfmimportdialog.ui
dialogs/snapdialog.ui
dialogs/saveplaylistsdialog.ui
widgets/trackslider.ui
widgets/fileview.ui
@@ -569,7 +589,7 @@ option(USE_INSTALL_PREFIX "Look for data in CMAKE_INSTALL_PREFIX" ON)
if(NOT APPLE)
set(NOT_APPLE ON)
optional_source(NOT_APPLE SOURCES widgets/qsearchfield_nonmac.cpp core/qtsystemtrayicon.cpp HEADERS core/qtsystemtrayicon.h)
optional_source(NOT_APPLE SOURCES widgets/qsearchfield_qt.cpp core/qtsystemtrayicon.cpp HEADERS core/qtsystemtrayicon.h)
endif()
if(HAVE_GLOBALSHORTCUTS)
@@ -609,43 +629,42 @@ optional_source(HAVE_VLC SOURCES engine/vlcengine.cpp HEADERS engine/vlcengine.h
# DBUS and MPRIS - Unix specific
if(UNIX AND HAVE_DBUS)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dbus)
optional_source(HAVE_DBUS SOURCES core/mpris2.cpp HEADERS core/mpris2.h)
optional_source(HAVE_UDISKS2 SOURCES device/udisks2lister.cpp HEADERS device/udisks2lister.h)
# MPRIS 2.0 DBUS interfaces
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.Player.xml core/mpris2.h mpris::Mpris2 core/mpris2_player Mpris2Player)
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.xml core/mpris2.h mpris::Mpris2 core/mpris2_root Mpris2Root)
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.TrackList.xml core/mpris2.h mpris::Mpris2 core/mpris2_tracklist Mpris2TrackList)
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.Player.xml core/mpris2.h mpris::Mpris2 mpris2_player Mpris2Player)
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.xml core/mpris2.h mpris::Mpris2 mpris2_root Mpris2Root)
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.TrackList.xml core/mpris2.h mpris::Mpris2 mpris2_tracklist Mpris2TrackList)
# MPRIS 2.1 DBUS interfaces
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.Playlists.xml core/mpris2.h mpris::Mpris2 core/mpris2_playlists Mpris2Playlists)
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.Playlists.xml core/mpris2.h mpris::Mpris2 mpris2_playlists Mpris2Playlists)
# org.freedesktop.Notifications DBUS interface
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.Notifications.xml dbus/notification)
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.Notifications.xml notification)
# org.gnome.SettingsDaemon interface
qt_add_dbus_interface(SOURCES dbus/org.gnome.SettingsDaemon.MediaKeys.xml dbus/gnomesettingsdaemon)
qt_add_dbus_interface(SOURCES dbus/org.gnome.SettingsDaemon.MediaKeys.xml gnomesettingsdaemon)
# org.mate.SettingsDaemon interface
qt_add_dbus_interface(SOURCES dbus/org.mate.SettingsDaemon.MediaKeys.xml dbus/matesettingsdaemon)
qt_add_dbus_interface(SOURCES dbus/org.mate.SettingsDaemon.MediaKeys.xml matesettingsdaemon)
# org.kde.KGlobalAccel interface
qt_add_dbus_interface(SOURCES dbus/org.kde.KGlobalAccel.xml dbus/kglobalaccel)
qt_add_dbus_interface(SOURCES dbus/org.kde.KGlobalAccel.Component.xml dbus/kglobalaccelcomponent)
qt_add_dbus_interface(SOURCES dbus/org.kde.KGlobalAccel.xml kglobalaccel)
qt_add_dbus_interface(SOURCES dbus/org.kde.KGlobalAccel.Component.xml kglobalaccelcomponent)
if(HAVE_UDISKS2)
set_source_files_properties(dbus/org.freedesktop.DBus.ObjectManager.xml PROPERTIES NO_NAMESPACE dbus/objectmanager INCLUDE dbus/metatypes.h)
set_source_files_properties(dbus/org.freedesktop.UDisks2.Filesystem.xml PROPERTIES NO_NAMESPACE dbus/udisks2filesystem INCLUDE dbus/metatypes.h)
set_source_files_properties(dbus/org.freedesktop.UDisks2.Block.xml PROPERTIES NO_NAMESPACE dbus/udisks2block INCLUDE dbus/metatypes.h)
set_source_files_properties(dbus/org.freedesktop.UDisks2.Drive.xml PROPERTIES NO_NAMESPACE dbus/udisks2drive INCLUDE dbus/metatypes.h)
set_source_files_properties(dbus/org.freedesktop.UDisks2.Job.xml PROPERTIES NO_NAMESPACE dbus/udisks2job INCLUDE dbus/metatypes.h)
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.DBus.ObjectManager.xml dbus/objectmanager)
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Filesystem.xml dbus/udisks2filesystem)
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Block.xml dbus/udisks2block)
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Drive.xml dbus/udisks2drive)
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Job.xml dbus/udisks2job)
set_source_files_properties(dbus/org.freedesktop.DBus.ObjectManager.xml PROPERTIES NO_NAMESPACE objectmanager INCLUDE dbus/metatypes.h)
set_source_files_properties(dbus/org.freedesktop.UDisks2.Filesystem.xml PROPERTIES NO_NAMESPACE udisks2filesystem INCLUDE dbus/metatypes.h)
set_source_files_properties(dbus/org.freedesktop.UDisks2.Block.xml PROPERTIES NO_NAMESPACE udisks2block INCLUDE dbus/metatypes.h)
set_source_files_properties(dbus/org.freedesktop.UDisks2.Drive.xml PROPERTIES NO_NAMESPACE udisks2drive INCLUDE dbus/metatypes.h)
set_source_files_properties(dbus/org.freedesktop.UDisks2.Job.xml PROPERTIES NO_NAMESPACE udisks2job INCLUDE dbus/metatypes.h)
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.DBus.ObjectManager.xml objectmanager)
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Filesystem.xml udisks2filesystem)
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Block.xml udisks2block)
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Drive.xml udisks2drive)
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Job.xml udisks2job)
endif(HAVE_UDISKS2)
endif(UNIX AND HAVE_DBUS)
@@ -781,8 +800,8 @@ optional_source(HAVE_AUDIOCD
# Platform specific - macOS
optional_source(APPLE
SOURCES
utilities/macosutils.mm
core/scoped_nsautorelease_pool.mm
core/mac_utilities.mm
core/mac_startup.mm
core/macsystemtrayicon.mm
core/macfslistener.mm
@@ -803,8 +822,10 @@ optional_source(APPLE
# Platform specific - Windows
optional_source(WIN32
SOURCES
utilities/winutils.cpp
engine/directsounddevicefinder.cpp
engine/mmdevicefinder.cpp
core/scopedwchararray.cpp
core/windows7thumbbar.cpp
HEADERS
core/windows7thumbbar.h
@@ -943,9 +964,14 @@ link_directories(
${SQLITE_LIBRARY_DIRS}
${SINGLEAPPLICATION_LIBRARY_DIRS}
${SINGLECOREAPPLICATION_LIBRARY_DIRS}
${Iconv_LIBRARY_DIRS}
)
if(HAVE_ICU)
link_directories(${ICU_LIBRARY_DIRS})
else()
link_directories(${Iconv_LIBRARY_DIRS})
endif()
if(HAVE_ALSA)
link_directories(${ALSA_LIBRARY_DIRS})
endif()
@@ -1057,11 +1083,21 @@ target_link_libraries(strawberry_lib PUBLIC
${QT_LIBRARIES}
${SINGLEAPPLICATION_LIBRARIES}
${SINGLECOREAPPLICATION_LIBRARIES}
${Iconv_LIBRARIES}
libstrawberry-common
libstrawberry-tagreader
)
if(HAVE_ICU)
target_include_directories(strawberry_lib SYSTEM PRIVATE ${ICU_INCLUDE_DIRS})
target_link_libraries(strawberry_lib PRIVATE ${ICU_LIBRARIES})
else()
if(FREEBSD AND NOT Iconv_LIBRARIES)
set(Iconv_LIBRARIES iconv)
endif()
target_include_directories(strawberry_lib SYSTEM PRIVATE ${Iconv_INCLUDE_DIRS})
target_link_libraries(strawberry_lib PRIVATE ${Iconv_LIBRARIES})
endif()
if(HAVE_ALSA)
target_include_directories(strawberry_lib SYSTEM PRIVATE ${ALSA_INCLUDE_DIRS})
target_link_libraries(strawberry_lib PRIVATE ${ALSA_LIBRARIES})
@@ -1140,10 +1176,6 @@ if(HAVE_LIBMTP)
target_link_libraries(strawberry_lib PRIVATE ${LIBMTP_LIBRARIES})
endif()
if(FREEBSD)
target_link_libraries(strawberry_lib PRIVATE iconv)
endif()
if(APPLE)
target_link_libraries(strawberry_lib PRIVATE
"-framework AppKit"

View File

@@ -32,10 +32,11 @@
#include <QVector>
#include <QPainter>
#include <QPalette>
#include <QBasicTimer>
#include <QShowEvent>
#include <QHideEvent>
#include <QTimerEvent>
#include <QtEvents>
#include "core/logging.h"
#include "engine/enginebase.h"
// INSTRUCTIONS Base2D
@@ -51,16 +52,38 @@
Analyzer::Base::Base(QWidget *parent, const uint scopeSize)
: QWidget(parent),
timeout_(40),
fht_(new FHT(scopeSize)),
engine_(nullptr),
lastscope_(512),
new_frame_(false),
is_playing_(false) {}
is_playing_(false),
timeout_(40) {
void Analyzer::Base::hideEvent(QHideEvent*) { timer_.stop(); }
setAttribute(Qt::WA_OpaquePaintEvent, true);
void Analyzer::Base::showEvent(QShowEvent*) { timer_.start(timeout(), this); }
}
Analyzer::Base::~Base() {
delete fht_;
}
void Analyzer::Base::showEvent(QShowEvent*) {
timer_.start(timeout(), this);
}
void Analyzer::Base::hideEvent(QHideEvent*) {
timer_.stop();
}
void Analyzer::Base::ChangeTimeout(const int timeout) {
timeout_ = timeout;
if (timer_.isActive()) {
timer_.stop();
timer_.start(timeout_, this);
}
}
void Analyzer::Base::transform(Scope &scope) {
@@ -154,7 +177,7 @@ int Analyzer::Base::resizeForBands(const int bands) {
}
else {
exp = 9;
}
}
resizeExponent(exp);
return fht_->size() / 2;
@@ -186,10 +209,6 @@ void Analyzer::Base::demo(QPainter &p) {
}
void Analyzer::Base::polishEvent() {
init();
}
void Analyzer::interpolate(const Scope &inVec, Scope &outVec) {
double pos = 0.0;

View File

@@ -44,30 +44,24 @@
class QHideEvent;
class QShowEvent;
class QTimerEvent;
class QPaintEvent;
class QTimerEvent;
namespace Analyzer {
typedef std::vector<float> Scope;
using Scope = std::vector<float>;
class Base : public QWidget {
Q_OBJECT
public:
~Base() override { delete fht_; }
~Base() override;
int timeout() const { return timeout_; }
void set_engine(EngineBase *engine) { engine_ = engine; }
void changeTimeout(int newTimeout) {
timeout_ = newTimeout;
if (timer_.isActive()) {
timer_.stop();
timer_.start(timeout_, this);
}
}
void ChangeTimeout(const int timeout);
virtual void framerateChanged() {}
@@ -76,10 +70,8 @@ class Base : public QWidget {
void hideEvent(QHideEvent*) override;
void showEvent(QShowEvent*) override;
void paintEvent(QPaintEvent*) override;
void timerEvent(QTimerEvent*) override;
void polishEvent();
void paintEvent(QPaintEvent *e) override;
void timerEvent(QTimerEvent *e) override;
int resizeExponent(int);
int resizeForBands(const int);
@@ -90,13 +82,13 @@ class Base : public QWidget {
protected:
QBasicTimer timer_;
int timeout_;
FHT *fht_;
EngineBase *engine_;
Scope lastscope_;
bool new_frame_;
bool is_playing_;
int timeout_;
};
void interpolate(const Scope&, Scope&);

View File

@@ -33,7 +33,6 @@
#include <QActionGroup>
#include <QSettings>
#include <QtEvents>
#include <QtDebug>
#include "analyzercontainer.h"
@@ -153,7 +152,7 @@ void AnalyzerContainer::ChangeAnalyzer(const int id) {
current_analyzer_->set_engine(engine_);
// Even if it is not supposed to happen, I don't want to get a dbz error
current_framerate_ = current_framerate_ == 0 ? kMediumFramerate : current_framerate_;
current_analyzer_->changeTimeout(1000 / current_framerate_);
current_analyzer_->ChangeTimeout(1000 / current_framerate_);
layout()->addWidget(current_analyzer_);
@@ -166,7 +165,7 @@ void AnalyzerContainer::ChangeFramerate(int new_framerate) {
if (current_analyzer_) {
// Even if it is not supposed to happen, I don't want to get a dbz error
new_framerate = new_framerate == 0 ? kMediumFramerate : new_framerate;
current_analyzer_->changeTimeout(1000 / new_framerate);
current_analyzer_->ChangeTimeout(1000 / new_framerate);
// notify the current analyzer that the framerate has changed
current_analyzer_->framerateChanged();

View File

@@ -74,7 +74,7 @@ class AnalyzerContainer : public QWidget {
void Load();
void Save();
void SaveFramerate(const int framerate);
template <typename T>
template<typename T>
void AddAnalyzerType();
void AddFramerate(const QString &name, const int framerate);
@@ -96,10 +96,9 @@ class AnalyzerContainer : public QWidget {
Analyzer::Base *current_analyzer_;
EngineBase *engine_;
};
template <typename T>
template<typename T>
void AnalyzerContainer::AddAnalyzerType() {
int id = analyzer_types_.count();

View File

@@ -63,8 +63,7 @@ BlockAnalyzer::BlockAnalyzer(QWidget *parent)
setMaximumWidth(kMaxColumns * (kWidth + 1) - 1);
// mxcl says null pixmaps cause crashes, so let's play it safe
std::fill(fade_bars_.begin(), fade_bars_.end(), QPixmap(1, 1));
std::fill(fade_bars_.begin(), fade_bars_.end(), QPixmap(1, 1));
}
void BlockAnalyzer::resizeEvent(QResizeEvent *e) {
@@ -89,7 +88,7 @@ void BlockAnalyzer::resizeEvent(QResizeEvent *e) {
if (rows_ != oldRows) {
barpixmap_ = QPixmap(kWidth, rows_ * (kHeight + 1));
std::fill(fade_bars_.begin(), fade_bars_.end(), QPixmap(kWidth, rows_ * (kHeight + 1)));
std::fill(fade_bars_.begin(), fade_bars_.end(), QPixmap(kWidth, rows_ * (kHeight + 1)));
yscale_.resize(rows_ + 1);

View File

@@ -65,14 +65,14 @@ class BlockAnalyzer : public Analyzer::Base {
private:
QPixmap *bar() { return &barpixmap_; }
int columns_, rows_; // number of rows and columns of blocks
int y_; // y-offset from top of widget
int columns_, rows_; // number of rows and columns of blocks
int y_; // y-offset from top of widget
QPixmap barpixmap_;
QPixmap topbarpixmap_;
QPixmap background_;
QPixmap canvas_;
Analyzer::Scope scope_; // so we don't create a vector every frame
QVector<double> store_; // current bar heights
Analyzer::Scope scope_; // so we don't create a vector every frame
QVector<double> store_; // current bar heights
QVector<double> yscale_;
QVector<QPixmap> fade_bars_;

View File

@@ -43,12 +43,12 @@
using Analyzer::Scope;
const int Rainbow::RainbowAnalyzer::kHeight[] = {21, 33};
const int Rainbow::RainbowAnalyzer::kWidth[] = {34, 53};
const int Rainbow::RainbowAnalyzer::kFrameCount[] = {6, 16};
const int Rainbow::RainbowAnalyzer::kRainbowHeight[] = {21, 16};
const int Rainbow::RainbowAnalyzer::kRainbowOverlap[] = {13, 15};
const int Rainbow::RainbowAnalyzer::kSleepingHeight[] = {24, 33};
const int Rainbow::RainbowAnalyzer::kHeight[] = { 21, 33 };
const int Rainbow::RainbowAnalyzer::kWidth[] = { 34, 53 };
const int Rainbow::RainbowAnalyzer::kFrameCount[] = { 6, 16 };
const int Rainbow::RainbowAnalyzer::kRainbowHeight[] = { 21, 16 };
const int Rainbow::RainbowAnalyzer::kRainbowOverlap[] = { 13, 15 };
const int Rainbow::RainbowAnalyzer::kSleepingHeight[] = { 24, 33 };
const char *Rainbow::NyanCatAnalyzer::kName = "Nyanalyzer Cat";
const char *Rainbow::RainbowDashAnalyzer::kName = "Rainbow Dash";

View File

@@ -93,7 +93,7 @@ class RainbowAnalyzer : public Analyzer::Base {
private:
// "constants" that get initialized in the constructor
float band_scale_[kRainbowBands]{};
float band_scale_[kRainbowBands] {};
QPen colors_[kRainbowBands];
// Rainbow Nyancat & Dash
@@ -104,7 +104,7 @@ class RainbowAnalyzer : public Analyzer::Base {
int frame_;
// The y positions of each point on the rainbow.
float history_[kHistorySize * kRainbowBands]{};
float history_[kHistorySize * kRainbowBands] {};
// A cache of the last frame's rainbow,
// so it can be used in the next frame.
@@ -142,6 +142,6 @@ class RainbowDashAnalyzer : public RainbowAnalyzer {
static const char *kName;
};
}
} // namespace Rainbow
#endif // RAINBOWANALYZER_H

View File

@@ -27,7 +27,6 @@
#include <QList>
#include <QSettings>
#include <QtConcurrentRun>
#include <QtDebug>
#include "core/application.h"
#include "core/taskmanager.h"
@@ -35,9 +34,9 @@
#include "core/player.h"
#include "core/tagreaderclient.h"
#include "core/thread.h"
#include "core/utilities.h"
#include "core/song.h"
#include "core/logging.h"
#include "utilities/threadutils.h"
#include "collection.h"
#include "collectionwatcher.h"
#include "collectionbackend.h"

View File

@@ -31,7 +31,7 @@
#include <QThread>
#include "core/song.h"
#include "core/utilities.h"
#include "utilities/threadutils.h"
class Application;
class Thread;

View File

@@ -47,11 +47,12 @@
#include "core/database.h"
#include "core/scopedtransaction.h"
#include "core/song.h"
#include "core/sqlrow.h"
#include "smartplaylists/smartplaylistsearch.h"
#include "directory.h"
#include "sqlrow.h"
#include "collectiondirectory.h"
#include "collectionbackend.h"
#include "collectionfilteroptions.h"
#include "collectionquery.h"
#include "collectiontask.h"
@@ -145,12 +146,12 @@ void CollectionBackend::ResetStatisticsAsync(const int id) {
void CollectionBackend::LoadDirectories() {
DirectoryList dirs = GetAllDirectories();
CollectionDirectoryList dirs = GetAllDirectories();
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
for (const Directory &dir : dirs) {
for (const CollectionDirectory &dir : dirs) {
emit DirectoryDiscovered(dir, SubdirsInDirectory(dir.id, db));
}
@@ -207,12 +208,12 @@ void CollectionBackend::ChangeDirPath(const int id, const QString &old_path, con
}
DirectoryList CollectionBackend::GetAllDirectories() {
CollectionDirectoryList CollectionBackend::GetAllDirectories() {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
DirectoryList ret;
CollectionDirectoryList ret;
SqlQuery q(db);
q.prepare(QString("SELECT ROWID, path FROM %1").arg(dirs_table_));
@@ -222,7 +223,7 @@ DirectoryList CollectionBackend::GetAllDirectories() {
}
while (q.next()) {
Directory dir;
CollectionDirectory dir;
dir.id = q.value(0).toInt();
dir.path = q.value(1).toString();
@@ -232,7 +233,7 @@ DirectoryList CollectionBackend::GetAllDirectories() {
}
SubdirectoryList CollectionBackend::SubdirsInDirectory(const int id) {
CollectionSubdirectoryList CollectionBackend::SubdirsInDirectory(const int id) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db = db_->Connect();
@@ -240,19 +241,19 @@ SubdirectoryList CollectionBackend::SubdirsInDirectory(const int id) {
}
SubdirectoryList CollectionBackend::SubdirsInDirectory(const int id, QSqlDatabase &db) {
CollectionSubdirectoryList CollectionBackend::SubdirsInDirectory(const int id, QSqlDatabase &db) {
SqlQuery q(db);
q.prepare(QString("SELECT path, mtime FROM %1 WHERE directory_id = :dir").arg(subdirs_table_));
q.BindValue(":dir", id);
if (!q.Exec()) {
db_->ReportErrors(q);
return SubdirectoryList();
return CollectionSubdirectoryList();
}
SubdirectoryList subdirs;
CollectionSubdirectoryList subdirs;
while (q.next()) {
Subdirectory subdir;
CollectionSubdirectory subdir;
subdir.directory_id = id;
subdir.path = q.value(0).toString();
subdir.mtime = q.value(1).toLongLong();
@@ -335,19 +336,19 @@ void CollectionBackend::AddDirectory(const QString &path) {
q.prepare(QString("INSERT INTO %1 (path, subdirs) VALUES (:path, 1)").arg(dirs_table_));
q.BindValue(":path", db_path);
if (!q.Exec()) {
db_->ReportErrors(q);
return;
db_->ReportErrors(q);
return;
}
Directory dir;
CollectionDirectory dir;
dir.path = canonical_path;
dir.id = q.lastInsertId().toInt();
emit DirectoryDiscovered(dir, SubdirectoryList());
emit DirectoryDiscovered(dir, CollectionSubdirectoryList());
}
void CollectionBackend::RemoveDirectory(const Directory &dir) {
void CollectionBackend::RemoveDirectory(const CollectionDirectory &dir) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
@@ -447,13 +448,13 @@ void CollectionBackend::SongPathChanged(const Song &song, const QFileInfo &new_f
}
void CollectionBackend::AddOrUpdateSubdirs(const SubdirectoryList &subdirs) {
void CollectionBackend::AddOrUpdateSubdirs(const CollectionSubdirectoryList &subdirs) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
ScopedTransaction transaction(&db);
for (const Subdirectory &subdir : subdirs) {
for (const CollectionSubdirectory &subdir : subdirs) {
if (subdir.mtime == 0) {
// Delete the subdirectory
SqlQuery q(db);
@@ -634,15 +635,13 @@ void CollectionBackend::AddOrUpdateSongs(const SongList &songs) {
added_songs << new_song;
continue;
}
}
// Create new song
int id = -1;
{ // Insert the row and create a new ID
{ // Insert the row and create a new ID
SqlQuery q(db);
q.prepare(QString("INSERT INTO %1 (" + Song::kColumnSpec + ") VALUES (" + Song::kBindSpec + ")").arg(songs_table_));
song.BindToQuery(&q);
@@ -656,7 +655,7 @@ void CollectionBackend::AddOrUpdateSongs(const SongList &songs) {
if (id == -1) return;
{ // Add to the FTS index
{ // Add to the FTS index
SqlQuery q(db);
q.prepare(QString("INSERT INTO %1 (ROWID, " + Song::kFtsColumnSpec + ") VALUES (:id, " + Song::kFtsBindSpec + ")").arg(fts_table_));
q.BindValue(":id", id);
@@ -902,12 +901,12 @@ void CollectionBackend::MarkSongsUnavailable(const SongList &songs, const bool u
}
QStringList CollectionBackend::GetAll(const QString &column, const QueryOptions &opt) {
QStringList CollectionBackend::GetAll(const QString &column, const CollectionFilterOptions &filter_options) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
CollectionQuery query(db, songs_table_, fts_table_, opt);
CollectionQuery query(db, songs_table_, fts_table_, filter_options);
query.SetColumnSpec("DISTINCT " + column);
query.AddCompilationRequirement(false);
@@ -924,12 +923,12 @@ QStringList CollectionBackend::GetAll(const QString &column, const QueryOptions
}
QStringList CollectionBackend::GetAllArtists(const QueryOptions &opt) {
QStringList CollectionBackend::GetAllArtists(const CollectionFilterOptions &opt) {
return GetAll("artist", opt);
}
QStringList CollectionBackend::GetAllArtistsWithAlbums(const QueryOptions &opt) {
QStringList CollectionBackend::GetAllArtistsWithAlbums(const CollectionFilterOptions &opt) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
@@ -969,15 +968,15 @@ QStringList CollectionBackend::GetAllArtistsWithAlbums(const QueryOptions &opt)
}
CollectionBackend::AlbumList CollectionBackend::GetAllAlbums(const QueryOptions &opt) {
CollectionBackend::AlbumList CollectionBackend::GetAllAlbums(const CollectionFilterOptions &opt) {
return GetAlbums(QString(), false, opt);
}
CollectionBackend::AlbumList CollectionBackend::GetAlbumsByArtist(const QString &artist, const QueryOptions &opt) {
CollectionBackend::AlbumList CollectionBackend::GetAlbumsByArtist(const QString &artist, const CollectionFilterOptions &opt) {
return GetAlbums(artist, false, opt);
}
SongList CollectionBackend::GetArtistSongs(const QString &effective_albumartist, const QueryOptions &opt) {
SongList CollectionBackend::GetArtistSongs(const QString &effective_albumartist, const CollectionFilterOptions &opt) {
QSqlDatabase db(db_->Connect());
QMutexLocker l(db_->Mutex());
@@ -995,7 +994,7 @@ SongList CollectionBackend::GetArtistSongs(const QString &effective_albumartist,
}
SongList CollectionBackend::GetAlbumSongs(const QString &effective_albumartist, const QString &album, const QueryOptions &opt) {
SongList CollectionBackend::GetAlbumSongs(const QString &effective_albumartist, const QString &album, const CollectionFilterOptions &opt) {
QSqlDatabase db(db_->Connect());
QMutexLocker l(db_->Mutex());
@@ -1014,7 +1013,7 @@ SongList CollectionBackend::GetAlbumSongs(const QString &effective_albumartist,
}
SongList CollectionBackend::GetSongsByAlbum(const QString &album, const QueryOptions &opt) {
SongList CollectionBackend::GetSongsByAlbum(const QString &album, const CollectionFilterOptions &opt) {
QSqlDatabase db(db_->Connect());
QMutexLocker l(db_->Mutex());
@@ -1287,11 +1286,11 @@ SongList CollectionBackend::GetSongsByFingerprint(const QString &fingerprint) {
}
CollectionBackend::AlbumList CollectionBackend::GetCompilationAlbums(const QueryOptions &opt) {
CollectionBackend::AlbumList CollectionBackend::GetCompilationAlbums(const CollectionFilterOptions &opt) {
return GetAlbums(QString(), true, opt);
}
SongList CollectionBackend::GetCompilationSongs(const QString &album, const QueryOptions &opt) {
SongList CollectionBackend::GetCompilationSongs(const QString &album, const CollectionFilterOptions &opt) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
@@ -1316,10 +1315,6 @@ SongList CollectionBackend::GetCompilationSongs(const QString &album, const Quer
}
Song::Source CollectionBackend::Source() const {
return source_;
}
void CollectionBackend::CompilationsNeedUpdating() {
QMutexLocker l(db_->Mutex());
@@ -1345,7 +1340,7 @@ void CollectionBackend::CompilationsNeedUpdating() {
if (album.isEmpty()) continue;
// Find the directory the song is in
QString directory = url.toString(QUrl::PreferLocalFile|QUrl::RemoveFilename);
QString directory = url.toString(QUrl::PreferLocalFile | QUrl::RemoveFilename);
CompilationInfo &info = compilation_info[directory + album];
info.urls << url;
@@ -1432,7 +1427,7 @@ bool CollectionBackend::UpdateCompilations(const QSqlDatabase &db, SongList &del
}
CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist, const bool compilation_required, const QueryOptions &opt) {
CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist, const bool compilation_required, const CollectionFilterOptions &opt) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
@@ -1481,7 +1476,7 @@ CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist,
info.art_manual = QUrl::fromLocalFile(art_manual);
}
info.filetype = Song::FileType(query.Value(6).toInt());
info.filetype = static_cast<Song::FileType>(query.Value(6).toInt());
QString filetype = Song::TextForFiletype(info.filetype);
info.cue_path = query.Value(7).toString();
@@ -1522,7 +1517,7 @@ CollectionBackend::Album CollectionBackend::GetAlbumArt(const QString &effective
ret.album = album;
ret.album_artist = effective_albumartist;
CollectionQuery query(db, songs_table_, fts_table_, QueryOptions());
CollectionQuery query(db, songs_table_, fts_table_);
query.SetColumnSpec("art_automatic, art_manual, url");
if (!effective_albumartist.isEmpty()) {
query.AddWhere("effective_albumartist", effective_albumartist);

View File

@@ -38,8 +38,9 @@
#include "core/song.h"
#include "core/sqlquery.h"
#include "collectionfilteroptions.h"
#include "collectionquery.h"
#include "directory.h"
#include "collectiondirectory.h"
class QThread;
class TaskManager;
@@ -53,7 +54,7 @@ class CollectionBackendInterface : public QObject {
explicit CollectionBackendInterface(QObject *parent = nullptr) : QObject(parent) {}
struct Album {
Album() {}
Album() : filetype(Song::FileType_Unknown) {}
Album(const QString &_album_artist, const QString &_album, const QUrl &_art_automatic, const QUrl &_art_manual, const QList<QUrl> &_urls, const Song::FileType _filetype, const QString &_cue_path)
: album_artist(_album_artist),
album(_album),
@@ -72,11 +73,13 @@ class CollectionBackendInterface : public QObject {
Song::FileType filetype;
QString cue_path;
};
typedef QList<Album> AlbumList;
using AlbumList = QList<Album>;
virtual QString songs_table() const = 0;
virtual QString fts_table() const = 0;
virtual Song::Source source() const = 0;
virtual Database *db() const = 0;
// Get a list of directories in the collection. Emits DirectoriesDiscovered.
@@ -88,23 +91,23 @@ class CollectionBackendInterface : public QObject {
virtual SongList FindSongsInDirectory(const int id) = 0;
virtual SongList SongsWithMissingFingerprint(const int id) = 0;
virtual SubdirectoryList SubdirsInDirectory(const int id) = 0;
virtual DirectoryList GetAllDirectories() = 0;
virtual CollectionSubdirectoryList SubdirsInDirectory(const int id) = 0;
virtual CollectionDirectoryList GetAllDirectories() = 0;
virtual void ChangeDirPath(const int id, const QString &old_path, const QString &new_path) = 0;
virtual SongList GetAllSongs() = 0;
virtual QStringList GetAllArtists(const QueryOptions &opt = QueryOptions()) = 0;
virtual QStringList GetAllArtistsWithAlbums(const QueryOptions &opt = QueryOptions()) = 0;
virtual SongList GetArtistSongs(const QString &effective_albumartist, const QueryOptions &opt = QueryOptions()) = 0;
virtual SongList GetAlbumSongs(const QString &effective_albumartist, const QString &album, const QueryOptions &opt = QueryOptions()) = 0;
virtual SongList GetSongsByAlbum(const QString &album, const QueryOptions &opt = QueryOptions()) = 0;
virtual QStringList GetAllArtists(const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
virtual QStringList GetAllArtistsWithAlbums(const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
virtual SongList GetArtistSongs(const QString &effective_albumartist, const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
virtual SongList GetAlbumSongs(const QString &effective_albumartist, const QString &album, const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
virtual SongList GetSongsByAlbum(const QString &album, const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
virtual SongList GetCompilationSongs(const QString &album, const QueryOptions &opt = QueryOptions()) = 0;
virtual SongList GetCompilationSongs(const QString &album, const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
virtual AlbumList GetAllAlbums(const QueryOptions &opt = QueryOptions()) = 0;
virtual AlbumList GetAlbumsByArtist(const QString &artist, const QueryOptions &opt = QueryOptions()) = 0;
virtual AlbumList GetCompilationAlbums(const QueryOptions &opt = QueryOptions()) = 0;
virtual AlbumList GetAllAlbums(const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
virtual AlbumList GetAlbumsByArtist(const QString &artist, const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
virtual AlbumList GetCompilationAlbums(const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
virtual void UpdateManualAlbumArtAsync(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_automatic = false) = 0;
virtual void UpdateAutomaticAlbumArtAsync(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_manual = false) = 0;
@@ -122,7 +125,7 @@ class CollectionBackendInterface : public QObject {
virtual Song GetSongByUrl(const QUrl &url, const qint64 beginning = 0) = 0;
virtual void AddDirectory(const QString &path) = 0;
virtual void RemoveDirectory(const Directory &dir) = 0;
virtual void RemoveDirectory(const CollectionDirectory &dir) = 0;
};
class CollectionBackend : public CollectionBackendInterface {
@@ -139,6 +142,8 @@ class CollectionBackend : public CollectionBackendInterface {
void ReportErrors(const CollectionQuery &query);
Song::Source source() const override { return source_; }
Database *db() const override { return db_; }
QString songs_table() const override { return songs_table_; }
@@ -155,24 +160,24 @@ class CollectionBackend : public CollectionBackendInterface {
SongList FindSongsInDirectory(const int id) override;
SongList SongsWithMissingFingerprint(const int id) override;
SubdirectoryList SubdirsInDirectory(const int id) override;
DirectoryList GetAllDirectories() override;
CollectionSubdirectoryList SubdirsInDirectory(const int id) override;
CollectionDirectoryList GetAllDirectories() override;
void ChangeDirPath(const int id, const QString &old_path, const QString &new_path) override;
SongList GetAllSongs() override;
QStringList GetAll(const QString &column, const QueryOptions &opt = QueryOptions());
QStringList GetAllArtists(const QueryOptions &opt = QueryOptions()) override;
QStringList GetAllArtistsWithAlbums(const QueryOptions &opt = QueryOptions()) override;
SongList GetArtistSongs(const QString &effective_albumartist, const QueryOptions &opt = QueryOptions()) override;
SongList GetAlbumSongs(const QString &effective_albumartist, const QString &album, const QueryOptions &opt = QueryOptions()) override;
SongList GetSongsByAlbum(const QString &album, const QueryOptions &opt = QueryOptions()) override;
QStringList GetAll(const QString &column, const CollectionFilterOptions &filter_options = CollectionFilterOptions());
QStringList GetAllArtists(const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
QStringList GetAllArtistsWithAlbums(const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
SongList GetArtistSongs(const QString &effective_albumartist, const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
SongList GetAlbumSongs(const QString &effective_albumartist, const QString &album, const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
SongList GetSongsByAlbum(const QString &album, const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
SongList GetCompilationSongs(const QString &album, const QueryOptions &opt = QueryOptions()) override;
SongList GetCompilationSongs(const QString &album, const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
AlbumList GetAllAlbums(const QueryOptions &opt = QueryOptions()) override;
AlbumList GetCompilationAlbums(const QueryOptions &opt = QueryOptions()) override;
AlbumList GetAlbumsByArtist(const QString &artist, const QueryOptions &opt = QueryOptions()) override;
AlbumList GetAllAlbums(const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
AlbumList GetCompilationAlbums(const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
AlbumList GetAlbumsByArtist(const QString &artist, const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
void UpdateManualAlbumArtAsync(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_automatic = false) override;
void UpdateAutomaticAlbumArtAsync(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_manual = false) override;
@@ -188,7 +193,7 @@ class CollectionBackend : public CollectionBackendInterface {
Song GetSongByUrl(const QUrl &url, qint64 beginning = 0) override;
void AddDirectory(const QString &path) override;
void RemoveDirectory(const Directory &dir) override;
void RemoveDirectory(const CollectionDirectory &dir) override;
bool ExecCollectionQuery(CollectionQuery *query, SongList &songs);
bool ExecCollectionQuery(CollectionQuery *query, SongMap &songs);
@@ -207,8 +212,6 @@ class CollectionBackend : public CollectionBackendInterface {
SongList SmartPlaylistsGetAllSongs();
SongList SmartPlaylistsFindSongs(const SmartPlaylistSearch &search);
Song::Source Source() const;
void AddOrUpdateSongsAsync(const SongList &songs);
void UpdateSongsBySongIDAsync(const SongMap &new_songs);
@@ -226,7 +229,7 @@ class CollectionBackend : public CollectionBackendInterface {
void UpdateMTimesOnly(const SongList &songs);
void DeleteSongs(const SongList &songs);
void MarkSongsUnavailable(const SongList &songs, const bool unavailable = true);
void AddOrUpdateSubdirs(const SubdirectoryList &subdirs);
void AddOrUpdateSubdirs(const CollectionSubdirectoryList &subdirs);
void CompilationsNeedUpdating();
void UpdateManualAlbumArt(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_automatic = false);
void UpdateAutomaticAlbumArt(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_manual = false);
@@ -248,8 +251,8 @@ class CollectionBackend : public CollectionBackendInterface {
void ExpireSongs(const int directory_id, const int expire_unavailable_songs_days);
signals:
void DirectoryDiscovered(Directory, SubdirectoryList);
void DirectoryDeleted(Directory);
void DirectoryDiscovered(CollectionDirectory, CollectionSubdirectoryList);
void DirectoryDeleted(CollectionDirectory);
void SongsDiscovered(SongList);
void SongsDeleted(SongList);
@@ -278,9 +281,9 @@ class CollectionBackend : public CollectionBackendInterface {
};
bool UpdateCompilations(const QSqlDatabase &db, SongList &deleted_songs, SongList &added_songs, const QUrl &url, const bool compilation_detected);
AlbumList GetAlbums(const QString &artist, const QString &album_artist, const bool compilation_required = false, const QueryOptions &opt = QueryOptions());
AlbumList GetAlbums(const QString &artist, const bool compilation_required, const QueryOptions &opt = QueryOptions());
SubdirectoryList SubdirsInDirectory(const int id, QSqlDatabase &db);
AlbumList GetAlbums(const QString &artist, const QString &album_artist, const bool compilation_required = false, const CollectionFilterOptions &opt = CollectionFilterOptions());
AlbumList GetAlbums(const QString &artist, const bool compilation_required, const CollectionFilterOptions &opt = CollectionFilterOptions());
CollectionSubdirectoryList SubdirsInDirectory(const int id, QSqlDatabase &db);
Song GetSongById(const int id, QSqlDatabase &db);
SongList GetSongsById(const QStringList &ids, QSqlDatabase &db);

View File

@@ -0,0 +1,57 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* 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 COLLECTIONDIRECTORY_H
#define COLLECTIONDIRECTORY_H
#include "config.h"
#include <QMetaType>
#include <QList>
#include <QString>
struct CollectionDirectory {
CollectionDirectory() : id(-1) {}
bool operator==(const CollectionDirectory &other) const {
return path == other.path && id == other.id;
}
QString path;
int id;
};
Q_DECLARE_METATYPE(CollectionDirectory)
using CollectionDirectoryList = QList<CollectionDirectory>;
Q_DECLARE_METATYPE(CollectionDirectoryList)
struct CollectionSubdirectory {
CollectionSubdirectory() : directory_id(-1), mtime(0) {}
int directory_id;
QString path;
qint64 mtime;
};
Q_DECLARE_METATYPE(CollectionSubdirectory)
using CollectionSubdirectoryList = QList<CollectionSubdirectory>;
Q_DECLARE_METATYPE(CollectionSubdirectoryList)
#endif // COLLECTIONDIRECTORY_H

View File

@@ -29,8 +29,8 @@
#include "core/filesystemmusicstorage.h"
#include "core/iconloader.h"
#include "core/musicstorage.h"
#include "core/utilities.h"
#include "directory.h"
#include "utilities/diskutils.h"
#include "collectiondirectory.h"
#include "collectionbackend.h"
#include "collectiondirectorymodel.h"
@@ -46,17 +46,17 @@ CollectionDirectoryModel::CollectionDirectoryModel(CollectionBackend *backend, Q
CollectionDirectoryModel::~CollectionDirectoryModel() = default;
void CollectionDirectoryModel::DirectoryDiscovered(const Directory &dir) {
void CollectionDirectoryModel::DirectoryDiscovered(const CollectionDirectory &dir) {
QStandardItem *item = new QStandardItem(dir.path);
item->setData(dir.id, kIdRole);
item->setIcon(dir_icon_);
storage_ << std::make_shared<FilesystemMusicStorage>(dir.path, dir.id);
storage_ << std::make_shared<FilesystemMusicStorage>(backend_->source(), dir.path, dir.id);
appendRow(item);
}
void CollectionDirectoryModel::DirectoryDeleted(const Directory &dir) {
void CollectionDirectoryModel::DirectoryDeleted(const CollectionDirectory &dir) {
for (int i = 0; i < rowCount(); ++i) {
if (item(i, 0)->data(kIdRole).toInt() == dir.id) {
@@ -80,7 +80,7 @@ void CollectionDirectoryModel::RemoveDirectory(const QModelIndex &idx) {
if (!backend_ || !idx.isValid()) return;
Directory dir;
CollectionDirectory dir;
dir.path = idx.data().toString();
dir.id = idx.data(kIdRole).toInt();

View File

@@ -34,7 +34,7 @@
class QModelIndex;
struct Directory;
struct CollectionDirectory;
class CollectionBackend;
class MusicStorage;
@@ -53,8 +53,8 @@ class CollectionDirectoryModel : public QStandardItemModel {
private slots:
// To be called by the backend
void DirectoryDiscovered(const Directory &directories);
void DirectoryDeleted(const Directory &directories);
void DirectoryDiscovered(const CollectionDirectory &directories);
void DirectoryDeleted(const CollectionDirectory &directories);
private:
static const int kIdRole = Qt::UserRole + 1;

View File

@@ -0,0 +1,42 @@
/*
* Strawberry Music Player
* Copyright 2023, 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 <QtGlobal>
#include <QDateTime>
#include "core/song.h"
#include "collectionfilteroptions.h"
CollectionFilterOptions::CollectionFilterOptions() : filter_mode_(FilterMode_All), max_age_(-1) {}
bool CollectionFilterOptions::Matches(const Song &song) const {
if (max_age_ != -1) {
const qint64 cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - max_age_;
if (song.ctime() <= cutoff) return false;
}
if (!filter_text_.isNull()) {
return song.artist().contains(filter_text_, Qt::CaseInsensitive) || song.album().contains(filter_text_, Qt::CaseInsensitive) || song.title().contains(filter_text_, Qt::CaseInsensitive);
}
return true;
}

View File

@@ -0,0 +1,65 @@
/*
* Strawberry Music Player
* Copyright 2023, 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 COLLECTIONFILTEROPTIONS_H
#define COLLECTIONFILTEROPTIONS_H
#include <QString>
#include "core/song.h"
class CollectionFilterOptions {
public:
explicit CollectionFilterOptions();
// Filter mode:
// - use the all songs table
// - use the duplicated songs view; by duplicated we mean those songs for which the (artist, album, title) tuple is found more than once in the songs table
// - use the untagged songs view; by untagged we mean those for which at least one of the (artist, album, title) tags is empty
// Please note that additional filtering based on FTS table (the filter attribute) won't work in Duplicates and Untagged modes.
enum FilterMode {
FilterMode_All,
FilterMode_Duplicates,
FilterMode_Untagged
};
FilterMode filter_mode() const { return filter_mode_; }
int max_age() const { return max_age_; }
QString filter_text() const { return filter_text_; }
void set_filter_mode(const FilterMode filter_mode) {
filter_mode_ = filter_mode;
filter_text_.clear();
}
void set_max_age(const int max_age) { max_age_ = max_age; }
void set_filter_text(const QString &filter_text) {
filter_mode_ = FilterMode_All;
filter_text_ = filter_text;
}
bool Matches(const Song &song) const;
private:
FilterMode filter_mode_;
int max_age_;
QString filter_text_;
};
#endif // COLLECTIONFILTEROPTIONS_H

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2019-2022, 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
@@ -45,6 +46,7 @@
#include "core/iconloader.h"
#include "core/song.h"
#include "core/logging.h"
#include "collectionfilteroptions.h"
#include "collectionmodel.h"
#include "collectionquery.h"
#include "savedgroupingmanager.h"
@@ -58,7 +60,12 @@ CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
: QWidget(parent),
ui_(new Ui_CollectionFilterWidget),
model_(nullptr),
group_by_dialog_(new GroupByDialog),
group_by_dialog_(new GroupByDialog(this)),
groupings_manager_(nullptr),
filter_age_menu_(nullptr),
group_by_menu_(nullptr),
collection_menu_(nullptr),
group_by_group_(nullptr),
filter_delay_(new QTimer(this)),
filter_applies_to_model_(true),
delay_behaviour_(DelayedOnLargeLibraries) {
@@ -68,24 +75,23 @@ CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
QString available_fields = Song::kFtsColumns.join(", ").replace(QRegularExpression("\\bfts"), "");
ui_->search_field->setToolTip(
QString("<html><head/><body><p>") +
tr("Prefix a word with a field name to limit the search to that field, e.g.:") +
QString(" ") +
QString("<span style=\"font-weight:600;\">") +
tr("artist") +
QString(":") +
QString("</span><span style=\"font-style:italic;\">Strawbs</span>") +
QString(" ") +
tr("searches the collection for all artists that contain the word") +
QString(" Strawbs.") +
QString("</p><p><span style=\"font-weight:600;\">") +
tr("Available fields") +
QString(": ") +
"</span><span style=\"font-style:italic;\">" +
available_fields +
QString("</span>.") +
QString("</p></body></html>")
);
QString("<html><head/><body><p>") +
tr("Prefix a word with a field name to limit the search to that field, e.g.:") +
QString(" ") +
QString("<span style=\"font-weight:600;\">") +
tr("artist") +
QString(":") +
QString("</span><span style=\"font-style:italic;\">Strawbs</span>") +
QString(" ") +
tr("searches the collection for all artists that contain the word") +
QString(" Strawbs.") +
QString("</p><p><span style=\"font-weight:600;\">") +
tr("Available fields") +
QString(": ") +
"</span><span style=\"font-style:italic;\">" +
available_fields +
QString("</span>.") +
QString("</p></body></html>"));
QObject::connect(ui_->search_field, &QSearchField::returnPressed, this, &CollectionFilterWidget::ReturnPressed);
QObject::connect(filter_delay_, &QTimer::timeout, this, &CollectionFilterWidget::FilterDelayTimeout);
@@ -115,13 +121,8 @@ CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
filter_ages_[ui_->filter_age_three_months] = 60 * 60 * 24 * 30 * 3;
filter_ages_[ui_->filter_age_year] = 60 * 60 * 24 * 365;
// "Group by ..."
group_by_group_ = CreateGroupByActions(this);
group_by_menu_ = new QMenu(tr("Group by"), this);
group_by_menu_->addActions(group_by_group_->actions());
QObject::connect(group_by_group_, &QActionGroup::triggered, this, &CollectionFilterWidget::GroupByClicked);
QObject::connect(ui_->save_grouping, &QAction::triggered, this, &CollectionFilterWidget::SaveGroupBy);
QObject::connect(ui_->manage_groupings, &QAction::triggered, this, &CollectionFilterWidget::ShowGroupingManager);
@@ -148,8 +149,8 @@ void CollectionFilterWidget::Init(CollectionModel *model) {
if (model_) {
QObject::disconnect(model_, nullptr, this, nullptr);
QObject::disconnect(model_, nullptr, group_by_dialog_.get(), nullptr);
QObject::disconnect(group_by_dialog_.get(), nullptr, model_, nullptr);
QObject::disconnect(model_, nullptr, group_by_dialog_, nullptr);
QObject::disconnect(group_by_dialog_, nullptr, model_, nullptr);
QList<QAction*> filter_ages = filter_ages_.keys();
for (QAction *action : filter_ages) {
QObject::disconnect(action, &QAction::triggered, model_, nullptr);
@@ -159,9 +160,9 @@ void CollectionFilterWidget::Init(CollectionModel *model) {
model_ = model;
// Connect signals
QObject::connect(model_, &CollectionModel::GroupingChanged, group_by_dialog_.get(), &GroupByDialog::CollectionGroupingChanged);
QObject::connect(model_, &CollectionModel::GroupingChanged, group_by_dialog_, &GroupByDialog::CollectionGroupingChanged);
QObject::connect(model_, &CollectionModel::GroupingChanged, this, &CollectionFilterWidget::GroupingChanged);
QObject::connect(group_by_dialog_.get(), &GroupByDialog::Accepted, model_, &CollectionModel::SetGroupBy);
QObject::connect(group_by_dialog_, &GroupByDialog::Accepted, model_, &CollectionModel::SetGroupBy);
QList<QAction*> filter_ages = filter_ages_.keys();
for (QAction *action : filter_ages) {
@@ -177,18 +178,33 @@ void CollectionFilterWidget::Init(CollectionModel *model) {
if (s.contains(group_by_version())) version = s.value(group_by_version(), 0).toInt();
if (version == 1) {
model_->SetGroupBy(CollectionModel::Grouping(
CollectionModel::GroupBy(s.value(group_by(1), static_cast<int>(CollectionModel::GroupBy_AlbumArtist)).toInt()),
CollectionModel::GroupBy(s.value(group_by(2), static_cast<int>(CollectionModel::GroupBy_AlbumDisc)).toInt()),
CollectionModel::GroupBy(s.value(group_by(3), static_cast<int>(CollectionModel::GroupBy_None)).toInt())));
CollectionModel::GroupBy(s.value(group_by_key(1), static_cast<int>(CollectionModel::GroupBy_AlbumArtist)).toInt()),
CollectionModel::GroupBy(s.value(group_by_key(2), static_cast<int>(CollectionModel::GroupBy_AlbumDisc)).toInt()),
CollectionModel::GroupBy(s.value(group_by_key(3), static_cast<int>(CollectionModel::GroupBy_None)).toInt())), s.value(separate_albums_by_grouping_key(), false).toBool());
}
else {
model_->SetGroupBy(CollectionModel::Grouping(CollectionModel::GroupBy_AlbumArtist, CollectionModel::GroupBy_AlbumDisc, CollectionModel::GroupBy_None));
model_->SetGroupBy(CollectionModel::Grouping(CollectionModel::GroupBy_AlbumArtist, CollectionModel::GroupBy_AlbumDisc, CollectionModel::GroupBy_None), false);
}
s.endGroup();
}
}
void CollectionFilterWidget::SetSettingsGroup(const QString &settings_group) {
settings_group_ = settings_group;
saved_groupings_settings_group_ = SavedGroupingManager::GetSavedGroupingsSettingsGroup(settings_group);
UpdateGroupByActions();
}
void CollectionFilterWidget::SetSettingsPrefix(const QString &prefix) {
settings_prefix_ = prefix;
}
void CollectionFilterWidget::ReloadSettings() {
QSettings s;
@@ -200,21 +216,10 @@ void CollectionFilterWidget::ReloadSettings() {
}
QString CollectionFilterWidget::group_by() {
QString CollectionFilterWidget::group_by_version() const {
if (settings_prefix_.isEmpty()) {
return QString("group_by");
}
else {
return QString("%1_group_by").arg(settings_prefix_);
}
}
QString CollectionFilterWidget::group_by_version() {
if (settings_prefix_.isEmpty()) {
return QString("group_by_version");
return "group_by_version";
}
else {
return QString("%1_group_by_version").arg(settings_prefix_);
@@ -222,7 +227,29 @@ QString CollectionFilterWidget::group_by_version() {
}
QString CollectionFilterWidget::group_by(const int number) { return group_by() + QString::number(number); }
QString CollectionFilterWidget::group_by_key() const {
if (settings_prefix_.isEmpty()) {
return "group_by";
}
else {
return QString("%1_group_by").arg(settings_prefix_);
}
}
QString CollectionFilterWidget::group_by_key(const int number) const { return group_by_key() + QString::number(number); }
QString CollectionFilterWidget::separate_albums_by_grouping_key() const {
if (settings_prefix_.isEmpty()) {
return "separate_albums_by_grouping";
}
else {
return QString("%1_separate_albums_by_grouping").arg(settings_prefix_);
}
}
void CollectionFilterWidget::UpdateGroupByActions() {
@@ -231,7 +258,7 @@ void CollectionFilterWidget::UpdateGroupByActions() {
delete group_by_group_;
}
group_by_group_ = CreateGroupByActions(this);
group_by_group_ = CreateGroupByActions(saved_groupings_settings_group_, this);
group_by_menu_->clear();
group_by_menu_->addActions(group_by_group_->actions());
QObject::connect(group_by_group_, &QActionGroup::triggered, this, &CollectionFilterWidget::GroupByClicked);
@@ -241,8 +268,7 @@ void CollectionFilterWidget::UpdateGroupByActions() {
}
QActionGroup *CollectionFilterWidget::CreateGroupByActions(QObject *parent) {
QActionGroup *CollectionFilterWidget::CreateGroupByActions(const QString &saved_groupings_settings_group, QObject *parent) {
QActionGroup *ret = new QActionGroup(parent);
@@ -269,9 +295,9 @@ QActionGroup *CollectionFilterWidget::CreateGroupByActions(QObject *parent) {
sep1->setSeparator(true);
ret->addAction(sep1);
// read saved groupings
// Read saved groupings
QSettings s;
s.beginGroup(CollectionModel::kSavedGroupingsSettingsGroup);
s.beginGroup(saved_groupings_settings_group);
int version = s.value("version").toInt();
if (version == 1) {
QStringList saved = s.childKeys();
@@ -318,20 +344,38 @@ QAction *CollectionFilterWidget::CreateGroupByAction(const QString &text, QObjec
void CollectionFilterWidget::SaveGroupBy() {
QString text = QInputDialog::getText(this, tr("Grouping Name"), tr("Grouping name:"));
if (!text.isEmpty() && model_) {
model_->SaveGrouping(text);
UpdateGroupByActions();
if (!model_) return;
QString name = QInputDialog::getText(this, tr("Grouping Name"), tr("Grouping name:"));
if (name.isEmpty()) return;
qLog(Debug) << "Saving current grouping to" << name;
QSettings s;
if (settings_group_.isEmpty() || settings_group_ == CollectionSettingsPage::kSettingsGroup) {
s.beginGroup(SavedGroupingManager::kSavedGroupingsSettingsGroup);
}
else {
s.beginGroup(QString(SavedGroupingManager::kSavedGroupingsSettingsGroup) + "_" + settings_group_);
}
QByteArray buffer;
QDataStream datastream(&buffer, QIODevice::WriteOnly);
datastream << model_->GetGroupBy();
s.setValue("version", "1");
s.setValue(name, buffer);
s.endGroup();
UpdateGroupByActions();
}
void CollectionFilterWidget::ShowGroupingManager() {
if (!groupings_manager_) {
groupings_manager_ = std::make_unique<SavedGroupingManager>();
groupings_manager_ = new SavedGroupingManager(saved_groupings_settings_group_, this);
QObject::connect(groupings_manager_, &SavedGroupingManager::UpdateGroupByActions, this, &CollectionFilterWidget::UpdateGroupByActions);
}
groupings_manager_->SetFilter(this);
groupings_manager_->UpdateModel();
groupings_manager_->show();
@@ -368,16 +412,16 @@ void CollectionFilterWidget::GroupByClicked(QAction *action) {
}
void CollectionFilterWidget::GroupingChanged(const CollectionModel::Grouping g) {
void CollectionFilterWidget::GroupingChanged(const CollectionModel::Grouping g, const bool separate_albums_by_grouping) {
if (!settings_group_.isEmpty()) {
// Save the settings
QSettings s;
s.beginGroup(settings_group_);
s.setValue(group_by_version(), 1);
s.setValue(group_by(1), static_cast<int>(g[0]));
s.setValue(group_by(2), static_cast<int>(g[1]));
s.setValue(group_by(3), static_cast<int>(g[2]));
s.setValue(group_by_key(1), static_cast<int>(g[0]));
s.setValue(group_by_key(2), static_cast<int>(g[1]));
s.setValue(group_by_key(3), static_cast<int>(g[2]));
s.setValue(separate_albums_by_grouping_key(), separate_albums_by_grouping);
s.endGroup();
}
@@ -388,6 +432,10 @@ void CollectionFilterWidget::GroupingChanged(const CollectionModel::Grouping g)
void CollectionFilterWidget::CheckCurrentGrouping(const CollectionModel::Grouping g) {
if (!group_by_group_) {
UpdateGroupByActions();
}
for (QAction *action : group_by_group_->actions()) {
if (action->property("group_by").isNull()) continue;
@@ -408,12 +456,12 @@ void CollectionFilterWidget::SetFilterHint(const QString &hint) {
ui_->search_field->setPlaceholderText(hint);
}
void CollectionFilterWidget::SetQueryMode(QueryOptions::QueryMode query_mode) {
void CollectionFilterWidget::SetFilterMode(CollectionFilterOptions::FilterMode filter_mode) {
ui_->search_field->clear();
ui_->search_field->setEnabled(query_mode == QueryOptions::QueryMode_All);
ui_->search_field->setEnabled(filter_mode == CollectionFilterOptions::FilterMode_All);
model_->SetFilterQueryMode(query_mode);
model_->SetFilterMode(filter_mode);
}

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2019-2022, 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
@@ -31,6 +32,7 @@
#include <QString>
#include "collectionquery.h"
#include "collectionqueryoptions.h"
#include "collectionmodel.h"
class QTimer;
@@ -60,9 +62,8 @@ class CollectionFilterWidget : public QWidget {
void Init(CollectionModel *model);
static QActionGroup *CreateGroupByActions(QObject *parent);
static QActionGroup *CreateGroupByActions(const QString &saved_groupings_settings_group, QObject *parent);
void UpdateGroupByActions();
void SetFilterHint(const QString &hint);
void SetApplyFilterToCollection(bool filter_applies_to_model) { filter_applies_to_model_ = filter_applies_to_model; }
void SetDelayBehaviour(DelayBehaviour behaviour) { delay_behaviour_ = behaviour; }
@@ -73,12 +74,13 @@ class CollectionFilterWidget : public QWidget {
QMenu *menu() const { return collection_menu_; }
void AddMenuAction(QAction *action);
void SetSettingsGroup(const QString &group) { settings_group_ = group; }
void SetSettingsPrefix(const QString &prefix) { settings_prefix_ = prefix; }
void SetSettingsGroup(const QString &group);
void SetSettingsPrefix(const QString &prefix);
QString group_by();
QString group_by_version();
QString group_by(const int number);
QString group_by_version() const;
QString group_by_key() const;
QString group_by_key(const int number) const;
QString separate_albums_by_grouping_key() const;
void ReloadSettings();
@@ -86,7 +88,8 @@ class CollectionFilterWidget : public QWidget {
void FocusSearchField();
public slots:
void SetQueryMode(QueryOptions::QueryMode query_mode);
void UpdateGroupByActions();
void SetFilterMode(CollectionFilterOptions::FilterMode filter_mode);
void FocusOnFilter(QKeyEvent *e);
signals:
@@ -99,7 +102,7 @@ class CollectionFilterWidget : public QWidget {
void keyReleaseEvent(QKeyEvent *e) override;
private slots:
void GroupingChanged(const CollectionModel::Grouping g);
void GroupingChanged(const CollectionModel::Grouping g, const bool separate_albums_by_grouping);
void GroupByClicked(QAction *action);
void SaveGroupBy();
void ShowGroupingManager();
@@ -115,8 +118,8 @@ class CollectionFilterWidget : public QWidget {
Ui_CollectionFilterWidget *ui_;
CollectionModel *model_;
std::unique_ptr<GroupByDialog> group_by_dialog_;
std::unique_ptr<SavedGroupingManager> groupings_manager_;
GroupByDialog *group_by_dialog_;
SavedGroupingManager *groupings_manager_;
QMenu *filter_age_menu_;
QMenu *group_by_menu_;
@@ -130,6 +133,7 @@ class CollectionFilterWidget : public QWidget {
DelayBehaviour delay_behaviour_;
QString settings_group_;
QString saved_groupings_settings_group_;
QString settings_prefix_;
};

View File

@@ -100,7 +100,7 @@ void CollectionItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem
// Draw the line under the item
QColor line_color = opt.palette.color(QPalette::Text);
QLinearGradient grad_color(opt.rect.bottomLeft(), opt.rect.bottomRight());
const double fade_start_end = (opt.rect.width()/3.0)/opt.rect.width();
const double fade_start_end = (opt.rect.width() / 3.0) / opt.rect.width();
line_color.setAlphaF(0.0);
grad_color.setColorAt(0, line_color);
line_color.setAlphaF(0.5);

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,8 @@
#include "config.h"
#include <optional>
#include <QtGlobal>
#include <QObject>
#include <QAbstractItemModel>
@@ -45,10 +47,12 @@
#include "core/simpletreemodel.h"
#include "core/song.h"
#include "core/sqlrow.h"
#include "covermanager/albumcoverloader.h"
#include "collectionfilteroptions.h"
#include "collectionquery.h"
#include "collectionqueryoptions.h"
#include "collectionitem.h"
#include "sqlrow.h"
#include "covermanager/albumcoverloaderoptions.h"
class QSettings;
@@ -64,8 +68,6 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
explicit CollectionModel(CollectionBackend *backend, Application *app, QObject *parent = nullptr);
~CollectionModel() override;
static const char *kSavedGroupingsSettingsGroup;
static const int kPrettyCoverSize;
static const char *kPixmapDiskCacheDir;
@@ -160,9 +162,6 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
// Whether or not to show letters heading in the collection view
void set_show_dividers(const bool show_dividers);
// Save the current grouping
void SaveGrouping(const QString &name);
// Reload settings.
void ReloadSettings();
@@ -195,20 +194,20 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
void ExpandAll(CollectionItem *item = nullptr) const;
const CollectionModel::Grouping GetGroupBy() const { return group_by_; }
void SetGroupBy(const CollectionModel::Grouping g);
void SetGroupBy(const CollectionModel::Grouping g, const std::optional<bool> separate_albums_by_grouping = std::optional<bool>());
static QString ContainerKey(const GroupBy type, const Song &song);
static QString ContainerKey(const GroupBy group_by, const bool separate_albums_by_grouping, const Song &song);
signals:
void TotalSongCountUpdated(int count);
void TotalArtistCountUpdated(int count);
void TotalAlbumCountUpdated(int count);
void GroupingChanged(CollectionModel::Grouping g);
void GroupingChanged(CollectionModel::Grouping g, bool separate_albums_by_grouping);
public slots:
void SetFilterAge(const int age);
void SetFilterText(const QString &text);
void SetFilterQueryMode(QueryOptions::QueryMode query_mode);
void SetFilterMode(CollectionFilterOptions::FilterMode filter_mode);
void SetFilterAge(const int filter_age);
void SetFilterText(const QString &filter_text);
void Init(const bool async = true);
void Reset();
@@ -235,34 +234,35 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result);
private:
// Provides some optimisations for loading the list of items in the root.
// Provides some optimizations for loading the list of items in the root.
// This gets called a lot when filtering the playlist, so it's nice to be able to do it in a background thread.
QueryResult RunQuery(CollectionItem *parent);
CollectionQueryOptions PrepareQuery(CollectionItem *parent);
QueryResult RunQuery(const CollectionFilterOptions &filter_options = CollectionFilterOptions(), const CollectionQueryOptions &query_options = CollectionQueryOptions());
void PostQuery(CollectionItem *parent, const QueryResult &result, const bool signal);
bool HasCompilations(const QSqlDatabase &db, const CollectionQuery &query);
bool HasCompilations(const QSqlDatabase &db, const CollectionFilterOptions &filter_options, const CollectionQueryOptions &query_options);
void BeginReset();
// Functions for working with queries and creating items.
// When the model is reset or when a node is lazy-loaded the Collection constructs a database query to populate the items.
// Filters are added for each parent item, restricting the songs returned to a particular album or artist for example.
static void InitQuery(const GroupBy type, CollectionQuery *q);
static void FilterQuery(const GroupBy type, CollectionItem *item, CollectionQuery *q);
static void SetQueryColumnSpec(const GroupBy group_by, const bool separate_albums_by_grouping, CollectionQueryOptions *query_options);
static void AddQueryWhere(const GroupBy group_by, const bool separate_albums_by_grouping, CollectionItem *item, CollectionQueryOptions *query_options);
// Items can be created either from a query that's been run to populate a node, or by a spontaneous SongsDiscovered emission from the backend.
CollectionItem *ItemFromQuery(const GroupBy type, const bool signal, const bool create_divider, CollectionItem *parent, const SqlRow &row, const int container_level);
CollectionItem *ItemFromSong(const GroupBy type, const bool signal, const bool create_divider, CollectionItem *parent, const Song &s, const int container_level);
CollectionItem *ItemFromQuery(const GroupBy group_by, const bool separate_albums_by_grouping, const bool signal, const bool create_divider, CollectionItem *parent, const SqlRow &row, const int container_level);
CollectionItem *ItemFromSong(const GroupBy group_by, const bool separate_albums_by_grouping, const bool signal, const bool create_divider, CollectionItem *parent, const Song &s, const int container_level);
// The "Various Artists" node is an annoying special case.
CollectionItem *CreateCompilationArtistNode(const bool signal, CollectionItem *parent);
// Helpers for ItemFromQuery and ItemFromSong
CollectionItem *InitItem(const GroupBy type, const bool signal, CollectionItem *parent, const int container_level);
void FinishItem(const GroupBy type, const bool signal, const bool create_divider, CollectionItem *parent, CollectionItem *item);
CollectionItem *InitItem(const GroupBy group_by, const bool signal, CollectionItem *parent, const int container_level);
void FinishItem(const GroupBy group_by, const bool signal, const bool create_divider, CollectionItem *parent, CollectionItem *item);
static QString DividerKey(const GroupBy type, CollectionItem *item);
static QString DividerDisplayText(const GroupBy type, const QString &key);
static QString DividerKey(const GroupBy group_by, CollectionItem *item);
static QString DividerDisplayText(const GroupBy group_by, const QString &key);
// Helpers
static bool IsCompilationArtistNode(const CollectionItem *node) { return node == node->parent->compilation_artist_node_; }
@@ -282,8 +282,9 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
int total_artist_count_;
int total_album_count_;
QueryOptions query_options_;
CollectionFilterOptions filter_options_;
Grouping group_by_;
bool separate_albums_by_grouping_;
// Keyed on database ID
QMap<int, CollectionItem*> song_nodes_;
@@ -310,7 +311,7 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
AlbumCoverLoaderOptions cover_loader_options_;
typedef QPair<CollectionItem*, QString> ItemAndCacheKey;
using ItemAndCacheKey = QPair<CollectionItem*, QString>;
QMap<quint64, ItemAndCacheKey> pending_art_;
QSet<QString> pending_cache_keys_;
};

View File

@@ -31,16 +31,16 @@
#include <QRegularExpression>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include "core/logging.h"
#include "core/sqlquery.h"
#include "core/song.h"
#include "collectionquery.h"
#include "collectionfilteroptions.h"
#include "collectionqueryoptions.h"
QueryOptions::QueryOptions() : max_age_(-1), query_mode_(QueryMode_All) {}
CollectionQuery::CollectionQuery(const QSqlDatabase &db, const QString &songs_table, const QString &fts_table, const QueryOptions &options)
CollectionQuery::CollectionQuery(const QSqlDatabase &db, const QString &songs_table, const QString &fts_table, const CollectionFilterOptions &filter_options)
: QSqlQuery(db),
songs_table_(songs_table),
fts_table_(fts_table),
@@ -49,7 +49,7 @@ CollectionQuery::CollectionQuery(const QSqlDatabase &db, const QString &songs_ta
duplicates_only_(false),
limit_(-1) {
if (!options.filter().isEmpty()) {
if (!filter_options.filter_text().isEmpty()) {
// We need to munge the filter text a little bit to get it to work as expected with sqlite's FTS5:
// 1) Append * to all tokens.
// 2) Prefix "fts" to column names.
@@ -57,9 +57,9 @@ CollectionQuery::CollectionQuery(const QSqlDatabase &db, const QString &songs_ta
// Split on whitespace
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QStringList tokens(options.filter().split(QRegularExpression("\\s+"), Qt::SkipEmptyParts));
QStringList tokens(filter_options.filter_text().split(QRegularExpression("\\s+"), Qt::SkipEmptyParts));
#else
QStringList tokens(options.filter().split(QRegularExpression("\\s+"), QString::SkipEmptyParts));
QStringList tokens(filter_options.filter_text().split(QRegularExpression("\\s+"), QString::SkipEmptyParts));
#endif
QString query;
for (QString token : tokens) {
@@ -100,49 +100,40 @@ CollectionQuery::CollectionQuery(const QSqlDatabase &db, const QString &songs_ta
}
}
if (options.max_age() != -1) {
qint64 cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - options.max_age();
if (filter_options.max_age() != -1) {
qint64 cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - filter_options.max_age();
where_clauses_ << "ctime > ?";
bound_values_ << cutoff;
}
// TODO: Currently you cannot use any QueryMode other than All and FTS at the same time.
// TODO: Currently you cannot use any FilterMode other than All and FTS at the same time.
// Joining songs, duplicated_songs and songs_fts all together takes a huge amount of time.
// The query takes about 20 seconds on my machine then. Why?
// Untagged mode could work with additional filtering but I'm disabling it just to be consistent
// this way filtering is available only in the All mode.
// Remember though that when you fix the Duplicates + FTS cooperation, enable the filtering in both Duplicates and Untagged modes.
duplicates_only_ = options.query_mode() == QueryOptions::QueryMode_Duplicates;
duplicates_only_ = filter_options.filter_mode() == CollectionFilterOptions::FilterMode_Duplicates;
if (options.query_mode() == QueryOptions::QueryMode_Untagged) {
if (filter_options.filter_mode() == CollectionFilterOptions::FilterMode_Untagged) {
where_clauses_ << "(artist = '' OR album = '' OR title ='')";
}
}
QString CollectionQuery::GetInnerQuery() const {
return duplicates_only_
? QString(" INNER JOIN (select * from duplicated_songs) dsongs "
"ON (%songs_table.artist = dsongs.dup_artist "
"AND %songs_table.album = dsongs.dup_album "
"AND %songs_table.title = dsongs.dup_title) ")
: QString();
}
void CollectionQuery::AddWhere(const QString &column, const QVariant &value, const QString &op) {
// Ignore 'literal' for IN
if (op.compare("IN", Qt::CaseInsensitive) == 0) {
QStringList values = value.toStringList();
QStringList final;
final.reserve(values.count());
QStringList final_values;
final_values.reserve(values.count());
for (const QString &single_value : values) {
final.append("?");
final_values.append("?");
bound_values_ << single_value;
}
where_clauses_ << QString("%1 IN (" + final.join(",") + ")").arg(column);
where_clauses_ << QString("%1 IN (" + final_values.join(",") + ")").arg(column);
}
else {
// Do integers inline - sqlite seems to get confused when you pass integers to bound parameters
@@ -155,11 +146,11 @@ void CollectionQuery::AddWhere(const QString &column, const QVariant &value, con
}
else if (
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
value.metaType().id() == QMetaType::QString
value.metaType().id() == QMetaType::QString
#else
value.type() == QVariant::String
value.type() == QVariant::String
#endif
&& value.toString().isNull()) {
&& value.toString().isNull()) {
where_clauses_ << QString("%1 %2 ?").arg(column, op);
bound_values_ << QString("");
}
@@ -187,6 +178,15 @@ void CollectionQuery::AddCompilationRequirement(const bool compilation) {
}
QString CollectionQuery::GetInnerQuery() const {
return duplicates_only_
? QString(" INNER JOIN (select * from duplicated_songs) dsongs "
"ON (%songs_table.artist = dsongs.dup_artist "
"AND %songs_table.album = dsongs.dup_album "
"AND %songs_table.title = dsongs.dup_title) ")
: QString();
}
bool CollectionQuery::Exec() {
QString sql;
@@ -213,32 +213,17 @@ bool CollectionQuery::Exec() {
sql.replace("%fts_table_noprefix", fts_table_.section('.', -1, -1));
sql.replace("%fts_table", fts_table_);
prepare(sql);
QSqlQuery::prepare(sql);
// Bind values
for (const QVariant &value : bound_values_) {
addBindValue(value);
QSqlQuery::addBindValue(value);
}
return exec();
return QSqlQuery::exec();
}
bool CollectionQuery::Next() { return next(); }
bool CollectionQuery::Next() { return QSqlQuery::next(); }
QVariant CollectionQuery::Value(const int column) const { return value(column); }
bool QueryOptions::Matches(const Song &song) const {
if (max_age_ != -1) {
const qint64 cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - max_age_;
if (song.ctime() <= cutoff) return false;
}
if (!filter_.isNull()) {
return song.artist().contains(filter_, Qt::CaseInsensitive) || song.album().contains(filter_, Qt::CaseInsensitive) || song.title().contains(filter_, Qt::CaseInsensitive);
}
return true;
}
QVariant CollectionQuery::Value(const int column) const { return QSqlQuery::value(column); }

View File

@@ -28,75 +28,23 @@
#include <QVariant>
#include <QString>
#include <QStringList>
#include <QMap>
#include <QSqlDatabase>
#include <QSqlQuery>
class Song;
// This structure let's you customize behaviour of any CollectionQuery.
struct QueryOptions {
// Modes of CollectionQuery:
// - use the all songs table
// - use the duplicated songs view; by duplicated we mean those songs for which the (artist, album, title) tuple is found more than once in the songs table
// - use the untagged songs view; by untagged we mean those for which at least one of the (artist, album, title) tags is empty
// Please note that additional filtering based on FTS table (the filter attribute) won't work in Duplicates and Untagged modes.
enum QueryMode {
QueryMode_All,
QueryMode_Duplicates,
QueryMode_Untagged
};
QueryOptions();
bool Matches(const Song &song) const;
QString filter() const { return filter_; }
void set_filter(const QString &filter) {
filter_ = filter;
query_mode_ = QueryMode_All;
}
int max_age() const { return max_age_; }
void set_max_age(int max_age) { max_age_ = max_age; }
QueryMode query_mode() const { return query_mode_; }
void set_query_mode(QueryMode query_mode) {
query_mode_ = query_mode;
filter_ = QString();
}
private:
QString filter_;
int max_age_;
QueryMode query_mode_;
};
#include "collectionfilteroptions.h"
#include "collectionqueryoptions.h"
class CollectionQuery : public QSqlQuery {
public:
explicit CollectionQuery(const QSqlDatabase &db, const QString &songs_table, const QString &fts_table, const QueryOptions &options = QueryOptions());
explicit CollectionQuery(const QSqlDatabase &db, const QString &songs_table, const QString &fts_table, const CollectionFilterOptions &filter_options = CollectionFilterOptions());
// Sets contents of SELECT clause on the query (list of columns to get).
void SetColumnSpec(const QString &spec) { column_spec_ = spec; }
// Sets an ORDER BY clause on the query.
void SetOrderBy(const QString &order_by) { order_by_ = order_by; }
// Adds a fragment of WHERE clause. When executed, this Query will connect all the fragments with AND operator.
// Please note that IN operator expects a QStringList as value.
void AddWhere(const QString &column, const QVariant &value, const QString &op = "=");
void AddWhereArtist(const QVariant &value);
void SetWhereClauses(const QStringList &where_clauses) { where_clauses_ = where_clauses; }
void SetBoundValues(const QVariantList &bound_values) { bound_values_ = bound_values; }
void SetDuplicatesOnly(const bool duplicates_only) { duplicates_only_ = duplicates_only; }
void SetIncludeUnavailable(const bool include_unavailable) { include_unavailable_ = include_unavailable; }
void SetLimit(const int limit) { limit_ = limit; }
void AddCompilationRequirement(const bool compilation);
QVariant Value(const int column) const;
QVariant value(const int column) const { return Value(column); }
bool Exec();
bool exec() { return QSqlQuery::exec(); }
bool Next();
QVariant Value(const int column) const;
QString column_spec() const { return column_spec_; }
QString order_by() const { return order_by_; }
@@ -107,6 +55,24 @@ class CollectionQuery : public QSqlQuery {
bool duplicates_only() const { return duplicates_only_; }
int limit() const { return limit_; }
// Sets contents of SELECT clause on the query (list of columns to get).
void SetColumnSpec(const QString &column_spec) { column_spec_ = column_spec; }
// Sets an ORDER BY clause on the query.
void SetOrderBy(const QString &order_by) { order_by_ = order_by; }
void SetWhereClauses(const QStringList &where_clauses) { where_clauses_ = where_clauses; }
// Adds a fragment of WHERE clause. When executed, this Query will connect all the fragments with AND operator.
// Please note that IN operator expects a QStringList as value.
void AddWhere(const QString &column, const QVariant &value, const QString &op = "=");
void AddWhereArtist(const QVariant &value);
void SetBoundValues(const QVariantList &bound_values) { bound_values_ = bound_values; }
void SetDuplicatesOnly(const bool duplicates_only) { duplicates_only_ = duplicates_only; }
void SetIncludeUnavailable(const bool include_unavailable) { include_unavailable_ = include_unavailable; }
void SetLimit(const int limit) { limit_ = limit; }
void AddCompilationRequirement(const bool compilation);
private:
QString GetInnerQuery() const;
@@ -125,4 +91,4 @@ class CollectionQuery : public QSqlQuery {
int limit_;
};
#endif // COLLECTIONQUERY_H
#endif // COLLECTIONQUERY_H

View File

@@ -0,0 +1,34 @@
/*
* Strawberry Music Player
* Copyright 2023, 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 <QVariant>
#include <QString>
#include "collectionqueryoptions.h"
#include "collectionfilteroptions.h"
CollectionQueryOptions::CollectionQueryOptions()
: compilation_requirement_(false),
query_have_compilations_(false) {}
void CollectionQueryOptions::AddWhere(const QString &column, const QVariant &value, const QString &op) {
where_clauses_ << Where(column, value, op);
}

View File

@@ -0,0 +1,57 @@
/*
* Strawberry Music Player
* Copyright 2023, 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 COLLECTIONQUERYOPTIONS_H
#define COLLECTIONQUERYOPTIONS_H
#include <QList>
#include <QVariant>
#include <QString>
class CollectionQueryOptions {
public:
explicit CollectionQueryOptions();
struct Where {
explicit Where(const QString _column = QString(), const QVariant _value = QString(), const QString _op = QString()) : column(_column), value(_value), op(_op) {}
QString column;
QVariant value;
QString op;
};
QString column_spec() const { return column_spec_; }
bool compilation_requirement() const { return compilation_requirement_; }
bool query_have_compilations() const { return query_have_compilations_; }
void set_column_spec(const QString &column_spec) { column_spec_ = column_spec; }
void set_compilation_requirement(const bool compilation_requirement) { compilation_requirement_ = compilation_requirement; }
void set_query_have_compilations(const bool query_have_compilations) { query_have_compilations_ = query_have_compilations; }
QList<Where> where_clauses() const { return where_clauses_; }
void AddWhere(const QString &column, const QVariant &value, const QString &op = "=");
private:
QString column_spec_;
bool compilation_requirement_;
bool query_have_compilations_;
QList<Where> where_clauses_;
};
#endif // COLLECTIONQUERYOPTIONS_H

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