Compare commits

...

214 Commits
1.0.4 ... 1.0.8

Author SHA1 Message Date
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
432 changed files with 26982 additions and 27498 deletions

View File

@@ -7,14 +7,12 @@ assignees: ''
---
See the FAQ before opening an issue: https://wiki.strawberrymusicplayer.org/wiki/FAQ
Check the Changelog to see if the issue is already fixed: https://github.com/strawberrymusicplayer/strawberry/blob/master/Changelog
If it's already fixed, try the latest development build from: https://builds.strawberrymusicplayer.org/
For technical issues, questions and discussion please use the forum on https://forum.strawberrymusicplayer.org/
Any issues related to feature requests will be closed. See the README for more details.
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/
**Describe the bug**
A clear and concise description of what the bug is.

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

@@ -1228,13 +1228,15 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
}
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();
qFatal("Missing GIO modules.");
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)) {
@@ -1243,6 +1245,11 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
}
}
if (!have_giomodule) {
qFatal("Missing GIO modules.");
}
}
// gst-plugin-scanner
@@ -1270,6 +1277,7 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
// GStreamer plugins.
QStringList gstreamer_plugins = QStringList()
<< "libgstaes.dylib"
<< "libgstaiff.dylib"
<< "libgstapetag.dylib"
<< "libgstapp.dylib"
@@ -1288,13 +1296,16 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
<< "libgstcoreelements.dylib"
<< "libgstdash.dylib"
<< "libgstequalizer.dylib"
<< "libgstflac.dylib"
<< "libgstfaac.dylib"
<< "libgstfaad.dylib"
<< "libgstfdkaac.dylib"
<< "libgstflac.dylib"
<< "libgstgio.dylib"
<< "libgstgme.dylib"
<< "libgsthls.dylib"
<< "libgsticydemux.dylib"
<< "libgstid3demux.dylib"
<< "libgstid3tag.dylib"
<< "libgstisomp4.dylib"
<< "libgstlame.dylib"
<< "libgstlibav.dylib"
@@ -1315,10 +1326,12 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
<< "libgstspeex.dylib"
<< "libgsttaglib.dylib"
<< "libgsttcp.dylib"
<< "libgsttwolame.dylib"
<< "libgsttypefindfunctions.dylib"
<< "libgstudp.dylib"
<< "libgstvolume.dylib"
<< "libgstvorbis.dylib"
<< "libgstwavenc.dylib"
<< "libgstwavpack.dylib"
<< "libgstwavparse.dylib"
<< "libgstxingmux.dylib";
@@ -1336,13 +1349,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();
@@ -1354,6 +1370,10 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
}
}
if (!missing_gst_plugins.isEmpty()) {
LogError() << "Missing gstreamer plugins" << missing_gst_plugins;
}
}
void createQtConf(const QString &appBundlePath)

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,10 @@
project(strawberry)
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.7)
cmake_policy(SET CMP0054 NEW)
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
cmake_policy(SET CMP0074 NEW)
endif()
include(CheckCXXCompilerFlag)
include(CheckCXXSourceRuns)
@@ -32,14 +35,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,8 +69,7 @@ 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()
@@ -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,13 @@ 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_USE_QSTRINGBUILDER
-DQT_NO_URL_CAST_FROM_STRING
-DQT_NO_CAST_TO_ASCII
)
if(WIN32)
add_definitions(-DUNICODE)
@@ -518,6 +538,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 +550,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()

View File

@@ -2,6 +2,73 @@ Strawberry Music Player
=======================
ChangeLog
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:

View File

