Compare commits

...

314 Commits
1.0.1 ... 1.0.7

Author SHA1 Message Date
Jonas Kvinge
9f2ec22e95 Release 1.0.7 2022-07-25 21:45:27 +02:00
Jonas Kvinge
65b2e506b1 CI: Remove Ubuntu Impish 2022-07-25 17:29:35 +02:00
Jonas Kvinge
8bc07b5286 nsi: Add libgpg-error-0.dll 2022-07-25 15:51:05 +02:00
Jonas Kvinge
fe0af63795 Update Changelog 2022-07-25 15:28:25 +02:00
Jonas Kvinge
44ce7f4c67 CI: Disable audio cd for Windows MinGW build 2022-07-25 15:27:17 +02:00
Jonas Kvinge
252936134b nsi: Remove gstwinrt-1.0-0.dll 2022-07-25 04:25:08 +02:00
Jonas Kvinge
e255b06945 macdeployqt: Update gstreamer plugins 2022-07-25 03:56:38 +02:00
Jonas Kvinge
d726568a23 nsi: Add gstwavenc 2022-07-25 03:55:38 +02:00
Jonas Kvinge
66880a6de7 nsi: Update gstreamer plugins 2022-07-25 03:23:34 +02:00
Jonas Kvinge
fda622a0c0 Update Changelog 2022-07-24 23:44:54 +02:00
Jonas Kvinge
efa7d10f40 nsi: Add twolame 2022-07-21 03:04:48 +02:00
Strawbs Bot
348a3fabab Update translations 2022-07-21 01:09:44 +02:00
Jonas Kvinge
1bbaee605c PlaylistParser: Check file extension case-insensitive 2022-07-20 14:56:55 +02:00
Jonas Kvinge
22edf7a2b3 TagReaderTagParser: Fix reading and writing rating 2022-07-20 11:44:46 +02:00
Jonas Kvinge
3ffcc29249 Add back save all playlists action 2022-07-20 01:09:00 +02:00
Jonas Kvinge
21f1fe52c0 Remove save all playlists action
It's hard-coded to m3u, needs a new select directory dialog with option to select different playlist formats.

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

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

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

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

Fixes #893
2022-02-11 02:32:19 +01:00
Jonas Kvinge
01d4d404c0 globalshortcut-x11: Formatting 2022-02-11 02:32:09 +01:00
Jonas Kvinge
354bbf820f globalshortcut-x11: Drop use of variable for display 2022-02-11 02:31:45 +01:00
Strawbs Bot
7620f9ebbe Update translations 2022-02-09 01:04:47 +01:00
Jonas Kvinge
9c2c668a04 Add MSVC builder to CI 2022-02-08 23:22:50 +01:00
Jonas Kvinge
b6f5a5712b QobuzRequest: Fix setting composer and performer
Fixes #891
2022-02-08 21:28:11 +01:00
Jonas Kvinge
9e9df6eb16 Remove Fedora 36 2022-02-08 20:36:56 +01:00
Jonas Kvinge
f510c993a6 Remove openSUSE Leap 15.4 2022-02-08 20:36:20 +01:00
Jonas Kvinge
8ddcbaac27 Update nsi 2022-02-08 16:33:39 +01:00
Jonas Kvinge
3fcab72900 Change debug to uppercase in nsi 2022-02-07 23:55:49 +01:00
Jonas Kvinge
70aa2233e2 Change path to lockedlist in nsi 2022-02-07 23:46:24 +01:00
Jonas Kvinge
8123a2924d Update .gitignore 2022-02-07 22:46:01 +01:00
Jonas Kvinge
dd3c308b09 Only include qtsparkle directories when HAVE_QTSPARKLE is set 2022-02-07 21:17:36 +01:00
Jonas Kvinge
e56ca2ffd6 Update nsi for MSVC builds 2022-02-07 20:56:32 +01:00
Strawbs Bot
57c98c363c Update translations 2022-02-07 01:02:46 +01:00
Jonas Kvinge
2211508061 Transcoder: Use g_free 2022-02-06 18:47:23 +01:00
Jonas Kvinge
848e41919d SongLoader: Use g_free 2022-02-06 18:46:59 +01:00
Jonas Kvinge
dac613a8bb MoodbarPipeline: Use g_free 2022-02-06 18:37:11 +01:00
Jonas Kvinge
a1735278df Add 3rdparty getopt for MSVC 2022-02-06 17:29:07 +01:00
Jonas Kvinge
3730bd04a4 Add protobuf include dirs 2022-02-06 08:41:05 +01:00
Jonas Kvinge
eee3445d2f Silence some conversion warnings 2022-02-06 04:19:45 +01:00
Jonas Kvinge
8bf473dc3a SingleApplication: Simplify code 2022-02-06 04:18:59 +01:00
Jonas Kvinge
e106dda794 SingleApplication: Make const 2022-02-06 04:18:40 +01:00
Jonas Kvinge
fc35d2a35c Collection: Add I/O priority and thread priority to initialization list 2022-02-06 04:14:02 +01:00
Strawbs Bot
aef9ff0d38 Update translations 2022-02-06 01:03:48 +01:00
Jonas Kvinge
192fb46d1d Use deleteLater() for Subsonic, Tidal and QObuz requests 2022-02-06 00:58:50 +01:00
Jonas Kvinge
1dd4eb05f2 Update SingleApplication 2022-02-06 00:07:15 +01:00
Jonas Kvinge
79f0c494fa Update Changelog 2022-02-05 19:37:32 +01:00
Jonas Kvinge
7caeb47637 GstEnginePipeline: Use std::shared_ptr with deleteLater() for fader timeline
Fixes #890
2022-02-05 19:33:21 +01:00
Jonas Kvinge
ffef339ebd TrackSliderSlider: Fix compile with Qt 5 2022-02-05 19:06:58 +01:00
Jonas Kvinge
817153b20b SingleApplication: Remove use of deprecated QCryptographicHash::addData 2022-02-05 18:58:43 +01:00
Jonas Kvinge
686eb2e786 TrackSliderSlider: Use different constructor for QMouseEvent 2022-02-05 18:54:00 +01:00
Jonas Kvinge
53d5192477 Allow deleting CUE songs 2022-02-05 15:56:18 +01:00
Strawbs Bot
a172f5fe85 Update translations 2022-02-05 01:02:55 +01:00
Jonas Kvinge
288408795b Disable open audio CD menu when compiled without audio CD support 2022-02-04 19:45:30 +01:00
Jonas Kvinge
4b5a811b08 CI: Copy libsoup-3.0-0.dll 2022-02-04 19:09:53 +01:00
Jonas Kvinge
c1259d8b6e EditTagDialog: Add scrollarea
Fixes #888
2022-02-04 19:08:04 +01:00
Jonas Kvinge
3acbe431f7 Replace non-translated characters with underscore 2022-02-04 19:07:15 +01:00
Jonas Kvinge
40f381257d Use libsoup3 in nsi 2022-02-04 01:36:17 +01:00
Strawbs Bot
beec983f21 Update translations 2022-02-04 01:01:49 +01:00
Strawbs Bot
d20750012e Update translations 2022-01-31 01:21:46 +01:00
Jonas Kvinge
e31c9d74fa Add advanced settings for configuring collection watcher 2022-01-30 04:24:33 +01:00
Jonas Kvinge
78adc388df SubsonicRequest: Make sure covers are only requested once per cover ID
Fixes #885
2022-01-30 02:30:51 +01:00
Jonas Kvinge
609413cda4 SubsonicRequest: Fix requesting album covers 2022-01-30 01:56:29 +01:00
Jonas Kvinge
63e5d6a94a Require Qt 5.9 2022-01-29 21:33:33 +01:00
Jonas Kvinge
fd5970b647 Player: Don't set volume lower than 0 or higher than 100.
Fixes #884
2022-01-29 20:32:33 +01:00
Strawbs Bot
af38b8f92b Update translations 2022-01-29 01:32:04 +01:00
Jonas Kvinge
e676e65f9e Update Changelog 2022-01-29 00:31:28 +01:00
Jonas Kvinge
4c479301ff Register MtpConnection as metatype
Fixes:

```
00:13:02.210 WARN  unknown                          QObject::connect: Cannot queue arguments of type 'MtpConnection*'
00:13:02.210 WARN  unknown                          (Make sure 'MtpConnection*' is registered using qRegisterMetaType().)
```
2022-01-29 00:17:37 +01:00
Jonas Kvinge
98178947ae GioLister: Use nullptr 2022-01-29 00:07:00 +01:00
Jonas Kvinge
0dbf3b462b CollectionWatcher: Remove broken nomedia/nomusic handling
It causes songs to be stuck when adding a nomedia file to an existing
directory.
2022-01-28 23:56:10 +01:00
Jonas Kvinge
cd9f8b569b CollectionWatcher: Ignore temp files 2022-01-28 23:53:58 +01:00
Jonas Kvinge
6b23728efa Fix deleting songs from filesystemdevices 2022-01-28 23:32:49 +01:00
Jonas Kvinge
ff0f7ee483 SubsonicSettingsPage: Remove insecure from hex description 2022-01-28 22:35:58 +01:00
Jonas Kvinge
74498c3ac9 Remove remaining sparkle integration 2022-01-28 21:26:37 +01:00
Jonas Kvinge
7a61e740e8 Subsonic: Add button to delete songs
Fixes #883
2022-01-28 21:26:28 +01:00
Enrique Garcia
81e6b55c39 subsonic configuration: use the entered password when clicking Test 2022-01-22 14:11:37 +01:00
Jonas Kvinge
e439ac0e0e Update to ffmpeg 5 in nsi 2022-01-19 21:20:51 +01:00
Jonas Kvinge
7b9d784a64 AnalyzerBase: Remove obsolete code 2022-01-17 22:45:19 +01:00
Jonas Kvinge
56b2630a1c Fix QToolButton stylesheet for Qt 5 2022-01-16 17:53:57 +01:00
Strawbs Bot
6d5597a732 Update translations 2022-01-16 01:03:01 +01:00
Jonas Kvinge
c0a9345358 Add OpenMandriva to CI 2022-01-15 19:47:43 +01:00
Jonas Kvinge
2e4ad81fff Fix copying sparkle 2022-01-15 14:50:33 +01:00
Jonas Kvinge
1aad85a4f9 Add openmandriva support to rpm spec 2022-01-15 14:43:06 +01:00
Jonas Kvinge
fbd2993239 Remove use of sparkle 2022-01-15 02:24:48 +01:00
Jonas Kvinge
203228bd05 Remove use of brew install --cask 2022-01-15 02:20:54 +01:00
Strawbs Bot
da7edebe90 Update translations 2022-01-15 01:03:39 +01:00
Jonas Kvinge
c7444a189e Replace SUUpdater with SPUStandardUpdaterController 2022-01-15 00:04:21 +01:00
Jonas Kvinge
29235c5fa6 Update stylesheet to use property name for popupMode on QToolButton 2022-01-14 23:25:36 +01:00
Strawbs Bot
bf8374ff9f Update translations 2022-01-14 01:01:58 +01:00
Strawbs Bot
ba05e85e48 Update translations 2022-01-12 01:35:28 +01:00
WGH
a9aab0702c GIOLister: ignore system mounts as defined by GIO
Strawberry has some heuristics to exclude things
like the root mount, /boot, tmpfs, etc. from the devices list.

However, it's somewhat incomplete. GIO (GLib component)
has more complete definition of "internal system mounts"
that should not be presented to the user.

Additionally, don't try to query filesystems free/total size
if it's internal, as that triggers automounting for autofs
filesystems (#410).
2022-01-11 18:05:09 +01:00
Strawbs Bot
b5cf83d501 Update translations 2022-01-11 01:02:44 +01:00
Jonas Kvinge
1cc2e6303a Show menu when clicking icon for collection and internet search tool buttons 2022-01-10 22:51:27 +01:00
Jonas Kvinge
4509a07fff Add openSUSE Leap 15.4 2022-01-09 12:19:13 +01:00
Jonas Kvinge
ea419f6d40 Add Ubuntu Jammy 2022-01-09 03:26:33 +01:00
Jonas Kvinge
c9b6707468 Add Debian Bookworm 2022-01-09 03:26:33 +01:00
Jonas Kvinge
cf512a35a7 Add Fedora 36 2022-01-09 03:26:33 +01:00
Strawbs Bot
bdd3e5343d Update translations 2022-01-09 01:02:36 +01:00
Jonas Kvinge
80fd8cd338 Log Qt version on startup 2022-01-08 21:33:14 +01:00
Jonas Kvinge
eb48592083 Turn on git revision 2022-01-08 21:33:06 +01:00
370 changed files with 24633 additions and 21658 deletions

View File

@@ -7,7 +7,8 @@ assignees: ''
---
For technical issues, questions and feature suggestions/requests please use the forum on https://forum.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

File diff suppressed because it is too large Load Diff

6
.gitignore vendored
View File

@@ -105,7 +105,6 @@ Thumbs.db
# Stuff in dist
maketarball.sh
changelog
PKGBUILD
# Translations
translations.pot
@@ -119,3 +118,8 @@ stage/
*.snap
/snap/.snapcraft/
/*_source.tar.bz2
# MSVC
CMakeSettings.json
/.vs/
/out/

5
3rdparty/README.md vendored
View File

@@ -23,3 +23,8 @@ macdeployqt
A modified version of Qt's official macdeployqt utility that fixes some issues,
this version also deploys gstreamer plugins.
Can safely be deleted on other platforms.
getopt
------
getopt included only when compiling with MSVC on Windows.

2
3rdparty/getopt/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,2 @@
add_library(getopt STATIC getopt.c)
target_include_directories(getopt PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

562
3rdparty/getopt/getopt.c vendored Normal file
View File

@@ -0,0 +1,562 @@
/* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
/*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <stdarg.h>
#include <stdio.h>
#include <windows.h>
#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
#ifdef REPLACE_GETOPT
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
#undef optreset /* see getopt.h */
#define optreset __mingw_optreset
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#endif
#define PRINT_ERROR ((opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
#define BADCH (int)'?'
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#ifndef __CYGWIN__
#define __progname __argv[0]
#else
extern char __declspec(dllimport) *__progname;
#endif
#ifdef __CYGWIN__
static char EMSG[] = "";
#else
#define EMSG ""
#endif
static int getopt_internal(int, char * const *, const char *,
const struct option *, int *, int);
static int parse_long_options(char * const *, const char *,
const struct option *, int *, int);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
static char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static const char recargchar[] = "option requires an argument -- %c";
static const char recargstring[] = "option requires an argument -- %s";
static const char ambig[] = "ambiguous option -- %.*s";
static const char noarg[] = "option doesn't take an argument -- %.*s";
static const char illoptchar[] = "unknown option -- %c";
static const char illoptstring[] = "unknown option -- %s";
static void
_vwarnx(const char *fmt,va_list ap)
{
(void)fprintf(stderr,"%s: ",__progname);
if (fmt != NULL)
(void)vfprintf(stderr,fmt,ap);
(void)fprintf(stderr,"\n");
}
static void
warnx(const char *fmt,...)
{
va_list ap;
va_start(ap,fmt);
_vwarnx(fmt,ap);
va_end(ap);
}
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(int a, int b)
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(int panonopt_start, int panonopt_end, int opt_end,
char * const *nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
/*
* parse_long_options --
* Parse long options in argc/argv argument vector.
* Returns -1 if short_too is set and the option does not match long_options.
*/
static int
parse_long_options(char * const *nargv, const char *options,
const struct option *long_options, int *idx, int short_too)
{
char *current_argv, *has_equal;
size_t current_argv_len;
int i, ambiguous, match;
#define IDENTICAL_INTERPRETATION(_x, _y) \
(long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
long_options[(_x)].flag == long_options[(_y)].flag && \
long_options[(_x)].val == long_options[(_y)].val)
current_argv = place;
match = -1;
ambiguous = 0;
optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
ambiguous = 0;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (match == -1) /* partial match */
match = i;
else if (!IDENTICAL_INTERPRETATION(i, match))
ambiguous = 1;
}
if (ambiguous) {
/* ambiguous abbreviation */
if (PRINT_ERROR)
warnx(ambig, (int)current_argv_len,
current_argv);
optopt = 0;
return (BADCH);
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
warnx(noarg, (int)current_argv_len,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return (BADARG);
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR)
warnx(recargstring,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return (BADARG);
}
} else { /* unknown option */
if (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
warnx(illoptstring, current_argv);
optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
#undef IDENTICAL_INTERPRETATION
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
*/
static int
getopt_internal(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx, int flags)
{
char *oli; /* option letter list index */
int optchar, short_too;
static int posixly_correct = -1;
if (options == NULL)
return (-1);
/*
* XXX Some GNU programs (like cvs) set optind to 0 instead of
* XXX using optreset. Work around this braindamage.
*/
if (optind == 0)
optind = optreset = 1;
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*
* CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
* optreset != 0 for GNU compatibility.
*/
if (posixly_correct == -1 || optreset != 0)
posixly_correct = (GetEnvironmentVariableW(L"POSIXLY_CORRECT", NULL, 0) != 0);
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
if (*options == '+' || *options == '-')
options++;
optarg = NULL;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[optind]) != '-' ||
(place[1] == '\0' && strchr(options, '-') == NULL)) {
place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = EMSG;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are getopt_long_only()
*/
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
if (*place == '-')
place++; /* --foo long option */
else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options,
idx, short_too);
if (optchar != -1) {
place = EMSG;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
if (PRINT_ERROR)
warnx(illoptchar, optchar);
optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else /* white space */
place = nargv[optind];
optchar = parse_long_options(nargv, options, long_options,
idx, 0);
place = EMSG;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return (optchar);
}
#ifdef REPLACE_GETOPT
/*
* getopt --
* Parse argc/argv argument vector.
*
* [eventually this will replace the BSD getopt]
*/
int
getopt(int nargc, char * const *nargv, const char *options)
{
/*
* We don't pass FLAG_PERMUTE to getopt_internal() since
* the BSD getopt(3) (unlike GNU) has never done this.
*
* Furthermore, since many privileged programs call getopt()
* before dropping privileges it makes sense to keep things
* as simple (and bug-free) as possible.
*/
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
}
#endif /* REPLACE_GETOPT */
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE));
}
/*
* getopt_long_only --
* Parse argc/argv argument vector.
*/
int
getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY));
}

95
3rdparty/getopt/getopt.h vendored Normal file
View File

@@ -0,0 +1,95 @@
#ifndef __GETOPT_H__
/**
* DISCLAIMER
* This file has no copyright assigned and is placed in the Public Domain.
* This file is part of the mingw-w64 runtime package.
*
* The mingw-w64 runtime package and its code is distributed in the hope that it
* will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR
* IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to
* warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#define __GETOPT_H__
/* All the headers include this file. */
#include <crtdefs.h>
#ifdef __cplusplus
extern "C" {
#endif
extern int optind; /* index of first non-option in argv */
extern int optopt; /* single option character, as parsed */
extern int opterr; /* flag to enable built-in diagnostics... */
/* (user may set to zero, to suppress) */
extern char *optarg; /* pointer to argument of current option */
extern int getopt(int nargc, char * const *nargv, const char *options);
#ifdef _BSD_SOURCE
/*
* BSD adds the non-standard `optreset' feature, for reinitialisation
* of `getopt' parsing. We support this feature, for applications which
* proclaim their BSD heritage, before including this header; however,
* to maintain portability, developers are advised to avoid it.
*/
# define optreset __mingw_optreset
extern int optreset;
#endif
#ifdef __cplusplus
}
#endif
/*
* POSIX requires the `getopt' API to be specified in `unistd.h';
* thus, `unistd.h' includes this header. However, we do not want
* to expose the `getopt_long' or `getopt_long_only' APIs, when
* included in this manner. Thus, close the standard __GETOPT_H__
* declarations block, and open an additional __GETOPT_LONG_H__
* specific block, only when *not* __UNISTD_H_SOURCED__, in which
* to declare the extended API.
*/
#endif /* !defined(__GETOPT_H__) */
#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
#define __GETOPT_LONG_H__
#ifdef __cplusplus
extern "C" {
#endif
struct option /* specification for a long form option... */
{
const char *name; /* option name, without leading hyphens */
int has_arg; /* does it take an argument? */
int *flag; /* where to save its status, or NULL */
int val; /* its associated status value */
};
enum /* permitted values for its `has_arg' field... */
{
no_argument = 0, /* option never takes an argument */
required_argument, /* option always requires an argument */
optional_argument /* option may take an argument */
};
extern int getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx);
extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx);
/*
* Previous MinGW implementation had...
*/
#ifndef HAVE_DECL_GETOPT
/*
* ...for the long form API only; keep this for compatibility.
*/
# define HAVE_DECL_GETOPT 1
#endif
#ifdef __cplusplus
}
#endif
#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */

View File