@@ -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,6 +23,7 @@ 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, 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/).
@@ -78,6 +80,7 @@ To build Strawberry from source you need the following installed on your system
* [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:
@@ -110,5 +113,5 @@ Strawberry is backwards compatible with Qt 5, to compile with Qt 5 use:
### :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

@@ -1,6 +1,6 @@
set(STRAWBERRY_VERSION_MAJOR 1)
set(STRAWBERRY_VERSION_MINOR 0)
set(STRAWBERRY_VERSION_PATCH 4)
set(STRAWBERRY_VERSION_PATCH 8)
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
set(INCLUDE_GIT_REVISION OFF)

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>

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

38
debian/copyright vendored
View File

@@ -81,7 +81,7 @@ Files: src/core/main.h
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
@@ -96,12 +96,14 @@ Files: src/core/main.h
ext/libstrawberry-tagreader/tagreadertagparser.cpp
ext/libstrawberry-tagreader/tagreadertagparser.h
ext/macdeploycheck/*
src/widgets/resizabletextedit.cpp
src/widgets/resizabletextedit.h
Copyright: 2012-2014, 2017-2022, 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>
@@ -109,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>
@@ -125,7 +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>
2018-2021, Jonas Kvinge <jonas@jkvinge.net>
License: GPL-3+
Files: src/core/appearance.cpp
@@ -139,13 +141,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+
@@ -193,12 +189,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
@@ -217,7 +217,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
@@ -232,12 +232,17 @@ 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
Files: src/widgets/volumeslider.cpp
src/widgets/volumeslider.h
Copyright: 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.
@@ -253,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

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

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

@@ -12,15 +12,11 @@ Categories=AudioVideo;Player;Qt;Audio;
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

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

View File

@@ -42,6 +42,10 @@
!define release
!endif
!if "@CMAKE_BUILD_TYPE@" == "RelWithDebInfo"
!define release
!endif
!if "@CMAKE_BUILD_TYPE@" == "Debug"
!define debug
!undef build_type
@@ -128,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
@@ -182,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
@@ -224,27 +245,28 @@ Section "Strawberry" Strawberry
File "avfilter-8.dll"
File "avformat-59.dll"
File "avutil-57.dll"
File "libFLAC-8.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 "libfdk-aac-2.dll"
File "libffi-8.dll"
File "libFLAC-8.dll"
File "libfreetype-6.dll"
File "libfaac-0.dll"
File "libfaad-2.dll"
File "libfftw3-3.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"
@@ -278,19 +300,18 @@ Section "Strawberry" Strawberry
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-31.dll"
File "libprotobuf-32.dll"
File "libpsl-5.dll"
File "libqtsparkle-qt6.dll"
File "libsoup-2.4-1.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 "libtwolame-0.dll"
File "libunistring-2.dll"
File "libvorbis-0.dll"
File "libvorbisenc-2.dll"
@@ -309,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
@@ -328,15 +354,21 @@ Section "Strawberry" Strawberry
File "libssl-3-x64.dll"
!endif
File "FLAC.dll"
File "avcodec-58.dll"
File "avfilter-7.dll"
File "avformat-58.dll"
File "avresample-4.dll"
File "avutil-56.dll"
File "brotlicommon.dll"
File "brotlidec.dll"
File "chromaprint.dll"
File "faad.dll"
File "fdk-aac.dll"
File "ffi-7.dll"
File "FLAC.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"
@@ -357,8 +389,7 @@ 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 "fftw3.dll"
File "harfbuzz.dll"
File "intl-8.dll"
File "libbs2b.dll"
File "libfaac_dll.dll"
@@ -369,30 +400,40 @@ Section "Strawberry" Strawberry
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 "qtsparkle-qt6.dll"
File "soup-2.4-1.dll"
File "soup-3.0-0.dll"
File "sqlite3.dll"
File "swresample-3.dll"
File "swscale-5.dll"
File "tag.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
@@ -400,7 +441,11 @@ Section "Strawberry" Strawberry
; Common files
File "icudt71.dll"
File "libfftw3-3.dll"
!ifdef msvc && debug
File "icuin71d.dll"
File "icuuc71d.dll"
File "Qt6Concurrentd.dll"
File "Qt6Cored.dll"
File "Qt6Guid.dll"
@@ -408,6 +453,8 @@ Section "Strawberry" Strawberry
File "Qt6Sqld.dll"
File "Qt6Widgetsd.dll"
!else
File "icuin71.dll"
File "icuuc71.dll"
File "Qt6Concurrent.dll"
File "Qt6Core.dll"
File "Qt6Gui.dll"
@@ -481,8 +528,10 @@ 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
@@ -528,7 +577,6 @@ Section "Gstreamer plugins" gstreamer-plugins
File "/oname=libgstaudiotestsrc.dll" "gstreamer-plugins\libgstaudiotestsrc.dll"
File "/oname=libgstautodetect.dll" "gstreamer-plugins\libgstautodetect.dll"
File "/oname=libgstbs2b.dll" "gstreamer-plugins\libgstbs2b.dll"
File "/oname=libgstcdio.dll" "gstreamer-plugins\libgstcdio.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"
@@ -538,9 +586,11 @@ Section "Gstreamer plugins" gstreamer-plugins
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"
@@ -560,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"
@@ -594,31 +647,37 @@ Section "Gstreamer plugins" gstreamer-plugins
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"
File "/oname=gstrtsp.dll" "gstreamer-plugins\gstrtsp.dll"
File "/oname=gstspeex.dll" "gstreamer-plugins\gstspeex.dll"
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"
@@ -688,27 +747,28 @@ Section "Uninstall"
Delete "$INSTDIR\avfilter-8.dll"
Delete "$INSTDIR\avformat-59.dll"
Delete "$INSTDIR\avutil-57.dll"
Delete "$INSTDIR\libFLAC-8.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\libfdk-aac-2.dll"
Delete "$INSTDIR\libffi-8.dll"
Delete "$INSTDIR\libFLAC-8.dll"
Delete "$INSTDIR\libfreetype-6.dll"
Delete "$INSTDIR\libfaac-0.dll"
Delete "$INSTDIR\libfaad-2.dll"
Delete "$INSTDIR\libfftw3-3.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"
@@ -742,19 +802,18 @@ Section "Uninstall"
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-31.dll"
Delete "$INSTDIR\libprotobuf-32.dll"
Delete "$INSTDIR\libpsl-5.dll"
Delete "$INSTDIR\libqtsparkle-qt6.dll"
Delete "$INSTDIR\libsoup-2.4-1.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\libtwolame-0.dll"
Delete "$INSTDIR\libunistring-2.dll"
Delete "$INSTDIR\libvorbis-0.dll"
Delete "$INSTDIR\libvorbisenc-2.dll"
@@ -768,14 +827,18 @@ Section "Uninstall"
Delete "$INSTDIR\swscale-6.dll"
Delete "$INSTDIR\zlib1.dll"
!ifdef debug
Delete "$INSTDIR\gdb.exe"
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
@@ -793,15 +856,21 @@ Section "Uninstall"
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\avresample-4.dll"
Delete "$INSTDIR\avutil-56.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\FLAC.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"
@@ -822,8 +891,7 @@ 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\fftw3.dll"
Delete "$INSTDIR\harfbuzz.dll"
Delete "$INSTDIR\intl-8.dll"
Delete "$INSTDIR\libbs2b.dll"
Delete "$INSTDIR\libfaac_dll.dll"
@@ -834,30 +902,40 @@ Section "Uninstall"
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\qtsparkle-qt6.dll"
Delete "$INSTDIR\soup-2.4-1.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\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
@@ -865,7 +943,11 @@ Section "Uninstall"
; Common files
Delete "$INSTDIR\icudt71.dll"
Delete "$INSTDIR\libfftw3-3.dll"
!ifdef msvc && debug
Delete "$INSTDIR\icuin71d.dll"
Delete "$INSTDIR\icuuc71d.dll"
Delete "$INSTDIR\Qt6Concurrentd.dll"
Delete "$INSTDIR\Qt6Cored.dll"
Delete "$INSTDIR\Qt6Guid.dll"
@@ -873,6 +955,8 @@ Section "Uninstall"
Delete "$INSTDIR\Qt6Sqld.dll"
Delete "$INSTDIR\Qt6Widgetsd.dll"
!else
Delete "$INSTDIR\icuin71.dll"
Delete "$INSTDIR\icuuc71.dll"
Delete "$INSTDIR\Qt6Concurrent.dll"
Delete "$INSTDIR\Qt6Core.dll"
Delete "$INSTDIR\Qt6Gui.dll"
@@ -893,6 +977,7 @@ Section "Uninstall"
!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"
@@ -901,6 +986,7 @@ Section "Uninstall"
!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"
@@ -926,7 +1012,6 @@ Section "Uninstall"
Delete "$INSTDIR\gstreamer-plugins\libgstaudiotestsrc.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstautodetect.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstbs2b.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstcdio.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstcoreelements.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstdash.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
@@ -936,9 +1021,11 @@ Section "Uninstall"
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"
@@ -958,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"
@@ -971,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"
@@ -994,31 +1084,37 @@ Section "Uninstall"
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"
Delete "$INSTDIR\gstreamer-plugins\gstrtsp.dll"
Delete "$INSTDIR\gstreamer-plugins\gstspeex.dll"
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);

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

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

View File

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

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 "core/logging.h"
#include "core/timeconstants.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, 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, 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, sample_count_bytes.size());
if (sample_count <= 0) return false;
quint64 loop_sample_count = GME::UnpackBytes32(loop_count_bytes, 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>
@@ -185,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);
@@ -195,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()));
@@ -248,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();
@@ -511,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) {
@@ -520,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());
@@ -1041,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;

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;
@@ -79,8 +78,6 @@ class TagReaderTagLib : public TagReaderBase {
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);
private:

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

@@ -140,7 +140,7 @@ int main(int argc, char **argv) {
}
else {
qLog(Error) << "Could not parse otool output line:" << output_line;
success = false;
continue;
}
}
}

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

@@ -34,28 +34,11 @@ 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)
@@ -12,6 +12,7 @@ set(SOURCES
core/commandlineoptions.cpp
core/database.cpp
core/sqlquery.cpp
core/sqlrow.cpp
core/metatypes.cpp
core/deletefiles.cpp
core/filesystemmusicstorage.cpp
@@ -59,8 +60,6 @@ set(SOURCES
context/contextview.cpp
context/contextalbum.cpp
context/contextalbumsmodel.cpp
context/contextalbumsview.cpp
collection/collection.cpp
collection/collectionmodel.cpp
@@ -73,7 +72,6 @@ set(SOURCES
collection/collectionfilterwidget.cpp
collection/collectionplaylistitem.cpp
collection/collectionquery.cpp
collection/sqlrow.cpp
collection/savedgroupingmanager.cpp
collection/groupbydialog.cpp
collection/collectiontask.cpp
@@ -188,6 +186,7 @@ set(SOURCES
dialogs/deleteconfirmationdialog.cpp
dialogs/lastfmimportdialog.cpp
dialogs/snapdialog.cpp
dialogs/saveplaylistsdialog.cpp
widgets/autoexpandingtreeview.cpp
widgets/busyindicator.cpp
@@ -212,6 +211,7 @@ set(SOURCES
widgets/tracksliderslider.cpp
widgets/loginstatewidget.cpp
widgets/ratingwidget.cpp
widgets/resizabletextedit.cpp
osd/osdbase.cpp
osd/osdpretty.cpp
@@ -298,8 +298,6 @@ set(HEADERS
context/contextview.h
context/contextalbum.h
context/contextalbumsmodel.h
context/contextalbumsview.h
collection/collection.h
collection/collectionmodel.h
@@ -420,6 +418,7 @@ set(HEADERS
dialogs/deleteconfirmationdialog.h
dialogs/lastfmimportdialog.h
dialogs/snapdialog.h
dialogs/saveplaylistsdialog.h
widgets/autoexpandingtreeview.h
widgets/busyindicator.h
@@ -445,6 +444,7 @@ set(HEADERS
widgets/qsearchfield.h
widgets/ratingwidget.h
widgets/forcescrollperpixel.h
widgets/resizabletextedit.h
osd/osdbase.h
osd/osdpretty.h
@@ -544,6 +544,7 @@ set(UI
dialogs/userpassdialog.ui
dialogs/lastfmimportdialog.ui
dialogs/snapdialog.ui
dialogs/saveplaylistsdialog.ui
widgets/trackslider.ui
widgets/fileview.ui
@@ -943,9 +944,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 +1063,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 +1156,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

@@ -57,7 +57,11 @@ Analyzer::Base::Base(QWidget *parent, const uint scopeSize)
lastscope_(512),
new_frame_(false),
is_playing_(false),
timeout_(40) {}
timeout_(40) {
setAttribute(Qt::WA_OpaquePaintEvent, true);
}
Analyzer::Base::~Base() {
delete fht_;

View File

@@ -33,7 +33,6 @@
#include <QActionGroup>
#include <QSettings>
#include <QtEvents>
#include <QtDebug>
#include "analyzercontainer.h"

View File

@@ -27,7 +27,6 @@
#include <QList>
#include <QSettings>
#include <QtConcurrentRun>
#include <QtDebug>
#include "core/application.h"
#include "core/taskmanager.h"

View File

@@ -47,10 +47,10 @@
#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 "collectionbackend.h"
#include "collectionquery.h"
#include "collectiontask.h"
@@ -1479,7 +1479,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();

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
@@ -58,7 +59,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) {
@@ -114,13 +120,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);
@@ -147,8 +148,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);
@@ -158,9 +159,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) {
@@ -176,15 +177,31 @@ 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() {
@@ -198,21 +215,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_);
@@ -220,7 +226,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() {
@@ -229,7 +257,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);
@@ -239,8 +267,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);
@@ -267,9 +294,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();
@@ -316,20 +343,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();
@@ -366,16 +411,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();
}
@@ -386,6 +431,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;

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
@@ -60,9 +61,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 +73,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,6 +87,7 @@ class CollectionFilterWidget : public QWidget {
void FocusSearchField();
public slots:
void UpdateGroupByActions();
void SetQueryMode(QueryOptions::QueryMode query_mode);
void FocusOnFilter(QKeyEvent *e);
@@ -99,7 +101,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 +117,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 +132,7 @@ class CollectionFilterWidget : public QWidget {
DelayBehaviour delay_behaviour_;
QString settings_group_;
QString saved_groupings_settings_group_;
QString settings_prefix_;
};

View File

@@ -25,6 +25,7 @@
#include <functional>
#include <algorithm>
#include <utility>
#include <optional>
#include <QObject>
#include <QtGlobal>
@@ -52,26 +53,24 @@
#include <QNetworkDiskCache>
#include <QSettings>
#include <QStandardPaths>
#include <QtDebug>
#include "core/application.h"
#include "core/database.h"
#include "core/iconloader.h"
#include "core/logging.h"
#include "core/taskmanager.h"
#include "core/sqlrow.h"
#include "collectionquery.h"
#include "collectionbackend.h"
#include "collectiondirectorymodel.h"
#include "collectionitem.h"
#include "collectionmodel.h"
#include "sqlrow.h"
#include "playlist/playlistmanager.h"
#include "playlist/songmimedata.h"
#include "covermanager/albumcoverloader.h"
#include "covermanager/albumcoverloaderresult.h"
#include "settings/collectionsettingspage.h"
const char *CollectionModel::kSavedGroupingsSettingsGroup = "SavedGroupings";
const int CollectionModel::kPrettyCoverSize = 32;
const char *CollectionModel::kPixmapDiskCacheDir = "pixmapcache";
@@ -86,6 +85,7 @@ CollectionModel::CollectionModel(CollectionBackend *backend, Application *app, Q
total_song_count_(0),
total_artist_count_(0),
total_album_count_(0),
separate_albums_by_grouping_(false),
artist_icon_(IconLoader::Load("folder-sound")),
album_icon_(IconLoader::Load("cdcase")),
init_task_id_(-1),
@@ -160,22 +160,6 @@ void CollectionModel::set_show_dividers(const bool show_dividers) {
}
void CollectionModel::SaveGrouping(const QString &name) {
qLog(Debug) << "Model, save to: " << name;
QByteArray buffer;
QDataStream ds(&buffer, QIODevice::WriteOnly);
ds << group_by_;
QSettings s;
s.beginGroup(kSavedGroupingsSettingsGroup);
s.setValue("version", "1");
s.setValue(name, buffer);
s.endGroup();
}
void CollectionModel::ReloadSettings() {
QSettings s;
@@ -239,13 +223,13 @@ void CollectionModel::SongsDiscovered(const SongList &songs) {
CollectionItem *container = root_;
QString key;
for (int i = 0; i < 3; ++i) {
GroupBy type = group_by_[i];
if (type == GroupBy_None) break;
GroupBy group_by = group_by_[i];
if (group_by == GroupBy_None) break;
if (!key.isEmpty()) key.append("-");
// Special case: if the song is a compilation and the current GroupBy level is Artists, then we want the Various Artists node :(
if (IsArtistGroupBy(type) && song.is_compilation()) {
if (IsArtistGroupBy(group_by) && song.is_compilation()) {
if (container->compilation_artist_node_ == nullptr) {
CreateCompilationArtistNode(true, container);
}
@@ -254,7 +238,7 @@ void CollectionModel::SongsDiscovered(const SongList &songs) {
}
else {
// Otherwise find the proper container at this level based on the item's key
key.append(ContainerKey(type, song));
key.append(ContainerKey(group_by, separate_albums_by_grouping_, song));
// Does it exist already?
if (container_nodes_[i].contains(key)) {
@@ -262,7 +246,7 @@ void CollectionModel::SongsDiscovered(const SongList &songs) {
}
else {
// Create the container
container = ItemFromSong(type, true, i == 0, container, song, i);
container = ItemFromSong(group_by, separate_albums_by_grouping_, true, i == 0, container, song, i);
container_nodes_[i].insert(key, container);
}
@@ -274,7 +258,7 @@ void CollectionModel::SongsDiscovered(const SongList &songs) {
if (!container->lazy_loaded && use_lazy_loading_) continue;
// We've gone all the way down to the deepest level and everything was already lazy loaded, so now we have to create the song in the container.
song_nodes_.insert(song.id(), ItemFromSong(GroupBy_None, true, false, container, song, -1));
song_nodes_.insert(song.id(), ItemFromSong(GroupBy_None, separate_albums_by_grouping_, true, false, container, song, -1));
}
}
@@ -311,11 +295,11 @@ CollectionItem *CollectionModel::CreateCompilationArtistNode(const bool signal,
}
QString CollectionModel::ContainerKey(const GroupBy type, const Song &song) {
QString CollectionModel::ContainerKey(const GroupBy group_by, const bool separate_albums_by_grouping, const Song &song) {
QString key;
switch (type) {
switch (group_by) {
case GroupBy_AlbumArtist:
key = TextOrUnknown(song.effective_albumartist());
break;
@@ -325,26 +309,32 @@ QString CollectionModel::ContainerKey(const GroupBy type, const Song &song) {
case GroupBy_Album:
key = TextOrUnknown(song.album());
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
if (separate_albums_by_grouping && !song.grouping().isEmpty()) key.append("-" + song.grouping());
break;
case GroupBy_AlbumDisc:
key = PrettyAlbumDisc(song.album(), song.disc());
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
if (separate_albums_by_grouping && !song.grouping().isEmpty()) key.append("-" + song.grouping());
break;
case GroupBy_YearAlbum:
key = PrettyYearAlbum(song.year(), song.album());
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
if (separate_albums_by_grouping && !song.grouping().isEmpty()) key.append("-" + song.grouping());
break;
case GroupBy_YearAlbumDisc:
key = PrettyYearAlbumDisc(song.year(), song.album(), song.disc());
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
if (separate_albums_by_grouping && !song.grouping().isEmpty()) key.append("-" + song.grouping());
break;
case GroupBy_OriginalYearAlbum:
key = PrettyYearAlbum(song.effective_originalyear(), song.album());
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
if (separate_albums_by_grouping && !song.grouping().isEmpty()) key.append("-" + song.grouping());
break;
case GroupBy_OriginalYearAlbumDisc:
key = PrettyYearAlbumDisc(song.effective_originalyear(), song.album(), song.disc());
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
if (separate_albums_by_grouping && !song.grouping().isEmpty()) key.append("-" + song.grouping());
break;
case GroupBy_Disc:
key = PrettyDisc(song.disc());
@@ -402,13 +392,13 @@ QString CollectionModel::ContainerKey(const GroupBy type, const Song &song) {
}
QString CollectionModel::DividerKey(const GroupBy type, CollectionItem *item) {
QString CollectionModel::DividerKey(const GroupBy group_by, CollectionItem *item) {
// Items which are to be grouped under the same divider must produce the same divider key. This will only get called for top-level items.
if (item->sort_text.isEmpty()) return QString();
switch (type) {
switch (group_by) {
case GroupBy_AlbumArtist:
case GroupBy_Artist:
case GroupBy_Album:
@@ -455,16 +445,16 @@ QString CollectionModel::DividerKey(const GroupBy type, CollectionItem *item) {
case GroupByCount:
return QString();
}
qLog(Error) << "Unknown GroupBy type" << type << "for item" << item->display_text;
qLog(Error) << "Unknown GroupBy" << group_by << "for item" << item->display_text;
return QString();
}
QString CollectionModel::DividerDisplayText(const GroupBy type, const QString &key) {
QString CollectionModel::DividerDisplayText(const GroupBy group_by, const QString &key) {
// Pretty display text for the dividers.
switch (type) {
switch (group_by) {
case GroupBy_AlbumArtist:
case GroupBy_Artist:
case GroupBy_Album:
@@ -505,10 +495,9 @@ QString CollectionModel::DividerDisplayText(const GroupBy type, const QString &k
case GroupBy_None:
case GroupByCount:
// fallthrough
;
break;
}
qLog(Error) << "Unknown GroupBy type" << type << "for divider key" << key;
qLog(Error) << "Unknown GroupBy" << group_by << "for divider key" << key;
return QString();
}
@@ -721,8 +710,8 @@ QVariant CollectionModel::data(const QModelIndex &idx, const int role) const {
if (use_pretty_covers_) {
bool is_album_node = false;
if (role == Qt::DecorationRole && item->type == CollectionItem::Type_Container) {
GroupBy container_type = group_by_[item->container_level];
is_album_node = IsAlbumGroupBy(container_type);
GroupBy container_group_by = group_by_[item->container_level];
is_album_node = IsAlbumGroupBy(container_group_by);
}
if (is_album_node) {
// It has const behaviour some of the time - that's ok right?
@@ -736,7 +725,7 @@ QVariant CollectionModel::data(const QModelIndex &idx, const int role) const {
QVariant CollectionModel::data(const CollectionItem *item, const int role) const {
GroupBy container_type = item->type == CollectionItem::Type_Container ? group_by_[item->container_level] : GroupBy_None;
GroupBy container_group_by = item->type == CollectionItem::Type_Container ? group_by_[item->container_level] : GroupBy_None;
switch (role) {
case Qt::DisplayRole:
@@ -746,7 +735,7 @@ QVariant CollectionModel::data(const CollectionItem *item, const int role) const
case Qt::DecorationRole:
switch (item->type) {
case CollectionItem::Type_Container:
switch (container_type) {
switch (container_group_by) {
case GroupBy_Album:
case GroupBy_AlbumDisc:
case GroupBy_YearAlbum:
@@ -773,7 +762,7 @@ QVariant CollectionModel::data(const CollectionItem *item, const int role) const
return item->type == CollectionItem::Type_Divider;
case Role_ContainerType:
return container_type;
return container_group_by;
case Role_Key:
return item->key;
@@ -844,26 +833,26 @@ CollectionModel::QueryResult CollectionModel::RunQuery(CollectionItem *parent) {
// Information about what we want the children to be
int child_level = parent == root_ ? 0 : parent->container_level + 1;
GroupBy child_type = child_level >= 3 ? GroupBy_None : group_by_[child_level];
GroupBy child_group_by = child_level >= 3 ? GroupBy_None : group_by_[child_level];
// Initialize the query. child_type says what type of thing we want (artists, songs, etc.)
// Initialize the query. child_group_by says what type of thing we want (artists, songs, etc.)
{
QMutexLocker l(backend_->db()->Mutex());
QSqlDatabase db(backend_->db()->Connect());
CollectionQuery q(db, backend_->songs_table(), backend_->fts_table(), query_options_);
InitQuery(child_type, &q);
InitQuery(child_group_by, separate_albums_by_grouping_, &q);
// Walk up through the item's parents adding filters as necessary
CollectionItem *p = parent;
while (p && p->type == CollectionItem::Type_Container) {
FilterQuery(group_by_[p->container_level], p, &q);
FilterQuery(group_by_[p->container_level], separate_albums_by_grouping_, p, &q);
p = p->parent;
}
// Artists GroupBy is special - we don't want compilation albums appearing
if (IsArtistGroupBy(child_type)) {
if (IsArtistGroupBy(child_group_by)) {
// Add the special Various artists node
if (show_various_artists_ && HasCompilations(db, q)) {
result.create_va = true;
@@ -897,7 +886,7 @@ void CollectionModel::PostQuery(CollectionItem *parent, const CollectionModel::Q
// Information about what we want the children to be
int child_level = parent == root_ ? 0 : parent->container_level + 1;
GroupBy child_type = child_level >= 3 ? GroupBy_None : group_by_[child_level];
GroupBy child_group_by = child_level >= 3 ? GroupBy_None : group_by_[child_level];
if (result.create_va && parent->compilation_artist_node_ == nullptr) {
CreateCompilationArtistNode(signal, parent);
@@ -906,10 +895,10 @@ void CollectionModel::PostQuery(CollectionItem *parent, const CollectionModel::Q
// Step through the results
for (const SqlRow &row : result.rows) {
// Create the item - it will get inserted into the model here
CollectionItem *item = ItemFromQuery(child_type, signal, child_level == 0, parent, row, child_level);
CollectionItem *item = ItemFromQuery(child_group_by, separate_albums_by_grouping_, signal, child_level == 0, parent, row, child_level);
// Save a pointer to it for later
if (child_type == GroupBy_None) {
if (child_group_by == GroupBy_None) {
song_nodes_.insert(item->metadata.id(), item);
}
else {
@@ -997,34 +986,52 @@ void CollectionModel::Reset() {
}
void CollectionModel::InitQuery(const GroupBy type, CollectionQuery *q) {
void CollectionModel::InitQuery(const GroupBy group_by, const bool separate_albums_by_grouping, CollectionQuery *q) {
// Say what type of thing we want to get back from the database.
switch (type) {
// Say what group_by of thing we want to get back from the database.
switch (group_by) {
case GroupBy_AlbumArtist:
q->SetColumnSpec("DISTINCT effective_albumartist");
break;
case GroupBy_Artist:
q->SetColumnSpec("DISTINCT artist");
break;
case GroupBy_Album:
q->SetColumnSpec("DISTINCT album, album_id");
case GroupBy_Album:{
QString query("DISTINCT album, album_id");
if (separate_albums_by_grouping) query.append(", grouping");
q->SetColumnSpec(query);
break;
case GroupBy_AlbumDisc:
q->SetColumnSpec("DISTINCT album, album_id, disc");
}
case GroupBy_AlbumDisc:{
QString query("DISTINCT album, album_id, disc");
if (separate_albums_by_grouping) query.append(", grouping");
q->SetColumnSpec(query);
break;
case GroupBy_YearAlbum:
q->SetColumnSpec("DISTINCT year, album, album_id, grouping");
}
case GroupBy_YearAlbum:{
QString query("DISTINCT year, album, album_id");
if (separate_albums_by_grouping) query.append(", grouping");
q->SetColumnSpec(query);
break;
case GroupBy_YearAlbumDisc:
q->SetColumnSpec("DISTINCT year, album, album_id, disc");
}
case GroupBy_YearAlbumDisc:{
QString query("DISTINCT year, album, album_id, disc");
if (separate_albums_by_grouping) query.append(", grouping");
q->SetColumnSpec(query);
break;
case GroupBy_OriginalYearAlbum:
q->SetColumnSpec("DISTINCT year, originalyear, album, album_id, grouping");
}
case GroupBy_OriginalYearAlbum:{
QString query("DISTINCT year, originalyear, album, album_id");
if (separate_albums_by_grouping) query.append(", grouping");
q->SetColumnSpec(query);
break;
case GroupBy_OriginalYearAlbumDisc:
q->SetColumnSpec("DISTINCT year, originalyear, album, album_id, disc");
}
case GroupBy_OriginalYearAlbumDisc:{
QString query("DISTINCT year, originalyear, album, album_id, disc");
if (separate_albums_by_grouping) query.append(", grouping");
q->SetColumnSpec(query);
break;
}
case GroupBy_Disc:
q->SetColumnSpec("DISTINCT disc");
break;
@@ -1069,11 +1076,11 @@ void CollectionModel::InitQuery(const GroupBy type, CollectionQuery *q) {
}
void CollectionModel::FilterQuery(const GroupBy type, CollectionItem *item, CollectionQuery *q) {
void CollectionModel::FilterQuery(const GroupBy group_by, const bool separate_albums_by_grouping, CollectionItem *item, CollectionQuery *q) {
// Say how we want the query to be filtered. This is done once for each parent going up the tree.
switch (type) {
switch (group_by) {
case GroupBy_AlbumArtist:
if (IsCompilationArtistNode(item)) {
q->AddCompilationRequirement(true);
@@ -1097,30 +1104,33 @@ void CollectionModel::FilterQuery(const GroupBy type, CollectionItem *item, Coll
case GroupBy_Album:
q->AddWhere("album", item->metadata.album());
q->AddWhere("album_id", item->metadata.album_id());
if (separate_albums_by_grouping) q->AddWhere("grouping", item->metadata.grouping());
break;
case GroupBy_AlbumDisc:
q->AddWhere("album", item->metadata.album());
q->AddWhere("album_id", item->metadata.album_id());
q->AddWhere("disc", item->metadata.disc());
if (separate_albums_by_grouping) q->AddWhere("grouping", item->metadata.grouping());
break;
case GroupBy_YearAlbum:
q->AddWhere("year", item->metadata.year());
q->AddWhere("album", item->metadata.album());
q->AddWhere("album_id", item->metadata.album_id());
q->AddWhere("grouping", item->metadata.grouping());
if (separate_albums_by_grouping) q->AddWhere("grouping", item->metadata.grouping());
break;
case GroupBy_YearAlbumDisc:
q->AddWhere("year", item->metadata.year());
q->AddWhere("album", item->metadata.album());
q->AddWhere("album_id", item->metadata.album_id());
q->AddWhere("disc", item->metadata.disc());
if (separate_albums_by_grouping) q->AddWhere("grouping", item->metadata.grouping());
break;
case GroupBy_OriginalYearAlbum:
q->AddWhere("year", item->metadata.year());
q->AddWhere("originalyear", item->metadata.originalyear());
q->AddWhere("album", item->metadata.album());
q->AddWhere("album_id", item->metadata.album_id());
q->AddWhere("grouping", item->metadata.grouping());
if (separate_albums_by_grouping) q->AddWhere("grouping", item->metadata.grouping());
break;
case GroupBy_OriginalYearAlbumDisc:
q->AddWhere("year", item->metadata.year());
@@ -1128,6 +1138,7 @@ void CollectionModel::FilterQuery(const GroupBy type, CollectionItem *item, Coll
q->AddWhere("album", item->metadata.album());
q->AddWhere("album_id", item->metadata.album_id());
q->AddWhere("disc", item->metadata.disc());
if (separate_albums_by_grouping) q->AddWhere("grouping", item->metadata.grouping());
break;
case GroupBy_Disc:
q->AddWhere("disc", item->metadata.disc());
@@ -1169,15 +1180,15 @@ void CollectionModel::FilterQuery(const GroupBy type, CollectionItem *item, Coll
break;
case GroupBy_None:
case GroupByCount:
qLog(Error) << "Unknown GroupBy type" << type << "used in filter";
qLog(Error) << "Unknown GroupBy" << group_by << "used in filter";
break;
}
}
CollectionItem *CollectionModel::InitItem(const GroupBy type, const bool signal, CollectionItem *parent, const int container_level) {
CollectionItem *CollectionModel::InitItem(const GroupBy group_by, const bool signal, CollectionItem *parent, const int container_level) {
CollectionItem::Type item_type = type == GroupBy_None ? CollectionItem::Type_Song : CollectionItem::Type_Container;
CollectionItem::Type item_type = group_by == GroupBy_None ? CollectionItem::Type_Song : CollectionItem::Type_Container;
if (signal) beginInsertRows(ItemToIndex(parent), static_cast<int>(parent->children.count()), static_cast<int>(parent->children.count()));
@@ -1190,25 +1201,25 @@ CollectionItem *CollectionModel::InitItem(const GroupBy type, const bool signal,
}
CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool signal, const bool create_divider, CollectionItem *parent, const SqlRow &row, const int container_level) {
CollectionItem *CollectionModel::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 *item = InitItem(type, signal, parent, container_level);
CollectionItem *item = InitItem(group_by, signal, parent, container_level);
if (parent != root_ && !parent->key.isEmpty()) {
item->key = parent->key + "-";
}
switch (type) {
switch (group_by) {
case GroupBy_AlbumArtist:{
item->metadata.set_albumartist(row.value(0).toString());
item->key.append(ContainerKey(type, item->metadata));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
item->display_text = TextOrUnknown(item->metadata.albumartist());
item->sort_text = SortTextForArtist(item->metadata.albumartist());
break;
}
case GroupBy_Artist:{
item->metadata.set_artist(row.value(0).toString());
item->key.append(ContainerKey(type, item->metadata));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
item->display_text = TextOrUnknown(item->metadata.artist());
item->sort_text = SortTextForArtist(item->metadata.artist());
break;
@@ -1216,7 +1227,8 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
case GroupBy_Album:{
item->metadata.set_album(row.value(0).toString());
item->metadata.set_album_id(row.value(1).toString());
item->key.append(ContainerKey(type, item->metadata));
item->metadata.set_grouping(row.value(2).toString());
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
item->display_text = TextOrUnknown(item->metadata.album());
item->sort_text = SortTextForArtist(item->metadata.album());
break;
@@ -1225,7 +1237,8 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
item->metadata.set_album(row.value(0).toString());
item->metadata.set_album_id(row.value(1).toString());
item->metadata.set_disc(row.value(2).toInt());
item->key.append(ContainerKey(type, item->metadata));
item->metadata.set_grouping(row.value(3).toString());
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
item->display_text = PrettyAlbumDisc(item->metadata.album(), item->metadata.disc());
item->sort_text = item->metadata.album() + SortTextForNumber(qMax(0, item->metadata.disc()));
break;
@@ -1235,7 +1248,7 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
item->metadata.set_album(row.value(1).toString());
item->metadata.set_album_id(row.value(2).toString());
item->metadata.set_grouping(row.value(3).toString());
item->key.append(ContainerKey(type, item->metadata));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
item->display_text = PrettyYearAlbum(item->metadata.year(), item->metadata.album());
item->sort_text = SortTextForNumber(qMax(0, item->metadata.year())) + item->metadata.grouping() + item->metadata.album();
break;
@@ -1245,7 +1258,8 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
item->metadata.set_album(row.value(1).toString());
item->metadata.set_album_id(row.value(2).toString());
item->metadata.set_disc(row.value(3).toInt());
item->key.append(ContainerKey(type, item->metadata));
item->metadata.set_grouping(row.value(4).toString());
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
item->display_text = PrettyYearAlbumDisc(item->metadata.year(), item->metadata.album(), item->metadata.disc());
item->sort_text = SortTextForNumber(qMax(0, item->metadata.year())) + item->metadata.album() + SortTextForNumber(qMax(0, item->metadata.disc()));
break;
@@ -1256,7 +1270,7 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
item->metadata.set_album(row.value(2).toString());
item->metadata.set_album_id(row.value(3).toString());
item->metadata.set_grouping(row.value(4).toString());
item->key.append(ContainerKey(type, item->metadata));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
item->display_text = PrettyYearAlbum(item->metadata.effective_originalyear(), item->metadata.album());
item->sort_text = SortTextForNumber(qMax(0, item->metadata.effective_originalyear())) + item->metadata.grouping() + item->metadata.album();
break;
@@ -1267,14 +1281,15 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
item->metadata.set_album(row.value(2).toString());
item->metadata.set_album_id(row.value(3).toString());
item->metadata.set_disc(row.value(4).toInt());
item->key.append(ContainerKey(type, item->metadata));
item->metadata.set_grouping(row.value(5).toString());
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
item->display_text = PrettyYearAlbumDisc(item->metadata.effective_originalyear(), item->metadata.album(), item->metadata.disc());
item->sort_text = SortTextForNumber(qMax(0, item->metadata.effective_originalyear())) + item->metadata.album() + SortTextForNumber(qMax(0, item->metadata.disc()));
break;
}
case GroupBy_Disc:{
item->metadata.set_disc(row.value(0).toInt());
item->key.append(ContainerKey(type, item->metadata));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
const int disc = qMax(0, row.value(0).toInt());
item->display_text = PrettyDisc(disc);
item->sort_text = SortTextForNumber(disc);
@@ -1282,7 +1297,7 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
}
case GroupBy_Year:{
item->metadata.set_year(row.value(0).toInt());
item->key.append(ContainerKey(type, item->metadata));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
const int year = qMax(0, item->metadata.year());
item->display_text = QString::number(year);
item->sort_text = SortTextForNumber(year) + " ";
@@ -1290,7 +1305,7 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
}
case GroupBy_OriginalYear:{
item->metadata.set_originalyear(row.value(0).toInt());
item->key.append(ContainerKey(type, item->metadata));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
const int year = qMax(0, item->metadata.originalyear());
item->display_text = QString::number(year);
item->sort_text = SortTextForNumber(year) + " ";
@@ -1298,44 +1313,44 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
}
case GroupBy_Genre:{
item->metadata.set_genre(row.value(0).toString());
item->key.append(ContainerKey(type, item->metadata));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
item->display_text = TextOrUnknown(item->metadata.genre());
item->sort_text = SortTextForArtist(item->metadata.genre());
break;
}
case GroupBy_Composer:{
item->metadata.set_composer(row.value(0).toString());
item->key.append(ContainerKey(type, item->metadata));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
item->display_text = TextOrUnknown(item->metadata.composer());
item->sort_text = SortTextForArtist(item->metadata.composer());
break;
}
case GroupBy_Performer:{
item->metadata.set_performer(row.value(0).toString());
item->key.append(ContainerKey(type, item->metadata));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
item->display_text = TextOrUnknown(item->metadata.performer());
item->sort_text = SortTextForArtist(item->metadata.performer());
break;
}
case GroupBy_Grouping:{
item->metadata.set_grouping(row.value(0).toString());
item->key.append(ContainerKey(type, item->metadata));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
item->display_text = TextOrUnknown(item->metadata.grouping());
item->sort_text = SortTextForArtist(item->metadata.grouping());
break;
}
case GroupBy_FileType:{
item->metadata.set_filetype(Song::FileType(row.value(0).toInt()));
item->key.append(ContainerKey(type, item->metadata));
item->metadata.set_filetype(static_cast<Song::FileType>(row.value(0).toInt()));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
item->display_text = item->metadata.TextForFiletype();
item->sort_text = item->metadata.TextForFiletype();
break;
}
case GroupBy_Format:{
item->metadata.set_filetype(Song::FileType(row.value(0).toInt()));
item->metadata.set_filetype(static_cast<Song::FileType>(row.value(0).toInt()));
item->metadata.set_samplerate(row.value(1).toInt());
item->metadata.set_bitdepth(row.value(2).toInt());
QString key = ContainerKey(type, item->metadata);
QString key = ContainerKey(group_by, separate_albums_by_grouping, item->metadata);
item->key.append(key);
item->display_text = key;
item->sort_text = key;
@@ -1343,7 +1358,7 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
}
case GroupBy_Samplerate:{
item->metadata.set_samplerate(row.value(0).toInt());
item->key.append(ContainerKey(type, item->metadata));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
const int samplerate = qMax(0, item->metadata.samplerate());
item->display_text = QString::number(samplerate);
item->sort_text = SortTextForNumber(samplerate) + " ";
@@ -1351,7 +1366,7 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
}
case GroupBy_Bitdepth:{
item->metadata.set_bitdepth(row.value(0).toInt());
item->key.append(ContainerKey(type, item->metadata));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
const int bitdepth = qMax(0, item->metadata.bitdepth());
item->display_text = QString::number(bitdepth);
item->sort_text = SortTextForNumber(bitdepth) + " ";
@@ -1359,7 +1374,7 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
}
case GroupBy_Bitrate:{
item->metadata.set_bitrate(row.value(0).toInt());
item->key.append(ContainerKey(type, item->metadata));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, item->metadata));
const int bitrate = qMax(0, item->metadata.bitrate());
item->display_text = QString::number(bitrate);
item->sort_text = SortTextForNumber(bitrate) + " ";
@@ -1379,31 +1394,31 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
break;
}
FinishItem(type, signal, create_divider, parent, item);
FinishItem(group_by, signal, create_divider, parent, item);
return item;
}
CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool signal, const bool create_divider, CollectionItem *parent, const Song &s, const int container_level) {
CollectionItem *CollectionModel::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) {
CollectionItem *item = InitItem(type, signal, parent, container_level);
CollectionItem *item = InitItem(group_by, signal, parent, container_level);
if (parent != root_ && !parent->key.isEmpty()) {
item->key = parent->key + "-";
}
switch (type) {
switch (group_by) {
case GroupBy_AlbumArtist:{
item->metadata.set_albumartist(s.effective_albumartist());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
item->display_text = TextOrUnknown(s.effective_albumartist());
item->sort_text = SortTextForArtist(s.effective_albumartist());
break;
}
case GroupBy_Artist:{
item->metadata.set_artist(s.artist());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
item->display_text = TextOrUnknown(s.artist());
item->sort_text = SortTextForArtist(s.artist());
break;
@@ -1411,7 +1426,8 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
case GroupBy_Album:{
item->metadata.set_album(s.album());
item->metadata.set_album_id(s.album_id());
item->key.append(ContainerKey(type, s));
item->metadata.set_grouping(s.grouping());
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
item->display_text = TextOrUnknown(s.album());
item->sort_text = SortTextForArtist(s.album());
break;
@@ -1420,7 +1436,8 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
item->metadata.set_album(s.album());
item->metadata.set_album_id(s.album_id());
item->metadata.set_disc(s.disc());
item->key.append(ContainerKey(type, s));
item->metadata.set_grouping(s.grouping());
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
item->display_text = PrettyAlbumDisc(s.album(), s.disc());
item->sort_text = s.album() + SortTextForNumber(qMax(0, s.disc()));
break;
@@ -1430,7 +1447,7 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
item->metadata.set_album(s.album());
item->metadata.set_album_id(s.album_id());
item->metadata.set_grouping(s.grouping());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
item->display_text = PrettyYearAlbum(s.year(), s.album());
item->sort_text = SortTextForNumber(qMax(0, s.year())) + s.grouping() + s.album();
break;
@@ -1440,7 +1457,8 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
item->metadata.set_album(s.album());
item->metadata.set_album_id(s.album_id());
item->metadata.set_disc(s.disc());
item->key.append(ContainerKey(type, s));
item->metadata.set_grouping(s.grouping());
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
item->display_text = PrettyYearAlbumDisc(s.year(), s.album(), s.disc());
item->sort_text = SortTextForNumber(qMax(0, s.year())) + s.album() + SortTextForNumber(qMax(0, s.disc()));
break;
@@ -1451,7 +1469,7 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
item->metadata.set_album(s.album());
item->metadata.set_album_id(s.album_id());
item->metadata.set_grouping(s.grouping());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
item->display_text = PrettyYearAlbum(s.effective_originalyear(), s.album());
item->sort_text = SortTextForNumber(qMax(0, s.effective_originalyear())) + s.grouping() + s.album();
break;
@@ -1463,14 +1481,14 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
item->metadata.set_album_id(s.album_id());
item->metadata.set_disc(s.disc());
item->metadata.set_grouping(s.grouping());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
item->display_text = PrettyYearAlbumDisc(s.effective_originalyear(), s.album(), s.disc());
item->sort_text = SortTextForNumber(qMax(0, s.effective_originalyear())) + s.album() + SortTextForNumber(qMax(0, s.disc()));
break;
}
case GroupBy_Disc:{
item->metadata.set_disc(s.disc());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
const int disc = qMax(0, s.disc());
item->display_text = PrettyDisc(disc);
item->sort_text = SortTextForNumber(disc);
@@ -1478,7 +1496,7 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
}
case GroupBy_Year:{
item->metadata.set_year(s.year());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
const int year = qMax(0, s.year());
item->display_text = QString::number(year);
item->sort_text = SortTextForNumber(year) + " ";
@@ -1486,7 +1504,7 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
}
case GroupBy_OriginalYear:{
item->metadata.set_originalyear(s.effective_originalyear());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
const int year = qMax(0, s.effective_originalyear());
item->display_text = QString::number(year);
item->sort_text = SortTextForNumber(year) + " ";
@@ -1494,35 +1512,35 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
}
case GroupBy_Genre:{
item->metadata.set_genre(s.genre());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
item->display_text = TextOrUnknown(s.genre());
item->sort_text = SortTextForArtist(s.genre());
break;
}
case GroupBy_Composer:{
item->metadata.set_composer(s.composer());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
item->display_text = TextOrUnknown(s.composer());
item->sort_text = SortTextForArtist(s.composer());
break;
}
case GroupBy_Performer:{
item->metadata.set_performer(s.performer());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
item->display_text = TextOrUnknown(s.performer());
item->sort_text = SortTextForArtist(s.performer());
break;
}
case GroupBy_Grouping:{
item->metadata.set_grouping(s.grouping());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
item->display_text = TextOrUnknown(s.grouping());
item->sort_text = SortTextForArtist(s.grouping());
break;
}
case GroupBy_FileType:{
item->metadata.set_filetype(s.filetype());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
item->display_text = s.TextForFiletype();
item->sort_text = s.TextForFiletype();
break;
@@ -1531,7 +1549,7 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
item->metadata.set_filetype(s.filetype());
item->metadata.set_samplerate(s.samplerate());
item->metadata.set_bitdepth(s.bitdepth());
QString key = ContainerKey(type, s);
QString key = ContainerKey(group_by, separate_albums_by_grouping, s);
item->key.append(key);
item->display_text = key;
item->sort_text = key;
@@ -1539,7 +1557,7 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
}
case GroupBy_Samplerate:{
item->metadata.set_samplerate(s.samplerate());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
const int samplerate = qMax(0, s.samplerate());
item->display_text = QString::number(samplerate);
item->sort_text = SortTextForNumber(samplerate) + " ";
@@ -1547,7 +1565,7 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
}
case GroupBy_Bitdepth:{
item->metadata.set_bitdepth(s.bitdepth());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
const int bitdepth = qMax(0, s.bitdepth());
item->display_text = QString::number(bitdepth);
item->sort_text = SortTextForNumber(bitdepth) + " ";
@@ -1555,7 +1573,7 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
}
case GroupBy_Bitrate:{
item->metadata.set_bitrate(s.bitrate());
item->key.append(ContainerKey(type, s));
item->key.append(ContainerKey(group_by, separate_albums_by_grouping, s));
const int bitrate = qMax(0, s.bitrate());
item->display_text = QString::number(bitrate);
item->sort_text = SortTextForNumber(bitrate) + " ";
@@ -1576,16 +1594,16 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
}
}
FinishItem(type, signal, create_divider, parent, item);
FinishItem(group_by, signal, create_divider, parent, item);
if (s.url().scheme() == "cdda") item->lazy_loaded = true;
return item;
}
void CollectionModel::FinishItem(const GroupBy type, const bool signal, const bool create_divider, CollectionItem *parent, CollectionItem *item) {
void CollectionModel::FinishItem(const GroupBy group_by, const bool signal, const bool create_divider, CollectionItem *parent, CollectionItem *item) {
if (type == GroupBy_None) item->lazy_loaded = true;
if (group_by == GroupBy_None) item->lazy_loaded = true;
if (signal) {
endInsertRows();
@@ -1593,7 +1611,7 @@ void CollectionModel::FinishItem(const GroupBy type, const bool signal, const bo
// Create the divider entry if we're supposed to
if (create_divider && show_dividers_) {
QString divider_key = DividerKey(type, item);
QString divider_key = DividerKey(group_by, item);
if (!divider_key.isEmpty()) {
item->sort_text.prepend(divider_key + " ");
}
@@ -1605,7 +1623,7 @@ void CollectionModel::FinishItem(const GroupBy type, const bool signal, const bo
CollectionItem *divider = new CollectionItem(CollectionItem::Type_Divider, root_);
divider->key = divider_key;
divider->display_text = DividerDisplayText(type, divider_key);
divider->display_text = DividerDisplayText(group_by, divider_key);
divider->sort_text = divider_key + " ";
divider->lazy_loaded = true;
@@ -1859,12 +1877,15 @@ bool CollectionModel::canFetchMore(const QModelIndex &parent) const {
}
void CollectionModel::SetGroupBy(const Grouping g) {
void CollectionModel::SetGroupBy(const Grouping g, const std::optional<bool> separate_albums_by_grouping) {
group_by_ = g;
if (separate_albums_by_grouping) {
separate_albums_by_grouping_ = separate_albums_by_grouping.value();
}
ResetAsync();
emit GroupingChanged(g);
emit GroupingChanged(g, separate_albums_by_grouping_);
}
@@ -1932,7 +1953,7 @@ void CollectionModel::ExpandAll(CollectionItem *item) const {
}
QDataStream &operator<<(QDataStream &s, const CollectionModel::Grouping g) {
s << quint32(g.first) << quint32(g.second) << quint32(g.third);
s << static_cast<quint32>(g.first) << static_cast<quint32>(g.second) << static_cast<quint32>(g.third);
return s;
}
@@ -1940,11 +1961,11 @@ QDataStream &operator>>(QDataStream &s, CollectionModel::Grouping &g) {
quint32 buf = 0;
s >> buf;
g.first = CollectionModel::GroupBy(buf);
g.first = static_cast<CollectionModel::GroupBy>(buf);
s >> buf;
g.second = CollectionModel::GroupBy(buf);
g.second = static_cast<CollectionModel::GroupBy>(buf);
s >> buf;
g.third = CollectionModel::GroupBy(buf);
g.third = static_cast<CollectionModel::GroupBy>(buf);
return s;
}

View File

@@ -24,6 +24,8 @@
#include "config.h"
#include <optional>
#include <QtGlobal>
#include <QObject>
#include <QAbstractItemModel>
@@ -45,10 +47,10 @@
#include "core/simpletreemodel.h"
#include "core/song.h"
#include "core/sqlrow.h"
#include "covermanager/albumcoverloader.h"
#include "collectionquery.h"
#include "collectionitem.h"
#include "sqlrow.h"
#include "covermanager/albumcoverloaderoptions.h"
class QSettings;
@@ -64,8 +66,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 +160,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,15 +192,15 @@ 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);
@@ -247,22 +244,22 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
// 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 InitQuery(const GroupBy group_by, const bool separate_albums_by_grouping, CollectionQuery *q);
static void FilterQuery(const GroupBy group_by, const bool separate_albums_by_grouping, CollectionItem *item, CollectionQuery *q);
// 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_; }
@@ -284,6 +281,7 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
QueryOptions query_options_;
Grouping group_by_;
bool separate_albums_by_grouping_;
// Keyed on database ID
QMap<int, CollectionItem*> song_nodes_;

View File

@@ -38,13 +38,11 @@
#include <QList>
#include <QSet>
#include <QTimer>
#include <QVariant>
#include <QString>
#include <QStringList>
#include <QUrl>
#include <QImage>
#include <QSettings>
#include <QtDebug>
#include "core/filesystemwatcherinterface.h"
#include "core/logging.h"
@@ -82,6 +80,7 @@ CollectionWatcher::CollectionWatcher(Song::Source source, QObject *parent)
song_tracking_(false),
mark_songs_unavailable_(source_ == Song::Source_Collection),
expire_unavailable_songs_days_(60),
overwrite_playcount_(false),
overwrite_rating_(false),
stop_requested_(false),
abort_requested_(false),
@@ -153,6 +152,7 @@ void CollectionWatcher::ReloadSettings() {
mark_songs_unavailable_ = false;
}
expire_unavailable_songs_days_ = s.value("expire_unavailable_songs", 60).toInt();
overwrite_playcount_ = s.value("overwrite_playcount", false).toBool();
overwrite_rating_ = s.value("overwrite_rating", false).toBool();
s.endGroup();
@@ -442,7 +442,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
QStringList files_on_disk;
SubdirectoryList my_new_subdirs;
// If a directory is moved then only its parent gets a changed notification, so we need to look and see if any of our children don't exist any more.
// If a directory is moved then only its parent gets a changed notification, so we need to look and see if any of our children don't exist anymore.
// If one has been removed, "rescan" it to get the deleted songs
SubdirectoryList previous_subdirs = t->GetImmediateSubdirs(path);
for (const Subdirectory &prev_subdir : previous_subdirs) {
@@ -462,7 +462,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
if (child_info.isDir()) {
if (!t->HasSeenSubdir(child)) {
// We haven't seen this subdirectory before - add it to a list and later we'll tell the backend about it and scan it.
// We haven't seen this subdirectory before - add it to a list, and later we'll tell the backend about it and scan it.
Subdirectory new_subdir;
new_subdir.directory_id = -1;
new_subdir.path = child;
@@ -734,7 +734,7 @@ void CollectionWatcher::UpdateCueAssociatedSongs(const QString &file,
const Song matching_cue_song = sections_map[new_cue_song.beginning_nanosec()];
new_cue_song.set_id(matching_cue_song.id());
if (!new_cue_song.has_embedded_cover()) new_cue_song.set_art_automatic(image);
new_cue_song.MergeUserSetData(matching_cue_song, true);
new_cue_song.MergeUserSetData(matching_cue_song, true, true);
AddChangedSong(file, matching_cue_song, new_cue_song, t);
used_ids.insert(matching_cue_song.id());
}
@@ -759,7 +759,7 @@ void CollectionWatcher::UpdateNonCueAssociatedSong(const QString &file,
const bool cue_deleted,
ScanTransaction *t) {
// If a CUE got deleted, we turn it's first section into the new 'raw' (cueless) song and we just remove the rest of the sections from the collection
// If a CUE got deleted, we turn it's first section into the new 'raw' (cueless) song, and we just remove the rest of the sections from the collection
const Song &matching_song = matching_songs.first();
if (cue_deleted) {
for (const Song &song : matching_songs) {
@@ -777,7 +777,7 @@ void CollectionWatcher::UpdateNonCueAssociatedSong(const QString &file,
song_on_disk.set_id(matching_song.id());
song_on_disk.set_fingerprint(fingerprint);
if (!song_on_disk.has_embedded_cover()) song_on_disk.set_art_automatic(image);
song_on_disk.MergeUserSetData(matching_song, !overwrite_rating_);
song_on_disk.MergeUserSetData(matching_song, !overwrite_playcount_, !overwrite_rating_);
AddChangedSong(file, matching_song, song_on_disk, t);
}
@@ -803,7 +803,7 @@ SongList CollectionWatcher::ScanNewFile(const QString &file, const QString &path
// Ignore FILEs pointing to other media files.
// Also, watch out for incorrect media files.
// Playlist parser for CUEs considers every entry in sheet valid and we don't want invalid media getting into collection!
// Playlist parser for CUEs considers every entry in sheet valid, and we don't want invalid media getting into collection!
QString file_nfd = file.normalized(QString::NormalizationForm_D);
SongList cue_congs = cue_parser_->Load(&cue_file, matching_cue, path, false);
cue_file.close();

View File

@@ -218,6 +218,7 @@ class CollectionWatcher : public QObject {
bool song_tracking_;
bool mark_songs_unavailable_;
int expire_unavailable_songs_days_;
bool overwrite_playcount_;
bool overwrite_rating_;
bool stop_requested_;

View File

@@ -108,22 +108,31 @@ GroupByDialog::GroupByDialog(QWidget *parent) : QDialog(parent), ui_(new Ui_Grou
GroupByDialog::~GroupByDialog() = default;
void GroupByDialog::Reset() {
ui_->combobox_first->setCurrentIndex(2); // Album Artist
ui_->combobox_second->setCurrentIndex(3); // Album
ui_->combobox_second->setCurrentIndex(4); // Album Disc
ui_->combobox_third->setCurrentIndex(0); // None
ui_->checkbox_separate_albums_by_grouping->setChecked(false);
}
void GroupByDialog::accept() {
emit Accepted(CollectionModel::Grouping(
p_->mapping_.get<tag_index>().find(ui_->combobox_first->currentIndex())->group_by,
p_->mapping_.get<tag_index>().find(ui_->combobox_second->currentIndex())->group_by,
p_->mapping_.get<tag_index>().find(ui_->combobox_third->currentIndex())->group_by)
p_->mapping_.get<tag_index>().find(ui_->combobox_third->currentIndex())->group_by),
ui_->checkbox_separate_albums_by_grouping->isChecked()
);
QDialog::accept();
}
void GroupByDialog::CollectionGroupingChanged(const CollectionModel::Grouping g) {
void GroupByDialog::CollectionGroupingChanged(const CollectionModel::Grouping g, const bool separate_albums_by_grouping) {
ui_->combobox_first->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[0])->combo_box_index);
ui_->combobox_second->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[1])->combo_box_index);
ui_->combobox_third->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[2])->combo_box_index);
ui_->checkbox_separate_albums_by_grouping->setChecked(separate_albums_by_grouping);
}

View File

@@ -45,11 +45,11 @@ class GroupByDialog : public QDialog {
~GroupByDialog() override;
public slots:
void CollectionGroupingChanged(const CollectionModel::Grouping g);
void CollectionGroupingChanged(const CollectionModel::Grouping g, const bool separate_albums_by_grouping);
void accept() override;
signals:
void Accepted(CollectionModel::Grouping g);
void Accepted(CollectionModel::Grouping g, bool separate_albums_by_grouping);
private slots:
void Reset();

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>354</width>
<height>246</height>
<width>394</width>
<height>273</height>
</rect>
</property>
<property name="windowTitle">
@@ -370,6 +370,13 @@
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkbox_separate_albums_by_grouping">
<property name="text">
<string>Separate albums by grouping tag</string>
</property>
</widget>
</item>
<item>
<spacer name="spacer_bottom">
<property name="orientation">

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2015, Nick Lanham <nick@afternight.org>
* Copyright 2019-2021, Jonas Kvinge <jonas@jkvinge.net>
* 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
@@ -22,35 +22,31 @@
#include "config.h"
#include <QDialog>
#include <QWidget>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include <QAbstractItemModel>
#include <QIODevice>
#include <QDataStream>
#include <QByteArray>
#include <QList>
#include <QVariant>
#include <QByteArray>
#include <QString>
#include <QStringList>
#include <QIODevice>
#include <QDataStream>
#include <QKeySequence>
#include <QPushButton>
#include <QTreeView>
#include <QSettings>
#include <QtDebug>
#include "core/logging.h"
#include "core/iconloader.h"
#include "collectionfilterwidget.h"
#include "collectionmodel.h"
#include "savedgroupingmanager.h"
#include "ui_savedgroupingmanager.h"
SavedGroupingManager::SavedGroupingManager(QWidget *parent)
const char *SavedGroupingManager::kSavedGroupingsSettingsGroup = "SavedGroupings";
SavedGroupingManager::SavedGroupingManager(const QString &saved_groupings_settings_group, QWidget *parent)
: QDialog(parent),
ui_(new Ui_SavedGroupingManager),
model_(new QStandardItemModel(0, 4, this)),
filter_(nullptr) {
saved_groupings_settings_group_(saved_groupings_settings_group) {
ui_->setupUi(this);
@@ -71,7 +67,17 @@ SavedGroupingManager::SavedGroupingManager(QWidget *parent)
SavedGroupingManager::~SavedGroupingManager() {
delete ui_;
delete model_;
}
QString SavedGroupingManager::GetSavedGroupingsSettingsGroup(const QString &settings_group) {
if (settings_group.isEmpty() || settings_group == CollectionSettingsPage::kSettingsGroup) {
return kSavedGroupingsSettingsGroup;
}
else {
return QString(kSavedGroupingsSettingsGroup) + "_" + settings_group;
}
}
QString SavedGroupingManager::GroupByToString(const CollectionModel::GroupBy g) {
@@ -151,7 +157,7 @@ void SavedGroupingManager::UpdateModel() {
model_->setRowCount(0); // don't use clear, it deletes headers
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();
@@ -186,7 +192,7 @@ void SavedGroupingManager::Remove() {
if (ui_->list->selectionModel()->hasSelection()) {
QSettings s;
s.beginGroup(CollectionModel::kSavedGroupingsSettingsGroup);
s.beginGroup(saved_groupings_settings_group_);
for (const QModelIndex &idx : ui_->list->selectionModel()->selectedRows()) {
if (idx.isValid()) {
qLog(Debug) << "Remove saved grouping: " << model_->item(idx.row(), 0)->text();
@@ -196,7 +202,8 @@ void SavedGroupingManager::Remove() {
s.endGroup();
}
UpdateModel();
filter_->UpdateGroupByActions();
emit UpdateGroupByActions();
}

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2015, Nick Lanham <nick@afternight.org>
* Copyright 2019-2021, Jonas Kvinge <jonas@jkvinge.net>
* 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
@@ -40,14 +40,20 @@ class SavedGroupingManager : public QDialog {
Q_OBJECT
public:
explicit SavedGroupingManager(QWidget *parent = nullptr);
explicit SavedGroupingManager(const QString &saved_groupings_settings_group, QWidget *parent = nullptr);
~SavedGroupingManager() override;
static const char *kSavedGroupingsSettingsGroup;
static QString GetSavedGroupingsSettingsGroup(const QString &settings_group);
void UpdateModel();
void SetFilter(CollectionFilterWidget *filter) { filter_ = filter; }
static QString GroupByToString(const CollectionModel::GroupBy g);
signals:
void UpdateGroupByActions();
private slots:
void UpdateButtonState();
void Remove();
@@ -55,7 +61,7 @@ class SavedGroupingManager : public QDialog {
private:
Ui_SavedGroupingManager *ui_;
QStandardItemModel *model_;
CollectionFilterWidget *filter_;
QString saved_groupings_settings_group_;
};
#endif // SAVEDGROUPINGMANAGER_H

View File

@@ -21,6 +21,8 @@
#cmakedefine HAVE_MUSICBRAINZ
#cmakedefine HAVE_GLOBALSHORTCUTS
#cmakedefine HAVE_X11_GLOBALSHORTCUTS
#cmakedefine HAVE_ICU
#cmakedefine USE_INSTALL_PREFIX
#cmakedefine HAVE_GSTREAMER

View File

@@ -1,6 +1,6 @@
/*
* Strawberry Music Player
* Copyright 2020-2021, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2020-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
@@ -43,7 +43,7 @@
#include "contextview.h"
#include "contextalbum.h"
const int ContextAlbum::kWidgetSpacing = 40;
const int ContextAlbum::kFadeTimeLineMs = 1000;
ContextAlbum::ContextAlbum(QWidget *parent)
: QWidget(parent),
@@ -51,23 +51,26 @@ ContextAlbum::ContextAlbum(QWidget *parent)
context_view_(nullptr),
album_cover_choice_controller_(nullptr),
downloading_covers_(false),
timeline_fade_(new QTimeLine(1000, this)),
timeline_fade_(new QTimeLine(kFadeTimeLineMs, this)),
image_strawberry_(":/pictures/strawberry.png"),
image_original_(image_strawberry_),
pixmap_previous_opacity_(0),
prev_width_(width()) {
pixmap_current_opacity_(1.0) {
setObjectName("context-widget-album");
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
cover_loader_options_.desired_height_ = 600;
cover_loader_options_.desired_height_ = width();
cover_loader_options_.pad_output_image_ = true;
cover_loader_options_.scale_output_image_ = true;
QImage image = ImageUtils::ScaleAndPad(image_strawberry_, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
if (!image.isNull()) pixmap_current_ = QPixmap::fromImage(image);
if (!image.isNull()) {
pixmap_current_ = QPixmap::fromImage(image);
}
QObject::connect(timeline_fade_, &QTimeLine::valueChanged, this, &ContextAlbum::FadePreviousTrack);
timeline_fade_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0
timeline_fade_->setDirection(QTimeLine::Forward);
QObject::connect(timeline_fade_, &QTimeLine::valueChanged, this, &ContextAlbum::FadeCurrentCover);
QObject::connect(timeline_fade_, &QTimeLine::finished, this, &ContextAlbum::FadeCurrentCoverFinished);
}
@@ -86,8 +89,21 @@ void ContextAlbum::Init(ContextView *context_view, AlbumCoverChoiceController *a
}
void ContextAlbum::contextMenuEvent(QContextMenuEvent *e) {
if (menu_ && image_original_ != image_strawberry_) menu_->popup(mapToGlobal(e->pos()));
QSize ContextAlbum::sizeHint() const {
return QSize(pixmap_current_.width(), pixmap_current_.height());
}
void ContextAlbum::paintEvent(QPaintEvent*) {
QPainter p(this);
p.setRenderHint(QPainter::SmoothPixmapTransform);
DrawPreviousCovers(&p);
DrawImage(&p, pixmap_current_, pixmap_current_opacity_);
DrawSpinner(&p);
p.end();
}
void ContextAlbum::mouseDoubleClickEvent(QMouseEvent *e) {
@@ -99,93 +115,146 @@ void ContextAlbum::mouseDoubleClickEvent(QMouseEvent *e) {
}
void ContextAlbum::paintEvent(QPaintEvent*) {
void ContextAlbum::contextMenuEvent(QContextMenuEvent *e) {
QPainter p(this);
DrawImage(&p);
// Draw the previous track's image if we're fading
if (!pixmap_previous_.isNull()) {
p.setOpacity(pixmap_previous_opacity_);
p.drawPixmap(0, 0, pixmap_previous_);
if (menu_ && image_original_ != image_strawberry_) {
menu_->popup(mapToGlobal(e->pos()));
}
else {
QWidget::contextMenuEvent(e);
}
}
void ContextAlbum::DrawImage(QPainter *p) {
p->setRenderHint(QPainter::SmoothPixmapTransform);
void ContextAlbum::UpdateWidth(const int new_width) {
if (width() != prev_width_) {
cover_loader_options_.desired_height_ = width() - kWidgetSpacing;
QImage image = ImageUtils::ScaleAndPad(image_original_, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
if (image.isNull()) pixmap_current_ = QPixmap();
else pixmap_current_ = QPixmap::fromImage(image);
prev_width_ = width();
if (new_width != cover_loader_options_.desired_height_) {
cover_loader_options_.desired_height_ = new_width;
ScaleCover();
ScalePreviousCovers();
updateGeometry();
}
p->drawPixmap(0, 0, width() - kWidgetSpacing, width() - kWidgetSpacing, pixmap_current_);
if (downloading_covers_ && spinner_animation_) {
p->drawPixmap(50, 50, 16, 16, spinner_animation_->currentPixmap());
}
}
void ContextAlbum::FadePreviousTrack(const qreal value) {
pixmap_previous_opacity_ = value;
if (qFuzzyCompare(pixmap_previous_opacity_, qreal(0.0))) {
image_previous_ = QImage();
pixmap_previous_ = QPixmap();
}
update();
if (value == 0 && image_original_ == image_strawberry_) {
emit FadeStopFinished();
}
}
void ContextAlbum::ScaleCover() {
cover_loader_options_.desired_height_ = width() - kWidgetSpacing;
QImage image = ImageUtils::ScaleAndPad(image_original_, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
if (image.isNull()) pixmap_current_ = QPixmap();
else pixmap_current_ = QPixmap::fromImage(image);
prev_width_ = width();
update();
}
void ContextAlbum::SetImage(QImage image) {
if (image.isNull()) image = image_strawberry_;
if (image.isNull()) {
image = image_strawberry_;
}
if (downloading_covers_) {
downloading_covers_ = false;
spinner_animation_.reset();
}
// Cache the current pixmap so we can fade between them
pixmap_previous_ = QPixmap(width() - kWidgetSpacing, width() - kWidgetSpacing);
pixmap_previous_.fill(palette().window().color());
pixmap_previous_opacity_ = 1.0;
QImage image_previous = image_original_;
QPixmap pixmap_previous = pixmap_current_;
qreal opacity_previous = pixmap_current_opacity_;
QPainter p(&pixmap_previous_);
DrawImage(&p);
p.end();
image_previous_ = image_original_;
image_original_ = image;
pixmap_current_opacity_ = 0.0;
ScaleCover();
// Were we waiting for this cover to load before we started fading?
if (!pixmap_previous_.isNull() && timeline_fade_) {
if (!pixmap_previous.isNull()) {
std::shared_ptr<PreviousCover> previous_cover = std::make_shared<PreviousCover>();
previous_cover->image = image_previous;
previous_cover->pixmap = pixmap_previous;
previous_cover->opacity = opacity_previous;
previous_cover->timeline.reset(new QTimeLine(kFadeTimeLineMs), [](QTimeLine *timeline) { timeline->deleteLater(); });
previous_cover->timeline->setDirection(QTimeLine::Backward);
previous_cover->timeline->setCurrentTime(timeline_fade_->state() == QTimeLine::Running ? timeline_fade_->currentTime() : kFadeTimeLineMs);
QObject::connect(previous_cover->timeline.get(), &QTimeLine::valueChanged, this, [this, previous_cover]() { FadePreviousCover(previous_cover); });
QObject::connect(previous_cover->timeline.get(), &QTimeLine::finished, this, [this, previous_cover]() { FadePreviousCoverFinished(previous_cover); });
previous_covers_ << previous_cover;
previous_cover->timeline->start();
}
if (timeline_fade_->state() == QTimeLine::Running) {
timeline_fade_->stop();
timeline_fade_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0
timeline_fade_->start();
}
timeline_fade_->start();
}
void ContextAlbum::DrawImage(QPainter *p, const QPixmap &pixmap, const qreal opacity) {
if (qFuzzyCompare(opacity, static_cast<qreal>(0.0))) return;
p->setOpacity(opacity);
p->drawPixmap(0, 0, pixmap.width(), pixmap.height(), pixmap);
}
void ContextAlbum::DrawSpinner(QPainter *p) {
if (downloading_covers_) {
p->drawPixmap(50, 50, 16, 16, spinner_animation_->currentPixmap());
}
}
void ContextAlbum::DrawPreviousCovers(QPainter *p) {
for (std::shared_ptr<PreviousCover> previous_cover : previous_covers_) {
DrawImage(p, previous_cover->pixmap, previous_cover->opacity);
}
}
void ContextAlbum::FadeCurrentCover(const qreal value) {
if (value <= pixmap_current_opacity_) return;
pixmap_current_opacity_ = value;
update();
}
void ContextAlbum::FadeCurrentCoverFinished() {
if (image_original_ == image_strawberry_) {
emit FadeStopFinished();
}
}
void ContextAlbum::FadePreviousCover(std::shared_ptr<PreviousCover> previous_cover) {
if (previous_cover->timeline->currentValue() >= previous_cover->opacity) return;
previous_cover->opacity = previous_cover->timeline->currentValue();
}
void ContextAlbum::FadePreviousCoverFinished(std::shared_ptr<PreviousCover> previous_cover) {
previous_covers_.removeAll(previous_cover);
}
void ContextAlbum::ScaleCover() {
QImage image = ImageUtils::ScaleAndPad(image_original_, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
if (image.isNull()) {
pixmap_current_ = QPixmap();
}
else {
pixmap_current_ = QPixmap::fromImage(image);
}
}
void ContextAlbum::ScalePreviousCovers() {
for (std::shared_ptr<PreviousCover> previous_cover : previous_covers_) {
QImage image = ImageUtils::ScaleAndPad(previous_cover->image, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
if (image.isNull()) {
previous_cover->pixmap = QPixmap();
}
else {
previous_cover->pixmap = QPixmap::fromImage(image);
}
}
}

View File

@@ -1,6 +1,6 @@
/*
* Strawberry Music Player
* Copyright 2020-2021, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2020-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
@@ -27,6 +27,7 @@
#include <QtGlobal>
#include <QObject>
#include <QWidget>
#include <QList>
#include <QString>
#include <QImage>
#include <QPixmap>
@@ -50,15 +51,31 @@ class ContextAlbum : public QWidget {
void Init(ContextView *context_view, AlbumCoverChoiceController *album_cover_choice_controller);
void SetImage(QImage image = QImage());
void UpdateWidth(const int width);
protected:
QSize sizeHint() const override;
void paintEvent(QPaintEvent*) override;
void contextMenuEvent(QContextMenuEvent *e) override;
void mouseDoubleClickEvent(QMouseEvent *e) override;
void contextMenuEvent(QContextMenuEvent *e) override;
private:
void DrawImage(QPainter *p);
struct PreviousCover {
PreviousCover() : opacity(0.0) {}
QImage image;
QPixmap pixmap;
qreal opacity;
std::shared_ptr<QTimeLine> timeline;
};
QList<std::shared_ptr<PreviousCover>> previous_covers_;
void DrawImage(QPainter *p, const QPixmap &pixmap, const qreal opacity);
void DrawSpinner(QPainter *p);
void DrawPreviousCovers(QPainter *p);
void ScaleCover();
void ScalePreviousCovers();
void GetCoverAutomatically();
signals:
@@ -67,13 +84,16 @@ class ContextAlbum : public QWidget {
private slots:
void Update() { update(); }
void AutomaticCoverSearchDone();
void FadePreviousTrack(const qreal value);
void FadeCurrentCover(const qreal value);
void FadeCurrentCoverFinished();
void FadePreviousCover(std::shared_ptr<PreviousCover> previouscover);
void FadePreviousCoverFinished(std::shared_ptr<PreviousCover> previouscover);
public slots:
void SearchCoverInProgress();
private:
static const int kWidgetSpacing;
static const int kFadeTimeLineMs;
private:
QMenu *menu_;
@@ -84,12 +104,9 @@ class ContextAlbum : public QWidget {
QTimeLine *timeline_fade_;
QImage image_strawberry_;
QImage image_original_;
QImage image_previous_;
QPixmap pixmap_current_;
QPixmap pixmap_previous_;
qreal pixmap_previous_opacity_;
qreal pixmap_current_opacity_;
std::unique_ptr<QMovie> spinner_animation_;
int prev_width_;
};
#endif // CONTEXTALBUM_H

View File

@@ -1,390 +0,0 @@
/*
* Strawberry Music Player
* This code was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <functional>
#include <algorithm>
#include <QObject>
#include <QtGlobal>
#include <QMutex>
#include <QMimeData>
#include <QMetaType>
#include <QVariant>
#include <QList>
#include <QSet>
#include <QRegularExpression>
#include <QString>
#include <QStringList>
#include <QUrl>
#include <QImage>
#include <QPixmapCache>
#include "core/application.h"
#include "core/database.h"
#include "core/iconloader.h"
#include "collection/collectionquery.h"
#include "collection/collectionbackend.h"
#include "collection/collectionmodel.h"
#include "collection/collectionitem.h"
#include "playlist/playlistmanager.h"
#include "playlist/songmimedata.h"
#include "covermanager/albumcoverloader.h"
#include "covermanager/albumcoverloaderoptions.h"
#include "covermanager/albumcoverloaderresult.h"
#include "contextalbumsmodel.h"
const int ContextAlbumsModel::kPrettyCoverSize = 32;
ContextAlbumsModel::ContextAlbumsModel(CollectionBackend *backend, Application *app, QObject *parent)
: SimpleTreeModel<CollectionItem>(new CollectionItem(this), parent),
backend_(backend),
app_(app),
album_icon_(IconLoader::Load("cdcase")) {
root_->lazy_loaded = true;
cover_loader_options_.get_image_data_ = false;
cover_loader_options_.scale_output_image_ = true;
cover_loader_options_.pad_output_image_ = true;
cover_loader_options_.desired_height_ = kPrettyCoverSize;
QObject::connect(app_->album_cover_loader(), &AlbumCoverLoader::AlbumCoverLoaded, this, &ContextAlbumsModel::AlbumCoverLoaded);
QIcon nocover = IconLoader::Load("cdcase");
QList<QSize> nocover_sizes = nocover.availableSizes();
no_cover_icon_ = nocover.pixmap(nocover_sizes.last()).scaled(kPrettyCoverSize, kPrettyCoverSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
ContextAlbumsModel::~ContextAlbumsModel() { delete root_; }
void ContextAlbumsModel::AddSongs(const SongList &songs) {
for (const Song &song : songs) {
if (song_nodes_.contains(song.id())) continue;
QString key = CollectionModel::ContainerKey(CollectionModel::GroupBy_Album, song);
CollectionItem *container = nullptr;
if (container_nodes_.contains(key)) {
container = container_nodes_[key];
}
else {
container = ItemFromSong(CollectionItem::Type_Container, true, root_, song, 0);
container_nodes_.insert(key, container);
}
song_nodes_[song.id()] = ItemFromSong(CollectionItem::Type_Song, true, container, song, -1);
}
}
QString ContextAlbumsModel::AlbumIconPixmapCacheKey(const QModelIndex &idx) {
QStringList path;
QModelIndex index_copy(idx);
while (index_copy.isValid()) {
path.prepend(index_copy.data().toString());
index_copy = index_copy.parent();
}
return "contextalbumsart:" + path.join("/");
}
QVariant ContextAlbumsModel::AlbumIcon(const QModelIndex &idx) {
CollectionItem *item = IndexToItem(idx);
if (!item) return no_cover_icon_;
// Check the cache for a pixmap we already loaded.
const QString cache_key = AlbumIconPixmapCacheKey(idx);
QPixmap cached_pixmap;
if (QPixmapCache::find(cache_key, &cached_pixmap)) {
return cached_pixmap;
}
// Maybe we're loading a pixmap already?
if (pending_cache_keys_.contains(cache_key)) {
return no_cover_icon_;
}
// No art is cached and we're not loading it already. Load art for the first song in the album.
SongList songs = GetChildSongs(idx);
if (!songs.isEmpty()) {
const quint64 id = app_->album_cover_loader()->LoadImageAsync(cover_loader_options_, songs.first());
pending_art_.insert(id, ItemAndCacheKey(item, cache_key));
pending_cache_keys_.insert(cache_key);
}
return no_cover_icon_;
}
void ContextAlbumsModel::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result) {
if (!pending_art_.contains(id)) return;
ItemAndCacheKey item_and_cache_key = pending_art_.take(id);
CollectionItem *item = item_and_cache_key.first;
if (!item) return;
const QString &cache_key = item_and_cache_key.second;
if (pending_cache_keys_.contains(cache_key)) {
pending_cache_keys_.remove(cache_key);
}
// Insert this image in the cache.
if (!result.success || result.image_scaled.isNull() || result.type == AlbumCoverLoaderResult::Type_ManuallyUnset) {
// Set the no_cover image so we don't continually try to load art.
QPixmapCache::insert(cache_key, no_cover_icon_);
}
else {
QPixmap image_pixmap;
image_pixmap = QPixmap::fromImage(result.image_scaled);
QPixmapCache::insert(cache_key, image_pixmap);
}
const QModelIndex idx = ItemToIndex(item);
emit dataChanged(idx, idx);
}
QVariant ContextAlbumsModel::data(const QModelIndex &idx, int role) const {
const CollectionItem *item = IndexToItem(idx);
if (role == Qt::DecorationRole && item->type == CollectionItem::Type_Container && item->container_level == 0) {
return const_cast<ContextAlbumsModel*>(this)->AlbumIcon(idx);
}
return data(item, role);
}
QVariant ContextAlbumsModel::data(const CollectionItem *item, int role) const {
switch (role) {
case Qt::DisplayRole:
case Qt::ToolTipRole:
return item->DisplayText();
case Qt::DecorationRole:
switch (item->type) {
case CollectionItem::Type_Container:
if (item->type == CollectionItem::Type_Container && item->container_level == 0) { return album_icon_; }
break;
default:
break;
}
break;
case Role_Type:
return item->type;
case Role_ContainerType:
return item->type;
case Role_Key:
return item->key;
case Role_Artist:
return item->metadata.artist();
case Role_Editable:
if (item->type == CollectionItem::Type_Container) {
// if we have even one non editable item as a child, we ourselves are not available for edit
if (!item->children.isEmpty()) {
for (CollectionItem *child : item->children) {
if (!data(child, role).toBool()) {
return false;
}
}
return true;
}
else {
return false;
}
}
else if (item->type == CollectionItem::Type_Song) {
return item->metadata.IsEditable();
}
else {
return false;
}
case Role_SortText:
return item->SortText();
default:
return QVariant();
}
return QVariant();
}
void ContextAlbumsModel::Reset() {
for (QMap<QString, CollectionItem*>::const_iterator it = container_nodes_.constBegin(); it != container_nodes_.constEnd(); ++it) {
const QString cache_key = AlbumIconPixmapCacheKey(ItemToIndex(it.value()));
QPixmapCache::remove(cache_key);
}
beginResetModel();
delete root_;
song_nodes_.clear();
container_nodes_.clear();
pending_art_.clear();
pending_cache_keys_.clear();
root_ = new CollectionItem(this);
root_->lazy_loaded = true;
endResetModel();
}
CollectionItem *ContextAlbumsModel::ItemFromSong(CollectionItem::Type item_type, const bool signal, CollectionItem *parent, const Song &s, const int container_level) {
if (signal) beginInsertRows(ItemToIndex(parent), static_cast<int>(parent->children.count()), static_cast<int>(parent->children.count()));
CollectionItem *item = new CollectionItem(item_type, parent);
item->container_level = container_level;
item->lazy_loaded = true;
if (item_type == CollectionItem::Type_Container) {
item->key = CollectionModel::ContainerKey(CollectionModel::GroupBy_Album, s);
item->display_text = CollectionModel::TextOrUnknown(s.album());
item->sort_text = CollectionModel::SortTextForArtist(s.album());
}
else {
item->key = s.album() + " " + s.title();
item->display_text = CollectionModel::TextOrUnknown(s.title());
item->sort_text = CollectionModel::SortTextForSong(s);
item->metadata = s;
}
if (signal) endInsertRows();
return item;
}
Qt::ItemFlags ContextAlbumsModel::flags(const QModelIndex &idx) const {
switch (IndexToItem(idx)->type) {
case CollectionItem::Type_Song:
case CollectionItem::Type_Container:
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
case CollectionItem::Type_Root:
case CollectionItem::Type_LoadingIndicator:
default:
return Qt::ItemIsEnabled;
}
}
QStringList ContextAlbumsModel::mimeTypes() const {
return QStringList() << "text/uri-list";
}
QMimeData *ContextAlbumsModel::mimeData(const QModelIndexList &indexes) const {
if (indexes.isEmpty()) return nullptr;
SongMimeData *data = new SongMimeData;
QList<QUrl> urls;
QSet<int> song_ids;
data->backend = backend_;
for (const QModelIndex &idx : indexes) {
GetChildSongs(IndexToItem(idx), &urls, &data->songs, &song_ids);
}
data->setUrls(urls);
data->name_for_new_playlist_ = PlaylistManager::GetNameForNewPlaylist(data->songs);
return data;
}
bool ContextAlbumsModel::CompareItems(const CollectionItem *a, const CollectionItem *b) const {
QVariant left(data(a, ContextAlbumsModel::Role_SortText));
QVariant right(data(b, ContextAlbumsModel::Role_SortText));
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (left.metaType().id() == QMetaType::Int)
#else
if (left.type() == QVariant::Int)
#endif
return left.toInt() < right.toInt();
else return left.toString() < right.toString();
}
void ContextAlbumsModel::GetChildSongs(CollectionItem *item, QList<QUrl> *urls, SongList *songs, QSet<int> *song_ids) const {
switch (item->type) {
case CollectionItem::Type_Container:{
QList<CollectionItem*> children = item->children;
std::sort(children.begin(), children.end(), std::bind(&ContextAlbumsModel::CompareItems, this, std::placeholders::_1, std::placeholders::_2));
for (CollectionItem *child : children) {
GetChildSongs(child, urls, songs, song_ids);
}
break;
}
case CollectionItem::Type_Song:
urls->append(item->metadata.url());
if (!song_ids->contains(item->metadata.id())) {
songs->append(item->metadata);
song_ids->insert(item->metadata.id());
}
break;
default:
break;
}
}
SongList ContextAlbumsModel::GetChildSongs(const QModelIndexList &indexes) const {
QList<QUrl> dontcare;
SongList ret;
QSet<int> song_ids;
for (const QModelIndex &idx : indexes) {
GetChildSongs(IndexToItem(idx), &dontcare, &ret, &song_ids);
}
return ret;
}
SongList ContextAlbumsModel::GetChildSongs(const QModelIndex &idx) const {
return GetChildSongs(QModelIndexList() << idx);
}

View File

@@ -1,111 +0,0 @@
/*
* Strawberry Music Player
* This code was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2013-2021, 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 CONTEXTALBUMSMODEL_H
#define CONTEXTALBUMSMODEL_H
#include "config.h"
#include <QtGlobal>
#include <QObject>
#include <QAbstractItemModel>
#include <QPair>
#include <QSet>
#include <QList>
#include <QMap>
#include <QVariant>
#include <QString>
#include <QStringList>
#include <QUrl>
#include <QImage>
#include <QPixmap>
#include <QIcon>
#include "core/simpletreemodel.h"
#include "core/song.h"
#include "collection/collectionquery.h"
#include "collection/collectionitem.h"
#include "covermanager/albumcoverloaderoptions.h"
#include "covermanager/albumcoverloaderresult.h"
class QMimeData;
class Application;
class CollectionBackend;
class CollectionItem;
class ContextAlbumsModel : public SimpleTreeModel<CollectionItem> {
Q_OBJECT
public:
explicit ContextAlbumsModel(CollectionBackend *backend, Application *app, QObject *parent = nullptr);
~ContextAlbumsModel() override;
static const int kPrettyCoverSize;
enum Role {
Role_Type = Qt::UserRole + 1,
Role_ContainerType,
Role_SortText,
Role_Key,
Role_Artist,
Role_Editable,
LastRole
};
void GetChildSongs(CollectionItem *item, QList<QUrl> *urls, SongList *songs, QSet<int> *song_ids) const;
SongList GetChildSongs(const QModelIndex &idx) const;
SongList GetChildSongs(const QModelIndexList &indexes) const;
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex &idx) const override;
QStringList mimeTypes() const override;
QMimeData *mimeData(const QModelIndexList &indexes) const override;
void Reset();
void AddSongs(const SongList &songs);
private slots:
void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result);
private:
CollectionItem *ItemFromSong(CollectionItem::Type item_type, const bool signal, CollectionItem *parent, const Song &s, const int container_level);
static QString AlbumIconPixmapCacheKey(const QModelIndex &idx);
QVariant AlbumIcon(const QModelIndex &idx);
QVariant data(const CollectionItem *item, int role) const;
bool CompareItems(const CollectionItem *a, const CollectionItem *b) const;
private:
CollectionBackend *backend_;
Application *app_;
QueryOptions query_options_;
QMap<QString, CollectionItem*> container_nodes_;
QMap<int, CollectionItem*> song_nodes_;
QIcon album_icon_;
QPixmap no_cover_icon_;
AlbumCoverLoaderOptions cover_loader_options_;
typedef QPair<CollectionItem*, QString> ItemAndCacheKey;
QMap<quint64, ItemAndCacheKey> pending_art_;
QSet<QString> pending_cache_keys_;
};
#endif // CONTEXTALBUMSMODEL_H

View File

@@ -1,434 +0,0 @@
/*
* Strawberry Music Player
* This code was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <memory>
#include <qcoreevent.h>
#include <QtGlobal>
#include <QTreeView>
#include <QItemSelectionModel>
#include <QSortFilterProxyModel>
#include <QAbstractItemView>
#include <QStyleOptionViewItem>
#include <QAbstractScrollArea>
#include <QMimeData>
#include <QList>
#include <QVariant>
#include <QString>
#include <QUrl>
#include <QLocale>
#include <QMessageBox>
#include <QMenu>
#include <QAction>
#include <QRect>
#include <QSize>
#include <QToolTip>
#include <QWhatsThis>
#include "core/application.h"
#include "core/iconloader.h"
#include "core/mimedata.h"
#include "core/utilities.h"
#include "collection/collectiondirectorymodel.h"
#include "collection/collectionmodel.h"
#include "collection/collectionitem.h"
#ifndef Q_OS_WIN
# include "device/devicemanager.h"
# include "device/devicestatefiltermodel.h"
#endif
#include "dialogs/edittagdialog.h"
#include "organize/organizedialog.h"
#include "contextalbumsmodel.h"
#include "contextalbumsview.h"
ContextItemDelegate::ContextItemDelegate(QObject *parent) : QStyledItemDelegate(parent) {}
bool ContextItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &idx) {
return true;
Q_UNUSED(option);
if (!event || !view) return false;
QString text = displayText(idx.data(), QLocale::system());
if (text.isEmpty() || !event) return false;
switch (event->type()) {
case QEvent::ToolTip: {
QSize real_text = sizeHint(option, idx);
QRect displayed_text = view->visualRect(idx);
bool is_elided = displayed_text.width() < real_text.width();
if (is_elided) {
QToolTip::showText(event->globalPos(), text, view);
}
else if (idx.data(Qt::ToolTipRole).isValid()) {
// If the item has a tooltip text, display it
QString tooltip_text = idx.data(Qt::ToolTipRole).toString();
QToolTip::showText(event->globalPos(), tooltip_text, view);
}
else {
// in case that another text was previously displayed
QToolTip::hideText();
}
return true;
}
case QEvent::QueryWhatsThis:
return true;
case QEvent::WhatsThis:
QWhatsThis::showText(event->globalPos(), text, view);
return true;
default:
break;
}
return false;
}
ContextAlbumsView::ContextAlbumsView(QWidget *parent)
: AutoExpandingTreeView(parent),
app_(nullptr),
context_menu_(nullptr),
load_(nullptr),
add_to_playlist_(nullptr),
add_to_playlist_enqueue_(nullptr),
open_in_new_playlist_(nullptr),
organize_(nullptr),
#ifndef Q_OS_WIN
copy_to_device_(nullptr),
#endif
edit_track_(nullptr),
edit_tracks_(nullptr),
show_in_browser_(nullptr),
is_in_keyboard_search_(false),
model_(nullptr) {
setStyleSheet("border: none;");
setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
setItemDelegate(new ContextItemDelegate(this));
setAttribute(Qt::WA_MacShowFocusRect, false);
setHeaderHidden(true);
setAllColumnsShowFocus(true);
setDragEnabled(true);
setDragDropMode(QAbstractItemView::DragOnly);
setSelectionMode(QAbstractItemView::ExtendedSelection);
SetAddOnDoubleClick(false);
}
ContextAlbumsView::~ContextAlbumsView() = default;
void ContextAlbumsView::SaveFocus() {
QModelIndex current = currentIndex();
QVariant type = model()->data(current, ContextAlbumsModel::Role_Type);
if (!type.isValid() || !(type.toInt() == CollectionItem::Type_Song || type.toInt() == CollectionItem::Type_Container || type.toInt() == CollectionItem::Type_Divider)) {
return;
}
last_selected_path_.clear();
last_selected_song_ = Song();
last_selected_container_ = QString();
switch (type.toInt()) {
case CollectionItem::Type_Song: {
QModelIndex index = current;
SongList songs = model_->GetChildSongs(index);
if (!songs.isEmpty()) {
last_selected_song_ = songs.last();
}
break;
}
case CollectionItem::Type_Container:
case CollectionItem::Type_Divider: {
break;
}
default:
return;
}
SaveContainerPath(current);
}
void ContextAlbumsView::SaveContainerPath(const QModelIndex &child) {
QModelIndex current = model()->parent(child);
QVariant type = model()->data(current, ContextAlbumsModel::Role_Type);
if (!type.isValid() || !(type.toInt() == CollectionItem::Type_Container || type.toInt() == CollectionItem::Type_Divider)) {
return;
}
QString text = model()->data(current, ContextAlbumsModel::Role_SortText).toString();
last_selected_path_ << text;
SaveContainerPath(current);
}
void ContextAlbumsView::RestoreFocus() {
if (last_selected_container_.isEmpty() && last_selected_song_.url().isEmpty()) {
return;
}
RestoreLevelFocus();
}
bool ContextAlbumsView::RestoreLevelFocus(const QModelIndex &parent) {
if (model()->canFetchMore(parent)) {
model()->fetchMore(parent);
}
int rows = model()->rowCount(parent);
for (int i = 0; i < rows; i++) {
QModelIndex current = model()->index(i, 0, parent);
QVariant type = model()->data(current, ContextAlbumsModel::Role_Type);
switch (type.toInt()) {
case CollectionItem::Type_Song:
if (!last_selected_song_.url().isEmpty()) {
QModelIndex index = qobject_cast<QSortFilterProxyModel*>(model())->mapToSource(current);
const SongList songs = model_->GetChildSongs(index);
if (std::any_of(songs.begin(), songs.end(), [this](const Song &song) { return song == last_selected_song_; })) {
setCurrentIndex(current);
return true;
}
}
break;
}
}
return false;
}
void ContextAlbumsView::Init(Application *app) {
app_ = app;
model_ = new ContextAlbumsModel(app_->collection_backend(), app_, this);
model_->Reset();
setModel(model_);
QObject::connect(model_, &ContextAlbumsModel::modelAboutToBeReset, this, &ContextAlbumsView::SaveFocus);
QObject::connect(model_, &ContextAlbumsModel::modelReset, this, &ContextAlbumsView::RestoreFocus);
}
void ContextAlbumsView::paintEvent(QPaintEvent *event) {
QTreeView::paintEvent(event);
}
void ContextAlbumsView::mouseReleaseEvent(QMouseEvent *e) {
QTreeView::mouseReleaseEvent(e);
}
void ContextAlbumsView::contextMenuEvent(QContextMenuEvent *e) {
if (!context_menu_) {
context_menu_ = new QMenu(this);
add_to_playlist_ = context_menu_->addAction(IconLoader::Load("media-playback-start"), tr("Append to current playlist"), this, &ContextAlbumsView::AddToPlaylist);
load_ = context_menu_->addAction(IconLoader::Load("media-playback-start"), tr("Replace current playlist"), this, &ContextAlbumsView::Load);
open_in_new_playlist_ = context_menu_->addAction(IconLoader::Load("document-new"), tr("Open in new playlist"), this, &ContextAlbumsView::OpenInNewPlaylist);
context_menu_->addSeparator();
add_to_playlist_enqueue_ = context_menu_->addAction(IconLoader::Load("go-next"), tr("Queue track"), this, &ContextAlbumsView::AddToPlaylistEnqueue);
context_menu_->addSeparator();
organize_ = context_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organize files..."), this, &ContextAlbumsView::Organize);
#ifndef Q_OS_WIN
copy_to_device_ = context_menu_->addAction(IconLoader::Load("device"), tr("Copy to device..."), this, &ContextAlbumsView::CopyToDevice);
#endif
context_menu_->addSeparator();
edit_track_ = context_menu_->addAction(IconLoader::Load("edit-rename"), tr("Edit track information..."), this, &ContextAlbumsView::EditTracks);
edit_tracks_ = context_menu_->addAction(IconLoader::Load("edit-rename"), tr("Edit tracks information..."), this, &ContextAlbumsView::EditTracks);
show_in_browser_ = context_menu_->addAction(IconLoader::Load("document-open-folder"), tr("Show in file browser..."), this, &ContextAlbumsView::ShowInBrowser);
context_menu_->addSeparator();
#ifndef Q_OS_WIN
copy_to_device_->setDisabled(app_->device_manager()->connected_devices_model()->rowCount() == 0);
QObject::connect(app_->device_manager()->connected_devices_model(), &DeviceStateFilterModel::IsEmptyChanged, copy_to_device_, &QAction::setDisabled);
#endif
}
context_menu_index_ = indexAt(e->pos());
if (!context_menu_index_.isValid()) return;
QModelIndexList selected_indexes = selectionModel()->selectedRows();
int regular_elements = 0;
int regular_editable = 0;
for (const QModelIndex &idx : selected_indexes) {
regular_elements++;
if (model_->data(idx, ContextAlbumsModel::Role_Editable).toBool()) {
regular_editable++;
}
}
// TODO: check if custom plugin actions should be enabled / visible
const int songs_selected = regular_elements;
const bool regular_elements_only = songs_selected == regular_elements && regular_elements > 0;
// in all modes
load_->setEnabled(songs_selected > 0);
add_to_playlist_->setEnabled(songs_selected > 0);
open_in_new_playlist_->setEnabled(songs_selected > 0);
add_to_playlist_enqueue_->setEnabled(songs_selected > 0);
// if neither edit_track not edit_tracks are available, we show disabled edit_track element
edit_track_->setVisible(regular_editable <= 1);
edit_track_->setEnabled(regular_editable == 1);
organize_->setVisible(regular_elements_only);
#ifndef Q_OS_WIN
copy_to_device_->setVisible(regular_elements_only);
#endif
// only when all selected items are editable
organize_->setEnabled(regular_elements == regular_editable);
#ifndef Q_OS_WIN
copy_to_device_->setEnabled(regular_elements == regular_editable);
#endif
context_menu_->popup(e->globalPos());
}
void ContextAlbumsView::Load() {
QMimeData *q_mimedata = model()->mimeData(selectedIndexes());
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
mimedata->clear_first_ = true;
}
emit AddToPlaylistSignal(q_mimedata);
}
void ContextAlbumsView::AddToPlaylist() {
emit AddToPlaylistSignal(model()->mimeData(selectedIndexes()));
}
void ContextAlbumsView::AddToPlaylistEnqueue() {
QMimeData *q_mimedata = model()->mimeData(selectedIndexes());
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
mimedata->enqueue_now_ = true;
}
emit AddToPlaylistSignal(q_mimedata);
}
void ContextAlbumsView::OpenInNewPlaylist() {
QMimeData *q_mimedata = model()->mimeData(selectedIndexes());
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
mimedata->open_in_new_playlist_ = true;
}
emit AddToPlaylistSignal(q_mimedata);
}
void ContextAlbumsView::scrollTo(const QModelIndex &idx, ScrollHint hint) {
if (is_in_keyboard_search_) {
QTreeView::scrollTo(idx, QAbstractItemView::PositionAtTop);
}
else {
QTreeView::scrollTo(idx, hint);
}
}
SongList ContextAlbumsView::GetSelectedSongs() const {
QModelIndexList selected_indexes = selectionModel()->selectedRows();
return model_->GetChildSongs(selected_indexes);
}
void ContextAlbumsView::Organize() {
if (!organize_dialog_) {
organize_dialog_ = std::make_unique<OrganizeDialog>(app_->task_manager(), app_->collection_backend(), this);
}
organize_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
organize_dialog_->SetCopy(false);
if (organize_dialog_->SetSongs(GetSelectedSongs())) {
organize_dialog_->show();
}
else {
QMessageBox::warning(this, tr("Error"), tr("None of the selected songs were suitable for copying to a device"));
}
}
void ContextAlbumsView::EditTracks() {
if (!edit_tag_dialog_) {
edit_tag_dialog_ = std::make_unique<EditTagDialog>(app_, this);
}
edit_tag_dialog_->SetSongs(GetSelectedSongs());
edit_tag_dialog_->show();
}
void ContextAlbumsView::CopyToDevice() {
#ifndef Q_OS_WIN
if (!organize_dialog_) {
organize_dialog_ = std::make_unique<OrganizeDialog>(app_->task_manager(), nullptr, this);
}
organize_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
organize_dialog_->SetCopy(true);
organize_dialog_->SetSongs(GetSelectedSongs());
organize_dialog_->show();
#endif
}
void ContextAlbumsView::ShowInBrowser() const {
const SongList songs = GetSelectedSongs();
QList<QUrl> urls;
urls.reserve(songs.count());
for (const Song &song : songs) {
urls << song.url();
}
Utilities::OpenInFileBrowser(urls);
}

View File

@@ -1,137 +0,0 @@
/*
* Strawberry Music Player
* This code was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2013-2021, 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 CONTEXTALBUMSVIEW_H
#define CONTEXTALBUMSVIEW_H
#include "config.h"
#include <memory>
#include <QObject>
#include <QAbstractItemModel>
#include <QAbstractItemView>
#include <QStyledItemDelegate>
#include <QStyleOption>
#include <QSet>
#include <QString>
#include "core/song.h"
#include "widgets/autoexpandingtreeview.h"
class QWidget;
class QMenu;
class QAction;
class QContextMenuEvent;
class QHelpEvent;
class QMouseEvent;
class QPaintEvent;
class Application;
class ContextAlbumsModel;
class EditTagDialog;
class OrganizeDialog;
class ContextItemDelegate : public QStyledItemDelegate {
Q_OBJECT
public:
explicit ContextItemDelegate(QObject *parent);
public slots:
bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &idx) override;
};
class ContextAlbumsView : public AutoExpandingTreeView {
Q_OBJECT
public:
explicit ContextAlbumsView(QWidget *parent = nullptr);
~ContextAlbumsView() override;
// Returns Songs currently selected in the collection view.
// Please note that the selection is recursive meaning that if for example an album is selected this will return all of it's songs.
SongList GetSelectedSongs() const;
void Init(Application *app);
// QTreeView
void scrollTo(const QModelIndex &idx, ScrollHint hint = EnsureVisible) override;
ContextAlbumsModel *albums_model() { return model_; }
public slots:
void SaveFocus();
void RestoreFocus();
protected:
// QWidget
void paintEvent(QPaintEvent *event) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void contextMenuEvent(QContextMenuEvent *e) override;
private slots:
void Load();
void AddToPlaylist();
void AddToPlaylistEnqueue();
void OpenInNewPlaylist();
void Organize();
void CopyToDevice();
void EditTracks();
void ShowInBrowser() const;
private:
void RecheckIsEmpty();
bool RestoreLevelFocus(const QModelIndex &parent = QModelIndex());
void SaveContainerPath(const QModelIndex &child);
private:
Application *app_;
QMenu *context_menu_;
QModelIndex context_menu_index_;
QAction *load_;
QAction *add_to_playlist_;
QAction *add_to_playlist_enqueue_;
QAction *open_in_new_playlist_;
QAction *organize_;
#ifndef Q_OS_WIN
QAction *copy_to_device_;
#endif
QAction *edit_track_;
QAction *edit_tracks_;
QAction *show_in_browser_;
std::unique_ptr<OrganizeDialog> organize_dialog_;
std::unique_ptr<EditTagDialog> edit_tag_dialog_;
bool is_in_keyboard_search_;
// Save focus
Song last_selected_song_;
QString last_selected_container_;
QSet<QString> last_selected_path_;
ContextAlbumsModel *model_;
};
#endif // CONTEXTALBUMSVIEW_H

View File

@@ -1,6 +1,6 @@
/*
* Strawberry Music Player
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2013-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
@@ -41,6 +41,7 @@
#include <QScrollArea>
#include <QSpacerItem>
#include <QLabel>
#include <QTextEdit>
#include <QSettings>
#include <QResizeEvent>
#include <QContextMenuEvent>
@@ -52,6 +53,7 @@
#include "core/song.h"
#include "core/utilities.h"
#include "core/iconloader.h"
#include "widgets/resizabletextedit.h"
#include "engine/engine_fwd.h"
#include "engine/enginebase.h"
#include "engine/enginetype.h"
@@ -66,8 +68,8 @@
#include "contextview.h"
#include "contextalbum.h"
#include "contextalbumsmodel.h"
#include "contextalbumsview.h"
const int ContextView::kWidgetSpacing = 50;
ContextView::ContextView(QWidget *parent)
: QWidget(parent),
@@ -75,18 +77,17 @@ ContextView::ContextView(QWidget *parent)
collectionview_(nullptr),
album_cover_choice_controller_(nullptr),
lyrics_fetcher_(nullptr),
menu_(new QMenu(this)),
menu_options_(new QMenu(this)),
action_show_album_(nullptr),
action_show_data_(nullptr),
action_show_output_(nullptr),
action_show_albums_(nullptr),
action_show_lyrics_(nullptr),
action_search_lyrics_(nullptr),
layout_container_(new QVBoxLayout()),
widget_scrollarea_(new QWidget(this)),
layout_scrollarea_(new QVBoxLayout()),
scrollarea_(new QScrollArea(this)),
label_top_(new QLabel(this)),
textedit_top_(new ResizableTextEdit(this)),
widget_album_(new ContextAlbum(this)),
widget_stacked_(new QStackedWidget(this)),
widget_stop_(new QWidget(this)),
@@ -94,19 +95,13 @@ ContextView::ContextView(QWidget *parent)
layout_stop_(new QVBoxLayout()),
layout_play_(new QVBoxLayout()),
label_stop_summary_(new QLabel(this)),
spacer_stop_bottom_(new QSpacerItem(0, 20, QSizePolicy::Expanding, QSizePolicy::Expanding)),
widget_play_data_(new QWidget(this)),
widget_play_output_(new QWidget(this)),
layout_play_data_(new QGridLayout()),
layout_play_output_(new QGridLayout()),
label_play_albums_(new QLabel(this)),
label_play_lyrics_(new QLabel(this)),
widget_albums_(new ContextAlbumsView(this)),
//spacer_play_album_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
textedit_play_lyrics_(new ResizableTextEdit(this)),
spacer_play_output_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
spacer_play_data_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
spacer_play_albums_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
spacer_play_bottom_(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Expanding)),
label_filetype_title_(new QLabel(this)),
label_length_title_(new QLabel(this)),
label_samplerate_title_(new QLabel(this)),
@@ -125,12 +120,10 @@ ContextView::ContextView(QWidget *parent)
label_engine_(new QLabel(this)),
label_device_icon_(new QLabel(this)),
label_engine_icon_(new QLabel(this)),
spacer_bottom_(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Expanding)),
lyrics_tried_(false),
lyrics_id_(-1),
font_size_headline_(0),
font_size_normal_(0),
prev_width_(0) {
font_size_normal_(0) {
setLayout(layout_container_);
@@ -143,23 +136,21 @@ ContextView::ContextView(QWidget *parent)
scrollarea_->setWidget(widget_scrollarea_);
scrollarea_->setContentsMargins(0, 0, 0, 0);
scrollarea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollarea_->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
widget_scrollarea_->setObjectName("context-widget-scrollarea");
widget_scrollarea_->setLayout(layout_scrollarea_);
widget_scrollarea_->setContentsMargins(0, 0, 0, 0);
label_top_->setAlignment(Qt::AlignTop | Qt::AlignLeft);
label_top_->setWordWrap(true);
label_top_->setMinimumHeight(50);
label_top_->setContentsMargins(0, 0, 32, 0);
label_top_->setTextInteractionFlags(Qt::TextSelectableByMouse);
textedit_top_->setReadOnly(true);
textedit_top_->setFrameShape(QFrame::NoFrame);
layout_scrollarea_->setObjectName("context-layout-scrollarea");
layout_scrollarea_->setContentsMargins(15, 15, 15, 15);
layout_scrollarea_->addWidget(label_top_);
layout_scrollarea_->addWidget(textedit_top_);
layout_scrollarea_->addWidget(widget_album_);
layout_scrollarea_->addWidget(widget_stacked_);
layout_scrollarea_->addSpacerItem(spacer_bottom_);
layout_scrollarea_->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Expanding));
widget_stacked_->setContentsMargins(0, 0, 0, 0);
widget_stacked_->addWidget(widget_stop_);
@@ -176,9 +167,10 @@ ContextView::ContextView(QWidget *parent)
// Stopped
layout_stop_->setContentsMargins(5, 0, 40, 0);
label_stop_summary_->setAlignment(Qt::AlignLeft | Qt::AlignTop);
layout_stop_->setContentsMargins(0, 0, 0, 0);
layout_stop_->addWidget(label_stop_summary_);
layout_stop_->addSpacerItem(spacer_stop_bottom_);
// Playing
@@ -244,23 +236,17 @@ ContextView::ContextView(QWidget *parent)
widget_play_data_->setLayout(layout_play_data_);
label_play_lyrics_->setWordWrap(true);
label_play_lyrics_->setTextInteractionFlags(Qt::TextSelectableByMouse);
textedit_play_lyrics_->setReadOnly(true);
textedit_play_lyrics_->setFrameShape(QFrame::NoFrame);
textedit_play_lyrics_->hide();
widget_albums_->hide();
label_play_albums_->setWordWrap(true);
label_play_albums_->hide();
layout_play_->setContentsMargins(5, 0, 40, 0);
layout_play_->setContentsMargins(0, 0, 0, 0);
layout_play_->addWidget(widget_play_output_);
layout_play_->addSpacerItem(spacer_play_output_);
layout_play_->addWidget(widget_play_data_);
layout_play_->addSpacerItem(spacer_play_data_);
layout_play_->addWidget(label_play_albums_);
layout_play_->addWidget(widget_albums_);
layout_play_->addSpacerItem(spacer_play_albums_);
layout_play_->addWidget(label_play_lyrics_);
layout_play_->addSpacerItem(spacer_play_bottom_);
layout_play_->addWidget(textedit_play_lyrics_);
layout_play_->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Expanding));
labels_play_ << label_engine_title_
<< label_device_title_
@@ -268,9 +254,7 @@ ContextView::ContextView(QWidget *parent)
<< label_length_title_
<< label_samplerate_title_
<< label_bitdepth_title_
<< label_bitrate_title_
<< label_play_albums_
<< label_play_lyrics_;
<< label_bitrate_title_;
labels_play_data_ << label_engine_icon_
<< label_engine_
@@ -280,25 +264,16 @@ ContextView::ContextView(QWidget *parent)
<< label_length_
<< label_samplerate_
<< label_bitdepth_
<< label_bitrate_
<< label_play_albums_
<< label_play_lyrics_;
<< label_bitrate_;
labels_play_all_ = labels_play_ << labels_play_data_;
textedit_play_ << textedit_play_lyrics_;
QObject::connect(widget_album_, &ContextAlbum::FadeStopFinished, this, &ContextView::FadeStopFinished);
}
void ContextView::resizeEvent(QResizeEvent*) {
if (width() != prev_width_) {
widget_album_->setFixedSize(width() - 15, width());
prev_width_ = width();
}
}
void ContextView::Init(Application *app, CollectionView *collectionview, AlbumCoverChoiceController *album_cover_choice_controller) {
app_ = app;
@@ -306,7 +281,6 @@ void ContextView::Init(Application *app, CollectionView *collectionview, AlbumCo
album_cover_choice_controller_ = album_cover_choice_controller;
widget_album_->Init(this, album_cover_choice_controller_);
widget_albums_->Init(app_);
lyrics_fetcher_ = new LyricsFetcher(app_->lyrics_providers(), this);
QObject::connect(collectionview_, &CollectionView::TotalSongCountUpdated_, this, &ContextView::UpdateNoSong);
@@ -332,10 +306,6 @@ void ContextView::AddActions() {
action_show_output_->setCheckable(true);
action_show_output_->setChecked(true);
action_show_albums_ = new QAction(tr("Show albums by artist"), this);
action_show_albums_->setCheckable(true);
action_show_albums_->setChecked(false);
action_show_lyrics_ = new QAction(tr("Show song lyrics"), this);
action_show_lyrics_->setCheckable(true);
action_show_lyrics_->setChecked(true);
@@ -344,20 +314,18 @@ void ContextView::AddActions() {
action_search_lyrics_->setCheckable(true);
action_search_lyrics_->setChecked(true);
menu_->addAction(action_show_album_);
menu_->addAction(action_show_data_);
menu_->addAction(action_show_output_);
menu_->addAction(action_show_albums_);
menu_->addAction(action_show_lyrics_);
menu_->addAction(action_search_lyrics_);
menu_->addSeparator();
menu_options_->addAction(action_show_album_);
menu_options_->addAction(action_show_data_);
menu_options_->addAction(action_show_output_);
menu_options_->addAction(action_show_lyrics_);
menu_options_->addAction(action_search_lyrics_);
menu_options_->addSeparator();
ReloadSettings();
QObject::connect(action_show_album_, &QAction::triggered, this, &ContextView::ActionShowAlbums);
QObject::connect(action_show_album_, &QAction::triggered, this, &ContextView::ActionShowAlbum);
QObject::connect(action_show_data_, &QAction::triggered, this, &ContextView::ActionShowData);
QObject::connect(action_show_output_, &QAction::triggered, this, &ContextView::ActionShowOutput);
QObject::connect(action_show_albums_, &QAction::triggered, this, &ContextView::ActionShowAlbums);
QObject::connect(action_show_lyrics_, &QAction::triggered, this, &ContextView::ActionShowLyrics);
QObject::connect(action_search_lyrics_, &QAction::triggered, this, &ContextView::ActionSearchLyrics);
@@ -372,7 +340,6 @@ void ContextView::ReloadSettings() {
action_show_album_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ALBUM], true).toBool());
action_show_data_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::TECHNICAL_DATA], false).toBool());
action_show_output_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ENGINE_AND_DEVICE], false).toBool());
action_show_albums_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ALBUMS_BY_ARTIST], false).toBool());
action_show_lyrics_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::SONG_LYRICS], true).toBool());
action_search_lyrics_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::SEARCH_LYRICS], true).toBool());
font_headline_ = s.value("font_headline", font().family()).toString();
@@ -392,6 +359,16 @@ void ContextView::ReloadSettings() {
}
void ContextView::resizeEvent(QResizeEvent *e) {
if (e->size().width() != e->oldSize().width()) {
widget_album_->UpdateWidth(width() - kWidgetSpacing);
}
QWidget::resizeEvent(e);
}
void ContextView::Playing() {}
void ContextView::Stopped() {
@@ -439,6 +416,7 @@ void ContextView::FadeStopFinished() {
widget_stacked_->setCurrentWidget(widget_stop_);
NoSong();
ResetSong();
widget_stacked_->updateGeometry();
}
@@ -456,9 +434,8 @@ void ContextView::NoSong() {
widget_album_->show();
}
label_top_->setStyleSheet("font: 20pt 'Open Sans', 'FreeSans', 'FreeSerif', 'Liberation Serif'; font-weight: Regular;");
label_top_->setText(tr("No song playing"));
textedit_top_->setStyleSheet("font: 20pt 'Open Sans', 'FreeSans', 'FreeSerif', 'Liberation Serif'; font-weight: Regular;");
textedit_top_->setText(tr("No song playing"));
QString html;
if (collectionview_->TotalSongs() == 1) html += tr("%1 song").arg(collectionview_->TotalSongs());
@@ -480,17 +457,20 @@ void ContextView::NoSong() {
void ContextView::UpdateFonts() {
QString font_style = QString("font: %2pt \"%1\"; font-weight: regular;").arg(font_normal_).arg(font_size_normal_);
for (QLabel *l : labels_play_all_) {
l->setStyleSheet(QString("font: %2pt \"%1\"; font-weight: regular;").arg(font_normal_).arg(font_size_normal_));
l->setStyleSheet(font_style);
}
for (QTextEdit *e : textedit_play_) {
e->setStyleSheet(font_style);
}
label_play_albums_->setStyleSheet(QString("background-color: #3DADE8; color: rgb(255, 255, 255); font: %1pt \"%2\"; font-weight: regular;").arg(font_size_normal_).arg(font_normal_));
}
void ContextView::SetSong() {
label_top_->setStyleSheet(QString("font: %2pt \"%1\"; font-weight: regular;").arg(font_headline_).arg(font_size_headline_));
label_top_->setText(QString("<b>%1</b><br />%2").arg(Utilities::ReplaceMessage(title_fmt_, song_playing_, "<br />", true), Utilities::ReplaceMessage(summary_fmt_, song_playing_, "<br />", true)));
textedit_top_->setStyleSheet(QString("font: %2pt \"%1\"; font-weight: regular;").arg(font_headline_).arg(font_size_headline_));
textedit_top_->setText(QString("<b>%1</b><br />%2").arg(Utilities::ReplaceMessage(title_fmt_, song_playing_, "<br />", true), Utilities::ReplaceMessage(summary_fmt_, song_playing_, "<br />", true)));
label_stop_summary_->clear();
@@ -603,51 +583,23 @@ void ContextView::SetSong() {
spacer_play_output_->changeSize(0, 0, QSizePolicy::Fixed);
}
if (action_show_albums_->isChecked() && song_prev_.artist() != song_playing_.artist()) {
CollectionBackend::AlbumList albumlist;
widget_albums_->albums_model()->Reset();
albumlist = app_->collection_backend()->GetAlbumsByArtist(song_playing_.effective_albumartist());
if (albumlist.count() > 1) {
label_play_albums_->show();
widget_albums_->show();
label_play_albums_->setText("<b>" + tr("Albums by %1").arg(song_playing_.effective_albumartist().toHtmlEscaped()) + "</b>");
for (const CollectionBackend::Album &album : albumlist) {
SongList songs = app_->collection_backend()->GetAlbumSongs(song_playing_.effective_albumartist(), album.album);
widget_albums_->albums_model()->AddSongs(songs);
}
spacer_play_albums_->changeSize(20, 10, QSizePolicy::Fixed);
}
else {
label_play_albums_->hide();
widget_albums_->hide();
label_play_albums_->clear();
spacer_play_albums_->changeSize(0, 0, QSizePolicy::Fixed);
}
}
else if (!action_show_albums_->isChecked()) {
label_play_albums_->hide();
widget_albums_->hide();
label_play_albums_->clear();
widget_albums_->albums_model()->Reset();
spacer_play_albums_->changeSize(0, 0, QSizePolicy::Fixed);
}
if (action_show_lyrics_->isChecked()) {
label_play_lyrics_->show();
label_play_lyrics_->setText(lyrics_);
if (action_show_lyrics_->isChecked() && !lyrics_.isEmpty()) {
textedit_play_lyrics_->setText(lyrics_);
textedit_play_lyrics_->show();
}
else {
label_play_lyrics_->hide();
label_play_lyrics_->clear();
textedit_play_lyrics_->clear();
textedit_play_lyrics_->hide();
}
widget_stacked_->setCurrentWidget(widget_play_);
widget_stacked_->updateGeometry();
}
void ContextView::UpdateSong(const Song &song) {
label_top_->setText(QString("<b>%1</b><br />%2").arg(Utilities::ReplaceMessage(title_fmt_, song, "<br />", true), Utilities::ReplaceMessage(summary_fmt_, song, "<br />", true)));
textedit_top_->setText(QString("<b>%1</b><br />%2").arg(Utilities::ReplaceMessage(title_fmt_, song, "<br />", true), Utilities::ReplaceMessage(summary_fmt_, song, "<br />", true)));
if (action_show_data_->isChecked()) {
if (song.filetype() != song_playing_.filetype()) label_filetype_->setText(song.TextForFiletype());
@@ -711,22 +663,43 @@ void ContextView::ResetSong() {
l->clear();
}
for (QTextEdit *l : textedit_play_) {
l->clear();
}
widget_play_output_->hide();
widget_play_data_->hide();
textedit_play_lyrics_->hide();
}
void ContextView::UpdateLyrics(const quint64 id, const QString &provider, const QString &lyrics) {
if (static_cast<qint64>(id) != lyrics_id_) return;
lyrics_ = lyrics + "\n\n(Lyrics from " + provider + ")\n";
lyrics_id_ = -1;
if (action_show_lyrics_->isChecked()) {
label_play_lyrics_->setText(lyrics_);
if (action_show_lyrics_->isChecked() && !lyrics_.isEmpty()) {
textedit_play_lyrics_->setText(lyrics_);
textedit_play_lyrics_->show();
}
else {
textedit_play_lyrics_->clear();
textedit_play_lyrics_->hide();
}
else label_play_lyrics_->clear();
}
void ContextView::contextMenuEvent(QContextMenuEvent *e) {
if (menu_) menu_->popup(mapToGlobal(e->pos()));
if (menu_options_ && widget_stacked_->currentWidget() == widget_stop_) {
menu_options_->popup(mapToGlobal(e->pos()));
}
else {
QWidget::contextMenuEvent(e);
}
}
void ContextView::dragEnterEvent(QDragEnterEvent *e) {
@@ -788,17 +761,6 @@ void ContextView::ActionShowOutput() {
}
void ContextView::ActionShowAlbums() {
QSettings s;
s.beginGroup(ContextSettingsPage::kSettingsGroup);
s.setValue(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ALBUMS_BY_ARTIST], action_show_albums_->isChecked());
s.endGroup();
song_prev_ = Song();
if (song_playing_.is_valid()) SetSong();
}
void ContextView::ActionShowLyrics() {
QSettings s;

View File

@@ -1,6 +1,6 @@
/*
* Strawberry Music Player
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2013-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,10 +45,10 @@ class QContextMenuEvent;
class QDragEnterEvent;
class QDropEvent;
class ResizableTextEdit;
class Application;
class CollectionView;
class AlbumCoverChoiceController;
class ContextAlbumsView;
class LyricsFetcher;
class ContextView : public QWidget {
@@ -60,12 +60,11 @@ class ContextView : public QWidget {
void Init(Application *app, CollectionView *collectionview, AlbumCoverChoiceController *album_cover_choice_controller);
ContextAlbum *album_widget() const { return widget_album_; }
ContextAlbumsView *albums_widget() const { return widget_albums_; }
bool album_enabled() const { return action_show_album_->isChecked(); }
Song song_playing() const { return song_playing_; }
protected:
void resizeEvent(QResizeEvent*) override;
void resizeEvent(QResizeEvent *e) override;
void contextMenuEvent(QContextMenuEvent*) override;
void dragEnterEvent(QDragEnterEvent*) override;
void dropEvent(QDropEvent*) override;
@@ -88,7 +87,6 @@ class ContextView : public QWidget {
void ActionShowAlbum();
void ActionShowData();
void ActionShowOutput();
void ActionShowAlbums();
void ActionShowLyrics();
void ActionSearchLyrics();
void UpdateNoSong();
@@ -104,16 +102,17 @@ class ContextView : public QWidget {
void AlbumCoverLoaded(const Song &song, const QImage &image);
private:
static const int kWidgetSpacing;
Application *app_;
CollectionView *collectionview_;
AlbumCoverChoiceController *album_cover_choice_controller_;
LyricsFetcher *lyrics_fetcher_;
QMenu *menu_;
QMenu *menu_options_;
QAction *action_show_album_;
QAction *action_show_data_;
QAction *action_show_output_;
QAction *action_show_albums_;
QAction *action_show_lyrics_;
QAction *action_search_lyrics_;
@@ -121,7 +120,7 @@ class ContextView : public QWidget {
QWidget *widget_scrollarea_;
QVBoxLayout *layout_scrollarea_;
QScrollArea *scrollarea_;
QLabel *label_top_;
ResizableTextEdit *textedit_top_;
ContextAlbum *widget_album_;
QStackedWidget *widget_stacked_;
QWidget *widget_stop_;
@@ -129,20 +128,14 @@ class ContextView : public QWidget {
QVBoxLayout *layout_stop_;
QVBoxLayout *layout_play_;
QLabel *label_stop_summary_;
QSpacerItem *spacer_stop_bottom_;
QWidget *widget_play_data_;
QWidget *widget_play_output_;
QGridLayout *layout_play_data_;
QGridLayout *layout_play_output_;
QLabel *label_play_albums_;
QLabel *label_play_lyrics_;
ContextAlbumsView *widget_albums_;
ResizableTextEdit *textedit_play_lyrics_;
//QSpacerItem *spacer_play_album_;
QSpacerItem *spacer_play_output_;
QSpacerItem *spacer_play_data_;
QSpacerItem *spacer_play_albums_;
QSpacerItem *spacer_play_bottom_;
QLabel *label_filetype_title_;
QLabel *label_length_title_;
@@ -165,8 +158,6 @@ class ContextView : public QWidget {
QLabel *label_device_icon_;
QLabel *label_engine_icon_;
QSpacerItem *spacer_bottom_;
Song song_playing_;
Song song_prev_;
QImage image_original_;
@@ -181,11 +172,10 @@ class ContextView : public QWidget {
qreal font_size_normal_;
QList<QLabel*> labels_play_;
QList<ResizableTextEdit*> textedit_play_;
QList<QLabel*> labels_play_data_;
QList<QLabel*> labels_play_all_;
int prev_width_;
};
#endif // CONTEXTVIEW_H

View File

@@ -22,7 +22,6 @@
#include <QApplication>
#include <QObject>
#include <QVariant>
#include <QPalette>
#include <QColor>
#include <QSettings>

View File

@@ -29,12 +29,10 @@
#include <QObject>
#include <QThread>
#include <QVariant>
#include <QString>
#include "core/lazy.h"
#include "core/tagreaderclient.h"
#include "core/song.h"
#include "core/logging.h"
#include "database.h"
@@ -99,33 +97,33 @@ using namespace std::chrono_literals;
class ApplicationImpl {
public:
explicit ApplicationImpl(Application *app) :
tag_reader_client_([=]() {
tag_reader_client_([app]() {
TagReaderClient *client = new TagReaderClient(app);
app->MoveToNewThread(client);
client->Start();
return client;
}),
database_([=]() {
database_([app]() {
Database *db = new Database(app, app);
app->MoveToNewThread(db);
QTimer::singleShot(30s, db, &Database::DoBackup);
return db;
}),
appearance_([=]() { return new Appearance(app); }),
task_manager_([=]() { return new TaskManager(app); }),
player_([=]() { return new Player(app, app); }),
device_finders_([=]() { return new DeviceFinders(app); }),
appearance_([app]() { return new Appearance(app); }),
task_manager_([app]() { return new TaskManager(app); }),
player_([app]() { return new Player(app, app); }),
device_finders_([app]() { return new DeviceFinders(app); }),
#ifndef Q_OS_WIN
device_manager_([=]() { return new DeviceManager(app, app); }),
device_manager_([app]() { return new DeviceManager(app, app); }),
#endif
collection_([=]() { return new SCollection(app, app); }),
playlist_backend_([=]() {
collection_([app]() { return new SCollection(app, app); }),
playlist_backend_([this, app]() {
PlaylistBackend *backend = new PlaylistBackend(app, app);
app->MoveToThread(backend, database_->thread());
return backend;
}),
playlist_manager_([=]() { return new PlaylistManager(app); }),
cover_providers_([=]() {
playlist_manager_([app]() { return new PlaylistManager(app); }),
cover_providers_([app]() {
CoverProviders *cover_providers = new CoverProviders(app);
// Initialize the repository of cover providers.
cover_providers->AddProvider(new LastFmCoverProvider(app, cover_providers->network(), app));
@@ -143,13 +141,13 @@ class ApplicationImpl {
cover_providers->ReloadSettings();
return cover_providers;
}),
album_cover_loader_([=]() {
album_cover_loader_([app]() {
AlbumCoverLoader *loader = new AlbumCoverLoader(app);
app->MoveToNewThread(loader);
return loader;
}),
current_albumcover_loader_([=]() { return new CurrentAlbumCoverLoader(app, app); }),
lyrics_providers_([=]() {
current_albumcover_loader_([app]() { return new CurrentAlbumCoverLoader(app, app); }),
lyrics_providers_([app]() {
LyricsProviders *lyrics_providers = new LyricsProviders(app);
// Initialize the repository of lyrics providers.
lyrics_providers->AddProvider(new AuddLyricsProvider(lyrics_providers->network(), app));
@@ -161,7 +159,7 @@ class ApplicationImpl {
lyrics_providers->ReloadSettings();
return lyrics_providers;
}),
internet_services_([=]() {
internet_services_([app]() {
InternetServices *internet_services = new InternetServices(app);
#ifdef HAVE_SUBSONIC
internet_services->AddService(new SubsonicService(app, internet_services));
@@ -174,13 +172,13 @@ class ApplicationImpl {
#endif
return internet_services;
}),
radio_services_([=]() { return new RadioServices(app, app); }),
scrobbler_([=]() { return new AudioScrobbler(app, app); }),
radio_services_([app]() { return new RadioServices(app, app); }),
scrobbler_([app]() { return new AudioScrobbler(app, app); }),
#ifdef HAVE_MOODBAR
moodbar_loader_([=]() { return new MoodbarLoader(app, app); }),
moodbar_controller_([=]() { return new MoodbarController(app, app); }),
moodbar_loader_([app]() { return new MoodbarLoader(app, app); }),
moodbar_controller_([app]() { return new MoodbarController(app, app); }),
#endif
lastfm_import_([=]() { return new LastFMImport(app); })
lastfm_import_([app]() { return new LastFMImport(app); })
{}
Lazy<TagReaderClient> tag_reader_client_;

View File

@@ -24,7 +24,6 @@
#include <cstdlib>
#include <getopt.h>
#include <iostream>
#include <type_traits>
#include <QtGlobal>
#include <QObject>
@@ -369,8 +368,8 @@ QString CommandlineOptions::tr(const char *source_text) {
QDataStream &operator<<(QDataStream &s, const CommandlineOptions &a) {
s << qint32(a.player_action_)
<< qint32(a.url_list_action_)
s << static_cast<quint32>(a.player_action_)
<< static_cast<quint32>(a.url_list_action_)
<< a.set_volume_
<< a.volume_modifier_
<< a.seek_to_
@@ -406,8 +405,8 @@ QDataStream &operator>>(QDataStream &s, CommandlineOptions &a) {
>> a.playlist_name_
>> a.window_size_;
a.player_action_ = CommandlineOptions::PlayerAction(player_action);
a.url_list_action_ = CommandlineOptions::UrlListAction(url_list_action);
a.player_action_ = static_cast<CommandlineOptions::PlayerAction>(player_action);
a.url_list_action_ = static_cast<CommandlineOptions::UrlListAction>(url_list_action);
return s;

View File

@@ -21,7 +21,6 @@
#include "config.h"
#include <cstddef>
#include <sqlite3.h>
#include <boost/scope_exit.hpp>
@@ -31,20 +30,15 @@
#include <QIODevice>
#include <QDir>
#include <QFile>
#include <QList>
#include <QByteArray>
#include <QVariant>
#include <QString>
#include <QStringBuilder>
#include <QStringList>
#include <QRegularExpression>
#include <QUrl>
#include <QSqlDriver>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QStandardPaths>
#include <QtDebug>
#include "core/logging.h"
#include "taskmanager.h"
@@ -55,6 +49,7 @@
const char *Database::kDatabaseFilename = "strawberry.db";
const int Database::kSchemaVersion = 15;
const int Database::kMinSupportedSchemaVersion = 10;
const char *Database::kMagicAllSongsTables = "%allsongstables";
int Database::sNextConnectionId = 1;
@@ -153,35 +148,8 @@ QSqlDatabase Database::Connect() {
UpdateDatabaseSchema(0, db);
}
if (SchemaVersion(&db) < 10) {
// Register unicode from unicode61 tokenizer to drop old FTS3 tables.
// We need it also to drop old devices later when loading devices.
// And that's done in a different thread after schemas are upgraded, so register it anyway.
#ifdef SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
QVariant v = db.driver()->handle();
if (v.isValid() && qstrcmp(v.typeName(), "sqlite3*") == 0) {
sqlite3 *handle = *static_cast<sqlite3**>(v.data());
if (handle) {
(void)sqlite3_db_config(handle, SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, nullptr);
}
else qLog(Fatal) << "Unable to enable FTS3 tokenizer";
}
#endif
SqlQuery get_fts_tokenizer(db);
get_fts_tokenizer.prepare("SELECT fts3_tokenizer(:name)");
get_fts_tokenizer.BindValue(":name", "unicode61");
if (get_fts_tokenizer.exec() && get_fts_tokenizer.next()) {
SqlQuery set_fts_tokenizer(db);
set_fts_tokenizer.prepare("SELECT fts3_tokenizer(:name, :pointer)");
set_fts_tokenizer.BindValue(":name", "unicode");
set_fts_tokenizer.BindValue(":pointer", get_fts_tokenizer.value(0));
if (!set_fts_tokenizer.exec()) {
qLog(Warning) << "Couldn't register FTS3 tokenizer : " << set_fts_tokenizer.lastError();
}
}
else {
qLog(Warning) << "Couldn't get FTS3 tokenizer : " << get_fts_tokenizer.lastError();
}
if (SchemaVersion(&db) < kMinSupportedSchemaVersion) {
qFatal("Database schema too old.");
}
// Attach external databases
@@ -399,7 +367,6 @@ void Database::ExecSchemaCommandsFromFile(QSqlDatabase &db, const QString &filen
QFile schema_file(filename);
if (!schema_file.open(QIODevice::ReadOnly)) {
qFatal("Couldn't open schema file %s for reading: %s", filename.toUtf8().constData(), schema_file.errorString().toUtf8().constData());
return;
}
QByteArray data = schema_file.readAll();
QString schema = QString::fromUtf8(data);
@@ -417,9 +384,9 @@ void Database::ExecSchemaCommands(QSqlDatabase &db, const QString &schema, int s
QStringList commands;
commands = schema.split(QRegularExpression("; *\n\n"));
// We don't want this list to reflect possible DB schema changes so we initialize it before executing any statements.
// If no outer transaction is provided the song tables need to be queried before beginning an inner transaction! Otherwise
// DROP TABLE commands on song tables may fail due to database locks.
// We don't want this list to reflect possible DB schema changes, so we initialize it before executing any statements.
// If no outer transaction is provided the song tables need to be queried before beginning an inner transaction!
// Otherwise DROP TABLE commands on song tables may fail due to database locks.
const QStringList song_tables(SongsTables(db, schema_version));
if (!in_transaction) {

View File

@@ -61,6 +61,7 @@ class Database : public QObject {
};
static const int kSchemaVersion;
static const int kMinSupportedSchemaVersion;
static const char *kDatabaseFilename;
static const char *kMagicAllSongsTables;

View File

@@ -27,12 +27,9 @@
#include <QFile>
#include <QFileInfo>
#include <QString>
#include <QUrl>
#include <QtDebug>
#include "core/logging.h"
#include "utilities.h"
#include "song.h"
#include "musicstorage.h"
#include "filesystemmusicstorage.h"
@@ -61,7 +58,7 @@ bool FilesystemMusicStorage::CopyToStorage(const CopyJob &job) {
return false;
}
// Remove the destination file if it exists and we want to overwrite
// Remove the destination file if it exists, and we want to overwrite
if (job.overwrite_) {
if (dest.exists()) QFile::remove(dest.absoluteFilePath());
if (!cover_dest.filePath().isEmpty() && cover_dest.exists()) QFile::remove(cover_dest.absoluteFilePath());

View File

@@ -40,7 +40,7 @@ class FileSystemWatcherInterface : public QObject {
static FileSystemWatcherInterface *Create(QObject *parent = nullptr);
signals:
void PathChanged(const QString &path);
void PathChanged(QString path);
};
#endif

View File

@@ -63,7 +63,7 @@ QIcon IconLoader::Load(const QString &name, const int fixed_size, const int min_
QList<int> sizes;
if (fixed_size == 0) {
sizes << 22 << 32 << 48 << 64;
sizes << 22 << 32 << 48 << 64 << 128;
}
else {
sizes << fixed_size;

View File

@@ -21,7 +21,6 @@
#include <QList>
#include <QBuffer>
#include <QVariant>
#include <QByteArray>
#include <QString>
#include <QStringList>
@@ -31,7 +30,6 @@
#include <QPixmap>
#include <QPainter>
#include <QSize>
#include <QSettings>
#include "imageutils.h"
#include "core/utilities.h"

View File

@@ -67,7 +67,7 @@
QDebug operator<<(QDebug dbg, NSObject *object) {
QString ns_format = [ [NSString stringWithFormat:@"%@", object] UTF8String];
QString ns_format = [[NSString stringWithFormat:@"%@", object] UTF8String];
dbg.nospace() << ns_format;
return dbg.space();
@@ -149,11 +149,12 @@ QDebug operator<<(QDebug dbg, NSObject *object) {
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(handleURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
key_tap_ = [ [SPMediaKeyTap alloc] initWithDelegate:self];
key_tap_ = [[SPMediaKeyTap alloc] initWithDelegate:self];
if ([SPMediaKeyTap usesGlobalMediaKeyTap]) {
if ([key_tap_ startWatchingMediaKeys]) {
qLog(Debug) << "Media key monitoring started";
} else {
}
else {
qLog(Warning) << "Failed to start media key monitoring";
}
}
@@ -181,7 +182,7 @@ QDebug operator<<(QDebug dbg, NSObject *object) {
qLog(Debug) << "Wants to open:" << filenames;
[filenames enumerateObjectsUsingBlock:^(id object, NSUInteger, BOOL*) {
[self application:app openFile:(NSString*)object];
[self application:app openFile:reinterpret_cast<NSString*>(object)];
}];
}
@@ -254,7 +255,7 @@ QDebug operator<<(QDebug dbg, NSObject *object) {
- (void)SetApplicationHandler:(PlatformInterface*)handler {
delegate_ = [ [AppDelegate alloc] initWithHandler:handler];
delegate_ = [[AppDelegate alloc] initWithHandler:handler];
// App-shortcut-handler set before delegate is set.
// this makes sure the delegate's shortcut_handler is set
[delegate_ setShortcutHandler:shortcut_handler_];
@@ -263,7 +264,7 @@ QDebug operator<<(QDebug dbg, NSObject *object) {
// FIXME
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
[ [NSUserNotificationCenter defaultUserNotificationCenter]setDelegate:delegate_];
[[NSUserNotificationCenter defaultUserNotificationCenter]setDelegate:delegate_];
#pragma GCC diagnostic pop
}
@@ -402,7 +403,7 @@ QKeySequence KeySequenceFromNSEvent(NSEvent *event) {
void DumpDictionary(CFDictionaryRef dict) {
NSDictionary *d = (NSDictionary*)dict;
NSDictionary *d = reinterpret_cast<NSDictionary*>(dict);
NSLog(@"%@", d);
}

View File

@@ -82,7 +82,7 @@ class MacSystemTrayIconPrivate {
// Don't look now.
// This must be called after our custom NSApplicationDelegate has been set.
[(AppDelegate*)([NSApp delegate]) setDockMenu:dock_menu_];
[reinterpret_cast<AppDelegate*>([NSApp delegate]) setDockMenu:dock_menu_];
ClearNowPlaying();
}

View File

@@ -120,7 +120,6 @@
#include "widgets/trackslider.h"
#include "osd/osdbase.h"
#include "context/contextview.h"
#include "context/contextalbumsview.h"
#include "collection/collection.h"
#include "collection/collectionbackend.h"
#include "collection/collectiondirectorymodel.h"
@@ -136,6 +135,7 @@
#include "playlist/playlistmanager.h"
#include "playlist/playlistsequence.h"
#include "playlist/playlistview.h"
#include "playlist/playlistfilter.h"
#include "queue/queue.h"
#include "queue/queueview.h"
#include "playlistparsers/playlistparser.h"
@@ -223,7 +223,11 @@ const int kTrackPositionUpdateTimeMs = 1000;
#ifdef HAVE_QTSPARKLE
# ifdef _MSC_VER
# ifdef _M_X64
constexpr char QTSPARKLE_URL[] = "https://www.strawberrymusicplayer.org/sparkle-windows-msvc-x64";
# else
constexpr char QTSPARKLE_URL[] = "https://www.strawberrymusicplayer.org/sparkle-windows-msvc-x86";
# endif
# else
# ifdef __x86_64__
constexpr char QTSPARKLE_URL[] = "https://www.strawberrymusicplayer.org/sparkle-windows-mingw-x64";
@@ -242,7 +246,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
app_(app),
tray_icon_(tray_icon),
osd_(osd),
console_([=]() {
console_([app]() {
Console *console = new Console(app);
return console;
}),
@@ -260,7 +264,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
playlist_list_(new PlaylistListContainer(this)),
queue_view_(new QueueView(this)),
settings_dialog_(std::bind(&MainWindow::CreateSettingsDialog, this)),
cover_manager_([=]() {
cover_manager_([this, app]() {
AlbumCoverManager *cover_manager = new AlbumCoverManager(app, app->collection_backend(), this);
cover_manager->Init();
@@ -270,18 +274,18 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
return cover_manager;
}),
equalizer_(new Equalizer),
organize_dialog_([=]() {
organize_dialog_([this, app]() {
OrganizeDialog *dialog = new OrganizeDialog(app->task_manager(), app->collection_backend(), this);
dialog->SetDestinationModel(app->collection()->model()->directory_model());
return dialog;
}),
#ifdef HAVE_GSTREAMER
transcode_dialog_([=]() {
transcode_dialog_([this]() {
TranscodeDialog *dialog = new TranscodeDialog(this);
return dialog;
}),
#endif
add_stream_dialog_([=]() {
add_stream_dialog_([this]() {
AddStreamDialog *add_stream_dialog = new AddStreamDialog;
QObject::connect(add_stream_dialog, &AddStreamDialog::accepted, this, &MainWindow::AddStreamAccepted);
return add_stream_dialog;
@@ -336,7 +340,8 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
hidden_(false),
exit_(false),
exit_count_(0),
delete_files_(false) {
delete_files_(false),
ignore_close_(false) {
qLog(Debug) << "Starting";
@@ -346,6 +351,8 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
// Initialize the UI
ui_->setupUi(this);
setWindowIcon(IconLoader::Load("strawberry"));
album_cover_choice_controller_->Init(app);
ui_->multi_loading_indicator->SetTaskManager(app_->task_manager());
@@ -830,7 +837,6 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
QObject::connect(this, &MainWindow::AlbumCoverReady, context_view_, &ContextView::AlbumCoverLoaded);
QObject::connect(this, &MainWindow::SearchCoverInProgress, context_view_->album_widget(), &ContextAlbum::SearchCoverInProgress);
QObject::connect(context_view_, &ContextView::AlbumEnabledChanged, this, &MainWindow::TabSwitched);
QObject::connect(context_view_->albums_widget(), &ContextAlbumsView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
// Analyzer
QObject::connect(ui_->analyzer, &AnalyzerContainer::WheelEvent, this, &MainWindow::VolumeWheelEvent);
@@ -920,7 +926,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
ui_->tabs->setCurrentIndex(settings_.value("current_tab", 1).toInt());
FancyTabWidget::Mode default_mode = FancyTabWidget::Mode_LargeSidebar;
int tab_mode_int = settings_.value("tab_mode", default_mode).toInt();
FancyTabWidget::Mode tab_mode = FancyTabWidget::Mode(tab_mode_int);
FancyTabWidget::Mode tab_mode = static_cast<FancyTabWidget::Mode>(tab_mode_int);
if (tab_mode == FancyTabWidget::Mode_None) tab_mode = default_mode;
ui_->tabs->SetMode(tab_mode);
@@ -960,10 +966,9 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
break;
case BehaviourSettingsPage::Startup_Hide:
if (tray_icon_->IsSystemTrayAvailable() && tray_icon_->isVisible()) {
hide();
break;
}
// fallthrough
[[fallthrough]];
case BehaviourSettingsPage::Startup_Remember:
default: {
@@ -980,7 +985,9 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
}
else {
hidden_ = settings_.value("hidden", false).toBool();
setVisible(!hidden_);
if (!hidden_) {
show();
}
}
break;
}
@@ -1222,7 +1229,8 @@ void MainWindow::Exit() {
QObject::connect(app_->player()->engine(), &EngineBase::FadeoutFinishedSignal, this, &MainWindow::DoExit);
if (app_->player()->GetState() == Engine::Playing) {
app_->player()->Stop();
hide();
ignore_close_ = true;
close();
if (tray_icon_->IsSystemTrayAvailable()) {
tray_icon_->setVisible(false);
}
@@ -1506,9 +1514,9 @@ void MainWindow::PlayIndex(const QModelIndex &idx, Playlist::AutoScroll autoscro
if (!idx.isValid()) return;
int row = idx.row();
if (idx.model() == app_->playlist_manager()->current()->proxy()) {
if (idx.model() == app_->playlist_manager()->current()->filter()) {
// The index was in the proxy model (might've been filtered), so we need to get the actual row in the source model.
row = app_->playlist_manager()->current()->proxy()->mapToSource(idx).row();
row = app_->playlist_manager()->current()->filter()->mapToSource(idx).row();
}
app_->playlist_manager()->SetActiveToCurrent();
@@ -1521,9 +1529,9 @@ void MainWindow::PlaylistDoubleClick(const QModelIndex &idx) {
if (!idx.isValid()) return;
QModelIndex source_idx = idx;
if (idx.model() == app_->playlist_manager()->current()->proxy()) {
if (idx.model() == app_->playlist_manager()->current()->filter()) {
// The index was in the proxy model (might've been filtered), so we need to get the actual row in the source model.
source_idx = app_->playlist_manager()->current()->proxy()->mapToSource(idx);
source_idx = app_->playlist_manager()->current()->filter()->mapToSource(idx);
}
switch (doubleclick_playlist_addmode_) {
@@ -1550,16 +1558,13 @@ void MainWindow::VolumeWheelEvent(const int delta) {
void MainWindow::ToggleShowHide() {
if (hidden_) {
show();
SetHiddenInTray(false);
}
else if (isActiveWindow()) {
hide();
setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
SetHiddenInTray(true);
}
else if (isMinimized()) {
hide();
setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
SetHiddenInTray(false);
}
@@ -1594,8 +1599,14 @@ void MainWindow::showEvent(QShowEvent *e) {
void MainWindow::closeEvent(QCloseEvent *e) {
if (ignore_close_) {
ignore_close_ = false;
QMainWindow::closeEvent(e);
return;
}
if (!exit_) {
if (!hidden_ && keep_running_ && e->spontaneous() && tray_icon_->IsSystemTrayAvailable()) {
if (!hidden_ && keep_running_ && tray_icon_->IsSystemTrayAvailable()) {
SetHiddenInTray(true);
}
else {
@@ -1616,7 +1627,8 @@ void MainWindow::SetHiddenInTray(const bool hidden) {
if (hidden) {
was_maximized_ = isMaximized();
was_minimized_ = isMinimized();
hide();
ignore_close_ = true;
close();
}
else {
if (was_minimized_) {
@@ -1758,7 +1770,7 @@ void MainWindow::AddToPlaylistFromAction(QAction *action) {
// Get the selected playlist items
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
const QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
if (!source_index.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
if (!item) continue;
@@ -1797,8 +1809,8 @@ void MainWindow::PlaylistMenuHidden() {
void MainWindow::PlaylistRightClick(const QPoint global_pos, const QModelIndex &index) {
QModelIndex source_index = index;
if (index.model() == app_->playlist_manager()->current()->proxy()) {
source_index = app_->playlist_manager()->current()->proxy()->mapToSource(index);
if (index.model() == app_->playlist_manager()->current()->filter()) {
source_index = app_->playlist_manager()->current()->filter()->mapToSource(index);
}
playlist_menu_index_ = source_index;
@@ -1837,7 +1849,7 @@ void MainWindow::PlaylistRightClick(const QPoint global_pos, const QModelIndex &
for (const QModelIndex &idx : selection) {
const QModelIndex src_idx = app_->playlist_manager()->current()->proxy()->mapToSource(idx);
const QModelIndex src_idx = app_->playlist_manager()->current()->filter()->mapToSource(idx);
if (!src_idx.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(src_idx.row());
@@ -2041,7 +2053,7 @@ void MainWindow::RescanSongs() {
SongList songs;
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
const QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
if (!source_index.isValid()) continue;
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
if (!item) continue;
@@ -2066,7 +2078,7 @@ void MainWindow::EditTracks() {
PlaylistItemList items;
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
const QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
if (!source_index.isValid()) continue;
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
if (!item) continue;
@@ -2113,7 +2125,7 @@ void MainWindow::RenumberTracks() {
}
for (const QModelIndex &proxy_index : indexes) {
const QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
if (!source_index.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
if (!item) continue;
@@ -2144,7 +2156,7 @@ void MainWindow::SelectionSetValue() {
QVariant column_value = app_->playlist_manager()->current()->data(playlist_menu_index_);
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
const QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
if (!source_index.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
if (!item) continue;
@@ -2172,7 +2184,7 @@ void MainWindow::EditValue() {
if (column == -1) {
for (int i = 0; i < ui_->playlist->view()->model()->columnCount(); ++i) {
if (ui_->playlist->view()->isColumnHidden(i)) continue;
if (!Playlist::column_is_editable(Playlist::Column(i))) continue;
if (!Playlist::column_is_editable(static_cast<Playlist::Column>(i))) continue;
column = i;
break;
}
@@ -2190,7 +2202,7 @@ void MainWindow::AddFile() {
PlaylistParser parser(app_->collection_backend());
// Show dialog
QStringList file_names = QFileDialog::getOpenFileNames(this, tr("Add file"), directory, QString("%1 (%2);;%3;;%4").arg(tr("Music"), FileView::kFileFilter, parser.filters(), tr(kAllFilesFilterSpec)));
QStringList file_names = QFileDialog::getOpenFileNames(this, tr("Add file"), directory, QString("%1 (%2);;%3;;%4").arg(tr("Music"), FileView::kFileFilter, parser.filters(PlaylistParser::Type_Load), tr(kAllFilesFilterSpec)));
if (file_names.isEmpty()) return;
@@ -2258,7 +2270,7 @@ void MainWindow::ShowInCollection() {
SongList songs;
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
const QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
if (!source_index.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
if (item && item->IsLocalCollectionItem()) {
@@ -2511,7 +2523,7 @@ void MainWindow::AddFilesToTranscoder() {
QStringList filenames;
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
const QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
if (!source_index.isValid()) continue;
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
if (!item) continue;
@@ -2623,7 +2635,7 @@ void MainWindow::PlaylistOrganizeSelected(const bool copy) {
SongList songs;
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
const QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
if (!source_index.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
if (!item) continue;
@@ -2645,7 +2657,7 @@ void MainWindow::PlaylistOpenInBrowser() {
QList<QUrl> urls;
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
const QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
if (!source_index.isValid()) continue;
urls << QUrl(source_index.sibling(source_index.row(), Playlist::Column_Filename).data().toString());
}
@@ -2658,7 +2670,7 @@ void MainWindow::PlaylistCopyUrl() {
QList<QUrl> urls;
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
const QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
if (!source_index.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
if (!item) continue;
@@ -2679,7 +2691,7 @@ void MainWindow::PlaylistQueue() {
QModelIndexList indexes;
indexes.reserve(selected_rows.count());
for (const QModelIndex &proxy_index : selected_rows) {
indexes << app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
indexes << app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
}
app_->playlist_manager()->current()->queue()->ToggleTracks(indexes);
@@ -2692,7 +2704,7 @@ void MainWindow::PlaylistQueuePlayNext() {
QModelIndexList indexes;
indexes.reserve(selected_rows.count());
for (const QModelIndex &proxy_index : selected_rows) {
indexes << app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
indexes << app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
}
app_->playlist_manager()->current()->queue()->InsertFirst(indexes);
@@ -2705,7 +2717,7 @@ void MainWindow::PlaylistSkip() {
QModelIndexList indexes;
indexes.reserve(selected_rows.count());
for (const QModelIndex &proxy_index : selected_rows) {
indexes << app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
indexes << app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
}
app_->playlist_manager()->current()->SkipTracks(indexes);
@@ -2719,7 +2731,7 @@ void MainWindow::PlaylistCopyToDevice() {
SongList songs;
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
const QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
if (!source_index.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
if (!item) continue;
@@ -2868,7 +2880,7 @@ void MainWindow::PlaylistViewSelectionModelChanged() {
void MainWindow::PlaylistCurrentChanged(const QModelIndex &proxy_current) {
const QModelIndex source_current = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_current);
const QModelIndex source_current = app_->playlist_manager()->current()->filter()->mapToSource(proxy_current);
// If the user moves the current index using the keyboard and then presses
// F2, we don't want that editing the last column that was right clicked on.
@@ -2920,7 +2932,7 @@ void MainWindow::AutoCompleteTags() {
// Get the selected songs and start fetching tags for them
SongList songs;
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
const QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
if (!source_index.isValid()) continue;
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
if (!item) continue;
@@ -3137,7 +3149,7 @@ void MainWindow::PlaylistDelete() {
QStringList files;
bool is_current_item = false;
for (const QModelIndex &proxy_idx : ui_->playlist->view()->selectionModel()->selectedRows()) {
QModelIndex source_idx = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_idx);
QModelIndex source_idx = app_->playlist_manager()->current()->filter()->mapToSource(proxy_idx);
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_idx.row());
if (!item || !item->Metadata().url().isLocalFile()) continue;
QString filename = item->Metadata().url().toLocalFile();

View File

@@ -395,6 +395,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
bool exit_;
int exit_count_;
bool delete_files_;
bool ignore_close_;
};

View File

@@ -15,7 +15,7 @@
</property>
<property name="windowIcon">
<iconset resource="../../data/icons.qrc">
<normaloff>:/icons/64x64/strawberry.png</normaloff>:/icons/64x64/strawberry.png</iconset>
<normaloff>:/icons/128x128/strawberry.png</normaloff>:/icons/128x128/strawberry.png</iconset>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="layout_centralWidget">
@@ -448,7 +448,7 @@
<x>0</x>
<y>0</y>
<width>1131</width>
<height>26</height>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="menu_music">
@@ -749,9 +749,9 @@
</property>
</action>
<action name="action_save_all_playlists">
<property name="text">
<string>&amp;Save all playlists</string>
</property>
<property name="text">
<string>&amp;Save all playlists...</string>
</property>
</action>
<action name="action_next_playlist">
<property name="text">
@@ -903,7 +903,6 @@
</customwidget>
</customwidgets>
<resources>
<include location="../../data/data.qrc"/>
<include location="../../data/icons.qrc"/>
</resources>
<connections/>

View File

@@ -21,8 +21,6 @@
#include "config.h"
#include <cstdlib>
#include <memory>
#include <algorithm>
#include <QApplication>
@@ -41,7 +39,6 @@
#include <QDBusMessage>
#include <QDBusArgument>
#include <QDBusObjectPath>
#include <QtDebug>
#include "core/logging.h"

View File

@@ -22,12 +22,10 @@
#include <QtGlobal>
#include <QMutex>
#include <QVariant>
#include <QString>
#include <QStringList>
#include <QUrl>
#include <QNetworkProxy>
#include <QtDebug>
#include <QSettings>
#include "core/logging.h"

View File

@@ -20,7 +20,6 @@
#include "config.h"
#include <QtGlobal>
#include <QObject>
#include <QNetworkReply>
#include <QTimerEvent>

View File

@@ -28,15 +28,12 @@
#include <QtGlobal>
#include <QObject>
#include <QSortFilterProxyModel>
#include <QList>
#include <QMap>
#include <QVariant>
#include <QString>
#include <QUrl>
#include <QDateTime>
#include <QSettings>
#include <QtDebug>
#include "core/logging.h"
@@ -58,6 +55,7 @@
#include "collection/collectionbackend.h"
#include "playlist/playlist.h"
#include "playlist/playlistfilter.h"
#include "playlist/playlistitem.h"
#include "playlist/playlistmanager.h"
#include "playlist/playlistsequence.h"
@@ -385,7 +383,7 @@ void Player::NextItem(const Engine::TrackChangeFlags change, const Playlist::Aut
if (change == Engine::Auto) {
const PlaylistSequence::RepeatMode repeat_mode = active_playlist->sequence()->repeat_mode();
if (repeat_mode != PlaylistSequence::Repeat_Off) {
if ((repeat_mode == PlaylistSequence::Repeat_Track && nb_errors_received_ >= 3) || (nb_errors_received_ >= app_->playlist_manager()->active()->proxy()->rowCount())) {
if ((repeat_mode == PlaylistSequence::Repeat_Track && nb_errors_received_ >= 3) || (nb_errors_received_ >= app_->playlist_manager()->active()->filter()->rowCount())) {
// We received too many "Error" state changes: probably looping over a playlist which contains only unavailable elements: stop now.
nb_errors_received_ = 0;
Stop();
@@ -448,7 +446,7 @@ void Player::PlayPlaylistInternal(const Engine::TrackChangeFlags change, const P
bool Player::HandleStopAfter(const Playlist::AutoScroll autoscroll) {
if (app_->playlist_manager()->active()->stop_after_current()) {
// Find what the next track would've been, and mark that one as current so it plays next time the user presses Play.
// Find what the next track would've been, and mark that one as current, so it plays next time the user presses Play.
const int next_row = app_->playlist_manager()->active()->next_row();
if (next_row != -1) {
app_->playlist_manager()->active()->set_current_row(next_row, autoscroll, true);
@@ -624,7 +622,7 @@ void Player::EngineStateChanged(const Engine::State state) {
break;
case Engine::Error:
emit Error();
// fallthrough
[[fallthrough]];
case Engine::Empty:
case Engine::Idle:
pause_time_ = QDateTime();
@@ -843,7 +841,7 @@ void Player::TrackAboutToEnd() {
if (engine_->is_autocrossfade_enabled()) {
// Crossfade is on, so just start playing the next track. The current one will fade out, and the new one will fade in
// But, if there's no next track and we don't want to fade out, then do nothing and just let the track finish to completion.
// But, if there's no next track, and we don't want to fade out, then do nothing and just let the track finish to completion.
if (!engine_->is_fadeout_enabled() && !has_next_row) return;
// If the next track is on the same album (or same cue file),
@@ -854,7 +852,7 @@ void Player::TrackAboutToEnd() {
}
}
// Crossfade is off, so start preloading the next track so we don't get a gap between songs.
// Crossfade is off, so start preloading the next track, so we don't get a gap between songs.
if (!has_next_row || !next_item) return;
QUrl url = next_item->StreamUrl();

View File

@@ -29,12 +29,10 @@
#include <QIcon>
#include <QString>
#include <QUrl>
#include <QSettings>
#include "song.h"
#include "iconloader.h"
#include "qtsystemtrayicon.h"
#include "settings/behavioursettingspage.h"
SystemTrayIcon::SystemTrayIcon(QObject *parent)
: QSystemTrayIcon(parent),

View File

@@ -25,8 +25,6 @@
#include <glib-object.h>
#include <QtDebug>
template<typename T>
class ScopedGObject {
public:

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