@@ -1214,28 +1214,42 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
// GIO modules
{
QString sourcePath = qgetenv("GIO_EXTRA_MODULES");
if (sourcePath.isEmpty()) {
if (QFileInfo::exists("/usr/local/lib/gio/modules/libgiognutls.so")) {
sourcePath = "/usr/local/lib/gio/modules/libgiognutls.so";
QString giomodule_path = qgetenv("GIO_EXTRA_MODULES");
if (giomodule_path.isEmpty()) {
if (QDir().exists("/usr/local/lib/gio/modules")) {
giomodule_path = "/usr/local/lib/gio/modules";
}
else if (QFileInfo::exists("/opt/local/lib/gio/modules/libgiognutls.so")) {
sourcePath = "/opt/local/lib/gio/modules/libgiognutls.so";
else if (QDir().exists("/opt/local/lib/gio/modules")) {
giomodule_path = "/opt/local/lib/gio/modules";
}
else {
qFatal("Missing GIO_EXTRA_MODULES");
}
}
else {
sourcePath = sourcePath + "/libgiognutls.so";
const QStringList giomodules = QStringList() << "libgiognutls.so" << "libgioopenssl.so";
bool have_giomodule = false;
for (const QString &giomodule : giomodules) {
const QString sourcePath = giomodule_path + "/" + giomodule;
QFileInfo fileinfo(sourcePath);
if (!fileinfo.exists()) {
LogError() << "Missing GIO module" << fileinfo.baseName();
continue;
}
have_giomodule = true;
const QString destinationPath = appBundleInfo.path + "/Contents/PlugIns/gio-modules/" + giomodule;
QDir dir;
if (dir.mkpath(QFileInfo(destinationPath).path()) && copyFilePrintStatus(sourcePath, destinationPath)) {
runStrip(destinationPath);
QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath, appBundleInfo.path, deploymentInfo.rpathsUsed, useDebugLibs);
deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
}
}
const QString destinationPath = appBundleInfo.path + "/Contents/PlugIns/gio-modules/libgiognutls.so";
QDir dir;
if (dir.mkpath(QFileInfo(destinationPath).path()) && copyFilePrintStatus(sourcePath, destinationPath)) {
runStrip(destinationPath);
QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath, appBundleInfo.path, deploymentInfo.rpathsUsed, useDebugLibs);
deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
if (!have_giomodule) {
qFatal("Missing GIO modules.");
}
}
// gst-plugin-scanner
@@ -1262,8 +1276,13 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
}
// GStreamer plugins.
QStringList gstreamer_plugins = QStringList() << "libgstapetag.dylib"
QStringList gstreamer_plugins = QStringList()
<< "libgstaes.dylib"
<< "libgstaiff.dylib"
<< "libgstapetag.dylib"
<< "libgstapp.dylib"
<< "libgstasf.dylib"
<< "libgstasfmux.dylib"
<< "libgstaudioconvert.dylib"
<< "libgstaudiofx.dylib"
<< "libgstaudiomixer.dylib"
@@ -1271,48 +1290,50 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
<< "libgstaudiorate.dylib"
<< "libgstaudioresample.dylib"
<< "libgstaudiotestsrc.dylib"
<< "libgstaudiovisualizers.dylib"
<< "libgstauparse.dylib"
<< "libgstautoconvert.dylib"
<< "libgstautodetect.dylib"
<< "libgstbs2b.dylib"
<< "libgstcdio.dylib"
<< "libgstcoreelements.dylib"
<< "libgstdash.dylib"
<< "libgstequalizer.dylib"
<< "libgstfaac.dylib"
<< "libgstfaad.dylib"
<< "libgstfdkaac.dylib"
<< "libgstflac.dylib"
<< "libgstgio.dylib"
<< "libgsthls.dylib"
<< "libgsticydemux.dylib"
<< "libgstid3demux.dylib"
<< "libgstlevel.dylib"
<< "libgstid3tag.dylib"
<< "libgstisomp4.dylib"
<< "libgstlame.dylib"
<< "libgstlibav.dylib"
<< "libgstmpg123.dylib"
<< "libgstmusepack.dylib"
<< "libgstogg.dylib"
<< "libgstopenmpt.dylib"
<< "libgstopus.dylib"
<< "libgstopusparse.dylib"
<< "libgstosxaudio.dylib"
<< "libgstplayback.dylib"
<< "libgstrawparse.dylib"
<< "libgstreplaygain.dylib"
<< "libgstsoup.dylib"
<< "libgstspectrum.dylib"
<< "libgsttypefindfunctions.dylib"
<< "libgstvolume.dylib"
<< "libgstxingmux.dylib"
<< "libgsttcp.dylib"
<< "libgstudp.dylib"
<< "libgstpbtypes.dylib"
<< "libgstplayback.dylib"
<< "libgstreplaygain.dylib"
<< "libgstrtp.dylib"
<< "libgstrtsp.dylib"
<< "libgstflac.dylib"
<< "libgstwavparse.dylib"
<< "libgstfaad.dylib"
<< "libgstogg.dylib"
<< "libgstopus.dylib"
<< "libgstasf.dylib"
<< "libgstsoup.dylib"
<< "libgstspectrum.dylib"
<< "libgstspeex.dylib"
<< "libgsttaglib.dylib"
<< "libgsttcp.dylib"
<< "libgsttwolame.dylib"
<< "libgsttypefindfunctions.dylib"
<< "libgstudp.dylib"
<< "libgstvolume.dylib"
<< "libgstvorbis.dylib"
<< "libgstisomp4.dylib"
<< "libgstlibav.dylib"
<< "libgstaiff.dylib"
<< "libgstlame.dylib";
// macports does not have these.
QStringList gstreamer_plugins_optional = QStringList() << "libgstopusparse.dylib"
<< "libgstfaac.dylib"
<< "libgstmusepack.dylib";
<< "libgstwavenc.dylib"
<< "libgstwavpack.dylib"
<< "libgstwavparse.dylib"
<< "libgstxingmux.dylib";
QString gstreamer_plugins_dir = qgetenv("GST_PLUGIN_PATH");
if (gstreamer_plugins_dir.isEmpty()) {
@@ -1327,13 +1348,16 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
}
}
QStringList missing_gst_plugins;
for (const QString &plugin : gstreamer_plugins) {
QFileInfo info(gstreamer_plugins_dir + "/" + plugin);
if (!info.exists()) {
info.setFile(gstreamer_plugins_dir + "/" + info.baseName() + QString(".so"));
if (!info.exists()) {
LogError() << "Missing gstreamer plugin" << info.baseName();
qFatal("Missing %s", info.baseName().toUtf8().constData());
missing_gst_plugins << info.baseName();
continue;
}
}
const QString &sourcePath = info.filePath();
@@ -1345,22 +1369,8 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
}
}
for (const QString &plugin : gstreamer_plugins_optional) {
QFileInfo info(gstreamer_plugins_dir + "/" + plugin);
if (!info.exists()) {
info.setFile(gstreamer_plugins_dir + "/" + info.baseName() + QString(".so"));
if (!info.exists()) {
LogWarning() << "Skip missing gstreamer plugin" << info.baseName();
continue;
}
}
const QString &sourcePath = info.filePath();
const QString destinationPath = appBundleInfo.path + "/Contents/PlugIns/gstreamer/" + info.fileName();
if (QDir().mkpath(QFileInfo(destinationPath).path()) && copyFilePrintStatus(sourcePath, destinationPath)) {
runStrip(destinationPath);
QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath, appBundleInfo.path, deploymentInfo.rpathsUsed, useDebugLibs);
deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
}
if (!missing_gst_plugins.isEmpty()) {
LogError() << "Missing gstreamer plugins" << missing_gst_plugins;
}
}

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) Itay Grudev 2015 - 2016
Copyright (c) Itay Grudev 2015 - 2020
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,7 +1,8 @@
SingleApplication
=================
[![CI](https://github.com/itay-grudev/SingleApplication/workflows/CI:%20Build%20Test/badge.svg)](https://github.com/itay-grudev/SingleApplication/actions)
This is a replacement of the QtSingleApplication for `Qt5`.
This is a replacement of the QtSingleApplication for `Qt5` and `Qt6`.
Keeps the Primary Instance of your Application and kills each subsequent
instances. It can (if enabled) spawn secondary (non-related to the primary)
@@ -15,18 +16,6 @@ class you specify via the `QAPPLICATION_CLASS` macro (`QCoreApplication` is the
default). Further usage is similar to the use of the `Q[Core|Gui]Application`
classes.
The library sets up a `QLocalServer` and a `QSharedMemory` block. The first
instance of your Application is your Primary Instance. It would check if the
shared memory block exists and if not it will start a `QLocalServer` and listen
for connections. Each subsequent instance of your application would check if the
shared memory block exists and if it does, it will connect to the QLocalServer
to notify the primary instance that a new instance had been started, after which
it would terminate with status code `0`. In the Primary Instance
`SingleApplication` would emit the `instanceStarted()` signal upon detecting
that a new instance had been started.
The library uses `stdlib` to terminate the program with the `exit()` function.
You can use the library as if you use any other `QCoreApplication` derived
class:
@@ -43,24 +32,49 @@ int main( int argc, char* argv[] )
```
To include the library files I would recommend that you add it as a git
submodule to your project and include it's contents with a `.pri` file. Here is
how:
submodule to your project. Here is how:
```bash
git submodule add git@github.com:itay-grudev/SingleApplication.git singleapplication
git submodule add https://github.com/itay-grudev/SingleApplication.git singleapplication
```
Then include the `singleapplication.pri` file in your `.pro` project file. Also
don't forget to specify which `QCoreApplication` class your app is using if it
is not `QCoreApplication`.
**Qmake:**
Then include the `singleapplication.pri` file in your `.pro` project file.
```qmake
include(singleapplication/singleapplication.pri)
DEFINES += QAPPLICATION_CLASS=QApplication
```
**CMake:**
Then include the subdirectory in your `CMakeLists.txt` project file.
```cmake
set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
add_subdirectory(src/third-party/singleapplication)
target_link_libraries(${PROJECT_NAME} SingleApplication::SingleApplication)
```
The library sets up a `QLocalServer` and a `QSharedMemory` block. The first
instance of your Application is your Primary Instance. It would check if the
shared memory block exists and if not it will start a `QLocalServer` and listen
for connections. Each subsequent instance of your application would check if the
shared memory block exists and if it does, it will connect to the QLocalServer
to notify the primary instance that a new instance had been started, after which
it would terminate with status code `0`. In the Primary Instance
`SingleApplication` would emit the `instanceStarted()` signal upon detecting
that a new instance had been started.
The library uses `stdlib` to terminate the program with the `exit()` function.
Also don't forget to specify which `QCoreApplication` class your app is using if it
is not `QCoreApplication` as in examples above.
The `Instance Started` signal
------------------------
-----------------------------
The SingleApplication class implements a `instanceStarted()` signal. You can
bind to that signal to raise your application's window when a new instance had
@@ -125,13 +139,22 @@ app.isSecondary();
*__Note:__ If your Primary Instance is terminated a newly launched instance
will replace the Primary one even if the Secondary flag has been set.*
Examples
--------
There are three examples provided in this repository:
* Basic example that prevents a secondary instance from starting [`examples/basic`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/basic)
* An example of a graphical application raising it's parent window [`examples/calculator`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/calculator)
* A console application sending the primary instance it's command line parameters [`examples/sending_arguments`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/sending_arguments)
API
---
### Members
```cpp
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100 )
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100, QString userData = QString() )
```
Depending on whether `allowSecondary` is set, this constructor may terminate
@@ -140,7 +163,7 @@ can be specified to set whether the SingleApplication block should work
user-wide or system-wide. Additionally the `Mode::SecondaryNotification` may be
used to notify the primary instance whenever a secondary instance had been
started (disabled by default). `timeout` specifies the maximum time in
milliseconds to wait for blocking operations.
milliseconds to wait for blocking operations. Setting `userData` provides additional data that will isolate this instance from other instances that do not have the same (or any) user data set.
*__Note:__ `argc` and `argv` may be changed as Qt removes arguments that it
recognizes.*
@@ -159,7 +182,8 @@ bool SingleApplication::sendMessage( QByteArray message, int timeout = 100 )
```
Sends `message` to the Primary Instance. Uses `timeout` as a the maximum timeout
in milliseconds for blocking functions
in milliseconds for blocking functions. Returns `true` if the message has been sent
successfully. If the message can't be sent or the function timeouts - returns `false`.
---
@@ -192,6 +216,22 @@ qint64 SingleApplication::primaryPid()
Returns the process ID (PID) of the primary instance.
---
```cpp
QString SingleApplication::primaryUser()
```
Returns the username the primary instance is running as.
---
```cpp
QString SingleApplication::currentUser()
```
Returns the username the current instance is running as.
### Signals
```cpp

View File

@@ -54,7 +54,7 @@
* @param options Optional flags to toggle specific behaviour
* @param timeout Maximum time blocking functions are allowed during app load
*/
SingleApplication::SingleApplication(int &argc, char *argv[], bool allowSecondary, Options options, int timeout)
SingleApplication::SingleApplication(int &argc, char *argv[], const bool allowSecondary, const Options options, const int timeout)
: app_t(argc, argv),
d_ptr(new SingleApplicationPrivate(this)) {
@@ -67,7 +67,7 @@ SingleApplication::SingleApplication(int &argc, char *argv[], bool allowSecondar
d->genBlockServerName();
// To mitigate QSharedMemory issues with large amount of processes attempting to attach at the same time
d->randomSleep();
SingleApplicationPrivate::randomSleep();
#ifdef Q_OS_UNIX
// By explicitly attaching it and then deleting it we make sure that the memory is deleted even after the process has crashed on Unix.
@@ -106,14 +106,14 @@ SingleApplication::SingleApplication(int &argc, char *argv[], bool allowSecondar
}
}
InstancesInfo *inst = static_cast<InstancesInfo*>(d->memory_->data());
InstancesInfo *instance = static_cast<InstancesInfo*>(d->memory_->data());
QElapsedTimer time;
time.start();
// Make sure the shared memory block is initialised and in consistent state
forever {
// If the shared memory block's checksum is valid continue
if (d->blockChecksum() == inst->checksum) break;
if (d->blockChecksum() == instance->checksum) break;
// If more than 5s have elapsed, assume the primary instance crashed and assume it's position
if (time.elapsed() > 5000) {
@@ -127,14 +127,14 @@ SingleApplication::SingleApplication(int &argc, char *argv[], bool allowSecondar
qDebug() << "SingleApplication: Unable to unlock memory for random wait.";
qDebug() << d->memory_->errorString();
}
d->randomSleep();
SingleApplicationPrivate::randomSleep();
if (!d->memory_->lock()) {
qCritical() << "SingleApplication: Unable to lock memory after random wait.";
abortSafely();
}
}
if (!inst->primary) {
if (!instance->primary) {
d->startPrimary();
if (!d->memory_->unlock()) {
qDebug() << "SingleApplication: Unable to unlock memory after primary start.";
@@ -178,8 +178,8 @@ SingleApplication::~SingleApplication() {
* Checks if the current application instance is primary.
* @return Returns true if the instance is primary, false otherwise.
*/
bool SingleApplication::isPrimary() {
Q_D(SingleApplication);
bool SingleApplication::isPrimary() const {
Q_D(const SingleApplication);
return d->server_ != nullptr;
}
@@ -187,8 +187,8 @@ bool SingleApplication::isPrimary() {
* Checks if the current application instance is secondary.
* @return Returns true if the instance is secondary, false otherwise.
*/
bool SingleApplication::isSecondary() {
Q_D(SingleApplication);
bool SingleApplication::isSecondary() const {
Q_D(const SingleApplication);
return d->server_ == nullptr;
}
@@ -197,8 +197,8 @@ bool SingleApplication::isSecondary() {
* It is reset when the first (primary) instance of your app starts and only incremented afterwards.
* @return Returns a unique instance id.
*/
quint32 SingleApplication::instanceId() {
Q_D(SingleApplication);
quint32 SingleApplication::instanceId() const {
Q_D(const SingleApplication);
return d->instanceNumber_;
}
@@ -207,8 +207,8 @@ quint32 SingleApplication::instanceId() {
* Especially useful when SingleApplication is coupled with OS. specific APIs.
* @return Returns the primary instance PID.
*/
qint64 SingleApplication::primaryPid() {
Q_D(SingleApplication);
qint64 SingleApplication::primaryPid() const {
Q_D(const SingleApplication);
return d->primaryPid();
}
@@ -216,8 +216,8 @@ qint64 SingleApplication::primaryPid() {
* Returns the username the primary instance is running as.
* @return Returns the username the primary instance is running as.
*/
QString SingleApplication::primaryUser() {
Q_D(SingleApplication);
QString SingleApplication::primaryUser() const {
Q_D(const SingleApplication);
return d->primaryUser();
}
@@ -225,9 +225,8 @@ QString SingleApplication::primaryUser() {
* Returns the username the current instance is running as.
* @return Returns the username the current instance is running as.
*/
QString SingleApplication::currentUser() {
Q_D(SingleApplication);
return d->getUsername();
QString SingleApplication::currentUser() const {
return SingleApplicationPrivate::getUsername();
}
/**
@@ -248,11 +247,7 @@ bool SingleApplication::sendMessage(const QByteArray &message, const int timeout
return false;
}
d->socket_->write(message);
const bool dataWritten = d->socket_->waitForBytesWritten(timeout);
d->socket_->flush();
return dataWritten;
return d->writeConfirmedMessage(timeout, message);
}
/**
@@ -265,6 +260,7 @@ void SingleApplication::abortSafely() {
qCritical() << "SingleApplication: " << d->memory_->error() << d->memory_->errorString();
delete d;
::exit(EXIT_FAILURE);
}

View File

@@ -48,7 +48,7 @@ class SingleApplicationPrivate;
class SingleApplication : public QApplication { // clazy:exclude=ctor-missing-parent-argument
Q_OBJECT
typedef QApplication app_t;
using app_t = QApplication;
public:
/**
@@ -88,46 +88,45 @@ class SingleApplication : public QApplication { // clazy:exclude=ctor-missing-p
* operations. It does not guarantee that the SingleApplication
* initialisation will be completed in given time, though is a good hint.
* Usually 4*timeout would be the worst case (fail) scenario.
* @see See the corresponding QAPPLICATION_CLASS constructor for reference
*/
explicit SingleApplication(int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 1000);
explicit SingleApplication(int &argc, char *argv[], const bool allowSecondary = false, const Options options = Mode::User, const int timeout = 1000);
~SingleApplication() override;
/**
* @brief Returns if the instance is the primary instance
* @returns {bool}
*/
bool isPrimary();
bool isPrimary() const;
/**
* @brief Returns if the instance is a secondary instance
* @returns {bool}
*/
bool isSecondary();
bool isSecondary() const;
/**
* @brief Returns a unique identifier for the current instance
* @returns {qint32}
*/
quint32 instanceId();
quint32 instanceId() const;
/**
* @brief Returns the process ID (PID) of the primary instance
* @returns {qint64}
*/
qint64 primaryPid();
qint64 primaryPid() const;
/**
* @brief Returns the username of the user running the primary instance
* @returns {QString}
*/
QString primaryUser();
QString primaryUser() const;
/**
* @brief Returns the username of the current user
* @returns {QString}
*/
QString currentUser();
QString currentUser() const;
/**
* @brief Sends a message to the primary instance. Returns true on success.

View File

@@ -44,6 +44,14 @@
# include <pwd.h>
#endif
#ifdef Q_OS_WIN
# ifndef NOMINMAX
# define NOMINMAX 1
# endif
# include <windows.h>
# include <lmcons.h>
#endif
#include <QObject>
#include <QThread>
#include <QIODevice>
@@ -53,7 +61,6 @@
#include <QCryptographicHash>
#include <QLocalServer>
#include <QLocalSocket>
#include <QDir>
#include <QElapsedTimer>
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
# include <QRandomGenerator>
@@ -64,11 +71,6 @@
#include "singleapplication.h"
#include "singleapplication_p.h"
#ifdef Q_OS_WIN
# include <windows.h>
# include <lmcons.h>
#endif
SingleApplicationPrivate::SingleApplicationPrivate(SingleApplication *ptr)
: q_ptr(ptr),
memory_(nullptr),
@@ -86,14 +88,14 @@ SingleApplicationPrivate::~SingleApplicationPrivate() {
if (memory_ != nullptr) {
memory_->lock();
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
if (server_ != nullptr) {
server_->close();
delete server_;
inst->primary = false;
inst->primaryPid = -1;
inst->primaryUser[0] = '\0';
inst->checksum = blockChecksum();
instance->primary = false;
instance->primaryPid = -1;
instance->primaryUser[0] = '\0';
instance->checksum = blockChecksum();
}
memory_->unlock();
@@ -142,7 +144,7 @@ QString SingleApplicationPrivate::getUsername() {
void SingleApplicationPrivate::genBlockServerName() {
QCryptographicHash appData(QCryptographicHash::Sha256);
appData.addData("SingleApplication", 17);
appData.addData("SingleApplication");
appData.addData(SingleApplication::app_t::applicationName().toUtf8());
appData.addData(SingleApplication::app_t::organizationName().toUtf8());
appData.addData(SingleApplication::app_t::organizationDomain().toUtf8());
@@ -152,7 +154,15 @@ void SingleApplicationPrivate::genBlockServerName() {
}
if (!(options_ & SingleApplication::Mode::ExcludeAppPath)) {
#ifdef Q_OS_WIN
#if defined(Q_OS_UNIX)
const QByteArray appImagePath = qgetenv("APPIMAGE");
if (appImagePath.isEmpty()) {
appData.addData(SingleApplication::app_t::applicationFilePath().toUtf8());
}
else {
appData.addData(appImagePath);
};
#elif defined(Q_OS_WIN)
appData.addData(SingleApplication::app_t::applicationFilePath().toLower().toUtf8());
#else
appData.addData(SingleApplication::app_t::applicationFilePath().toUtf8());
@@ -171,26 +181,24 @@ void SingleApplicationPrivate::genBlockServerName() {
void SingleApplicationPrivate::initializeMemoryBlock() const {
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
inst->primary = false;
inst->secondary = 0;
inst->primaryPid = -1;
inst->primaryUser[0] = '\0';
inst->checksum = blockChecksum();
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
instance->primary = false;
instance->secondary = 0;
instance->primaryPid = -1;
instance->primaryUser[0] = '\0';
instance->checksum = blockChecksum();
}
void SingleApplicationPrivate::startPrimary() {
Q_Q(SingleApplication);
// Reset the number of connections
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
inst->primary = true;
inst->primaryPid = q->applicationPid();
qstrncpy(inst->primaryUser, getUsername().toUtf8().data(), sizeof(inst->primaryUser));
inst->checksum = blockChecksum();
instance->primary = true;
instance->primaryPid = QCoreApplication::applicationPid();
qstrncpy(instance->primaryUser, getUsername().toUtf8().data(), sizeof(instance->primaryUser));
instance->checksum = blockChecksum();
instanceNumber_ = 0;
// Successful creation means that no main process exists
// So we start a QLocalServer to listen for connections
@@ -212,11 +220,11 @@ void SingleApplicationPrivate::startPrimary() {
void SingleApplicationPrivate::startSecondary() {
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
inst->secondary += 1;
inst->checksum = blockChecksum();
instanceNumber_ = inst->secondary;
instance->secondary += 1;
instance->checksum = blockChecksum();
instanceNumber_ = instance->secondary;
}
@@ -263,25 +271,53 @@ bool SingleApplicationPrivate::connectToPrimary(const int timeout, const Connect
writeStream << instanceNumber_;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length())));
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length())));
#else
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
#endif
writeStream << checksum;
// The header indicates the message length that follows
return writeConfirmedMessage(static_cast<int>(timeout - time.elapsed()), initMsg);
}
void SingleApplicationPrivate::writeAck(QLocalSocket *sock) {
sock->putChar('\n');
}
bool SingleApplicationPrivate::writeConfirmedMessage(const int timeout, const QByteArray &msg) const {
QElapsedTimer time;
time.start();
// Frame 1: The header indicates the message length that follows
QByteArray header;
QDataStream headerStream(&header, QIODevice::WriteOnly);
headerStream.setVersion(QDataStream::Qt_5_8);
headerStream << static_cast<quint64>(initMsg.length());
headerStream << static_cast<quint64>(msg.length());
socket_->write(header);
socket_->write(initMsg);
bool result = socket_->waitForBytesWritten(static_cast<int>(timeout - time.elapsed()));
if (!writeConfirmedFrame(static_cast<int>(timeout - time.elapsed()), header)) {
return false;
}
// Frame 2: The message
return writeConfirmedFrame(static_cast<int>(timeout - time.elapsed()), msg);
}
bool SingleApplicationPrivate::writeConfirmedFrame(const int timeout, const QByteArray &msg) const {
socket_->write(msg);
socket_->flush();
return result;
bool result = socket_->waitForReadyRead(timeout);
if (result) {
socket_->read(1);
return true;
}
return false;
}
@@ -300,8 +336,8 @@ quint16 SingleApplicationPrivate::blockChecksum() const {
qint64 SingleApplicationPrivate::primaryPid() const {
memory_->lock();
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
qint64 pid = inst->primaryPid;
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
qint64 pid = instance->primaryPid;
memory_->unlock();
return pid;
@@ -311,8 +347,8 @@ qint64 SingleApplicationPrivate::primaryPid() const {
QString SingleApplicationPrivate::primaryUser() const {
memory_->lock();
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
QByteArray username = inst->primaryUser;
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
QByteArray username = instance->primaryUser;
memory_->unlock();
return QString::fromUtf8(username);
@@ -328,26 +364,30 @@ void SingleApplicationPrivate::slotConnectionEstablished() {
connectionMap_.insert(nextConnSocket, ConnectionInfo());
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this, [nextConnSocket, this]() {
const ConnectionInfo info = connectionMap_[nextConnSocket];
const ConnectionInfo &info = connectionMap_[nextConnSocket];
slotClientConnectionClosed(nextConnSocket, info.instanceId);
});
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, this, [nextConnSocket, this]() {
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, nextConnSocket, &QLocalSocket::deleteLater);
QObject::connect(nextConnSocket, &QLocalSocket::destroyed, this, [nextConnSocket, this]() {
connectionMap_.remove(nextConnSocket);
nextConnSocket->deleteLater();
});
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this, [nextConnSocket, this]() {
const ConnectionInfo info = connectionMap_[nextConnSocket];
const ConnectionInfo &info = connectionMap_[nextConnSocket];
switch (info.stage) {
case StageHeader:
readInitMessageHeader(nextConnSocket);
case StageInitHeader:
readMessageHeader(nextConnSocket, StageInitBody);
break;
case StageBody:
case StageInitBody:
readInitMessageBody(nextConnSocket);
break;
case StageConnected:
slotDataAvailable(nextConnSocket, info.instanceId);
case StageConnectedHeader:
readMessageHeader(nextConnSocket, StageConnectedBody);
break;
case StageConnectedBody:
this->slotDataAvailable(nextConnSocket, info.instanceId);
break;
default:
break;
@@ -356,7 +396,7 @@ void SingleApplicationPrivate::slotConnectionEstablished() {
}
void SingleApplicationPrivate::readInitMessageHeader(QLocalSocket *sock) {
void SingleApplicationPrivate::readMessageHeader(QLocalSocket *sock, const SingleApplicationPrivate::ConnectionStage nextStage) {
if (!connectionMap_.contains(sock)) {
return;
@@ -373,30 +413,34 @@ void SingleApplicationPrivate::readInitMessageHeader(QLocalSocket *sock) {
quint64 msgLen = 0;
headerStream >> msgLen;
ConnectionInfo &info = connectionMap_[sock];
info.stage = StageBody;
info.stage = nextStage;
info.msgLen = msgLen;
if (sock->bytesAvailable() >= static_cast<qint64>(msgLen)) {
readInitMessageBody(sock);
writeAck(sock);
}
bool SingleApplicationPrivate::isFrameComplete(QLocalSocket *sock) {
if (!connectionMap_.contains(sock)) {
return false;
}
const ConnectionInfo &info = connectionMap_[sock];
return (sock->bytesAvailable() >= static_cast<qint64>(info.msgLen));
}
void SingleApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
Q_Q(SingleApplication);
if (!connectionMap_.contains(sock)) {
return;
}
ConnectionInfo &info = connectionMap_[sock];
if (sock->bytesAvailable() < static_cast<qint64>(info.msgLen)) {
if (!isFrameComplete(sock)) {
return;
}
// Read the message body
QByteArray msgBytes = sock->read(static_cast<qint64>(info.msgLen));
QByteArray msgBytes = sock->readAll();
QDataStream readStream(msgBytes);
readStream.setVersion(QDataStream::Qt_5_8);
@@ -431,23 +475,34 @@ void SingleApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
return;
}
ConnectionInfo &info = connectionMap_[sock];
info.instanceId = instanceId;
info.stage = StageConnected;
info.stage = StageConnectedHeader;
if (connectionType == NewInstance || (connectionType == SecondaryInstance && options_ & SingleApplication::Mode::SecondaryNotification)) {
Q_EMIT q->instanceStarted();
emit q->instanceStarted();
}
if (sock->bytesAvailable() > 0) {
slotDataAvailable(sock, instanceId);
}
writeAck(sock);
}
void SingleApplicationPrivate::slotDataAvailable(QLocalSocket *dataSocket, const quint32 instanceId) {
Q_Q(SingleApplication);
Q_EMIT q->receivedMessage(instanceId, dataSocket->readAll());
if (!isFrameComplete(dataSocket)) {
return;
}
const QByteArray message = dataSocket->readAll();
writeAck(dataSocket);
ConnectionInfo &info = connectionMap_[dataSocket];
info.stage = StageConnectedHeader;
emit q->receivedMessage(instanceId, message);
}
@@ -465,7 +520,7 @@ void SingleApplicationPrivate::randomSleep() {
QThread::msleep(QRandomGenerator::global()->bounded(8U, 18U));
#else
qsrand(QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max());
QThread::msleep(8 + static_cast<unsigned long>(static_cast<float>(qrand()) / RAND_MAX * 10));
QThread::msleep(qrand() % 11 + 8);
#endif
}

View File

@@ -71,9 +71,10 @@ class SingleApplicationPrivate : public QObject {
Reconnect = 3
};
enum ConnectionStage : quint8 {
StageHeader = 0,
StageBody = 1,
StageConnected = 2,
StageInitHeader = 0,
StageInitBody = 1,
StageConnectedHeader = 2,
StageConnectedBody = 3,
};
Q_DECLARE_PUBLIC(SingleApplication)
@@ -89,8 +90,12 @@ class SingleApplicationPrivate : public QObject {
quint16 blockChecksum() const;
qint64 primaryPid() const;
QString primaryUser() const;
void readInitMessageHeader(QLocalSocket *socket);
bool isFrameComplete(QLocalSocket *sock);
void readMessageHeader(QLocalSocket *socket, const ConnectionStage nextStage);
void readInitMessageBody(QLocalSocket *socket);
void writeAck(QLocalSocket *sock);
bool writeConfirmedFrame(const int timeout, const QByteArray &msg) const;
bool writeConfirmedMessage(const int timeout, const QByteArray &msg) const;
static void randomSleep();
SingleApplication *q_ptr;

View File

@@ -54,7 +54,7 @@
* @param options Optional flags to toggle specific behaviour
* @param timeout Maximum time blocking functions are allowed during app load
*/
SingleCoreApplication::SingleCoreApplication(int &argc, char *argv[], bool allowSecondary, Options options, int timeout)
SingleCoreApplication::SingleCoreApplication(int &argc, char *argv[], const bool allowSecondary, const Options options, const int timeout)
: app_t(argc, argv),
d_ptr(new SingleCoreApplicationPrivate(this)) {
@@ -67,7 +67,7 @@ SingleCoreApplication::SingleCoreApplication(int &argc, char *argv[], bool allow
d->genBlockServerName();
// To mitigate QSharedMemory issues with large amount of processes attempting to attach at the same time
d->randomSleep();
SingleCoreApplicationPrivate::randomSleep();
#ifdef Q_OS_UNIX
// By explicitly attaching it and then deleting it we make sure that the memory is deleted even after the process has crashed on Unix.
@@ -106,14 +106,14 @@ SingleCoreApplication::SingleCoreApplication(int &argc, char *argv[], bool allow
}
}
InstancesInfo *inst = static_cast<InstancesInfo*>(d->memory_->data());
InstancesInfo *instance = static_cast<InstancesInfo*>(d->memory_->data());
QElapsedTimer time;
time.start();
// Make sure the shared memory block is initialised and in consistent state
forever {
// If the shared memory block's checksum is valid continue
if (d->blockChecksum() == inst->checksum) break;
if (d->blockChecksum() == instance->checksum) break;
// If more than 5s have elapsed, assume the primary instance crashed and assume it's position
if (time.elapsed() > 5000) {
@@ -127,14 +127,14 @@ SingleCoreApplication::SingleCoreApplication(int &argc, char *argv[], bool allow
qDebug() << "SingleCoreApplication: Unable to unlock memory for random wait.";
qDebug() << d->memory_->errorString();
}
d->randomSleep();
SingleCoreApplicationPrivate::randomSleep();
if (!d->memory_->lock()) {
qCritical() << "SingleCoreApplication: Unable to lock memory after random wait.";
abortSafely();
}
}
if (!inst->primary) {
if (!instance->primary) {
d->startPrimary();
if (!d->memory_->unlock()) {
qDebug() << "SingleCoreApplication: Unable to unlock memory after primary start.";
@@ -178,8 +178,8 @@ SingleCoreApplication::~SingleCoreApplication() {
* Checks if the current application instance is primary.
* @return Returns true if the instance is primary, false otherwise.
*/
bool SingleCoreApplication::isPrimary() {
Q_D(SingleCoreApplication);
bool SingleCoreApplication::isPrimary() const {
Q_D(const SingleCoreApplication);
return d->server_ != nullptr;
}
@@ -187,8 +187,8 @@ bool SingleCoreApplication::isPrimary() {
* Checks if the current application instance is secondary.
* @return Returns true if the instance is secondary, false otherwise.
*/
bool SingleCoreApplication::isSecondary() {
Q_D(SingleCoreApplication);
bool SingleCoreApplication::isSecondary() const {
Q_D(const SingleCoreApplication);
return d->server_ == nullptr;
}
@@ -197,8 +197,8 @@ bool SingleCoreApplication::isSecondary() {
* It is reset when the first (primary) instance of your app starts and only incremented afterwards.
* @return Returns a unique instance id.
*/
quint32 SingleCoreApplication::instanceId() {
Q_D(SingleCoreApplication);
quint32 SingleCoreApplication::instanceId() const {
Q_D(const SingleCoreApplication);
return d->instanceNumber_;
}
@@ -207,8 +207,8 @@ quint32 SingleCoreApplication::instanceId() {
* Especially useful when SingleCoreApplication is coupled with OS. specific APIs.
* @return Returns the primary instance PID.
*/
qint64 SingleCoreApplication::primaryPid() {
Q_D(SingleCoreApplication);
qint64 SingleCoreApplication::primaryPid() const {
Q_D(const SingleCoreApplication);
return d->primaryPid();
}
@@ -216,8 +216,8 @@ qint64 SingleCoreApplication::primaryPid() {
* Returns the username the primary instance is running as.
* @return Returns the username the primary instance is running as.
*/
QString SingleCoreApplication::primaryUser() {
Q_D(SingleCoreApplication);
QString SingleCoreApplication::primaryUser() const {
Q_D(const SingleCoreApplication);
return d->primaryUser();
}
@@ -225,9 +225,8 @@ QString SingleCoreApplication::primaryUser() {
* Returns the username the current instance is running as.
* @return Returns the username the current instance is running as.
*/
QString SingleCoreApplication::currentUser() {
Q_D(SingleCoreApplication);
return d->getUsername();
QString SingleCoreApplication::currentUser() const {
return SingleCoreApplicationPrivate::getUsername();
}
/**
@@ -248,11 +247,7 @@ bool SingleCoreApplication::sendMessage(const QByteArray &message, const int tim
return false;
}
d->socket_->write(message);
const bool dataWritten = d->socket_->waitForBytesWritten(timeout);
d->socket_->flush();
return dataWritten;
return d->writeConfirmedMessage(timeout, message);
}
/**
@@ -265,6 +260,7 @@ void SingleCoreApplication::abortSafely() {
qCritical() << "SingleCoreApplication: " << d->memory_->error() << d->memory_->errorString();
delete d;
::exit(EXIT_FAILURE);
}

View File

@@ -45,10 +45,10 @@ class SingleCoreApplicationPrivate;
* @brief The SingleCoreApplication class handles multiple instances of the same Application
* @see QCoreApplication
*/
class SingleCoreApplication : public QCoreApplication {
class SingleCoreApplication : public QCoreApplication { // clazy:exclude=ctor-missing-parent-argument
Q_OBJECT
typedef QCoreApplication app_t;
using app_t = QCoreApplication;
public:
/**
@@ -96,37 +96,37 @@ class SingleCoreApplication : public QCoreApplication {
* @brief Returns if the instance is the primary instance
* @returns {bool}
*/
bool isPrimary();
bool isPrimary() const;
/**
* @brief Returns if the instance is a secondary instance
* @returns {bool}
*/
bool isSecondary();
bool isSecondary() const;
/**
* @brief Returns a unique identifier for the current instance
* @returns {qint32}
*/
quint32 instanceId();
quint32 instanceId() const;
/**
* @brief Returns the process ID (PID) of the primary instance
* @returns {qint64}
*/
qint64 primaryPid();
qint64 primaryPid() const;
/**
* @brief Returns the username of the user running the primary instance
* @returns {QString}
*/
QString primaryUser();
QString primaryUser() const;
/**
* @brief Returns the username of the current user
* @returns {QString}
*/
QString currentUser();
QString currentUser() const;
/**
* @brief Sends a message to the primary instance. Returns true on success.

View File

@@ -44,6 +44,14 @@
# include <pwd.h>
#endif
#ifdef Q_OS_WIN
# ifndef NOMINMAX
# define NOMINMAX 1
# endif
# include <windows.h>
# include <lmcons.h>
#endif
#include <QObject>
#include <QThread>
#include <QIODevice>
@@ -53,7 +61,6 @@
#include <QCryptographicHash>
#include <QLocalServer>
#include <QLocalSocket>
#include <QDir>
#include <QElapsedTimer>
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
# include <QRandomGenerator>
@@ -64,11 +71,6 @@
#include "singlecoreapplication.h"
#include "singlecoreapplication_p.h"
#ifdef Q_OS_WIN
# include <windows.h>
# include <lmcons.h>
#endif
SingleCoreApplicationPrivate::SingleCoreApplicationPrivate(SingleCoreApplication *ptr)
: q_ptr(ptr),
memory_(nullptr),
@@ -86,14 +88,14 @@ SingleCoreApplicationPrivate::~SingleCoreApplicationPrivate() {
if (memory_ != nullptr) {
memory_->lock();
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
if (server_ != nullptr) {
server_->close();
delete server_;
inst->primary = false;
inst->primaryPid = -1;
inst->primaryUser[0] = '\0';
inst->checksum = blockChecksum();
instance->primary = false;
instance->primaryPid = -1;
instance->primaryUser[0] = '\0';
instance->checksum = blockChecksum();
}
memory_->unlock();
@@ -142,7 +144,7 @@ QString SingleCoreApplicationPrivate::getUsername() {
void SingleCoreApplicationPrivate::genBlockServerName() {
QCryptographicHash appData(QCryptographicHash::Sha256);
appData.addData("SingleApplication", 17);
appData.addData("SingleApplication");
appData.addData(SingleCoreApplication::app_t::applicationName().toUtf8());
appData.addData(SingleCoreApplication::app_t::organizationName().toUtf8());
appData.addData(SingleCoreApplication::app_t::organizationDomain().toUtf8());
@@ -152,7 +154,15 @@ void SingleCoreApplicationPrivate::genBlockServerName() {
}
if (!(options_ & SingleCoreApplication::Mode::ExcludeAppPath)) {
#ifdef Q_OS_WIN
#if defined(Q_OS_UNIX)
const QByteArray appImagePath = qgetenv("APPIMAGE");
if (appImagePath.isEmpty()) {
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toUtf8());
}
else {
appData.addData(appImagePath);
};
#elif defined(Q_OS_WIN)
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toLower().toUtf8());
#else
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toUtf8());
@@ -171,26 +181,24 @@ void SingleCoreApplicationPrivate::genBlockServerName() {
void SingleCoreApplicationPrivate::initializeMemoryBlock() const {
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
inst->primary = false;
inst->secondary = 0;
inst->primaryPid = -1;
inst->primaryUser[0] = '\0';
inst->checksum = blockChecksum();
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
instance->primary = false;
instance->secondary = 0;
instance->primaryPid = -1;
instance->primaryUser[0] = '\0';
instance->checksum = blockChecksum();
}
void SingleCoreApplicationPrivate::startPrimary() {
Q_Q(SingleCoreApplication);
// Reset the number of connections
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
inst->primary = true;
inst->primaryPid = q->applicationPid();
qstrncpy(inst->primaryUser, getUsername().toUtf8().data(), sizeof(inst->primaryUser));
inst->checksum = blockChecksum();
instance->primary = true;
instance->primaryPid = QCoreApplication::applicationPid();
qstrncpy(instance->primaryUser, getUsername().toUtf8().data(), sizeof(instance->primaryUser));
instance->checksum = blockChecksum();
instanceNumber_ = 0;
// Successful creation means that no main process exists
// So we start a QLocalServer to listen for connections
@@ -212,11 +220,11 @@ void SingleCoreApplicationPrivate::startPrimary() {
void SingleCoreApplicationPrivate::startSecondary() {
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
inst->secondary += 1;
inst->checksum = blockChecksum();
instanceNumber_ = inst->secondary;
instance->secondary += 1;
instance->checksum = blockChecksum();
instanceNumber_ = instance->secondary;
}
@@ -263,25 +271,53 @@ bool SingleCoreApplicationPrivate::connectToPrimary(const int timeout, const Con
writeStream << instanceNumber_;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length())));
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length())));
#else
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
#endif
writeStream << checksum;
// The header indicates the message length that follows
return writeConfirmedMessage(static_cast<int>(timeout - time.elapsed()), initMsg);
}
void SingleCoreApplicationPrivate::writeAck(QLocalSocket *sock) {
sock->putChar('\n');
}
bool SingleCoreApplicationPrivate::writeConfirmedMessage(const int timeout, const QByteArray &msg) const {
QElapsedTimer time;
time.start();
// Frame 1: The header indicates the message length that follows
QByteArray header;
QDataStream headerStream(&header, QIODevice::WriteOnly);
headerStream.setVersion(QDataStream::Qt_5_8);
headerStream << static_cast<quint64>(initMsg.length());
headerStream << static_cast<quint64>(msg.length());
socket_->write(header);
socket_->write(initMsg);
bool result = socket_->waitForBytesWritten(timeout - static_cast<int>(time.elapsed()));
if (!writeConfirmedFrame(static_cast<int>(timeout - time.elapsed()), header)) {
return false;
}
// Frame 2: The message
return writeConfirmedFrame(static_cast<int>(timeout - time.elapsed()), msg);
}
bool SingleCoreApplicationPrivate::writeConfirmedFrame(const int timeout, const QByteArray &msg) const {
socket_->write(msg);
socket_->flush();
return result;
bool result = socket_->waitForReadyRead(timeout);
if (result) {
socket_->read(1);
return true;
}
return false;
}
@@ -300,8 +336,8 @@ quint16 SingleCoreApplicationPrivate::blockChecksum() const {
qint64 SingleCoreApplicationPrivate::primaryPid() const {
memory_->lock();
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
qint64 pid = inst->primaryPid;
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
qint64 pid = instance->primaryPid;
memory_->unlock();
return pid;
@@ -311,8 +347,8 @@ qint64 SingleCoreApplicationPrivate::primaryPid() const {
QString SingleCoreApplicationPrivate::primaryUser() const {
memory_->lock();
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
QByteArray username = inst->primaryUser;
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
QByteArray username = instance->primaryUser;
memory_->unlock();
return QString::fromUtf8(username);
@@ -328,26 +364,30 @@ void SingleCoreApplicationPrivate::slotConnectionEstablished() {
connectionMap_.insert(nextConnSocket, ConnectionInfo());
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this, [nextConnSocket, this]() {
const ConnectionInfo info = connectionMap_[nextConnSocket];
const ConnectionInfo &info = connectionMap_[nextConnSocket];
slotClientConnectionClosed(nextConnSocket, info.instanceId);
});
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, this, [nextConnSocket, this]() {
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, nextConnSocket, &QLocalSocket::deleteLater);
QObject::connect(nextConnSocket, &QLocalSocket::destroyed, this, [nextConnSocket, this]() {
connectionMap_.remove(nextConnSocket);
nextConnSocket->deleteLater();
});
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this, [nextConnSocket, this]() {
const ConnectionInfo info = connectionMap_[nextConnSocket];
const ConnectionInfo &info = connectionMap_[nextConnSocket];
switch (info.stage) {
case StageHeader:
readInitMessageHeader(nextConnSocket);
case StageInitHeader:
readMessageHeader(nextConnSocket, StageInitBody);
break;
case StageBody:
case StageInitBody:
readInitMessageBody(nextConnSocket);
break;
case StageConnected:
slotDataAvailable(nextConnSocket, info.instanceId);
case StageConnectedHeader:
readMessageHeader(nextConnSocket, StageConnectedBody);
break;
case StageConnectedBody:
this->slotDataAvailable(nextConnSocket, info.instanceId);
break;
default:
break;
@@ -356,7 +396,7 @@ void SingleCoreApplicationPrivate::slotConnectionEstablished() {
}
void SingleCoreApplicationPrivate::readInitMessageHeader(QLocalSocket *sock) {
void SingleCoreApplicationPrivate::readMessageHeader(QLocalSocket *sock, SingleCoreApplicationPrivate::ConnectionStage nextStage) {
if (!connectionMap_.contains(sock)) {
return;
@@ -373,30 +413,34 @@ void SingleCoreApplicationPrivate::readInitMessageHeader(QLocalSocket *sock) {
quint64 msgLen = 0;
headerStream >> msgLen;
ConnectionInfo &info = connectionMap_[sock];
info.stage = StageBody;
info.stage = nextStage;
info.msgLen = msgLen;
if (sock->bytesAvailable() >= static_cast<qint64>(msgLen)) {
readInitMessageBody(sock);
writeAck(sock);
}
bool SingleCoreApplicationPrivate::isFrameComplete(QLocalSocket *sock) {
if (!connectionMap_.contains(sock)) {
return false;
}
ConnectionInfo &info = connectionMap_[sock];
return (sock->bytesAvailable() >= static_cast<qint64>(info.msgLen));
}
void SingleCoreApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
Q_Q(SingleCoreApplication);
if (!connectionMap_.contains(sock)) {
return;
}
ConnectionInfo &info = connectionMap_[sock];
if (sock->bytesAvailable() < static_cast<qint64>(info.msgLen)) {
if (!isFrameComplete(sock)) {
return;
}
// Read the message body
QByteArray msgBytes = sock->read(static_cast<qint64>(info.msgLen));
QByteArray msgBytes = sock->readAll();
QDataStream readStream(msgBytes);
readStream.setVersion(QDataStream::Qt_5_8);
@@ -431,23 +475,34 @@ void SingleCoreApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
return;
}
ConnectionInfo &info = connectionMap_[sock];
info.instanceId = instanceId;
info.stage = StageConnected;
info.stage = StageConnectedHeader;
if (connectionType == NewInstance || (connectionType == SecondaryInstance && options_ & SingleCoreApplication::Mode::SecondaryNotification)) {
Q_EMIT q->instanceStarted();
emit q->instanceStarted();
}
if (sock->bytesAvailable() > 0) {
slotDataAvailable(sock, instanceId);
}
writeAck(sock);
}
void SingleCoreApplicationPrivate::slotDataAvailable(QLocalSocket *dataSocket, const quint32 instanceId) {
Q_Q(SingleCoreApplication);
Q_EMIT q->receivedMessage(instanceId, dataSocket->readAll());
if (!isFrameComplete(dataSocket)) {
return;
}
const QByteArray message = dataSocket->readAll();
writeAck(dataSocket);
ConnectionInfo &info = connectionMap_[dataSocket];
info.stage = StageConnectedHeader;
emit q->receivedMessage(instanceId, message);
}
@@ -465,7 +520,7 @@ void SingleCoreApplicationPrivate::randomSleep() {
QThread::msleep(QRandomGenerator::global()->bounded(8U, 18U));
#else
qsrand(QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max());
QThread::msleep(8 + static_cast<unsigned long>(static_cast<float>(qrand()) / RAND_MAX * 10));
QThread::msleep(qrand() % 11 + 8);
#endif
}

View File

@@ -71,9 +71,10 @@ class SingleCoreApplicationPrivate : public QObject {
Reconnect = 3
};
enum ConnectionStage : quint8 {
StageHeader = 0,
StageBody = 1,
StageConnected = 2,
StageInitHeader = 0,
StageInitBody = 1,
StageConnectedHeader = 2,
StageConnectedBody = 3,
};
Q_DECLARE_PUBLIC(SingleCoreApplication)
@@ -89,8 +90,12 @@ class SingleCoreApplicationPrivate : public QObject {
quint16 blockChecksum() const;
qint64 primaryPid() const;
QString primaryUser() const;
void readInitMessageHeader(QLocalSocket *socket);
bool isFrameComplete(QLocalSocket *sock);
void readMessageHeader(QLocalSocket *socket, const ConnectionStage nextStage);
void readInitMessageBody(QLocalSocket *socket);
void writeAck(QLocalSocket *sock);
bool writeConfirmedFrame(const int timeout, const QByteArray &msg) const;
bool writeConfirmedMessage(const int timeout, const QByteArray &msg) const;
static void randomSleep();
SingleCoreApplication *q_ptr;

View File

@@ -32,14 +32,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 +66,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()
@@ -117,6 +124,9 @@ endif()
pkg_check_modules(GLIB REQUIRED glib-2.0)
pkg_check_modules(GOBJECT REQUIRED gobject-2.0)
pkg_check_modules(GIO REQUIRED gio-2.0)
if(UNIX)
pkg_check_modules(GIO_UNIX gio-unix-2.0)
endif()
pkg_check_modules(LIBCDIO libcdio)
pkg_check_modules(GSTREAMER gstreamer-1.0)
pkg_check_modules(GSTREAMER_BASE gstreamer-base-1.0)
@@ -155,7 +165,7 @@ if(DBUS_FOUND AND NOT WIN32)
list(APPEND QT_COMPONENTS DBus)
endif()
set(QT_OPTIONAL_COMPONENTS Test)
set(QT_MIN_VERSION 5.8)
set(QT_MIN_VERSION 5.9)
if(BUILD_WITH_QT6 OR QT_VERSION_MAJOR EQUAL 6)
set(QT_VERSION_MAJOR 6 CACHE STRING "" FORCE)
@@ -292,7 +302,6 @@ set(SINGLEAPPLICATION_LIBRARIES singleapplication)
set(SINGLECOREAPPLICATION_LIBRARIES singlecoreapplication)
if(APPLE)
find_library(SPARKLE Sparkle PATHS "/usr/local/opt/sparkle")
add_subdirectory(3rdparty/SPMediaKeyTap)
set(SPMEDIAKEYTAP_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/SPMediaKeyTap)
set(SPMEDIAKEYTAP_LIBRARIES SPMediaKeyTap)
@@ -300,7 +309,7 @@ if(APPLE)
add_subdirectory(ext/macdeploycheck)
endif()
if(NOT SPARKLE AND (APPLE OR WIN32))
if(WIN32)
if(BUILD_WITH_QT6)
pkg_check_modules(QTSPARKLE qtsparkle-qt6)
else()
@@ -311,6 +320,12 @@ if(NOT SPARKLE AND (APPLE OR WIN32))
endif()
endif()
if(WIN32 AND MSVC)
add_subdirectory(3rdparty/getopt)
set(GETOPT_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/getopt)
set(GETOPT_LIBRARIES getopt)
endif()
if(WIN32 AND NOT MSVC)
# RC compiler
string(REPLACE "gcc" "windres" CMAKE_RC_COMPILER_INIT ${CMAKE_C_COMPILER})
@@ -391,6 +406,11 @@ optional_component(GIO ON "Devices: GIO device backend"
DEPENDS "Unix or Windows" "NOT APPLE"
)
optional_component(GIO_UNIX ON "Devices: GIO device backend (Unix support)"
DEPENDS "libgio-unix" GIO_UNIX_FOUND
DEPENDS "Unix" "UNIX"
)
optional_component(LIBGPOD ON "Devices: iPod classic support"
DEPENDS "libgpod" LIBGPOD_FOUND
DEPENDS "gdk-pixbuf" GDK_PIXBUF_FOUND
@@ -400,11 +420,6 @@ optional_component(LIBMTP ON "Devices: MTP support"
DEPENDS "libmtp" LIBMTP_FOUND
)
optional_component(SPARKLE ON "Sparkle integration"
DEPENDS "macOS" APPLE
DEPENDS "Sparkle" SPARKLE
)
if(BUILD_WITH_QT6)
optional_component(TRANSLATIONS ON "Translations"
DEPENDS "gettext" GETTEXT_FOUND
@@ -419,9 +434,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
@@ -482,12 +497,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)
@@ -510,6 +526,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)
@@ -518,7 +538,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()

109
Changelog
View File

@@ -2,6 +2,115 @@ Strawberry Music Player
=======================
ChangeLog
Version 1.0.7 (2022.07.25)
Bugfixes:
* Fixed checking file extension case-insensitive when loading and saving playlists.
* Fixed reading and saving rating with TagParser.
* (macOS/Windows) Fixed playlist column alignment. Applied patch for Qt bug QTBUG-103576 (#999).
* (Windows|MinGW) Fixed HLS streaming.
* (Windows|MSVC) Fixed MP3 encoding.
Enhancements
* Added option for selecting file extension when saving all playlists.
Version 1.0.6 (2022.07.17)
Bugfixes:
* Fixed certain albums not added to playlist in correct track order from search for Tidal and QObuz.
* Fixed songs not added to playlist in numeric order when added from file view with right click (#977).
* Fixed "Stop after this track" graying out next track in dynamic mode (#912).
* Fixed a gstreamer caps leak when transcoding songs.
* Fixed errors in translation files (#994).
Enhancements
* Add songs to the collection even when they have invalid ctime or mtime.
* Made ListenBrainz scrobbler respect "Prefer album artist" option (#989).
* Send track duration, number, player name and version when scrobbling to ListenBrainz (#995).
* (macOS) Added missing HLS streaming plugin.
Version 1.0.5 (2022.06.10)
Bugfixes:
* Fixed smart playlist filetype search.
* Fixed Radio Paradise URLs to use HTTPS instead of HTTP.
* Fixed horizontal scrolling not affecting currently playing track (#952).
* Fixed keep running in the background when window is closed with Wayland (#964).
* Fixed percent-encoding of URLs when loading and saving XSPF playlists (#821).
* Fixed fancy tabbar context menu showing on right clicks outside of tabbar when a song is playing.
* Fixed possible duplicating songs in the database when moving songs to the collection using the organize feature.
* (Windows|MSVC) Fixed moodbar fftw3 crash with (older) CPU's that does not support AVX2 (#944).
* (Windows|MSVC) Fixed using libiconv for converting characters when organizing files like with MinGW.
Enhancements
* Show more details in error dialog on GStreamer errors (#958).
* Allow setting blur amount of playlist background image up to 100px (#939).
* Include 128x128 icon sizes (#954).
* Show right click copy context menu in context view on top text and lyrics (#965).
* Improve fading between album covers in context view.
* Added option for overwriting database playcounts in collection settings (#962).
* Added option for disabling bar on currently playing track (#972).
* (Debian) Added Qt 6 support to debian files and build with Qt 6 for Debian Bookworm, Ubuntu Jammy and newer.
* (Windows|MSVC) Added libav/ffmpeg plugin.
Version 1.0.4 (2022.04.10)
Bugfixes:
* Fixed use-after-free memory in ALSA PCM device finder.
* Translate global shortcuts.
* (Windows) Fixed registering 0-9 numpad keys in global shortcuts.
Enhancements
* Added save all playlists action.
* (Windows) Made updater support both MSVC and MinGW.
* (Windows) Added HLS support.
Other:
* Removed use of custom font in context.
Version 1.0.3 (2022.03.24)
Bugfixes:
* Remove slash and backslash from filenames when saving album covers using album directory cover filenames (#903).
* Remove playlist file-extensions from accepted audio file extensions (#909).
* Fixed Qobuz requests only receiving the first 50 albums (#922).
* (Windows|MinGW) Fixed streaming stopping at the end of each track. libsoup downgraded from 3.0 to 2.74.
* (Windows|MSVC) Fixed initial database schema failure caused by CRLF line-endings in schema files.
New features
* Added support for bs2b (Improved headphone listening of stereo audio records using Bauer stereophonic-to-binaural DSP) (#249).
Version 1.0.2 (2022.02.20)
Bugfixes:
* Fixed showing menu when clicking icon for collection and internet search tool buttons
* Fixed ignoring devices with system mounts as defined by GIO (#410).
* Fixed updating database when deleting songs from filesystem devices.
* Fixed unregistered metatype when listing songs from MTP devices with Qt 6.
* Fixed using entered password when testing Subsonic settings before pressing save (#879).
* Fixed downloading Subsonic album covers.
* Fixed subsonic album covers downloaded several times for each album when MD5 authentication was enabled (#885).
* Fixed volume going to 100% when pressing volume down with MRPIS2 and global shortcuts (#884).
* Fixed incorrect rounding when setting volume through MPRIS2 (#894).
* Fixed delete from disk not showing up in the menu when one or more CUE songs were selected.
* Fixed possible crashes when switching songs when fading is enabled (#890).
* Fixed X11 global shortcuts not working unless window was in focus with Qt 6.2 and higher (#893).
* Fixed scrobbler re-sending scrobbles to fast on error (#898).
Enhancements
* Log Qt version on startup.
* Added button for deleting existing Subsonic songs (#883).
* Make collection watcher ignore files with "qt_temp" filename and tmp extension.
* Require Qt 5.9 or higher.
* Added scrollbars to edit tag dialog (#888).
* Added advanced settings for configuring collection watcher.
* Disable open audio CD menu when compiled without audio CD support.
* Replaced use of deprecated QMouseEvent constructor as of Qt 6.4.
* Replaced use of deprecated QCryptographicHash::addData overload as of Qt 6.4.
Removed features:
* Removed broken "nomedia" / "nomusic" file handling.
Version 1.0.1 (2022.01.08)
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/
@@ -23,7 +24,8 @@ Resources:
### :bangbang: Opening an issue:
* Search for the issue to see if it is already solved, or if there is an open issue for it already. If there is an open issue already, you can comment on it if you have additional information that could be useful to us.
* For technical problems, questions and feature requests please use our forum on https://forum.strawberrymusicplayer.org/ that is better suited for discussion. It also better allows answers from the community instead of just the developers on GitHub.
* For technical problems, discussion, questions and feature suggestions use the forum (https://forum.strawberrymusicplayer.org/) instead. The forum is better suited for discussion.
* We do not take feature requests from users on GitHub. Any issues related to feature requests will be closed. This does not necessarily mean that we won't add new features, but we don't have time to take feature requests or answer questions about new features from users. It is still possible to suggest or discuss new features on the forum (https://forum.strawberrymusicplayer.org/).
### :moneybag: Sponsoring:
@@ -66,15 +68,14 @@ It has so far been tested to work on Linux, OpenBSD, FreeBSD, macOS and Windows.
To build Strawberry from source you need the following installed on your system with the additional development packages/headers:
* [CMake](https://cmake.org/)
* [GNU Make](https://www.gnu.org/software/make/)
* [GCC](https://gcc.gnu.org/) or [clang](https://clang.llvm.org/) compiler
* [GCC](https://gcc.gnu.org/), [Clang](https://clang.llvm.org/) or [MSVC](https://visualstudio.microsoft.com/vs/features/cplusplus/) compiler
* [Boost](https://www.boost.org/)
* [GLib](https://developer.gnome.org/glib/)
* [Protobuf](https://developers.google.com/protocol-buffers/)
* [Qt 5.8 or higher (or Qt 6) with components Core, Gui, Widgets, Concurrent, Network and Sql](https://www.qt.io/)
* [Qt 5.9 or higher (or Qt 6) with components Core, Gui, Widgets, Concurrent, Network and Sql](https://www.qt.io/)
* [SQLite 3.9 or newer with FTS5](https://www.sqlite.org)
* [ALSA (Linux required)](https://www.alsa-project.org/)
* [D-Bus (Linux required)](https://www.freedesktop.org/wiki/Software/dbus/)
* [Protobuf](https://developers.google.com/protocol-buffers/)
* [ALSA (Required on Linux)](https://www.alsa-project.org/)
* [D-Bus (Required on Linux)](https://www.freedesktop.org/wiki/Software/dbus/)
* [GStreamer](https://gstreamer.freedesktop.org/) or [VLC](https://www.videolan.org)
* [GnuTLS](https://www.gnutls.org/)
* [TagLib 1.11.1 or higher](https://www.taglib.org/) or [TagParser](https://github.com/Martchus/tagparser)
@@ -88,8 +89,7 @@ Optional dependencies:
* MTP devices: [libmtp](http://libmtp.sourceforge.net/)
* iPod Classic devices: [libgpod](http://www.gtkpod.org/libgpod/)
Either GStreamer or VLC engine is required, but only GStreamer is fully implemented, and works best, it is therefore recommended to use GStreamer.
You should also install the gstreamer plugins base and good, and optionally bad, ugly and libav.
You should also install the gstreamer plugins base and good, and optionally bad, ugly and libav to support all audio formats.
### :wrench: Compiling from source
@@ -101,15 +101,15 @@ You should also install the gstreamer plugins base and good, and optionally bad,
cd strawberry
mkdir build && cd build
cmake ..
cmake .. -DBUILD_WITH_QT6=ON
make -j$(nproc)
sudo make install
To compile with Qt 6 use:
cmake .. -DBUILD_WITH_QT6=ON
Strawberry is backwards compatible with Qt 5, to compile with Qt 5 use:
cmake .. -DBUILD_WITH_QT5=ON
### :penguin: Packaging status
[![Packaging status](https://repology.org/badge/vertical-allrepos/strawberry.svg)](https://repology.org/metapackage/strawberry/versions)
[![Packaging status](https://repology.org/badge/vertical-allrepos/strawberry.svg?exclude_unsupported=1)](https://repology.org/metapackage/strawberry/versions)

View File

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

View File

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

View File

@@ -12,10 +12,17 @@ if (LSB_RELEASE_EXEC AND RPMBUILD_EXEC)
OUTPUT_VARIABLE DIST_RELEASE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | sed 's/\\.//g' | cut -d' ' -f3"
OUTPUT_VARIABLE DIST_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (${DIST_NAME} STREQUAL "openmandrivalinux")
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | sed 's/\\./0/g' | cut -d' ' -f3"
OUTPUT_VARIABLE DIST_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
else()
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | sed 's/\\.//g' | cut -d' ' -f3"
OUTPUT_VARIABLE DIST_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()
if (DIST_NAME)
message(STATUS "Distro Name: ${DIST_NAME}")
@@ -44,6 +51,8 @@ if (LSB_RELEASE_EXEC AND RPMBUILD_EXEC)
set(RPM_DISTRO "el${DIST_VERSION}")
elseif (${DIST_NAME} STREQUAL "mageia" AND DIST_RELEASE)
set(RPM_DISTRO "mga${DIST_RELEASE}")
elseif (${DIST_NAME} STREQUAL "openmandrivalinux" AND DIST_VERSION)
set(RPM_DISTRO "omv${DIST_VERSION}")
endif()
if(NOT RPM_DISTRO)

View File

@@ -1,6 +1,6 @@
set(STRAWBERRY_VERSION_MAJOR 1)
set(STRAWBERRY_VERSION_MINOR 0)
set(STRAWBERRY_VERSION_PATCH 1)
set(STRAWBERRY_VERSION_PATCH 7)
#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>
@@ -46,7 +37,6 @@
<file>pictures/rainbowdash.png</file>
<file>pictures/star-on.png</file>
<file>pictures/star-off.png</file>
<file>fonts/HumongousofEternitySt.ttf</file>
<file>mood/sample.mood</file>
<file>text/ghosts.txt</file>
</qresource>

Binary file not shown.

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -31,39 +31,40 @@
background-color: %palette-base;
}
#context-scrollarea {
background-color: %palette-base;
}
QToolButton {
border: 2px solid transparent;
border-radius: 3px;
padding: 1px;
}
QToolButton::menu-button {
width: 16px;
border: none;
}
QToolButton[popupMode="1"] {
padding-right: 16px;
}
QToolButton:hover {
border: 2px solid %palette-highlight;
background-color: %palette-highlight-lighter;
}
QToolButton:hover[popupMode="1"] {
padding-right: 16px;
}
QToolButton:pressed {
border: 2px solid %palette-highlight-darker;
background-color: %palette-highlight-lighter;
}
QToolButton:pressed[popupMode="1"] {
QToolButton[popupMode="MenuButtonPopup"], QToolButton:hover[popupMode="MenuButtonPopup"], QToolButton:pressed[popupMode="MenuButtonPopup"] {
padding-right: 16px;
}
/* For backwards compatibility with Qt 5 as it does not support property name */
QToolButton[popupMode="1"], QToolButton:hover[popupMode="1"], QToolButton:pressed[popupMode="1"] {
padding-right: 16px;
}
QToolButton::menu-button {
width: 16px;
border: none;
}
macos {
font-size: 11pt;
}
@@ -71,4 +72,3 @@ macos {
macos QMenu {
font-size: 13pt;
}

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,7 @@ Build-Depends: debhelper (>= 11),
libasound2-dev,
libpulse-dev,
libtag1-dev,
qtbase5-dev,
qtbase5-private-dev,
qtbase5-dev-tools,
qttools5-dev,
libqt5x11extras5-dev,
@DEBIAN_BUILD_DEPENDS_QT_PACKAGES@,
libgstreamer1.0-dev,
libgstreamer-plugins-base1.0-dev,
libcdio-dev,
@@ -28,20 +25,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 +45,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

183
debian/copyright vendored
View File

@@ -1,10 +1,11 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: strawberry
Upstream-Contact: Jonas Kvinge <jonas@jkvinge.net>
Source: https://www.strawberrymusicplayer.org/
Source: https://github.com/strawberrymusicplayer/strawberry
Files: *
Copyright: 2010-2015, David Sansome <me@davidsansome.com>
2012-2014, 2017-2022 Jonas Kvinge <jonas@jkvinge.net>
License: GPL-3+
Files: src/core/timeconstants.h
@@ -13,14 +14,13 @@ Files: src/core/timeconstants.h
ext/libstrawberry-common/core/messagehandler.cpp
ext/libstrawberry-common/core/messagehandler.h
Copyright: 2011, 2012, David Sansome <me@davidsansome.com>
2018-2022, Jonas Kvinge <jonas@jkvinge.net>
License: Apache-2.0
Files: src/core/main.h
src/core/iconloader.cpp
src/core/iconloader.h
src/core/iconmapper.h
src/config.h.in
src/version.h.in
src/context/contextview.cpp
src/context/contextview.h
src/context/contextalbum.cpp
@@ -29,6 +29,8 @@ Files: src/core/main.h
src/engine/enginetype.h
src/engine/alsadevicefinder.cpp
src/engine/alsadevicefinder.h
src/engine/alsapcmdevicefinder.cpp
src/engine/alsapcmdevicefinder.h
src/engine/mmdevicefinder.cpp
src/engine/mmdevicefinder.h
src/engine/devicefinder.cpp
@@ -69,11 +71,17 @@ Files: src/core/main.h
src/covermanager/spotifycoverprovider.h
src/covermanager/musixmatchcoverprovider.cpp
src/covermanager/musixmatchcoverprovider.h
src/globalshortcuts/globalshortcutsbackend-system.cpp
src/globalshortcuts/globalshortcutsbackend-system.h
src/globalshortcuts/globalshortcutsbackend-kde.cpp
src/globalshortcuts/globalshortcutsbackend-kde.h
src/globalshortcuts/globalshortcutsbackend-mate.cpp
src/globalshortcuts/globalshortcutsbackend-mate.h
src/globalshortcuts/globalshortcutsbackend-x11.cpp
src/globalshortcuts/globalshortcutsbackend-x11.h
src/globalshortcuts/globalshortcutsbackend-win.cpp
src/globalshortcuts/globalshortcutsbackend-win.h
src/globalshortcuts/globalshortcut.cpp
src/globalshortcuts/globalshortcut.h
src/globalshortcuts/globalshortcut-X11.cpp
src/globalshortcuts/globalshortcut-x11.cpp
src/globalshortcuts/globalshortcut-win.cpp
src/globalshortcuts/keymapper_x11.h
src/globalshortcuts/keymapper_win.h
@@ -81,132 +89,21 @@ Files: src/core/main.h
src/scrobbler/*
src/subsonic/*
src/tidal/*
src/qobuz/*
src/radios/*
src/transcoder/transcoderoptionswavpack.cpp
src/transcoder/transcoderoptionswavpack.h
Copyright: 2012-2014, 2017-2020, Jonas Kvinge <jonas@jkvinge.net>
License: GPL-3+
Files: src/core/main.cpp
src/core/mainwindow.cpp
src/core/mainwindow.h
src/core/player.cpp
src/core/player.h
src/core/song.cpp
src/core/song.h
src/core/songloader.cpp
src/core/songloader.h
src/core/urlhandler.cpp
src/core/urlhandler.h
src/core/utilities.cpp
src/core/utilities.h
src/core/networkaccessmanager.cpp
src/core/networkaccessmanager.h
src/core/threadsafenetworkdiskcache.cpp
src/core/threadsafenetworkdiskcache.h
src/core/filesystemmusicstorage.cpp
src/core/filesystemmusicstorage.h
src/core/stylesheetloader.cpp
src/core/stylesheetloader.h
src/engine/gstenginepipeline.cpp
src/engine/gstenginepipeline.h
src/engine/vlcengine.cpp
src/engine/vlcengine.h
src/collection/collectionwatcher.cpp
src/collection/collectionwatcher.h
src/collection/collectionbackend.cpp
src/collection/collectionbackend.h
src/collection/collectionmodel.cpp
src/collection/collectionmodel.h
src/context/contextalbumsmodel.cpp
src/context/contextalbumsview.cpp
src/context/contextalbumsmodel.h
src/context/contextalbumsview.h
src/widgets/playingwidget.cpp
src/widgets/playingwidget.h
src/osd/osdbase.cpp
src/osd/osdbase.h
src/osd/osdpretty.cpp
src/osd/osdpretty.h
src/osd/osddbus.cpp
src/osd/osddbus.h
src/osd/osdmac.cpp
src/osd/osdmac.h
src/dialogs/about.cpp
src/dialogs/about.h
src/playlist/playlist.cpp
src/playlist/playlist.h
src/playlist/playlistitem.cpp
src/playlist/playlistitem.h
src/playlist/playlistdelegates.cpp
src/playlist/playlistdelegates.h
src/playlist/playlistbackend.cpp
src/playlist/playlistbackend.h
src/playlist/playlistview.cpp
src/playlist/playlistview.h
src/playlist/songplaylistitem.cpp
src/playlist/songplaylistitem.h
src/internet/internetplaylistitem.cpp
src/internet/internetsearch.cpp
src/internet/internetsearch.h
src/internet/internetsearchview.cpp
src/internet/internetsearchview.h
src/internet/internetservices.cpp
src/internet/internetservices.h
src/internet/internetsongsview.cpp
src/internet/internetsongsview.h
src/internet/internetcollectionview.cpp
src/internet/internetcollectionview.h
ext/libstrawberry-tagreader/tagreader.cpp
ext/libstrawberry-tagreader/tagreader.h
src/device/devicemanager.cpp
src/device/devicemanager.h
src/device/deviceinfo.cpp
src/device/deviceinfo.h
src/device/deviceproperties.cpp
src/device/deviceproperties.h
src/device/deviceview.cpp
src/device/deviceview.h
src/device/connecteddevice.cpp
src/device/connecteddevice.h
src/device/mtpconnection.cpp
src/device/mtpconnection.h
src/device/mtpdevice.cpp
src/device/mtpdevice.h
src/globalshortcuts/globalshortcutsmanager.cpp
src/globalshortcuts/globalshortcutsmanager.h
src/settings/shortcutssettingspage.cpp
src/settings/shortcutssettingspage.h
src/settings/appearancesettingspage.cpp
src/settings/appearancesettingspage.h
src/organize/organize.cpp
src/organize/organize.h
src/organize/organizedialog.cpp
src/organize/organizedialog.h
src/organize/organizeerrordialog.cpp
src/organize/organizeerrordialog.h
src/transcoder/transcoder.cpp
src/transcoder/transcoder.h
src/musicbrainz/musicbrainzclient.cpp
src/musicbrainz/musicbrainzclient.h
src/covermanager/albumcoverloader.cpp
src/covermanager/albumcoverloader.h
src/covermanager/currentalbumcoverloader.cpp
src/covermanager/currentalbumcoverloader.h
src/covermanager/albumcoverchoicecontroller.cpp
src/covermanager/albumcoverchoicecontroller.h
src/covermanager/albumcoverfetchersearch.cpp
src/covermanager/albumcoverfetchersearch.h
src/covermanager/coverproviders.cpp
src/covermanager/coverproviders.h
src/covermanager/coverprovider.cpp
src/covermanager/coverprovider.h
Copyright: 2010, 2012-2014 David Sansome <me@davidsansome.com>
2012-2014, 2017-2020 Jonas Kvinge <jonas@jkvinge.net>
ext/libstrawberry-tagreader/tagreadertagparser.cpp
ext/libstrawberry-tagreader/tagreadertagparser.h
ext/macdeploycheck/*
src/widgets/resizabletextedit.cpp
src/widgets/resizabletextedit.h
Copyright: 2012-2014, 2017-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>
@@ -214,7 +111,7 @@ License: GPL-3+
Files: src/engine/gstengine.cpp
src/engine/gstengine.h
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
Copyright: 2017-2021, Jonas Kvinge <jonas@jkvinge.net>
2006, Paul Cifarelli <paul@cifarelli.net>
2005, Jakub Stachowski <qbast@go2.pl>
2003-2005, Mark Kretschmann <markey@web.de>
@@ -230,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
@@ -244,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+
@@ -298,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
@@ -322,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
@@ -337,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.
@@ -358,6 +258,7 @@ License: GPL-2+
Files: src/widgets/qsearchfield_nonmac.cpp
src/widgets/qsearchfield_mac.mm
src/widgets/qsearchfield.h
src/widgets/qocoa_mac.h
Copyright: 2011, Mike McQuaid <mike@mikemcquaid.com>
License: Expat
@@ -367,7 +268,7 @@ Copyright: 2010, Spotify AB
License: BSD-3-clause
Files: 3rdparty/singleapplication/*
Copyright: 2015-2018, Itay Grudev
Copyright: 2015-2022, Itay Grudev
License: MIT

View File

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

1
debian/rules vendored
View File

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

4
dist/CMakeLists.txt vendored
View File

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

View File

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

View File

@@ -11,10 +11,33 @@ if ! [ "$gitrev" = "ON" ]; then
exclude_vcs="--exclude-vcs"
fi
cmds="gtar tar"
for cmd in $cmds
do
which $cmd >/dev/null 2>&1
if [ ! $? -eq 0 ]; then
continue
fi
result=$($cmd --version 2>&1 | head -n1)
if [ ! $? -eq 0 ]; then
continue
fi
echo "$result" | grep "^.* (GNU tar) .*$" >/dev/null 2>&1
if [ ! $? -eq 0 ]; then
continue
fi
TAR=$cmd
done
if [ "$TAR" = "" ]; then
echo "ERROR: Missing GNU Tar"
exit 1
fi
echo "Creating $name-$version.tar.xz..."
rm -f "$name-$version.tar.xz"
tar -cJf $name-$version.tar.xz \
${TAR} -cJf $name-$version.tar.xz \
--transform "s,^$rootnoslash,$name-$version," $exclude_vcs \
--exclude=".directory" \
--exclude="*.tar" \
@@ -37,7 +60,6 @@ tar -cJf $name-$version.tar.xz \
--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

@@ -1,6 +1,6 @@
Name: strawberry
Version: @STRAWBERRY_VERSION_RPM_V@
%if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos}
%if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos} || "%{?_vendor}" == "openmandriva"
Release: @STRAWBERRY_VERSION_RPM_R@%{?dist}
%else
Release: @STRAWBERRY_VERSION_RPM_R@.@RPM_DISTRO@
@@ -138,7 +138,7 @@ Features:
export CXXFLAGS="-fPIC $RPM_OPT_FLAGS"
%endif
%{cmake} -DQT_VERSION_MAJOR=@QT_VERSION_MAJOR@
%if 0%{?centos} || (0%{?mageia} && 0%{?mageia} <= 7)
%if 0%{?centos} || (0%{?mageia} && 0%{?mageia} <= 7) || "%{?_vendor}" == "openmandriva"
%make_build
%else
%cmake_build
@@ -148,7 +148,7 @@ Features:
%if 0%{?centos}
%make_install
%else
%if 0%{?mageia}
%if 0%{?mageia} || "%{?_vendor}" == "openmandriva"
%make_install -C build
%else
%cmake_install

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

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

View File

@@ -1,21 +1,51 @@
!if "@ARCH@" == x86
!define build_type ""
!define compiler "unknown"
!define arch "unknown"
!if "@ARCH@" == "x86"
!define arch_x86
!undef arch
!define arch "x86"
!endif
!if "@ARCH@" == i686-w64-mingw32.shared
!if "@ARCH@" == "i686-w64-mingw32.shared"
!define arch_x86
!undef arch
!define arch "x86"
!endif
!if "@ARCH@" == x86_64
!if "@ARCH@" == "x86_64"
!define arch_x64
!undef arch
!define arch "x64"
!endif
!if "@ARCH@" == x86_64-w64-mingw32.shared
!if "@ARCH@" == "x86_64-w64-mingw32.shared"
!define arch_x64
!undef arch
!define arch "x64"
!endif
!if "@CMAKE_BUILD_TYPE@" == Debug
!if "@MINGW@" == "1"
!define mingw
!undef compiler
!define compiler "mingw"
!endif
!if "@MSVC@" == "1"
!define msvc
!undef compiler
!define compiler "msvc"
!endif
!if "@CMAKE_BUILD_TYPE@" == "Release"
!define release
!endif
!if "@CMAKE_BUILD_TYPE@" == "Debug"
!define debug
!undef build_type
!define build_type "-Debug"
!endif
!ifdef debug
@@ -70,14 +100,27 @@ SetCompressor /SOLID lzma
!include "FileAssociation.nsh"
!include "Capabilities.nsh"
!include LogicLib.nsh
!include Registry.nsh
!include x64.nsh
!define MUI_ICON "strawberry.ico"
!define MUI_COMPONENTSPAGE_SMALLDESC
ReserveFile "${NSISDIR}/Plugins/x86-unicode/LockedList.dll"
ReserveFile "${NSISDIR}/Plugins/LockedList64.dll"
!ifdef mingw
ReserveFile "${NSISDIR}/Plugins/x86-unicode/LockedList.dll"
ReserveFile "${NSISDIR}/Plugins/LockedList64.dll"
ReserveFile "${NSISDIR}/Plugins/registry.dll"
ReserveFile "${NSISDIR}/Plugins/x86-unicode/INetC.dll"
!endif
!ifdef msvc
ReserveFile "${NSISDIR}\Plugins\x86-unicode\LockedList.dll"
ReserveFile "${NSISDIR}\Plugins\LockedList64.dll"
ReserveFile "${NSISDIR}\Plugins\registry.dll"
ReserveFile "${NSISDIR}\Plugins\x86-unicode\INetC.dll"
!endif
!define LockedListPATH $InstallDir
; Installer pages
@@ -97,21 +140,8 @@ UninstPage custom un.LockedListPageShow
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
Name "${PRODUCT_NAME}"
!ifdef arch_x86
!ifdef debug
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-Debug-x86.exe"
!else
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-x86.exe"
!endif
!endif
!ifdef arch_x64
!ifdef debug
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-Debug-x64.exe"
!else
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-x64.exe"
!endif
!endif
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}${build_type}-${compiler}-${arch}.exe"
InstallDir "${PRODUCT_INSTALL_DIR}"
@@ -166,6 +196,8 @@ SectionEnd
Section "Strawberry" Strawberry
SetOutPath "$INSTDIR"
; Common executables
File "strawberry.exe"
File "strawberry-tagreader.exe"
File "strawberry.ico"
@@ -173,40 +205,46 @@ Section "Strawberry" Strawberry
File "gst-launch-1.0.exe"
File "gst-discoverer-1.0.exe"
; MinGW specific files
!ifdef mingw
!ifdef arch_x86
File "libgcc_s_sjlj-1.dll"
File "libcrypto-3.dll"
File "libssl-3.dll"
!endif
!ifdef arch_x64
File "libgcc_s_seh-1.dll"
File "libcrypto-3-x64.dll"
File "libssl-3-x64.dll"
!endif
File "avcodec-58.dll"
File "avfilter-7.dll"
File "avformat-58.dll"
File "avutil-56.dll"
File "avcodec-59.dll"
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 "libffi-8.dll"
File "libfftw3-3.dll"
File "libFLAC-8.dll"
File "libfreetype-6.dll"
File "libfaac-0.dll"
File "libfaad-2.dll"
File "libfdk-aac-2.dll"
File "libffi-8.dll"
File "libfreetype-6.dll"
File "libgcrypt-20.dll"
File "libgio-2.0-0.dll"
File "libglib-2.0-0.dll"
File "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"
@@ -232,24 +270,26 @@ Section "Strawberry" Strawberry
File "libjpeg-9.dll"
File "liblzma-5.dll"
File "libmp3lame-0.dll"
File "libmpcdec.dll"
File "libmpg123-0.dll"
File "libnettle-8.dll"
File "libnghttp2.dll"
File "libogg-0.dll"
File "libopenmpt-0.dll"
File "libopus-0.dll"
File "liborc-0.4-0.dll"
File "libpcre-1.dll"
File "libpcre2-16-0.dll"
File "libpng16-16.dll"
File "libprotobuf-32.dll"
File "libpsl-5.dll"
File "libprotobuf-30.dll"
File "libqtsparkle-qt6.dll"
File "libsoup-3.0-0.dll"
File "libspeex-1.dll"
File "libsqlite3-0.dll"
File "libssp-0.dll"
File "libstdc++-6.dll"
File "libsoup-2.4-1.dll"
File "libtag.dll"
File "libtasn1-6.dll"
File "libtwolame-0.dll"
File "libunistring-2.dll"
File "libvorbis-0.dll"
File "libvorbisenc-2.dll"
@@ -258,15 +298,9 @@ Section "Strawberry" Strawberry
File "libwinpthread-1.dll"
File "libxml2-2.dll"
File "libzstd.dll"
File "postproc-55.dll"
File "Qt6Concurrent.dll"
File "Qt6Core.dll"
File "Qt6Gui.dll"
File "Qt6Network.dll"
File "Qt6Sql.dll"
File "Qt6Widgets.dll"
File "swresample-3.dll"
File "swscale-5.dll"
File "postproc-56.dll"
File "swresample-4.dll"
File "swscale-6.dll"
File "zlib1.dll"
!ifdef debug
@@ -274,8 +308,127 @@ 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
; MSVC specific files
!ifdef msvc
!ifdef arch_x86
File "libcrypto-3.dll"
File "libssl-3.dll"
!endif
!ifdef arch_x64
File "libcrypto-3-x64.dll"
File "libssl-3-x64.dll"
!endif
File "FLAC.dll"
File "avcodec-58.dll"
File "avfilter-7.dll"
File "avformat-58.dll"
File "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 "gio-2.0-0.dll"
File "glib-2.0-0.dll"
File "gmodule-2.0-0.dll"
File "gnutls.dll"
File "gobject-2.0-0.dll"
File "gstadaptivedemux-1.0-0.dll"
File "gstapp-1.0-0.dll"
File "gstaudio-1.0-0.dll"
File "gstbadaudio-1.0-0.dll"
File "gstbase-1.0-0.dll"
File "gstfft-1.0-0.dll"
File "gstisoff-1.0-0.dll"
File "gstnet-1.0-0.dll"
File "gstpbutils-1.0-0.dll"
File "gstreamer-1.0-0.dll"
File "gstriff-1.0-0.dll"
File "gstrtp-1.0-0.dll"
File "gstrtsp-1.0-0.dll"
File "gstsdp-1.0-0.dll"
File "gsttag-1.0-0.dll"
File "gsturidownloader-1.0-0.dll"
File "gstvideo-1.0-0.dll"
File "intl-8.dll"
File "libbs2b.dll"
File "libfaac_dll.dll"
File "libiconv.dll"
File "liblzma.dll"
File "libmp3lame.dll"
File "libopenmpt.dll"
File "libspeex.dll"
File "mpcdec.dll"
File "mpg123.dll"
File "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 "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 "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 "libpng16d.dll"
File "libprotobufd.dll"
File "libxml2d.dll"
File "pcre2-8d.dll"
File "pcre2-16d.dll"
File "twolamed.dll"
File "zlibd.dll"
!endif
!endif ; MSVC
; Common files
File "libfftw3-3.dll"
!ifdef msvc && debug
File "Qt6Concurrentd.dll"
File "Qt6Cored.dll"
File "Qt6Guid.dll"
File "Qt6Networkd.dll"
File "Qt6Sqld.dll"
File "Qt6Widgetsd.dll"
!else
File "Qt6Concurrent.dll"
File "Qt6Core.dll"
File "Qt6Gui.dll"
File "Qt6Network.dll"
File "Qt6Sql.dll"
File "Qt6Widgets.dll"
!endif
; Register Strawberry with Default Programs
@@ -312,39 +465,72 @@ SectionEnd
Section "GIO modules" gio-modules
SetOutPath "$INSTDIR\gio-modules"
!ifdef mingw
File "/oname=libgiognutls.dll" "gio-modules\libgiognutls.dll"
File "/oname=libgioopenssl.dll" "gio-modules\libgioopenssl.dll"
!endif
!ifdef msvc
File "/oname=giognutls.dll" "gio-modules\giognutls.dll"
File "/oname=gioopenssl.dll" "gio-modules\gioopenssl.dll"
!endif
SectionEnd
Section "Qt Platform plugins" platforms
SetOutPath "$INSTDIR\platforms"
!ifdef msvc && debug
File "/oname=qwindowsd.dll" "platforms\qwindowsd.dll"
!else
File "/oname=qwindows.dll" "platforms\qwindows.dll"
!endif
SectionEnd
Section "Qt styles" styles
SetOutPath "$INSTDIR\styles"
!ifdef msvc && debug
File "/oname=qwindowsvistastyled.dll" "styles\qwindowsvistastyled.dll"
!else
File "/oname=qwindowsvistastyle.dll" "styles\qwindowsvistastyle.dll"
!endif
SectionEnd
Section "Qt TLS plugins" tls
SetOutPath "$INSTDIR\tls"
!ifdef msvc && debug
File "/oname=qschannelbackendd.dll" "tls\qschannelbackendd.dll"
File "/oname=qopensslbackendd.dll" "tls\qopensslbackendd.dll"
!else
File "/oname=qschannelbackend.dll" "tls\qschannelbackend.dll"
File "/oname=qopensslbackend.dll" "tls\qopensslbackend.dll"
!endif
SectionEnd
Section "Qt SQL Drivers" sqldrivers
SetOutPath "$INSTDIR\sqldrivers"
!ifdef msvc && debug
File "/oname=qsqlited.dll" "sqldrivers\qsqlited.dll"
!else
File "/oname=qsqlite.dll" "sqldrivers\qsqlite.dll"
!endif
SectionEnd
Section "Qt imageformats" imageformats
SetOutPath "$INSTDIR\imageformats"
!ifdef msvc && debug
File "/oname=qgifd.dll" "imageformats\qgifd.dll"
File "/oname=qicod.dll" "imageformats\qicod.dll"
File "/oname=qjpegd.dll" "imageformats\qjpegd.dll"
!else
File "/oname=qgif.dll" "imageformats\qgif.dll"
File "/oname=qico.dll" "imageformats\qico.dll"
File "/oname=qjpeg.dll" "imageformats\qjpeg.dll"
!endif
SectionEnd
Section "Gstreamer plugins" gstreamer-plugins
SetOutPath "$INSTDIR\gstreamer-plugins"
!ifdef mingw
File "/oname=libgstaes.dll" "gstreamer-plugins\libgstaes.dll"
File "/oname=libgstaiff.dll" "gstreamer-plugins\libgstaiff.dll"
File "/oname=libgstapetag.dll" "gstreamer-plugins\libgstapetag.dll"
File "/oname=libgstapp.dll" "gstreamer-plugins\libgstapp.dll"
@@ -358,20 +544,25 @@ Section "Gstreamer plugins" gstreamer-plugins
File "/oname=libgstaudioresample.dll" "gstreamer-plugins\libgstaudioresample.dll"
File "/oname=libgstaudiotestsrc.dll" "gstreamer-plugins\libgstaudiotestsrc.dll"
File "/oname=libgstautodetect.dll" "gstreamer-plugins\libgstautodetect.dll"
File "/oname=libgstcdio.dll" "gstreamer-plugins\libgstcdio.dll"
File "/oname=libgstbs2b.dll" "gstreamer-plugins\libgstbs2b.dll"
File "/oname=libgstcoreelements.dll" "gstreamer-plugins\libgstcoreelements.dll"
File "/oname=libgstdash.dll" "gstreamer-plugins\libgstdash.dll"
File "/oname=libgstdirectsound.dll" "gstreamer-plugins\libgstdirectsound.dll"
File "/oname=libgstequalizer.dll" "gstreamer-plugins\libgstequalizer.dll"
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
File "/oname=libgstfaac.dll" "gstreamer-plugins\libgstfaac.dll"
File "/oname=libgstfaad.dll" "gstreamer-plugins\libgstfaad.dll"
File "/oname=libgstfdkaac.dll" "gstreamer-plugins\libgstfdkaac.dll"
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
File "/oname=libgstgio.dll" "gstreamer-plugins\libgstgio.dll"
File "/oname=libgsthls.dll" "gstreamer-plugins\libgsthls.dll"
File "/oname=libgsticydemux.dll" "gstreamer-plugins\libgsticydemux.dll"
File "/oname=libgstid3demux.dll" "gstreamer-plugins\libgstid3demux.dll"
File "/oname=libgstid3tag.dll" "gstreamer-plugins\libgstid3tag.dll"
File "/oname=libgstisomp4.dll" "gstreamer-plugins\libgstisomp4.dll"
File "/oname=libgstlame.dll" "gstreamer-plugins\libgstlame.dll"
File "/oname=libgstlibav.dll" "gstreamer-plugins\libgstlibav.dll"
File "/oname=libgstmpg123.dll" "gstreamer-plugins\libgstmpg123.dll"
File "/oname=libgstmusepack.dll" "gstreamer-plugins\libgstmusepack.dll"
File "/oname=libgstogg.dll" "gstreamer-plugins\libgstogg.dll"
File "/oname=libgstopenmpt.dll" "gstreamer-plugins\libgstopenmpt.dll"
File "/oname=libgstopus.dll" "gstreamer-plugins\libgstopus.dll"
@@ -386,14 +577,77 @@ 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"
File "/oname=gstasf.dll" "gstreamer-plugins\gstasf.dll"
File "/oname=gstasfmux.dll" "gstreamer-plugins\gstasfmux.dll"
File "/oname=gstaudioconvert.dll" "gstreamer-plugins\gstaudioconvert.dll"
File "/oname=gstaudiofx.dll" "gstreamer-plugins\gstaudiofx.dll"
File "/oname=gstaudiomixer.dll" "gstreamer-plugins\gstaudiomixer.dll"
File "/oname=gstaudioparsers.dll" "gstreamer-plugins\gstaudioparsers.dll"
File "/oname=gstaudiorate.dll" "gstreamer-plugins\gstaudiorate.dll"
File "/oname=gstaudioresample.dll" "gstreamer-plugins\gstaudioresample.dll"
File "/oname=gstaudiotestsrc.dll" "gstreamer-plugins\gstaudiotestsrc.dll"
File "/oname=gstautodetect.dll" "gstreamer-plugins\gstautodetect.dll"
File "/oname=gstbs2b.dll" "gstreamer-plugins\gstbs2b.dll"
File "/oname=gstcoreelements.dll" "gstreamer-plugins\gstcoreelements.dll"
File "/oname=gstdash.dll" "gstreamer-plugins\gstdash.dll"
File "/oname=gstdirectsound.dll" "gstreamer-plugins\gstdirectsound.dll"
File "/oname=gstequalizer.dll" "gstreamer-plugins\gstequalizer.dll"
File "/oname=gstfaac.dll" "gstreamer-plugins\gstfaac.dll"
File "/oname=gstfaad.dll" "gstreamer-plugins\gstfaad.dll"
File "/oname=gstfdkaac.dll" "gstreamer-plugins\gstfdkaac.dll"
File "/oname=gstflac.dll" "gstreamer-plugins\gstflac.dll"
File "/oname=gstgio.dll" "gstreamer-plugins\gstgio.dll"
File "/oname=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=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=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"
!endif ; MSVC
SectionEnd
@@ -439,6 +693,10 @@ Section "Uninstall"
Delete "$INSTDIR\gst-launch-1.0.exe"
Delete "$INSTDIR\gst-discoverer-1.0.exe"
; MinGW specific files
!ifdef mingw
!ifdef arch_x86
Delete "$INSTDIR\libgcc_s_sjlj-1.dll"
Delete "$INSTDIR\libcrypto-3.dll"
@@ -451,28 +709,31 @@ Section "Uninstall"
Delete "$INSTDIR\libssl-3-x64.dll"
!endif
Delete "$INSTDIR\avcodec-58.dll"
Delete "$INSTDIR\avfilter-7.dll"
Delete "$INSTDIR\avformat-58.dll"
Delete "$INSTDIR\avutil-56.dll"
Delete "$INSTDIR\avcodec-59.dll"
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\libffi-8.dll"
Delete "$INSTDIR\libfftw3-3.dll"
Delete "$INSTDIR\libFLAC-8.dll"
Delete "$INSTDIR\libfreetype-6.dll"
Delete "$INSTDIR\libfaac-0.dll"
Delete "$INSTDIR\libfaad-2.dll"
Delete "$INSTDIR\libfdk-aac-2.dll"
Delete "$INSTDIR\libffi-8.dll"
Delete "$INSTDIR\libfreetype-6.dll"
Delete "$INSTDIR\libgcrypt-20.dll"
Delete "$INSTDIR\libgio-2.0-0.dll"
Delete "$INSTDIR\libglib-2.0-0.dll"
Delete "$INSTDIR\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"
@@ -498,24 +759,26 @@ Section "Uninstall"
Delete "$INSTDIR\libjpeg-9.dll"
Delete "$INSTDIR\liblzma-5.dll"
Delete "$INSTDIR\libmp3lame-0.dll"
Delete "$INSTDIR\libmpcdec.dll"
Delete "$INSTDIR\libmpg123-0.dll"
Delete "$INSTDIR\libnettle-8.dll"
Delete "$INSTDIR\libnghttp2.dll"
Delete "$INSTDIR\libogg-0.dll"
Delete "$INSTDIR\libopenmpt-0.dll"
Delete "$INSTDIR\libopus-0.dll"
Delete "$INSTDIR\liborc-0.4-0.dll"
Delete "$INSTDIR\libpcre-1.dll"
Delete "$INSTDIR\libpcre2-16-0.dll"
Delete "$INSTDIR\libpng16-16.dll"
Delete "$INSTDIR\libprotobuf-32.dll"
Delete "$INSTDIR\libpsl-5.dll"
Delete "$INSTDIR\libprotobuf-30.dll"
Delete "$INSTDIR\libqtsparkle-qt6.dll"
Delete "$INSTDIR\libsoup-3.0-0.dll"
Delete "$INSTDIR\libspeex-1.dll"
Delete "$INSTDIR\libsqlite3-0.dll"
Delete "$INSTDIR\libssp-0.dll"
Delete "$INSTDIR\libstdc++-6.dll"
Delete "$INSTDIR\libsoup-2.4-1.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"
@@ -524,15 +787,9 @@ Section "Uninstall"
Delete "$INSTDIR\libwinpthread-1.dll"
Delete "$INSTDIR\libxml2-2.dll"
Delete "$INSTDIR\libzstd.dll"
Delete "$INSTDIR\postproc-55.dll"
Delete "$INSTDIR\Qt6Concurrent.dll"
Delete "$INSTDIR\Qt6Core.dll"
Delete "$INSTDIR\Qt6Gui.dll"
Delete "$INSTDIR\Qt6Network.dll"
Delete "$INSTDIR\Qt6Sql.dll"
Delete "$INSTDIR\Qt6Widgets.dll"
Delete "$INSTDIR\swresample-3.dll"
Delete "$INSTDIR\swscale-5.dll"
Delete "$INSTDIR\postproc-56.dll"
Delete "$INSTDIR\swresample-4.dll"
Delete "$INSTDIR\swscale-6.dll"
Delete "$INSTDIR\zlib1.dll"
!ifdef debug
@@ -540,69 +797,281 @@ Section "Uninstall"
Delete "$INSTDIR\libexpat-1.dll"
Delete "$INSTDIR\libmman.dll"
Delete "$INSTDIR\libmpfr-6.dll"
Delete "$INSTDIR\libpcre2-8d.dll"
Delete "$INSTDIR\libpcre2-16d.dll"
Delete "$INSTDIR\libreadline8.dll"
Delete "$INSTDIR\libtermcap.dll"
!else
Delete "$INSTDIR\libpcre2-8.dll"
Delete "$INSTDIR\libpcre2-16.dll"
!endif
!endif ; MinGW
; MSVC specific files
!ifdef msvc
!ifdef arch_x86
Delete "$INSTDIR\libcrypto-3.dll"
Delete "$INSTDIR\libssl-3.dll"
!endif
!ifdef arch_x64
Delete "$INSTDIR\libcrypto-3-x64.dll"
Delete "$INSTDIR\libssl-3-x64.dll"
!endif
Delete "$INSTDIR\FLAC.dll"
Delete "$INSTDIR\avcodec-58.dll"
Delete "$INSTDIR\avfilter-7.dll"
Delete "$INSTDIR\avformat-58.dll"
Delete "$INSTDIR\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\gio-2.0-0.dll"
Delete "$INSTDIR\glib-2.0-0.dll"
Delete "$INSTDIR\gmodule-2.0-0.dll"
Delete "$INSTDIR\gnutls.dll"
Delete "$INSTDIR\gobject-2.0-0.dll"
Delete "$INSTDIR\gstadaptivedemux-1.0-0.dll"
Delete "$INSTDIR\gstapp-1.0-0.dll"
Delete "$INSTDIR\gstaudio-1.0-0.dll"
Delete "$INSTDIR\gstbadaudio-1.0-0.dll"
Delete "$INSTDIR\gstbase-1.0-0.dll"
Delete "$INSTDIR\gstfft-1.0-0.dll"
Delete "$INSTDIR\gstisoff-1.0-0.dll"
Delete "$INSTDIR\gstnet-1.0-0.dll"
Delete "$INSTDIR\gstpbutils-1.0-0.dll"
Delete "$INSTDIR\gstreamer-1.0-0.dll"
Delete "$INSTDIR\gstriff-1.0-0.dll"
Delete "$INSTDIR\gstrtp-1.0-0.dll"
Delete "$INSTDIR\gstrtsp-1.0-0.dll"
Delete "$INSTDIR\gstsdp-1.0-0.dll"
Delete "$INSTDIR\gsttag-1.0-0.dll"
Delete "$INSTDIR\gsturidownloader-1.0-0.dll"
Delete "$INSTDIR\gstvideo-1.0-0.dll"
Delete "$INSTDIR\intl-8.dll"
Delete "$INSTDIR\libbs2b.dll"
Delete "$INSTDIR\libfaac_dll.dll"
Delete "$INSTDIR\libiconv.dll"
Delete "$INSTDIR\liblzma.dll"
Delete "$INSTDIR\libmp3lame.dll"
Delete "$INSTDIR\libopenmpt.dll"
Delete "$INSTDIR\libspeex.dll"
Delete "$INSTDIR\mpcdec.dll"
Delete "$INSTDIR\mpg123.dll"
Delete "$INSTDIR\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\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\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\libpng16d.dll"
Delete "$INSTDIR\libprotobufd.dll"
Delete "$INSTDIR\libxml2d.dll"
Delete "$INSTDIR\pcre2-8d.dll"
Delete "$INSTDIR\pcre2-16d.dll"
Delete "$INSTDIR\twolamed.dll"
Delete "$INSTDIR\zlibd.dll"
!endif
!endif ; MSVC
; Common files
Delete "$INSTDIR\libfftw3-3.dll"
!ifdef msvc && debug
Delete "$INSTDIR\Qt6Concurrentd.dll"
Delete "$INSTDIR\Qt6Cored.dll"
Delete "$INSTDIR\Qt6Guid.dll"
Delete "$INSTDIR\Qt6Networkd.dll"
Delete "$INSTDIR\Qt6Sqld.dll"
Delete "$INSTDIR\Qt6Widgetsd.dll"
!else
Delete "$INSTDIR\Qt6Concurrent.dll"
Delete "$INSTDIR\Qt6Core.dll"
Delete "$INSTDIR\Qt6Gui.dll"
Delete "$INSTDIR\Qt6Network.dll"
Delete "$INSTDIR\Qt6Sql.dll"
Delete "$INSTDIR\Qt6Widgets.dll"
!endif
!ifdef mingw
Delete "$INSTDIR\gio-modules\libgiognutls.dll"
Delete "$INSTDIR\gio-modules\libgioopenssl.dll"
!endif
!ifdef msvc
Delete "$INSTDIR\gio-modules\giognutls.dll"
Delete "$INSTDIR\gio-modules\gioopenssl.dll"
!endif
!ifdef msvc && debug
Delete "$INSTDIR\platforms\qwindowsd.dll"
Delete "$INSTDIR\styles\qwindowsvistastyled.dll"
Delete "$INSTDIR\tls\qschannelbackendd.dll"
Delete "$INSTDIR\tls\qopensslbackendd.dll"
Delete "$INSTDIR\sqldrivers\qsqlited.dll"
Delete "$INSTDIR\imageformats\qgifd.dll"
Delete "$INSTDIR\imageformats\qicod.dll"
Delete "$INSTDIR\imageformats\qjpegd.dll"
!else
Delete "$INSTDIR\platforms\qwindows.dll"
Delete "$INSTDIR\styles\qwindowsvistastyle.dll"
Delete "$INSTDIR\tls\qschannelbackend.dll"
Delete "$INSTDIR\tls\qopensslbackend.dll"
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
Delete "$INSTDIR\imageformats\qgif.dll"
Delete "$INSTDIR\imageformats\qico.dll"
Delete "$INSTDIR\imageformats\qjpeg.dll"
!endif
Delete $INSTDIR\gstreamer-plugins\libgstaiff.dll"
Delete $INSTDIR\gstreamer-plugins\libgstapetag.dll"
Delete $INSTDIR\gstreamer-plugins\libgstapp.dll"
Delete $INSTDIR\gstreamer-plugins\libgstasf.dll"
Delete $INSTDIR\gstreamer-plugins\libgstasfmux.dll"
Delete $INSTDIR\gstreamer-plugins\libgstaudioconvert.dll"
Delete $INSTDIR\gstreamer-plugins\libgstaudiofx.dll"
Delete $INSTDIR\gstreamer-plugins\libgstaudiomixer.dll"
Delete $INSTDIR\gstreamer-plugins\libgstaudioparsers.dll"
Delete $INSTDIR\gstreamer-plugins\libgstaudiorate.dll"
Delete $INSTDIR\gstreamer-plugins\libgstaudioresample.dll"
Delete $INSTDIR\gstreamer-plugins\libgstaudiotestsrc.dll"
Delete $INSTDIR\gstreamer-plugins\libgstautodetect.dll"
Delete $INSTDIR\gstreamer-plugins\libgstcdio.dll"
Delete $INSTDIR\gstreamer-plugins\libgstcoreelements.dll"
Delete $INSTDIR\gstreamer-plugins\libgstdash.dll"
Delete $INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
Delete $INSTDIR\gstreamer-plugins\libgstequalizer.dll"
Delete $INSTDIR\gstreamer-plugins\libgstflac.dll"
Delete $INSTDIR\gstreamer-plugins\libgstfaac.dll"
Delete $INSTDIR\gstreamer-plugins\libgstfaad.dll"
Delete $INSTDIR\gstreamer-plugins\libgstgio.dll"
Delete $INSTDIR\gstreamer-plugins\libgsticydemux.dll"
Delete $INSTDIR\gstreamer-plugins\libgstid3demux.dll"
Delete $INSTDIR\gstreamer-plugins\libgstisomp4.dll"
Delete $INSTDIR\gstreamer-plugins\libgstlame.dll"
Delete $INSTDIR\gstreamer-plugins\libgstlibav.dll"
Delete $INSTDIR\gstreamer-plugins\libgstogg.dll"
Delete $INSTDIR\gstreamer-plugins\libgstopenmpt.dll"
Delete $INSTDIR\gstreamer-plugins\libgstopus.dll"
Delete $INSTDIR\gstreamer-plugins\libgstopusparse.dll"
Delete $INSTDIR\gstreamer-plugins\libgstpbtypes.dll"
Delete $INSTDIR\gstreamer-plugins\libgstplayback.dll"
Delete $INSTDIR\gstreamer-plugins\libgstreplaygain.dll"
Delete $INSTDIR\gstreamer-plugins\libgstrtp.dll"
Delete $INSTDIR\gstreamer-plugins\libgstrtsp.dll"
Delete $INSTDIR\gstreamer-plugins\libgstsoup.dll"
Delete $INSTDIR\gstreamer-plugins\libgstspectrum.dll"
Delete $INSTDIR\gstreamer-plugins\libgstspeex.dll"
Delete $INSTDIR\gstreamer-plugins\libgsttaglib.dll"
Delete $INSTDIR\gstreamer-plugins\libgsttcp.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\libgstwavpack.dll"
Delete $INSTDIR\gstreamer-plugins\libgstwavparse.dll"
Delete $INSTDIR\gstreamer-plugins\libgstxingmux.dll"
; MinGW GStreamer plugins
!ifdef mingw
Delete "$INSTDIR\gstreamer-plugins\libgstaes.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaiff.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstapetag.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstapp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstasf.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstasfmux.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudioconvert.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudiofx.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudiomixer.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudioparsers.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudiorate.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudioresample.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudiotestsrc.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstautodetect.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstbs2b.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstcoreelements.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstdash.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstequalizer.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstfaac.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstfaad.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstfdkaac.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstflac.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstgio.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsthls.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsticydemux.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstid3demux.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstid3tag.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstisomp4.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstlame.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstlibav.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstmpg123.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstmusepack.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstogg.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstopenmpt.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstopus.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstopusparse.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstpbtypes.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstplayback.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstreplaygain.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstrtp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstrtsp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstsoup.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstspectrum.dll"
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"
!endif ; mingw
; 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"
Delete "$INSTDIR\gstreamer-plugins\gstasf.dll"
Delete "$INSTDIR\gstreamer-plugins\gstasfmux.dll"
Delete "$INSTDIR\gstreamer-plugins\gstaudioconvert.dll"
Delete "$INSTDIR\gstreamer-plugins\gstaudiofx.dll"
Delete "$INSTDIR\gstreamer-plugins\gstaudiomixer.dll"
Delete "$INSTDIR\gstreamer-plugins\gstaudioparsers.dll"
Delete "$INSTDIR\gstreamer-plugins\gstaudiorate.dll"
Delete "$INSTDIR\gstreamer-plugins\gstaudioresample.dll"
Delete "$INSTDIR\gstreamer-plugins\gstaudiotestsrc.dll"
Delete "$INSTDIR\gstreamer-plugins\gstautodetect.dll"
Delete "$INSTDIR\gstreamer-plugins\gstbs2b.dll"
Delete "$INSTDIR\gstreamer-plugins\gstcoreelements.dll"
Delete "$INSTDIR\gstreamer-plugins\gstdash.dll"
Delete "$INSTDIR\gstreamer-plugins\gstdirectsound.dll"
Delete "$INSTDIR\gstreamer-plugins\gstequalizer.dll"
Delete "$INSTDIR\gstreamer-plugins\gstfaac.dll"
Delete "$INSTDIR\gstreamer-plugins\gstfaad.dll"
Delete "$INSTDIR\gstreamer-plugins\gstfdkaac.dll"
Delete "$INSTDIR\gstreamer-plugins\gstflac.dll"
Delete "$INSTDIR\gstreamer-plugins\gstgio.dll"
Delete "$INSTDIR\gstreamer-plugins\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\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\gstwavenc.dll"
Delete "$INSTDIR\gstreamer-plugins\gstwavpack.dll"
Delete "$INSTDIR\gstreamer-plugins\gstwavparse.dll"
Delete "$INSTDIR\gstreamer-plugins\gstxingmux.dll"
!endif ; msvc
Delete $INSTDIR\Uninstall.exe"

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

@@ -61,7 +61,7 @@ static const char *kMessageHandlerMagic = "__logging_message__";
static const size_t kMessageHandlerMagicLength = strlen(kMessageHandlerMagic);
static QtMessageHandler sOriginalMessageHandler = nullptr;
template <class T>
template<class T>
static T CreateLogger(Level level, const QString &class_name, int line, const char *category);
void GLog(const char *domain, int level, const char *message, void*) {
@@ -88,7 +88,7 @@ void GLog(const char *domain, int level, const char *message, void*) {
}
template <class T>
template<class T>
class DebugBase : public QDebug {
public:
DebugBase() : QDebug(sNullDevice) {}
@@ -314,11 +314,11 @@ QString LinuxDemangle(const QString &symbol) {
QString DarwinDemangle(const QString &symbol);
QString DarwinDemangle(const QString &symbol) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
# if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QStringList split = symbol.split(' ', Qt::SkipEmptyParts);
#else
# else
QStringList split = symbol.split(' ', QString::SkipEmptyParts);
#endif
# endif
QString mangled_function = split[3];
return CXXDemangle(mangled_function);
@@ -379,7 +379,7 @@ QDebug CreateLoggerError(int line, const char *pretty_function, const char *cate
namespace {
template <typename T>
template<typename T>
QString print_duration(T duration, const std::string &unit) {
return QString("%1%2").arg(duration.count()).arg(unit.c_str());
}

View File

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

View File

@@ -79,7 +79,7 @@ class _MessageHandlerBase : public QObject {
// Reads and writes uint32 length encoded MessageType messages to a socket.
// You should subclass this and implement the MessageArrived(MessageType) method.
template <typename MT>
template<typename MT>
class AbstractMessageHandler : public _MessageHandlerBase {
public:
AbstractMessageHandler(QIODevice *device, QObject *parent);
@@ -115,11 +115,11 @@ class AbstractMessageHandler : public _MessageHandlerBase {
QMap<int, ReplyType*> pending_replies_;
};
template <typename MT>
template<typename MT>
AbstractMessageHandler<MT>::AbstractMessageHandler(QIODevice *device, QObject *parent)
: _MessageHandlerBase(device, parent) {}
template <typename MT>
template<typename MT>
void AbstractMessageHandler<MT>::SendMessage(const MessageType &message) {
Q_ASSERT(QThread::currentThread() == thread());
@@ -127,7 +127,7 @@ void AbstractMessageHandler<MT>::SendMessage(const MessageType &message) {
WriteMessage(QByteArray(data.data(), data.size()));
}
template <typename MT>
template<typename MT>
void AbstractMessageHandler<MT>::SendMessageAsync(const MessageType &message) {
std::string data = message.SerializeAsString();
QMetaObject::invokeMethod(this, "WriteMessage", Qt::QueuedConnection, Q_ARG(QByteArray, QByteArray(data.data(), data.size())));

View File

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

View File

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

View File

@@ -25,3 +25,27 @@ const std::string TagReaderBase::kEmbeddedCover = "(embedded)";
TagReaderBase::TagReaderBase() = default;
TagReaderBase::~TagReaderBase() = default;
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

@@ -47,6 +47,9 @@ 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 float ConvertPOPMRating(const int POPM_rating);
static int ConvertToPOPMRating(const float rating);
protected:
static const std::string kEmbeddedCover;

View File

@@ -22,6 +22,7 @@
#include <string>
#include <memory>
#include <algorithm>
#include <sys/stat.h>
#include <taglib/taglib.h>
@@ -113,6 +114,7 @@ class TagLibFileRefFactory : public FileRefFactory {
return new TagLib::FileRef(QFile::encodeName(filename).constData());
#endif
}
private:
Q_DISABLE_COPY(TagLibFileRefFactory)
};
@@ -130,11 +132,11 @@ TagLib::String QStringToTaglibString(const QString &s) {
} // namespace
namespace {
const char *kMP4_OriginalYear_ID = "----:com.apple.iTunes:ORIGINAL YEAR";
const char *kMP4_OriginalYear_ID = "----:com.apple.iTunes:ORIGINAL YEAR";
const char *kMP4_FMPS_Playcount_ID = "----:com.apple.iTunes:FMPS_Playcount";
const char *kMP4_FMPS_Rating_ID = "----:com.apple.iTunes:FMPS_Rating";
const char *kASF_OriginalDate_ID = "WM/OriginalReleaseTime";
const char *kASF_OriginalYear_ID = "WM/OriginalReleaseYear";
const char *kMP4_FMPS_Rating_ID = "----:com.apple.iTunes:FMPS_Rating";
const char *kASF_OriginalDate_ID = "WM/OriginalReleaseTime";
const char *kASF_OriginalYear_ID = "WM/OriginalReleaseYear";
} // namespace
@@ -194,12 +196,17 @@ 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));
@@ -265,7 +272,7 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
if (tag) Decode(tag->comment(), song->mutable_comment());
}
else if (TagLib::WavPack::File *file_wavpack = dynamic_cast<TagLib::WavPack::File *>(fileref->file())) {
else if (TagLib::WavPack::File *file_wavpack = dynamic_cast<TagLib::WavPack::File*>(fileref->file())) {
song->set_bitdepth(file_wavpack->audioProperties()->bitsPerSample());
if (file_wavpack->APETag()) {
ParseAPETag(file_wavpack->APETag()->itemListMap(), &disc, &compilation, song);
@@ -306,7 +313,9 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
if (!map["TCMP"].isEmpty()) compilation = TStringToQString(map["TCMP"].front()->toString()).trimmed();
if (!map["TDOR"].isEmpty()) { song->set_originalyear(map["TDOR"].front()->toString().substr(0, 4).toInt()); }
if (!map["TDOR"].isEmpty()) {
song->set_originalyear(map["TDOR"].front()->toString().substr(0, 4).toInt());
}
else if (!map["TORY"].isEmpty()) {
song->set_originalyear(map["TORY"].front()->toString().substr(0, 4).toInt());
}
@@ -321,7 +330,7 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
if (!map["APIC"].isEmpty()) song->set_art_automatic(kEmbeddedCover);
// Find a suitable comment tag. For now we ignore iTunNORM comments.
for (uint i = 0 ; i < map["COMM"].size() ; ++i) {
for (uint i = 0; i < map["COMM"].size(); ++i) {
const TagLib::ID3v2::CommentsFrame *frame = dynamic_cast<const TagLib::ID3v2::CommentsFrame*>(map["COMM"][i]);
if (frame && TStringToQString(frame->description()) != "iTunNORM") {
@@ -450,7 +459,7 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
}
if (attributes_map.contains("FMPS/Rating")) {
const TagLib::ASF::AttributeList& attributes = attributes_map["FMPS/Rating"];
const TagLib::ASF::AttributeList &attributes = attributes_map["FMPS/Rating"];
if (!attributes.isEmpty()) {
float rating = TStringToQString(attributes.front().toString()).toFloat();
if (song->rating() <= 0 && rating > 0) {
@@ -679,7 +688,7 @@ bool TagReaderTagLib::SaveFile(const QString &filename, const spb::tagreader::So
else if (TagLib::MP4::File *file_mp4 = dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
TagLib::MP4::Tag *tag = file_mp4->tag();
if (!tag) return false;
tag->setItem("disk", TagLib::MP4::Item(song.disc() <= 0 -1 ? 0 : song.disc(), 0));
tag->setItem("disk", TagLib::MP4::Item(song.disc() <= 0 - 1 ? 0 : song.disc(), 0));
tag->setItem("\251wrt", TagLib::StringList(TagLib::String(song.composer(), TagLib::String::UTF8)));
tag->setItem("\251grp", TagLib::StringList(TagLib::String(song.grouping(), TagLib::String::UTF8)));
tag->setItem("\251lyr", TagLib::StringList(TagLib::String(song.lyrics(), TagLib::String::UTF8)));
@@ -743,7 +752,7 @@ void TagReaderTagLib::SetTextFrame(const char *id, const std::string &value, Tag
}
// Update and add the frames
for (int i = 0 ; i < frames_buffer.size() ; ++i) {
for (int i = 0; i < frames_buffer.size(); ++i) {
TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame(frames_buffer.at(i));
if (i == 0) {
frame->setText(StdStringToTaglibString(value));
@@ -799,7 +808,7 @@ void TagReaderTagLib::SetUnsyncLyricsFrame(const std::string &value, TagLib::ID3
}
// Update and add the frames
for (int i = 0 ; i < frames_buffer.size() ; ++i) {
for (int i = 0; i < frames_buffer.size(); ++i) {
TagLib::ID3v2::UnsynchronizedLyricsFrame *frame = new TagLib::ID3v2::UnsynchronizedLyricsFrame(frames_buffer.at(i));
if (i == 0) {
frame->setText(StdStringToTaglibString(value));
@@ -983,7 +992,7 @@ bool TagReaderTagLib::SaveEmbeddedArt(const QString &filename, const QByteArray
// Remove existing covers
TagLib::ID3v2::FrameList apiclist = tag->frameListMap()["APIC"];
for (TagLib::ID3v2::FrameList::ConstIterator it = apiclist.begin() ; it != apiclist.end() ; ++it ) {
for (TagLib::ID3v2::FrameList::ConstIterator it = apiclist.begin(); it != apiclist.end(); ++it) {
TagLib::ID3v2::AttachedPictureFrame *frame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(*it);
tag->removeFrame(frame, false);
}
@@ -994,7 +1003,7 @@ bool TagReaderTagLib::SaveEmbeddedArt(const QString &filename, const QByteArray
frontcover = new TagLib::ID3v2::AttachedPictureFrame("APIC");
frontcover->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
frontcover->setMimeType("image/jpeg");
frontcover->setPicture(TagLib::ByteVector(data.constData(), data.count()));
frontcover->setPicture(TagLib::ByteVector(data.constData(), data.size()));
tag->addFrame(frontcover);
}
}
@@ -1008,7 +1017,7 @@ bool TagReaderTagLib::SaveEmbeddedArt(const QString &filename, const QByteArray
if (tag->contains("covr")) tag->removeItem("covr");
}
else {
covers.append(TagLib::MP4::CoverArt(TagLib::MP4::CoverArt::JPEG, TagLib::ByteVector(data.constData(), data.count())));
covers.append(TagLib::MP4::CoverArt(TagLib::MP4::CoverArt::JPEG, TagLib::ByteVector(data.constData(), data.size())));
tag->setItem("covr", covers);
}
}
@@ -1038,30 +1047,6 @@ TagLib::ID3v2::PopularimeterFrame *TagReaderTagLib::GetPOPMFrameFromTag(TagLib::
}
float TagReaderTagLib::ConvertPOPMRating(const int POPM_rating) {
if (POPM_rating < 0x01) return 0.0;
else if (POPM_rating < 0x40) return 0.20;
else if (POPM_rating < 0x80) return 0.40;
else if (POPM_rating < 0xC0) return 0.60;
else if (POPM_rating < 0xFC) return 0.80;
return 1.0;
}
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

@@ -75,13 +75,11 @@ class TagReaderTagLib : public TagReaderBase {
void SetTextFrame(const char *id, const std::string &value, TagLib::ID3v2::Tag *tag) const;
void SetUserTextFrame(const QString &description, const QString &value, TagLib::ID3v2::Tag *tag) const;
void SetUserTextFrame(const std::string &description, const std::string &value, TagLib::ID3v2::Tag *tag) const;
void SetUnsyncLyricsFrame(const std::string& value, TagLib::ID3v2::Tag* tag) const;
void SetUnsyncLyricsFrame(const std::string &value, TagLib::ID3v2::Tag *tag) const;
QByteArray LoadEmbeddedAPEArt(const TagLib::APE::ItemListMap &map) const;
static float ConvertPOPMRating(const int POPM_rating);
static int ConvertToPOPMRating(const float rating);
static TagLib::ID3v2::PopularimeterFrame *GetPOPMFrameFromTag(TagLib::ID3v2::Tag* tag);
static TagLib::ID3v2::PopularimeterFrame *GetPOPMFrameFromTag(TagLib::ID3v2::Tag *tag);
private:
FileRefFactory *factory_;

View File

@@ -106,12 +106,17 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
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 {
@@ -151,7 +156,7 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
const auto tracks = taginfo.tracks();
for (const auto track : tracks) {
switch(track->format().general) {
switch (track->format().general) {
case TagParser::GeneralMediaFormat::Flac:
song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_FLAC);
break;
@@ -174,7 +179,7 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_OGGSPEEX);
break;
case TagParser::GeneralMediaFormat::Mpeg1Audio:
switch(track->format().sub) {
switch (track->format().sub) {
case TagParser::SubFormats::Mpeg1Layer3:
song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_MPEG);
break;
@@ -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
@@ -464,7 +473,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

@@ -99,7 +99,7 @@ int main(int argc, char **argv) {
QRegularExpressionMatch match = regexp.match(output_line);
if (match.hasMatch()) {
QString library = match.captured(1);
if (QFileInfo(library).fileName() == QFileInfo(filepath).fileName()) { // It's this.
if (QFileInfo(library).fileName() == QFileInfo(filepath).fileName()) { // It's this.
continue;
}
else if (library.startsWith("@executable_path")) {
@@ -113,7 +113,7 @@ int main(int argc, char **argv) {
else if (library.startsWith("@rpath")) {
QString real_path = library;
real_path = real_path.replace("@rpath", bundle_path + "/Contents/Frameworks");
if (!QFile(real_path).exists() && !real_path.endsWith("QtSvg")) { // FIXME: Ignore broken svg image plugin.
if (!QFile(real_path).exists() && !real_path.endsWith("QtSvg")) { // FIXME: Ignore broken svg image plugin.
qLog(Error) << real_path << "does not exist for" << filepath;
success = false;
}
@@ -127,7 +127,7 @@ int main(int argc, char **argv) {
success = false;
}
}
else if (library.startsWith("/System/Library/") || library.startsWith("/usr/lib/")) { // System library
else if (library.startsWith("/System/Library/") || library.startsWith("/usr/lib/")) { // System library
continue;
}
else if (library.endsWith("libgcc_s.1.dylib")) { // fftw points to it for some reason.

View File

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

View File

@@ -28,7 +28,7 @@
#include "tagreaderworker.h"
TagReaderWorker::TagReaderWorker(QIODevice *socket, QObject *parent)
: AbstractMessageHandler<spb::tagreader::Message>(socket, parent) {}
: AbstractMessageHandler<spb::tagreader::Message>(socket, parent) {}
void TagReaderWorker::MessageArrived(const spb::tagreader::Message &message) {

View File

@@ -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,7 +944,6 @@ link_directories(
${SQLITE_LIBRARY_DIRS}
${SINGLEAPPLICATION_LIBRARY_DIRS}
${SINGLECOREAPPLICATION_LIBRARY_DIRS}
${QTSPARKLE_LIBRARY_DIRS}
${Iconv_LIBRARY_DIRS}
)
@@ -986,6 +986,10 @@ if(HAVE_GIO)
link_directories(${GIO_LIBRARY_DIRS})
endif()
if(HAVE_GIO_UNIX)
link_directories(${GIO_UNIX_LIBRARY_DIRS})
endif()
if(HAVE_AUDIOCD)
link_directories(${LIBCDIO_LIBRARY_DIRS})
endif()
@@ -1006,6 +1010,10 @@ if(USE_TAGPARSER AND TAGPARSER_FOUND)
link_directories(${TAGPARSER_LIBRARY_DIRS})
endif()
if(HAVE_QTSPARKLE)
link_directories(${QTSPARKLE_LIBRARY_DIRS})
endif()
add_library(strawberry_lib STATIC
${SOURCES}
${MOC}
@@ -1022,6 +1030,7 @@ target_include_directories(strawberry_lib SYSTEM PUBLIC
${GOBJECT_INCLUDE_DIRS}
${GNUTLS_INCLUDE_DIRS}
${SQLITE_INCLUDE_DIRS}
${PROTOBUF_INCLUDE_DIRS}
)
if(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H)
@@ -1049,7 +1058,6 @@ target_link_libraries(strawberry_lib PUBLIC
${QT_LIBRARIES}
${SINGLEAPPLICATION_LIBRARIES}
${SINGLECOREAPPLICATION_LIBRARIES}
${QTSPARKLE_LIBRARIES}
${Iconv_LIBRARIES}
libstrawberry-common
libstrawberry-tagreader
@@ -1113,6 +1121,11 @@ if(HAVE_GIO)
target_link_libraries(strawberry_lib PRIVATE ${GIO_LIBRARIES})
endif()
if(HAVE_GIO_UNIX)
target_include_directories(strawberry_lib SYSTEM PRIVATE ${GIO_UNIX_INCLUDE_DIRS})
target_link_libraries(strawberry_lib PRIVATE ${GIO_UNIX_LIBRARIES})
endif()
if(HAVE_AUDIOCD)
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBCDIO_INCLUDE_DIRS})
target_link_libraries(strawberry_lib PRIVATE ${LIBCDIO_LIBRARIES})
@@ -1143,19 +1156,25 @@ if(APPLE)
"-framework ScriptingBridge"
)
target_link_libraries(strawberry_lib PRIVATE ${SPMEDIAKEYTAP_LIBRARIES})
if(HAVE_SPARKLE)
target_include_directories(strawberry_lib SYSTEM PRIVATE ${SPARKLE}/Headers)
target_link_libraries(strawberry_lib PRIVATE ${SPARKLE})
endif()
endif()
if(WIN32)
target_link_libraries(strawberry_lib PRIVATE dsound dwmapi)
if(MSVC)
target_link_libraries(strawberry_lib PRIVATE sqlite3)
if (GETOPT_INCLUDE_DIRS)
target_include_directories(strawberry_lib SYSTEM PRIVATE ${GETOPT_INCLUDE_DIRS})
endif()
if(GETOPT_LIBRARIES)
target_link_libraries(strawberry_lib PRIVATE ${GETOPT_LIBRARIES})
endif()
endif()
endif()
if(HAVE_QTSPARKLE)
target_include_directories(strawberry_lib SYSTEM PRIVATE ${QTSPARKLE_INCLUDE_DIRS})
target_link_libraries(strawberry_lib PRIVATE ${QTSPARKLE_LIBRARIES})
endif()
###############################################################################

View File

@@ -32,10 +32,11 @@
#include <QVector>
#include <QPainter>
#include <QPalette>
#include <QBasicTimer>
#include <QShowEvent>
#include <QHideEvent>
#include <QTimerEvent>
#include <QtEvents>
#include "core/logging.h"
#include "engine/enginebase.h"
// INSTRUCTIONS Base2D
@@ -47,27 +48,38 @@
//
// TODO:
// Make an INSTRUCTIONS file
// can't mod scope in analyze you have to use transform
// for 2D use setErasePixmap Qt function insetead of m_background
// make the linker happy only for gcc < 4.0
#if !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 0)) && \
!defined(Q_OS_WIN32)
template class Analyzer::Base<QWidget>;
#endif
// can't mod scope in analyze you have to use transform for 2D use setErasePixmap Qt function insetead of m_background
Analyzer::Base::Base(QWidget *parent, const uint scopeSize)
: QWidget(parent),
timeout_(40),
fht_(new FHT(scopeSize)),
engine_(nullptr),
lastscope_(512),
new_frame_(false),
is_playing_(false) {}
is_playing_(false),
timeout_(40) {}
void Analyzer::Base::hideEvent(QHideEvent*) { timer_.stop(); }
Analyzer::Base::~Base() {
delete fht_;
}
void Analyzer::Base::showEvent(QShowEvent*) { timer_.start(timeout(), this); }
void Analyzer::Base::showEvent(QShowEvent*) {
timer_.start(timeout(), this);
}
void Analyzer::Base::hideEvent(QHideEvent*) {
timer_.stop();
}
void Analyzer::Base::ChangeTimeout(const int timeout) {
timeout_ = timeout;
if (timer_.isActive()) {
timer_.stop();
timer_.start(timeout_, this);
}
}
void Analyzer::Base::transform(Scope &scope) {
@@ -80,7 +92,7 @@ void Analyzer::Base::transform(Scope &scope) {
}
fht_->logSpectrum(scope.data(), aux.data());
fht_->scale(scope.data(), 1.0 / 20);
fht_->scale(scope.data(), 1.0F / 20);
scope.resize(fht_->size() / 2); // second half of values are rubbish
@@ -161,7 +173,7 @@ int Analyzer::Base::resizeForBands(const int bands) {
}
else {
exp = 9;
}
}
resizeExponent(exp);
return fht_->size() / 2;
@@ -193,10 +205,6 @@ void Analyzer::Base::demo(QPainter &p) {
}
void Analyzer::Base::polishEvent() {
init();
}
void Analyzer::interpolate(const Scope &inVec, Scope &outVec) {
double pos = 0.0;

View File

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

View File

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

View File

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

View File

@@ -63,8 +63,7 @@ BlockAnalyzer::BlockAnalyzer(QWidget *parent)
setMaximumWidth(kMaxColumns * (kWidth + 1) - 1);
// mxcl says null pixmaps cause crashes, so let's play it safe
std::fill(fade_bars_.begin(), fade_bars_.end(), QPixmap(1, 1));
std::fill(fade_bars_.begin(), fade_bars_.end(), QPixmap(1, 1));
}
void BlockAnalyzer::resizeEvent(QResizeEvent *e) {
@@ -89,7 +88,7 @@ void BlockAnalyzer::resizeEvent(QResizeEvent *e) {
if (rows_ != oldRows) {
barpixmap_ = QPixmap(kWidth, rows_ * (kHeight + 1));
std::fill(fade_bars_.begin(), fade_bars_.end(), QPixmap(kWidth, rows_ * (kHeight + 1)));
std::fill(fade_bars_.begin(), fade_bars_.end(), QPixmap(kWidth, rows_ * (kHeight + 1)));
yscale_.resize(rows_ + 1);
@@ -130,7 +129,7 @@ void BlockAnalyzer::transform(Analyzer::Scope &s) {
for (uint x = 0; x < s.size(); ++x) s[x] *= 2;
fht_->spectrum(s.data());
fht_->scale(s.data(), 1.0 / 20);
fht_->scale(s.data(), 1.0F / 20);
// the second half is pretty dull, so only show it if the user has a large analyzer by setting to scope_.size() if large we prevent interpolation of large analyzers, this is good!
s.resize(scope_.size() <= kMaxColumns / 2 ? kMaxColumns / 2 : scope_.size());

View File

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

View File

@@ -102,7 +102,7 @@ void BoomAnalyzer::resizeEvent(QResizeEvent *e) {
void BoomAnalyzer::transform(Scope &s) {
fht_->spectrum(s.data());
fht_->scale(s.data(), 1.0 / 50);
fht_->scale(s.data(), 1.0F / 50);
s.resize(scope_.size() <= static_cast<quint64>(kMaxBandCount) / 2 ? kMaxBandCount / 2 : scope_.size());

View File

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

View File

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

View File

@@ -59,6 +59,8 @@ SCollection::SCollection(Application *app, QObject *parent)
watcher_(nullptr),
watcher_thread_(nullptr),
original_thread_(nullptr),
io_priority_(Utilities::IoPriority::IOPRIO_CLASS_IDLE),
thread_priority_(QThread::Priority::IdlePriority),
save_playcounts_to_files_(false),
save_ratings_to_files_(false) {
@@ -94,11 +96,18 @@ void SCollection::Init() {
watcher_ = new CollectionWatcher(Song::Source_Collection);
watcher_thread_ = new Thread(this);
watcher_thread_->SetIoPriority(Utilities::IOPRIO_CLASS_IDLE);
#ifndef Q_OS_WIN32
if (io_priority_ != Utilities::IoPriority::IOPRIO_CLASS_NONE) {
watcher_thread_->SetIoPriority(io_priority_);
}
#endif
watcher_->moveToThread(watcher_thread_);
watcher_thread_->start(QThread::IdlePriority);
qLog(Debug) << watcher_ << "moved to thread" << watcher_thread_;
qLog(Debug) << watcher_ << "moved to thread" << watcher_thread_ << "with I/O priority" << io_priority_ << "and thread priority" << thread_priority_;
watcher_thread_->start(thread_priority_);
watcher_->set_backend(backend_);
watcher_->set_task_manager(app_->task_manager());
@@ -176,6 +185,8 @@ void SCollection::ReloadSettings() {
QSettings s;
s.beginGroup(CollectionSettingsPage::kSettingsGroup);
io_priority_ = static_cast<Utilities::IoPriority>(s.value("io_priority", Utilities::IOPRIO_CLASS_IDLE).toInt());
thread_priority_ = static_cast<QThread::Priority>(s.value("thread_priority", QThread::Priority::IdlePriority).toInt());
save_playcounts_to_files_ = s.value("save_playcounts", false).toBool();
save_ratings_to_files_ = s.value("save_ratings", false).toBool();
s.endGroup();

View File

@@ -28,10 +28,10 @@
#include <QList>
#include <QHash>
#include <QString>
#include <QThread>
#include "core/song.h"
class QThread;
#include "core/utilities.h"
class Application;
class Thread;
@@ -99,6 +99,8 @@ class SCollection : public QObject {
QList<QObject*> wait_for_exit_;
Utilities::IoPriority io_priority_;
QThread::Priority thread_priority_;
bool save_playcounts_to_files_;
bool save_ratings_to_files_;
};

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"
@@ -335,8 +335,8 @@ void CollectionBackend::AddDirectory(const QString &path) {
q.prepare(QString("INSERT INTO %1 (path, subdirs) VALUES (:path, 1)").arg(dirs_table_));
q.BindValue(":path", db_path);
if (!q.Exec()) {
db_->ReportErrors(q);
return;
db_->ReportErrors(q);
return;
}
Directory dir;
@@ -634,15 +634,13 @@ void CollectionBackend::AddOrUpdateSongs(const SongList &songs) {
added_songs << new_song;
continue;
}
}
// Create new song
int id = -1;
{ // Insert the row and create a new ID
{ // Insert the row and create a new ID
SqlQuery q(db);
q.prepare(QString("INSERT INTO %1 (" + Song::kColumnSpec + ") VALUES (" + Song::kBindSpec + ")").arg(songs_table_));
song.BindToQuery(&q);
@@ -656,7 +654,7 @@ void CollectionBackend::AddOrUpdateSongs(const SongList &songs) {
if (id == -1) return;
{ // Add to the FTS index
{ // Add to the FTS index
SqlQuery q(db);
q.prepare(QString("INSERT INTO %1 (ROWID, " + Song::kFtsColumnSpec + ") VALUES (:id, " + Song::kFtsBindSpec + ")").arg(fts_table_));
q.BindValue(":id", id);
@@ -1345,7 +1343,7 @@ void CollectionBackend::CompilationsNeedUpdating() {
if (album.isEmpty()) continue;
// Find the directory the song is in
QString directory = url.toString(QUrl::PreferLocalFile|QUrl::RemoveFilename);
QString directory = url.toString(QUrl::PreferLocalFile | QUrl::RemoveFilename);
CompilationInfo &info = compilation_info[directory + album];
info.urls << url;
@@ -1481,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();
@@ -1801,6 +1799,12 @@ void CollectionBackend::ResetStatistics(const int id) {
}
void CollectionBackend::DeleteAllAsync() {
QMetaObject::invokeMethod(this, "DeleteAll", Qt::QueuedConnection);
}
void CollectionBackend::DeleteAll() {
{

View File

@@ -197,7 +197,7 @@ class CollectionBackend : public CollectionBackendInterface {
void IncrementSkipCountAsync(const int id, const float progress);
void ResetStatisticsAsync(const int id);
void DeleteAll();
void DeleteAllAsync();
Song GetSongBySongId(const QString &song_id);
SongList GetSongsBySongId(const QStringList &song_ids);
@@ -234,6 +234,7 @@ class CollectionBackend : public CollectionBackendInterface {
void IncrementPlayCount(const int id);
void IncrementSkipCount(const int id, const float progress);
void ResetStatistics(const int id);
void DeleteAll();
void SongPathChanged(const Song &song, const QFileInfo &new_file, const std::optional<int> new_collection_directory_id);
SongList GetSongsBy(const QString &artist, const QString &album, const QString &title);

View File

@@ -68,24 +68,23 @@ CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
QString available_fields = Song::kFtsColumns.join(", ").replace(QRegularExpression("\\bfts"), "");
ui_->search_field->setToolTip(
QString("<html><head/><body><p>") +
tr("Prefix a word with a field name to limit the search to that field, e.g.:") +
QString(" ") +
QString("<span style=\"font-weight:600;\">") +
tr("artist") +
QString(":") +
QString("</span><span style=\"font-style:italic;\">Strawbs</span>") +
QString(" ") +
tr("searches the collection for all artists that contain the word") +
QString(" Strawbs.") +
QString("</p><p><span style=\"font-weight:600;\">") +
tr("Available fields") +
QString(": ") +
"</span><span style=\"font-style:italic;\">" +
available_fields +
QString("</span>.") +
QString("</p></body></html>")
);
QString("<html><head/><body><p>") +
tr("Prefix a word with a field name to limit the search to that field, e.g.:") +
QString(" ") +
QString("<span style=\"font-weight:600;\">") +
tr("artist") +
QString(":") +
QString("</span><span style=\"font-style:italic;\">Strawbs</span>") +
QString(" ") +
tr("searches the collection for all artists that contain the word") +
QString(" Strawbs.") +
QString("</p><p><span style=\"font-weight:600;\">") +
tr("Available fields") +
QString(": ") +
"</span><span style=\"font-style:italic;\">" +
available_fields +
QString("</span>.") +
QString("</p></body></html>"));
QObject::connect(ui_->search_field, &QSearchField::returnPressed, this, &CollectionFilterWidget::ReturnPressed);
QObject::connect(filter_delay_, &QTimer::timeout, this, &CollectionFilterWidget::FilterDelayTimeout);
@@ -136,6 +135,7 @@ CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
ui_->options->setMenu(collection_menu_);
QObject::connect(ui_->search_field, &QSearchField::textChanged, this, &CollectionFilterWidget::FilterTextChanged);
QObject::connect(ui_->options, &QToolButton::clicked, ui_->options, &QToolButton::showMenu);
ReloadSettings();
@@ -176,16 +176,15 @@ 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(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())));
}
else {
model_->SetGroupBy(CollectionModel::Grouping(CollectionModel::GroupBy_AlbumArtist, CollectionModel::GroupBy_AlbumDisc, CollectionModel::GroupBy_None));
}
s.endGroup();
}
}
void CollectionFilterWidget::ReloadSettings() {

View File

@@ -38,10 +38,6 @@
</item>
<item>
<widget class="QToolButton" name="options">
<property name="styleSheet">
<string notr="true">padding-right: 16px;
</string>
</property>
<property name="iconSize">
<size>
<width>16</width>

View File

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

View File

@@ -59,12 +59,12 @@
#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"
@@ -325,26 +325,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 (!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 (!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 (!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 (!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 (!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 (!song.grouping().isEmpty()) key.append("-" + song.grouping());
break;
case GroupBy_Disc:
key = PrettyDisc(song.disc());
@@ -476,7 +482,7 @@ QString CollectionModel::DividerDisplayText(const GroupBy type, const QString &k
case GroupBy_Genre:
case GroupBy_FileType:
case GroupBy_Format:
if (key == "0") return "0-9";
if (key == "0") return "0-9";
return key.toUpper();
case GroupBy_YearAlbum:
@@ -1008,22 +1014,22 @@ void CollectionModel::InitQuery(const GroupBy type, CollectionQuery *q) {
q->SetColumnSpec("DISTINCT artist");
break;
case GroupBy_Album:
q->SetColumnSpec("DISTINCT album, album_id");
q->SetColumnSpec("DISTINCT album, album_id, grouping");
break;
case GroupBy_AlbumDisc:
q->SetColumnSpec("DISTINCT album, album_id, disc");
q->SetColumnSpec("DISTINCT album, album_id, disc, grouping");
break;
case GroupBy_YearAlbum:
q->SetColumnSpec("DISTINCT year, album, album_id, grouping");
break;
case GroupBy_YearAlbumDisc:
q->SetColumnSpec("DISTINCT year, album, album_id, disc");
q->SetColumnSpec("DISTINCT year, album, album_id, disc, grouping");
break;
case GroupBy_OriginalYearAlbum:
q->SetColumnSpec("DISTINCT year, originalyear, album, album_id, grouping");
break;
case GroupBy_OriginalYearAlbumDisc:
q->SetColumnSpec("DISTINCT year, originalyear, album, album_id, disc");
q->SetColumnSpec("DISTINCT year, originalyear, album, album_id, disc, grouping");
break;
case GroupBy_Disc:
q->SetColumnSpec("DISTINCT disc");
@@ -1097,11 +1103,13 @@ 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());
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());
q->AddWhere("grouping", item->metadata.grouping());
break;
case GroupBy_YearAlbum:
q->AddWhere("year", item->metadata.year());
@@ -1114,6 +1122,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());
q->AddWhere("grouping", item->metadata.grouping());
break;
case GroupBy_OriginalYearAlbum:
q->AddWhere("year", item->metadata.year());
@@ -1128,6 +1137,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());
q->AddWhere("grouping", item->metadata.grouping());
break;
case GroupBy_Disc:
q->AddWhere("disc", item->metadata.disc());
@@ -1216,6 +1226,7 @@ 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->metadata.set_grouping(row.value(2).toString());
item->key.append(ContainerKey(type, item->metadata));
item->display_text = TextOrUnknown(item->metadata.album());
item->sort_text = SortTextForArtist(item->metadata.album());
@@ -1225,6 +1236,7 @@ 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->metadata.set_grouping(row.value(3).toString());
item->key.append(ContainerKey(type, item->metadata));
item->display_text = PrettyAlbumDisc(item->metadata.album(), item->metadata.disc());
item->sort_text = item->metadata.album() + SortTextForNumber(qMax(0, item->metadata.disc()));
@@ -1245,6 +1257,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_disc(row.value(3).toInt());
item->metadata.set_grouping(row.value(4).toString());
item->key.append(ContainerKey(type, 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()));
@@ -1267,6 +1280,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_disc(row.value(4).toInt());
item->metadata.set_grouping(row.value(5).toString());
item->key.append(ContainerKey(type, 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()));
@@ -1325,14 +1339,14 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
break;
}
case GroupBy_FileType:{
item->metadata.set_filetype(Song::FileType(row.value(0).toInt()));
item->metadata.set_filetype(static_cast<Song::FileType>(row.value(0).toInt()));
item->key.append(ContainerKey(type, 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);
@@ -1411,6 +1425,7 @@ 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->metadata.set_grouping(s.grouping());
item->key.append(ContainerKey(type, s));
item->display_text = TextOrUnknown(s.album());
item->sort_text = SortTextForArtist(s.album());
@@ -1420,6 +1435,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_disc(s.disc());
item->metadata.set_grouping(s.grouping());
item->key.append(ContainerKey(type, s));
item->display_text = PrettyAlbumDisc(s.album(), s.disc());
item->sort_text = s.album() + SortTextForNumber(qMax(0, s.disc()));
@@ -1440,6 +1456,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_disc(s.disc());
item->metadata.set_grouping(s.grouping());
item->key.append(ContainerKey(type, 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()));
@@ -1932,7 +1949,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 +1957,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

@@ -45,10 +45,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;

View File

@@ -155,11 +155,11 @@ void CollectionQuery::AddWhere(const QString &column, const QVariant &value, con
}
else if (
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
value.metaType().id() == QMetaType::QString
value.metaType().id() == QMetaType::QString
#else
value.type() == QVariant::String
value.type() == QVariant::String
#endif
&& value.toString().isNull()) {
&& value.toString().isNull()) {
where_clauses_ << QString("%1 %2 ?").arg(column, op);
bound_values_ << QString("");
}

View File

@@ -125,4 +125,4 @@ class CollectionQuery : public QSqlQuery {
int limit_;
};
#endif // COLLECTIONQUERY_H
#endif // COLLECTIONQUERY_H

View File

@@ -425,7 +425,7 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
#endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
action_delete_files_->setVisible(regular_elements == regular_editable && delete_files_);
action_delete_files_->setVisible(delete_files_);
#else
action_delete_files_->setVisible(false);
#endif
@@ -440,7 +440,7 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
#endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
action_delete_files_->setEnabled(regular_elements == regular_editable && delete_files_);
action_delete_files_->setEnabled(delete_files_);
#else
action_delete_files_->setEnabled(false);
#endif
@@ -671,10 +671,17 @@ void CollectionView::Delete() {
if (!delete_files_) return;
SongList selected_songs = GetSelectedSongs();
SongList songs;
QStringList files;
songs.reserve(selected_songs.count());
files.reserve(selected_songs.count());
for (const Song &song : selected_songs) {
files << song.url().toString();
QString filename = song.url().toLocalFile();
if (!files.contains(filename)) {
songs << song;
files << filename;
}
}
if (DeleteConfirmationDialog::warning(files) != QDialogButtonBox::Yes) return;
@@ -683,7 +690,7 @@ void CollectionView::Delete() {
DeleteFiles *delete_files = new DeleteFiles(app_->task_manager(), storage, true);
QObject::connect(delete_files, &DeleteFiles::Finished, this, &CollectionView::DeleteFilesFinished);
delete_files->Start(selected_songs);
delete_files->Start(songs);
}

View File

@@ -68,11 +68,6 @@
using namespace std::chrono_literals;
namespace {
static const char *kNoMediaFile = ".nomedia";
static const char *kNoMusicFile = ".nomusic";
} // namespace
QStringList CollectionWatcher::sValidImages = QStringList() << "jpg" << "png" << "gif" << "jpeg";
CollectionWatcher::CollectionWatcher(Song::Source source, QObject *parent)
@@ -84,9 +79,10 @@ CollectionWatcher::CollectionWatcher(Song::Source source, QObject *parent)
original_thread_(nullptr),
scan_on_startup_(true),
monitor_(true),
song_tracking_(true),
mark_songs_unavailable_(true),
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),
@@ -149,9 +145,16 @@ void CollectionWatcher::ReloadSettings() {
scan_on_startup_ = s.value("startup_scan", true).toBool();
monitor_ = s.value("monitor", true).toBool();
QStringList filters = s.value("cover_art_patterns", QStringList() << "front" << "cover").toStringList();
song_tracking_ = s.value("song_tracking", false).toBool();
mark_songs_unavailable_ = song_tracking_ ? true : s.value("mark_songs_unavailable", true).toBool();
if (source_ == Song::Source_Collection) {
song_tracking_ = s.value("song_tracking", false).toBool();
mark_songs_unavailable_ = song_tracking_ ? true : s.value("mark_songs_unavailable", true).toBool();
}
else {
song_tracking_ = false;
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();
@@ -238,7 +241,7 @@ void CollectionWatcher::ScanTransaction::AddToProgressMax(const quint64 n) {
void CollectionWatcher::ScanTransaction::CommitNewOrUpdatedSongs() {
if (!deleted_songs.isEmpty()) {
if (mark_songs_unavailable_) {
if (mark_songs_unavailable_ && watcher_->source() == Song::Source_Collection) {
emit watcher_->SongsUnavailable(deleted_songs);
}
else {
@@ -413,7 +416,6 @@ void CollectionWatcher::AddDirectory(const Directory &dir, const SubdirectoryLis
void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory &subdir, const quint64 files_count, ScanTransaction *t, const bool force_noincremental) {
QFileInfo path_info(path);
QDir path_dir(path);
// Do not scan symlinked dirs that are already in collection
if (path_info.isSymLink()) {
@@ -425,11 +427,6 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
}
}
// Do not scan directories containing a .nomedia or .nomusic file
if (path_dir.exists(kNoMediaFile) || path_dir.exists(kNoMusicFile)) {
return;
}
bool songs_missing_fingerprint = false;
#ifdef HAVE_SONGFINGERPRINTING
if (song_tracking_) {
@@ -479,7 +476,10 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
else {
QString ext_part(ExtensionPart(child));
QString dir_part(DirectoryPart(child));
if (sValidImages.contains(ext_part)) {
if (child_info.suffix() == "tmp" || child_info.baseName() == "qt_temp") {
t->AddToProgress(1);
}
else if (sValidImages.contains(ext_part)) {
album_art[dir_part] << child;
t->AddToProgress(1);
}
@@ -736,7 +736,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());
}
@@ -779,7 +779,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);
}
@@ -1217,9 +1217,6 @@ quint64 CollectionWatcher::FilesCountForPath(ScanTransaction *t, const QString &
QFileInfo path_info(child);
if (path_info.isDir()) {
if (path_info.exists(kNoMediaFile) || path_info.exists(kNoMusicFile)) {
continue;
}
if (path_info.isSymLink()) {
QString real_path = path_info.symLinkTarget();
for (const Directory &dir : std::as_const(watched_dirs_)) {

View File

@@ -51,6 +51,8 @@ class CollectionWatcher : public QObject {
public:
explicit CollectionWatcher(Song::Source source, QObject *parent = nullptr);
Song::Source source() { return source_; }
void set_backend(CollectionBackend *backend) { backend_ = backend; }
void set_task_manager(TaskManager *task_manager) { task_manager_ = task_manager; }
void set_device_name(const QString &device_name) { device_name_ = device_name; }
@@ -216,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

@@ -7,6 +7,7 @@
#cmakedefine HAVE_BACKTRACE
#cmakedefine HAVE_GIO
#cmakedefine HAVE_GIO_UNIX
#cmakedefine HAVE_DBUS
#cmakedefine HAVE_X11
#cmakedefine HAVE_UDISKS2
@@ -15,7 +16,6 @@
#cmakedefine HAVE_LIBGPOD
#cmakedefine HAVE_LIBMTP
#cmakedefine HAVE_LIBPULSE
#cmakedefine HAVE_SPARKLE
#cmakedefine HAVE_QTSPARKLE
#cmakedefine HAVE_SONGFINGERPRINTING
#cmakedefine HAVE_MUSICBRAINZ

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