Compare commits

..

1589 Commits

Author SHA1 Message Date
Jonas Kvinge
c028770f8e Release 1.0.18 2023-07-02 01:27:51 +02:00
Jonas Kvinge
8f1a99b37e CI: Remove Fedora 36 2023-07-02 01:02:10 +02:00
Jonas Kvinge
e66651a4cb Song: Remove unused application include 2023-07-02 00:29:30 +02:00
Jonas Kvinge
1d9a052870 AlbumCoverChoiceController: Move result declaration 2023-07-02 00:29:19 +02:00
Jonas Kvinge
d3ee749c14 CollectionBackendTest: Fix build 2023-07-01 22:34:51 +02:00
Jonas Kvinge
33076aa33a Update Changelog 2023-07-01 22:26:52 +02:00
Jonas Kvinge
2a2663eeb5 Update Changelog 2023-06-29 20:31:16 +02:00
Jonas Kvinge
fa04eb67db Convert old embedded and unset art in the new schema 2023-06-29 20:21:50 +02:00
Jonas Kvinge
f8ad8a7211 Disable clang-format 2023-06-29 19:06:27 +02:00
Jonas Kvinge
5f4d6dffef AlbumCoverLoader: Fix loading existing album covers from disk 2023-06-29 00:44:00 +02:00
Jonas Kvinge
b9c7510946 AlbumCoverLoader: Fix Handling default image in finish task 2023-06-28 23:52:39 +02:00
dependabot[bot]
c0e709a0e3 Bump vmactions/freebsd-vm from 0.3.0 to 0.3.1
Bumps [vmactions/freebsd-vm](https://github.com/vmactions/freebsd-vm) from 0.3.0 to 0.3.1.
- [Release notes](https://github.com/vmactions/freebsd-vm/releases)
- [Commits](https://github.com/vmactions/freebsd-vm/compare/v0.3.0...v0.3.1)

---
updated-dependencies:
- dependency-name: vmactions/freebsd-vm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-26 20:16:20 +02:00
Jonas Kvinge
e690be1bdd DeviceDatabaseBackend: Fix device schema version mismatch
schema_version in device-schema.sql is 4.
2023-06-26 20:06:11 +02:00
Jonas Kvinge
6ed5190276 Remove AudD lyrics 2023-06-25 01:14:12 +02:00
Jonas Kvinge
4c4a351fbd CI: Add ubuntu mantic for ppa 2023-06-25 00:28:21 +02:00
Jonas Kvinge
435ffc75b6 CI: Add debian trixie 2023-06-24 03:40:23 +02:00
Jonas Kvinge
4dbc06bdd0 CI: Add ubuntu mantic 2023-06-24 03:38:32 +02:00
Jonas Kvinge
5a7cbb2f3d CI: Add OpenMandriva Cooker, remove Lx 4.2 2023-06-24 00:56:53 +02:00
Jonas Kvinge
354b55cbbc Use QFileInfo::path instead of QUrl::RemoveFilename 2023-06-15 21:06:18 +02:00
Jonas Kvinge
b87a950357 CoverUtils: Only create path if it doesn't exist 2023-06-15 21:04:11 +02:00
Jonas Kvinge
950c236720 AlbumCoverManager: Fix clear and unset actions 2023-06-15 20:35:41 +02:00
Jonas Kvinge
32982be4f2 EditTagDialog: Allow clearing unset cover 2023-06-15 20:34:03 +02:00
Jonas Kvinge
f467331934 Add ifdefs around #pragma GCC diagnostic 2023-06-15 20:10:25 +02:00
Jonas Kvinge
ec839e6aae KDSingleApplicationLocalSocket: Ignore missing declaration 2023-06-15 19:48:00 +02:00
Jonas Kvinge
45f1521da6 Update Changelog 2023-06-14 23:10:56 +02:00
Jonas Kvinge
841a44a18e KDSingleApplicationLocalSocket: Remove extra semicolon 2023-06-14 23:10:50 +02:00
Dakes
1deacaecf9 FilterParser: Add ability to filter by rating
Playlists can now be filtered by the rating from 0-5 like:
rating:0 rating:<3 rating:!=0
or by a float value, like:
rating:f0.1 rating:>=f0.5
2023-06-09 21:31:15 +02:00
Jonas Kvinge
6af8e6c25b Update Changelog 2023-06-09 00:16:46 +02:00
Jonas Kvinge
b0849d21f3 TidalStreamURLRequest: Ignore different track ID 2023-06-08 17:36:24 +02:00
Jonas Kvinge
5b60ea8e77 MainWindow: Remove F2 from edit tag shortcut
Fixes #1210
2023-06-07 19:38:59 +02:00
Andrei Stepanov
ec3f95a260 Add Russian translation to desktop file 2023-06-07 17:41:17 +02:00
Jonas Kvinge
0bfd4d2e04 CI: Only run SSH key setup step for master branch 2023-06-07 16:57:27 +02:00
Jonas Kvinge
a6ba0cfc97 KDSingleApplicationLocalSocket: Exclude XDG_SESSION_ID from socket name 2023-06-07 01:23:01 +02:00
Jonas Kvinge
6d55eb5974 CollectionModel: Fix icon disk cache 2023-06-07 00:51:53 +02:00
Jonas Kvinge
972053c699 MoodbarLoader: Fix loading cached moodbars 2023-06-07 00:50:35 +02:00
Jonas Kvinge
9db7896828 Prefix class for ReloadSettings 2023-06-06 23:20:42 +02:00
Jonas Kvinge
be6f93735d Simplify if statements 2023-06-06 23:19:45 +02:00
Jonas Kvinge
3bcea249ac TagReaderTagLib: Initialize cover_format 2023-06-06 23:19:25 +02:00
Jonas Kvinge
8ee32dfa88 Add static_cast to silence narrowing conversion warnings 2023-06-06 23:18:49 +02:00
Jonas Kvinge
e2f9411b46 EditTagDialog: Initialize cover_action 2023-06-06 23:17:29 +02:00
Jonas Kvinge
0bd68c3817 KDSingleApplicationLocalSocket: Add static_cast to silence narrowing conversion warnings 2023-06-06 22:25:19 +02:00
Jonas Kvinge
f03505ab67 KDSingleApplicationLocalSocket: Remove useless std::move 2023-06-06 22:24:10 +02:00
Jonas Kvinge
f1ae795c0f KDSingleApplicationLocalSocket: Initialize socket 2023-06-06 22:23:54 +02:00
Jonas Kvinge
50fcda2763 OSDDBus: Remove use of QImage::isGrayscale, Always expect RGB
Fixes #1205
2023-06-06 21:43:05 +02:00
Jonas Kvinge
331aa382f9 Rewrite album cover loader 2023-06-06 20:41:01 +02:00
Jonas Kvinge
3c160c2f13 CI: Fix /etc/dnf/dnf.conf for Fedora 39 2023-06-06 00:09:48 +02:00
Jonas Kvinge
4fd617a32f nsi: Add libgcc_s_sjlj-1.dll and libwinpthread-1.dll for MSVC x86 2023-06-05 00:41:34 +02:00
Jonas Kvinge
0d294eb218 CI: Add /opt/local/bin to PATH for macports build 2023-06-05 00:35:11 +02:00
Jonas Kvinge
a49e3b90b0 CI: Use macOS 12 for FreeBSD vm 2023-06-03 19:19:57 +02:00
Jonas Kvinge
201392f22e CI: Use latest macports release 2023-06-03 19:11:18 +02:00
Jonas Kvinge
3fa4ee772f CI: Bump MACOSX_DEPLOYMENT_TARGET 2023-06-03 19:10:57 +02:00
Jonas Kvinge
529c83c572 CI: Bump macOS version 2023-06-03 15:50:53 +02:00
Jonas Kvinge
6a9e56e9d9 nsi: Add gstwinrt-1.0-0.dll 2023-06-01 21:37:18 +02:00
Jonas Kvinge
716e80fb84 UWPDeviceFinder: Fix EngineDeviceList 2023-06-01 21:35:48 +02:00
Jonas Kvinge
80067b806d TranscodeDialog: Append number to filename if it already exists
Fixes #1200
2023-06-01 20:42:47 +02:00
Jonas Kvinge
315073f9a7 Add EngineDevice class 2023-06-01 19:31:19 +02:00
Jonas Kvinge
a1dbbba1a1 ContextView: Remove engine and device 2023-06-01 19:29:52 +02:00
Jonas Kvinge
cb8a0b6853 ContextSettingsPage: Remove engine and device 2023-06-01 19:29:52 +02:00
Jonas Kvinge
a5a29f7ad3 DeviceFinder: Add typedef DeviceList 2023-06-01 18:43:43 +02:00
Jonas Kvinge
8e14ef7c0c GstStartup: Set rank for directsoundsink higher than wasapisink for MinGW
Fixes #1204
2023-06-01 18:31:55 +02:00
Jonas Kvinge
c270391772 Add WASAPI2 plugin
Fixes #1204
2023-06-01 18:16:51 +02:00
Jonas Kvinge
e466cb6e30 Add UWP device finder 2023-06-01 18:11:30 +02:00
Jonas Kvinge
f0df9dc0fb GstEngine: Append "2" to wasapi2sink description 2023-06-01 17:22:11 +02:00
Strawbs Bot
b31c08083a Update translations 2023-05-30 01:02:07 +02:00
Jonas Kvinge
145a8d5b67 Bump LSMinimumSystemVersion in Info.plist
Fixes #1206
2023-05-29 11:25:43 +02:00
Jonas Kvinge
60d7a4e7ee AlbumCoverManager: Fix invalid reference 2023-05-29 11:24:41 +02:00
Jonas Kvinge
b52ffd09b2 Use find_package Protobuf CONFIG 2023-05-14 23:54:36 +02:00
Jonas Kvinge
58278ab1e4 Replace protobuf_generate_cpp with protobuf_generate 2023-05-14 20:07:36 +02:00
Strawbs Bot
000cf5fd5a Update translations 2023-05-13 01:01:35 +02:00
Jonas Kvinge
216b58e392 CI: Upload *.xz to source path 2023-05-07 12:39:35 +02:00
Jonas Kvinge
279cce49ba CI: Fix MSVC tarball filename 2023-05-07 11:27:56 +02:00
Jonas Kvinge
8184b77b13 CI: Improve MSVC build 2023-05-07 05:25:47 +02:00
Jonas Kvinge
b8b731ab04 CI: Upload Ubuntu PPA 2023-05-07 04:28:56 +02:00
Jonas Kvinge
1d4c39d13d CI: Upload release 2023-05-07 02:24:39 +02:00
Jonas Kvinge
ac26f5b2ef Add git to debian/control 2023-05-07 02:24:24 +02:00
Jonas Kvinge
c07447d8f5 CI: Upload artifacts 2023-05-07 01:09:18 +02:00
Jonas Kvinge
833ddf5f4c CI: Use -S and -B for cmake command 2023-05-06 14:18:35 +02:00
Jonas Kvinge
4dc4f468bb CI: Add Mageia 2023-05-06 14:08:34 +02:00
Strawbs Bot
1aff69d3cf Update translations 2023-05-06 01:02:19 +02:00
Robert Marshall
f2f63a703e class CueParser Process composer metadata in cue files
Use composer as an alternative to songwriter

..and move a misplaced comment
2023-05-05 17:47:37 +02:00
Jonas Kvinge
97e6b17f96 ContextView: QFontDatabase::families is not static in Qt 5 2023-05-05 17:46:02 +02:00
Jonas Kvinge
b90d284b08 ContextView: Check for default font family 2023-05-05 16:43:34 +02:00
Jonas Kvinge
840a65c630 ContextSettingsPage: Use constant for default font family 2023-05-05 16:43:01 +02:00
Jonas Kvinge
e5c89d4881 KDSingleApplicationLocalSocket: Use namespace and constexpr 2023-05-05 16:42:12 +02:00
Jonas Kvinge
0fc6638294 KDSingleApplicationLocalSocket: Formatting 2023-05-05 16:41:50 +02:00
Strawbs Bot
7c7724e41c Update translations 2023-05-05 01:29:26 +02:00
Jonas Kvinge
31319711dd Remove fixed font size on macOS
Possible fix for #1184
2023-05-05 00:34:48 +02:00
Jonas Kvinge
8954729d55 KDSingleApplicationPrivate: Remove unused initialize declaration 2023-05-04 19:42:27 +02:00
Jonas Kvinge
ae4dc442b9 Update Changelog 2023-05-04 19:22:00 +02:00
Jonas Kvinge
919ff414e6 Replace SingleApplication with KDSingleApplication 2023-05-04 09:44:54 +02:00
Strawbs Bot
b861703dad Update translations 2023-05-04 01:15:19 +02:00
Jonas Kvinge
2f17647cd3 Use const reference for AlbumCoverLoaderResult 2023-05-03 21:43:22 +02:00
Jonas Kvinge
f8d2c7eba3 Bump required Qt version to 5.12 2023-05-03 20:50:58 +02:00
Jonas Kvinge
e511b2faf9 Use new connect syntax for QMetaObject::invokeMethod 2023-05-03 20:08:51 +02:00
Jonas Kvinge
301e6b194a Replace 0 msec singleshot with invoke method 2023-05-03 19:55:58 +02:00
Jonas Kvinge
1208ca3ad4 ContextView: Simplify font code 2023-05-03 01:59:13 +02:00
Jonas Kvinge
84e7cd0df8 CollectionWatcher: Connect PathChanged signal once 2023-05-03 01:17:10 +02:00
Strawbs Bot
7e1077426e Update translations 2023-05-02 01:01:40 +02:00
Jonas Kvinge
1e2c437a08 CMakeLists: Remove hardcoded sqlite3 link with MSVC 2023-05-01 19:20:00 +02:00
Jonas Kvinge
a7ce1d1225 CI: Strip gdb.exe 2023-05-01 17:26:12 +02:00
Jonas Kvinge
1d3223e9c6 Add getopt supporting unicode
Fixes #1191
2023-05-01 16:44:18 +02:00
Jonas Kvinge
b01f3f4bb5 CI: Build on macOS with macports 2023-04-29 21:11:05 +02:00
Strawbs Bot
ee4cd11ae1 Update translations 2023-04-29 01:01:40 +02:00
Jonas Kvinge
154f8b307e CI: Add openSUSE Leap 15.5 2023-04-28 21:28:24 +02:00
Jonas Kvinge
7aac7872e3 CI: Disable D-Bus on macOS
Fixes #1163
2023-04-28 16:59:28 +02:00
Jonas Kvinge
b2630032e7 CI: Remove CodeQL 2023-04-27 21:39:25 +02:00
Jonas Kvinge
80136b602b CI: Check that all files are included in nsi 2023-04-26 19:04:59 +02:00
Strawbs Bot
3df29ed2a9 Update translations 2023-04-25 01:01:22 +02:00
Jonas Kvinge
69658f2022 AlbumCoverChoiceController: Check for nullptr in SearchForCover 2023-04-23 19:27:01 +02:00
Jonas Kvinge
5fd0a0831f GstEngine: Include all outputs that starts with "Sink/Audio" 2023-04-23 01:28:52 +02:00
Strawbs Bot
43b299ebd1 Update translations 2023-04-23 01:21:40 +02:00
Jonas Kvinge
9612304023 GstEngine: Use _stricmp with MSVC 2023-04-23 01:20:11 +02:00
Jonas Kvinge
3154e59b36 EngineBase: Remove extra semicolon 2023-04-22 20:41:22 +02:00
Jonas Kvinge
2d5a496678 Update debian/copyright 2023-04-22 19:48:51 +02:00
Jonas Kvinge
4c1c322b54 Rename AnalyzerBase 2023-04-22 19:45:21 +02:00
Jonas Kvinge
e9f3281694 Rename EngineBase 2023-04-22 19:13:42 +02:00
Jonas Kvinge
c3534affdb EngineBase: Remove PluginDetails 2023-04-22 17:18:29 +02:00
Jonas Kvinge
c6e62b3263 GstStartup: Remove setting rank for wasapisink and directsoundsink 2023-04-22 17:15:41 +02:00
Jonas Kvinge
d8ce177ce7 GstEngine: Remove class comment 2023-04-22 17:14:49 +02:00
Jonas Kvinge
726bfbefb0 Replace gst_element_factory_get_klass with gst_element_factory_get_metadata 2023-04-22 16:49:37 +02:00
Jonas Kvinge
5c4a6487c0 Update Changelog 2023-04-22 15:27:46 +02:00
Jonas Kvinge
3145433099 SystemTrayIcon: Simply icon loading 2023-04-22 15:27:34 +02:00
Jonas Kvinge
bdf6844b74 Database: Move error_reported 2023-04-22 14:38:45 +02:00
Jonas Kvinge
9ad430915c CddaDevice: Remove application.h include 2023-04-22 14:31:25 +02:00
Jonas Kvinge
60bbd71a22 Remove NetworkAccessManager from song loader 2023-04-22 14:05:48 +02:00
Jonas Kvinge
c96498758f Fix and improve gapless playback
If "about-to-finish" was emitted before the preload time was reached, we never set the next uri, so gapless playback was broken.
Make sure to always set the next uri, and increase preload gap from 5 to 8 seconds.
2023-04-22 03:54:11 +02:00
Strawbs Bot
f4600bd8eb Update translations 2023-04-22 01:21:46 +02:00
Jonas Kvinge
7202a5734c ListenBrainzScrobbler: Only send duration_ms when valid 2023-04-21 20:54:18 +02:00
Jonas Kvinge
8edb6eaa81 Song: Add missing const 2023-04-21 20:48:30 +02:00
Jonas Kvinge
b8eecc05fd AlbumCoverLoader: Use own NetworkAccessManager instance
Since AlbumCoverLoader runs in it's own thread.
2023-04-21 20:29:43 +02:00
Jonas Kvinge
7fc5aef553 Use one instance of NetworkAccessManager 2023-04-21 20:20:53 +02:00
Jonas Kvinge
bee6b7f946 Rename original_url to media_url 2023-04-21 16:20:00 +02:00
Jonas Kvinge
3bedfb6ac8 GstEngine: Formatting 2023-04-21 15:07:17 +02:00
Jonas Kvinge
f49bf0192b Engine::Base: Formatting 2023-04-21 15:06:44 +02:00
Jonas Kvinge
f36ac5272b Scrobbler: Simplify error handling 2023-04-21 02:11:26 +02:00
Strawbs Bot
f0fe446f7f Update translations 2023-04-21 01:01:44 +02:00
Jonas Kvinge
d9c4720a3e ListenBrainzScrobbler: Split artist mbids by slash 2023-04-20 21:55:11 +02:00
monochromec
4de5d8f2a3 Fixed typo and improved wording of Rosetta notice 2023-04-20 16:29:48 +02:00
Strawbs Bot
8651311016 Update translations 2023-04-19 01:08:38 +02:00
Jonas Kvinge
1d27c5a14c MainWindow: Add missing QSettings declaration 2023-04-18 20:17:01 +02:00
Jonas Kvinge
b0b8ff2d49 CollectionModel: URL percent encode disk cache keys
Fixes #1183
2023-04-18 18:42:37 +02:00
Jonas Kvinge
cd03e1fc74 Make it possible to not show Rosetta warning
Fixes #1180
2023-04-18 18:03:39 +02:00
Jonas Kvinge
b273a449e3 Add common message dialog 2023-04-18 17:44:42 +02:00
Jonas Kvinge
b637867f9e MainWindow: Hide checkbox, set size, center rosetta warning 2023-04-18 16:54:43 +02:00
Jonas Kvinge
41d5792b27 Add screen utilities for screen and center widget on screen 2023-04-18 16:54:35 +02:00
Jonas Kvinge
d22712a25b nsi: Update ICU to 73 2023-04-15 17:50:57 +02:00
Jonas Kvinge
33968ee5da CI: Fix macOS build 2023-04-15 17:50:31 +02:00
Strawbs Bot
9baf1774e0 Update translations 2023-04-15 01:01:23 +02:00
Strawbs Bot
9ca66e4061 Update translations 2023-04-12 01:01:23 +02:00
Jonas Kvinge
db2d34f840 FavoriteWidget: Use icon loader for star icons
Fixes #1178
2023-04-10 21:29:52 +02:00
Strawbs Bot
195cc61df7 Update translations 2023-04-10 01:22:37 +02:00
Jonas Kvinge
aaa530e72b Add const/references to all signal parameters 2023-04-09 20:23:42 +02:00
Jonas Kvinge
fa856ee905 Remove directory.h 2023-04-09 20:17:45 +02:00
Strawbs Bot
2bf7a5c4d3 Update translations 2023-04-08 01:27:44 +02:00
Jonas Kvinge
780b982635 SmartPlaylistSearchTermWidget: Fix loading search terms
Fixes #1172
2023-04-07 23:05:07 +02:00
Jonas Kvinge
74bbc1f19f PlaylistGenerator: Use std::make_shared 2023-04-07 22:41:10 +02:00
Jonas Kvinge
e314545f2e Database: Fix SQL query error message 2023-04-07 20:54:31 +02:00
Jonas Kvinge
f1a3a12c1c CollectionBackend: Fix SQL query error message 2023-04-07 20:54:15 +02:00
Jonas Kvinge
ef080c3cb1 PlaylistView: Fix resetting album cover 2023-04-07 20:07:40 +02:00
Jonas Kvinge
7313db5ac0 Add compile test for QX11Application
if Qt was compiled without XCB, globalshortcut-x11 failed to compile.
2023-04-07 15:57:39 +02:00
Jonas Kvinge
bf9aa524ed CI: Fix macOS build 2023-04-07 02:31:59 +02:00
Jonas Kvinge
b59aa0827e GstEnginePipeline: Always set initial volume 2023-04-07 02:30:41 +02:00
Strawbs Bot
2584f1293e Update translations 2023-04-07 01:13:27 +02:00
Jonas Kvinge
de9d28adea CI: Add Fedora 39 2023-04-06 23:37:23 +02:00
Jonas Kvinge
b660287779 Use std::shared_ptrfor AlbumCoverLoaderResult
Reduces memory fragmentation with Qt 6
2023-04-06 23:18:10 +02:00
Jonas Kvinge
962536bc83 AlbumCoverLoaderResult: Use enum class for type 2023-04-06 01:23:42 +02:00
Strawbs Bot
ee4fcf8100 Update translations 2023-04-04 01:01:21 +02:00
Strawbs Bot
9a4ed1a19d Update translations 2023-03-31 21:56:09 +02:00
Gaganpreet Arora
c1d0702b4d QobuzRequest: Handle multiple discs in integration
Albums with multiple discs are not being handled which results in tracks
being listed out of order. If the disc (media_number) is present in
JSON, we use it to set the disc in the Song object.
2023-03-31 21:21:58 +02:00
Jonas Kvinge
af1c46543b Turn on git revision 2023-03-30 17:50:03 +02:00
Jonas Kvinge
e2f5486987 Release 1.0.17 2023-03-29 18:54:51 +02:00
Jonas Kvinge
b0d390aaf1 Update Changelog 2023-03-29 18:49:35 +02:00
Jonas Kvinge
bae1b42394 OSDPretty: Respect device pixel ratio 2023-03-29 18:23:06 +02:00
Jonas Kvinge
a2533edd57 PlayingWidget: Make previous pixmap respect device pixel ratio 2023-03-29 00:24:38 +02:00
Jonas Kvinge
7b88c198fe SongSourceDelegate: Fix compile with Qt 5 2023-03-29 00:14:21 +02:00
Jonas Kvinge
c49cb0c119 ImageUtils: Formatting 2023-03-29 00:09:40 +02:00
Jonas Kvinge
03aabeb848 AlbumCoverManager: Respect device pixel ratio 2023-03-29 00:06:56 +02:00
Jonas Kvinge
1d3a837f7a SongSourceDelegate: Respect device pixel ratio 2023-03-29 00:04:34 +02:00
Jonas Kvinge
92adc18b8f ContextAlbum: Make size hint respect device pixel ratio 2023-03-28 18:21:19 +02:00
Fletcher Dostie
e4697c8ff1 Render context art at correct size 2023-03-28 17:54:56 +02:00
Jonas Kvinge
b741f1a580 Turn on git revision 2023-03-28 01:48:09 +02:00
Jonas Kvinge
8ee6de4162 Release 1.0.16 2023-03-27 22:28:02 +02:00
Jonas Kvinge
2b9e7db924 TagReaderTagLib: Touch file over saving cover art 2023-03-26 22:37:21 +02:00
Jonas Kvinge
49384ce294 TagReaderTagLib: Fix reading MusicBrainz from ID3v2 tags 2023-03-26 04:33:15 +02:00
Jonas Kvinge
ac59fff346 TagReaderTagLib: Formatting 2023-03-26 04:14:03 +02:00
Jonas Kvinge
a3e9f152d8 CollectionSettingsPage: Remove iopriority hide 2023-03-26 03:14:52 +02:00
Jonas Kvinge
ffe6a81b9a Collection: Always use Idle priority for watcher 2023-03-26 00:10:29 +01:00
Jonas Kvinge
9bb051b4eb CollectionSettingsPage: Remove settings for IO and thread priority and workers 2023-03-26 00:09:41 +01:00
Jonas Kvinge
c1465a890f TagReaderClient: Always use 1 tagreader worker 2023-03-26 00:08:55 +01:00
Jonas Kvinge
c3ee3318d7 WorkerPool: Default to 1 worker 2023-03-26 00:08:23 +01:00
Jonas Kvinge
272976f0b7 TagReaderClient: Fix default save options 2023-03-25 23:54:15 +01:00
Jonas Kvinge
4724b170b1 AuddLyricsProvider: Disable provider by default
Since we are currently missing API key.
2023-03-25 19:20:10 +01:00
Jonas Kvinge
337bd4bcef ListenBrainzScrobbler: Make sure we only add the same artist id once 2023-03-25 19:14:26 +01:00
Jonas Kvinge
0604c78453 CollectionBackend: Check for changed fingerprint 2023-03-25 18:35:14 +01:00
Jonas Kvinge
c8169adf7c CollectionModel: Guard against invalid disc and year 2023-03-25 18:32:41 +01:00
Jonas Kvinge
7b610d131c CollectionModel: Replace qMax with std::max 2023-03-25 18:31:21 +01:00
Jonas Kvinge
18da55453f EditTagDialog: Not set for track, disc, year, etc to -1 2023-03-25 18:29:12 +01:00
Jonas Kvinge
2aeab8b672 CollectionModel: Remove unused QByteArray include 2023-03-25 18:26:53 +01:00
Jonas Kvinge
9c21707a55 Update Changelog 2023-03-25 16:49:19 +01:00
Jonas Kvinge
b02ac833ad CollectionWatcher: Fix rescan songs feature 2023-03-25 16:38:03 +01:00
Jonas Kvinge
4de912cf41 Song: Fix missing colon in SQL bind value 2023-03-25 16:34:26 +01:00
Jonas Kvinge
ed260c6e20 CollectionWatcher: Check for changed AcoustID and MusicBrainz 2023-03-25 14:35:12 +01:00
Jonas Kvinge
fab38f693d Scrobbler: Refactor and add MusicBrainz integration 2023-03-25 14:25:21 +01:00
Jonas Kvinge
aedbd52e9d Add AcoustID 2023-03-24 22:48:22 +01:00
Jonas Kvinge
4cbcb9d99c Update list of lyrics providers in README.md and dist files 2023-03-24 21:23:10 +01:00
Jonas Kvinge
e967d15b4e Add AudD lyrics provider 2023-03-24 21:16:11 +01:00
Fletcher Dostie
bb43cc63ec Fix album art rendering on High DPI displays 2023-03-24 21:02:55 +01:00
Jonas Kvinge
ca176c319d Add Acoustid and MusicBrainz tags to database schema 2023-03-24 21:00:58 +01:00
Jonas Kvinge
17c960ecd4 Song: Add Acoustid fingerprint and MusicBrainz tags 2023-03-24 20:57:46 +01:00
Jonas Kvinge
b766ae3498 Song: Use static_cast from int to Source 2023-03-24 20:54:42 +01:00
Jonas Kvinge
faf4c817cd TagReaderTagLib: Read AcoustID fingerprint 2023-03-24 20:54:05 +01:00
Jonas Kvinge
b4e1f283c9 tagreadermessages: Add AcoustID fingerprint tags to protobuf 2023-03-24 19:52:45 +01:00
Jonas Kvinge
52c83d592c Rename Stands4 to Lyrics.com 2023-03-22 23:36:15 +01:00
Jonas Kvinge
c8caea0d30 GstEnginePipeline: Use constexpr 2023-03-22 23:29:56 +01:00
Jonas Kvinge
7a6c54d8e7 GstEnginePipeline: Remove hard-coded num-bands 2023-03-22 23:29:24 +01:00
Strawbs Bot
7082e52a4f Update translations 2023-03-21 01:01:49 +01:00
Strawbs Bot
6cdca617e0 Update translations 2023-03-20 01:14:38 +01:00
Jonas Kvinge
a1adc1a75a Add option for strict SSL mode in backend settings 2023-03-19 23:02:17 +01:00
Jonas Kvinge
b16bec704a GstEnginePipeline: Use "source-setup" instead of "notify::source" signal
This works with both playbin 2 and 3.

Possible fix for #1148
2023-03-19 22:28:12 +01:00
Jonas Kvinge
664a8c79a1 GstEnginePipeline: Check for ssl-strict property 2023-03-19 22:13:16 +01:00
Jonas Kvinge
bbf3d8e1a4 Update Changelog 2023-03-19 22:03:55 +01:00
Jonas Kvinge
a35146440c TagReaderTagLib: Read MusicBrainz tags 2023-03-19 21:55:26 +01:00
Jonas Kvinge
8e79fafca9 tagreadermessages: Add MusicBrainz tags to protobuf 2023-03-19 21:50:54 +01:00
Jonas Kvinge
6f8780d3cc TagReaderGME: Add header guard comment 2023-03-19 21:29:45 +01:00
Jonas Kvinge
264065a355 TagreaderGME: Don't call QByteArray::operator[]() on temporary 2023-03-19 20:42:30 +01:00
Jonas Kvinge
b606e4cd1a TagReaderTagLib: Rename Decode to TStringToStdString 2023-03-19 20:35:47 +01:00
Jonas Kvinge
01d0eeaed0 FileViewList: Add reserve 2023-03-19 20:32:06 +01:00
Jonas Kvinge
8c4e24e65d filemanagerutils: Add namespace comment 2023-03-19 20:31:46 +01:00
Jonas Kvinge
19c9f9698d QobuzService: Make DecodeAppSecret const 2023-03-19 20:31:31 +01:00
Jonas Kvinge
ae87c1b578 Stands4LyricsProvider: Remove unused variable 2023-03-19 20:24:07 +01:00
Jonas Kvinge
c42b1f5548 GstEnginePipeline: Cast guint to int 2023-03-19 19:38:36 +01:00
Jonas Kvinge
87ffbb0a85 Equalizer: Remove redundant QString cast 2023-03-19 19:38:12 +01:00
Jonas Kvinge
702851a958 TagReaderTagLib: Use constexpr 2023-03-19 19:34:05 +01:00
Jonas Kvinge
650f200a0b TagReaderBase: Remove unused Decode function 2023-03-19 19:33:34 +01:00
Jonas Kvinge
14d215bdf3 ContextView: Add static_cast for font size 2023-03-19 19:32:41 +01:00
Jonas Kvinge
12aebc2fe9 Sonogram: Remove unused destructor 2023-03-19 19:32:23 +01:00
Jonas Kvinge
f41b051ec7 LyricsSearchResult: Add missing const reference 2023-03-19 19:31:43 +01:00
Jonas Kvinge
25144eee89 Add CONTRIBUTING.md 2023-03-19 16:07:12 +01:00
Jonas Kvinge
0c62147536 SongLoader: Remove probe and bus watch 2023-03-19 05:08:35 +01:00
Jonas Kvinge
7b282e21de Fix compile with GStreamer disabled 2023-03-19 05:08:35 +01:00
Strawbs Bot
c1fbe6d84c Update translations 2023-03-19 01:20:59 +01:00
Jonas Kvinge
e20cbe4170 Save embedded cover in the same process as tags
Possible fix for #1158
2023-03-18 20:03:07 +01:00
Jonas Kvinge
394955a03f Replace QList<QByteArray> with QByteArrayList 2023-03-18 19:41:36 +01:00
Jonas Kvinge
16b4f5d065 DeviceDatabaseBackend: Remove use of QSqlDatabase::exec() 2023-03-18 02:20:03 +01:00
Jonas Kvinge
c95295d8b4 Console: Remove use of QSqlDatabase::exec() 2023-03-18 01:49:03 +01:00
Strawbs Bot
658dce2607 Update translations 2023-03-18 01:01:44 +01:00
Jonas Kvinge
01f8d0a27e SavedGroupingManager: Add missing collectionsettingspage include 2023-03-18 01:01:28 +01:00
Jonas Kvinge
39e1bfc84f CollectionBackend: Add default for ResetStatistics save_tags to false 2023-03-18 01:00:28 +01:00
Jonas Kvinge
e394416fa7 CollectionFilterWidget: Add missing collectionsettingspage include 2023-03-18 00:59:39 +01:00
Strawbs Bot
f1108bc0e2 Update translations 2023-03-15 01:01:28 +01:00
Jonas Kvinge
ff31815d49 SmartPlaylistSearchTerm: Revert if / else 2023-03-11 18:16:48 +01:00
Jonas Kvinge
604aa63b47 SmartPlaylists: Rename variable collection to collection_backend 2023-03-11 17:18:35 +01:00
Jonas Kvinge
ec4d036f50 SmartPlaylistsModel: Add missing endArray 2023-03-11 17:17:23 +01:00
Jonas Kvinge
1bf1c4ac63 nsi: Simplify macro code 2023-03-09 16:14:32 +01:00
Jonas Kvinge
981d46fbd4 Link abseil_dll for MSVC 2023-03-09 16:14:32 +01:00
Jonas Kvinge
eb6a353c31 nsi: Add libabsl 2023-03-09 16:14:32 +01:00
Strawbs Bot
ff673b1941 Update translations 2023-03-09 01:01:45 +01:00
Jonas Kvinge
8b55cf8a3a Check for policy 2023-03-08 19:01:18 +01:00
Jonas Kvinge
d8682b4403 Workaround absl linking errors on Windows with protobuf 3.22 2023-03-08 18:57:52 +01:00
Jonas Kvinge
40a4bf195a Link with Protobuf_LIBRARIES 2023-03-08 18:56:15 +01:00
Jonas Kvinge
312c5cbc3f macosutils: Formatting 2023-03-08 01:03:57 +01:00
Strawbs Bot
f314c56ef0 Update translations 2023-03-08 01:02:01 +01:00
Jonas Kvinge
ea8e5180ff Detect if running under Rosetta 2023-03-07 23:04:00 +01:00
Jonas Kvinge
7f76c3f2ce CI: Add Ubuntu Lunar 2023-03-07 20:53:49 +01:00
Jonas Kvinge
e4c5e99d0f MainWindow: Add macOS warning if running on different CPU 2023-03-07 20:14:37 +01:00
Jonas Kvinge
80cfca5de2 CI: Set HOMEBREW_NO_INSTALL_FROM_API for macOS 2023-03-07 01:15:38 +01:00
Strawbs Bot
9556a14de9 Update translations 2023-03-07 01:02:32 +01:00
Jonas Kvinge
2025fc8325 Update list of lyrics providers in README.md and dist files 2023-03-06 21:50:42 +01:00
Jonas Kvinge
2dd0f6a9ba Remove AudD lyrics provider 2023-03-06 21:46:00 +01:00
Jonas Kvinge
a42039d6e5 Lyrics: Match both album artist and artist in lyrics results 2023-03-06 21:42:59 +01:00
Jonas Kvinge
7fafa8adfb QtFSListener: Log watcher errors 2023-03-05 01:23:28 +01:00
Jonas Kvinge
f789657552 SingleApplication: Add boost include dirs 2023-03-05 01:04:57 +01:00
Jonas Kvinge
3e183bc10e SingleApplication: Change lambda capture order 2023-03-05 00:10:34 +01:00
Jonas Kvinge
16e5d93be3 SingleApplication: Add memory include 2023-03-05 00:08:45 +01:00
Jonas Kvinge
6515e06a13 SingleApplication: Refactor startup code 2023-03-04 23:47:36 +01:00
Jonas Kvinge
9ae0b32318 nsi: Update ffmpeg dlls for MinGW 2023-03-04 23:43:40 +01:00
Jonas Kvinge
4cb3bc4185 SingleApplication: Share code between SingleApplication and SingleCoreApplication 2023-03-04 20:48:21 +01:00
Jonas Kvinge
f9ca24598e Turn on git revision 2023-03-04 16:13:45 +01:00
Jonas Kvinge
3ccc892d6a Release 1.0.15 2023-03-04 15:46:51 +01:00
Jonas Kvinge
d7cacea843 Update Changelog 2023-03-04 15:45:33 +01:00
Strawbs Bot
e30233ac74 Update translations 2023-03-03 01:01:55 +01:00
Jonas Kvinge
7c57631fcf SingleApplication: Only include QNativeIpcKey with Qt 6.6 and higher 2023-03-02 23:03:33 +01:00
Jonas Kvinge
0adc084dad SingleApplication: Use new QSharedMemory constructor with Qt 6.6 and higher 2023-03-02 22:57:33 +01:00
Jonas Kvinge
e22199817c SingleApplicationPrivate: Move variable 2023-03-02 22:56:41 +01:00
Jonas Kvinge
78f691d006 SingleApplication: Remove semicolon 2023-03-02 22:56:17 +01:00
Jonas Kvinge
749bae1f16 SingleApplication: Use enum class for Mode 2023-03-02 22:55:50 +01:00
Jonas Kvinge
1043e24322 SingleApplication: Remove exit 2023-03-02 22:55:21 +01:00
Jonas Kvinge
a6d10b1fa7 GstEnginePipeline: Check that audio bin exists before unref 2023-02-27 18:50:09 +01:00
Jonas Kvinge
a3159423f8 nsi: Update libiconv for MSVC 2023-02-24 22:09:35 +01:00
Jonas Kvinge
ecb5ca321b CI: Use Windows 2022 and msvc toolset 14.3 2023-02-24 22:03:30 +01:00
Jonas Kvinge
fd827fdfd8 Add CodeQL 2023-02-22 18:53:21 +01:00
Jonas Kvinge
92d77b14d5 CI: Minor cleanup 2023-02-21 18:43:01 +01:00
dependabot[bot]
be67d89d8b Bump vmactions/freebsd-vm from 0.2.9 to 0.3.0
Bumps [vmactions/freebsd-vm](https://github.com/vmactions/freebsd-vm) from 0.2.9 to 0.3.0.
- [Release notes](https://github.com/vmactions/freebsd-vm/releases)
- [Commits](https://github.com/vmactions/freebsd-vm/compare/v0.2.9...v0.3.0)

---
updated-dependencies:
- dependency-name: vmactions/freebsd-vm
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-21 01:59:45 +00:00
Jonas Kvinge
ddd1ce732a dependabot formatting 2023-02-20 20:32:04 +01:00
Jonas Kvinge
012d82183c Add dependabot 2023-02-20 20:28:41 +01:00
Jonas Kvinge
f9c98ebcb3 CI: Use build_type specific container image for mingw 2023-02-20 18:47:28 +01:00
Jonas Kvinge
10fe861dde nsi: Move protobuf to common files 2023-02-19 11:01:28 +01:00
Strawbs Bot
16c027ecab Update translations 2023-02-19 01:21:50 +01:00
Jonas Kvinge
cc578e7cc5 Sonogram: Remove unused parameter variable 2023-02-18 18:44:14 +01:00
Jonas Kvinge
6972d3c4f9 Sonogram: Change int to size_t 2023-02-18 17:52:01 +01:00
Jonas Kvinge
46b164f2fb nsi: Update protobuf dll 2023-02-18 17:30:38 +01:00
Jonas Kvinge
5431307527 CollectionFilterOptions: Match album artist too 2023-02-18 17:05:41 +01:00
Jonas Kvinge
79bf194ed6 CollectionModel: Fix compilation requirement query
Fixes #1140
2023-02-18 16:40:12 +01:00
Jonas Kvinge
506e670aa7 CI: Fix macOS build 2023-02-18 15:21:59 +01:00
Jonas Kvinge
fdfe164dd1 SmartPlaylistsModel: Save smart playlist type as int 2023-02-18 14:34:02 +01:00
Jonas Kvinge
af37056179 Change TrackChangeType to enum 2023-02-18 14:33:43 +01:00
Jonas Kvinge
b0fc7187cf PlaylistSettingsPage: Add Q_DECLARE_METATYPE for PathType 2023-02-18 14:33:19 +01:00
Jonas Kvinge
33ad1a7a86 Song: Add Q_DECLARE_METATYPE for Source and FileType 2023-02-18 14:33:01 +01:00
Jonas Kvinge
dd72fb4ca5 Use C++11 enum class 2023-02-18 14:09:30 +01:00
Jonas Kvinge
e6c5f76872 FancyTabWidget: Remove extra namespace 2023-02-18 14:09:30 +01:00
Jonas Kvinge
14aa22d590 Stands4LyricsProvider: Use direct URL if API usage limit exceeds 2023-02-18 14:09:30 +01:00
Strawbs Bot
5ed4293641 Update translations 2023-02-12 01:02:28 +01:00
Jonas Kvinge
f9fefcda57 Update Changelog 2023-02-11 01:49:10 +01:00
Jonas Kvinge
99b40293db Stands4LyricsProvider: Use percent encoding 2023-02-11 01:39:14 +01:00
Jonas Kvinge
9b06e85f94 Stands4LyricsProvider: Use API for search 2023-02-11 01:33:33 +01:00
Jonas Kvinge
93d1d40ea5 LyricsProvider: Default to empty results 2023-02-11 01:33:33 +01:00
Strawbs Bot
98597c047a Update translations 2023-02-11 01:19:51 +01:00
Jonas Kvinge
a5c1f4b0ee EditTagDialog: Fix saving play statistics
Fixes #1124
2023-02-10 22:51:48 +01:00
Jonas Kvinge
3d4c98d981 Playlist: Fix tag inline editing for steams
Fixes #1130
2023-02-10 22:49:57 +01:00
Jonas Kvinge
384e7dedb5 PlaylistView: Move ifdef 2023-02-10 22:47:55 +01:00
Jonas Kvinge
7df4453560 OrganizeFormat: Use suffix instead of complete suffix
Fixes #1136
2023-02-10 22:47:11 +01:00
Jonas Kvinge
d406a1c341 GstEnginePipeline: Use playbin3 with GStreamer 1.22.0 and higher 2023-02-10 22:43:55 +01:00
Jonas Kvinge
6671d97b4a GstEnginePipeline: Free audio bin in destructor
When the audio bin failed to initialize, we tried to disconnect signals and probes after the audio bin was already freed.
Instead, free the audio bin in the destructor after disconnecting signals and probes.

Fixes #1133 and #1123
2023-02-10 22:42:37 +01:00
Strawbs Bot
d02de72830 Update translations 2023-02-06 01:01:22 +01:00
Strawbs Bot
08f5172028 Update translations 2023-01-23 01:01:39 +01:00
4fury-c3440d8
04f062547d TagReaderTagParser: Fix timeconstants.h include 2023-01-22 13:22:02 +01:00
Jonas Kvinge
4717d783dc Stands4LyricsProvider: Finish search when no lyrics are found 2023-01-21 15:55:47 +01:00
Strawbs Bot
93af064b36 Update translations 2023-01-21 01:02:43 +01:00
Jonas Kvinge
c78d73d727 LastPlayedItemDelegate: Show blank for zero or invalid time 2023-01-20 23:45:33 +01:00
Jonas Kvinge
b69b3228be DateItemDelegate: Show blank for zero or invalid time 2023-01-20 23:45:19 +01:00
Jonas Kvinge
377f54700d TidalRequest: Make cover optional 2023-01-20 23:35:47 +01:00
Jonas Kvinge
d276339c80 Add lyrics from stands4 (lyrics.com) 2023-01-20 22:48:52 +01:00
Jonas Kvinge
b982a6a762 LyricsProvider: Improve parsing from HTML function 2023-01-20 22:45:05 +01:00
Jonas Kvinge
536fe637aa About: Remove e-mail addresses 2023-01-20 19:32:49 +01:00
Strawbs Bot
69f36eaa25 Update translations 2023-01-15 01:01:48 +01:00
Strawbs Bot
d6927a70bb Update translations 2023-01-14 01:01:51 +01:00
Jonas Kvinge
1b1892a187 Sonogram: Fix parameter mismatch in header 2023-01-13 23:46:38 +01:00
Sungrak Choi
5bea71cd5c Add Sonogram analyzer
Co-Authored-By: Jonas Kvinge <jonas@jkvinge.net>
2023-01-13 23:41:43 +01:00
Jonas Kvinge
bb8d4e70ae Turn on git revision 2023-01-13 22:53:39 +01:00
Jonas Kvinge
8d8c7e8b7b Release 1.0.14 2023-01-13 22:21:54 +01:00
Jonas Kvinge
9ff1f4d7b4 Update Changelog 2023-01-13 22:15:07 +01:00
Strawbs Bot
3a60dfe025 Update translations 2023-01-13 01:01:53 +01:00
Jonas Kvinge
d358854e16 Transcoder: Use static cast 2023-01-12 23:37:12 +01:00
Jonas Kvinge
129587e94a TranscoderOptionsMP3: Change default settings 2023-01-12 23:36:34 +01:00
Jonas Kvinge
0f575f4639 main: Remove explicitly enabling debug messages
Fixes #1106
2023-01-11 22:08:58 +01:00
Jonas Kvinge
7aac741571 GstEnginePipeline: Fix setting initial volume
Fixes #1104
2023-01-11 18:52:14 +01:00
Jonas Kvinge
b8a9da8a4e GstEngine: Use QUrl::isLocalFile 2023-01-10 18:26:42 +01:00
Jonas Kvinge
be6b974334 MoodbarPipeline: Fix saving moodbar if the URL contains host
Fixes #1101
2023-01-10 18:18:49 +01:00
knuxify
194e81205b CollectionBackendTest: Fix compile 2023-01-10 17:38:30 +01:00
Jonas Kvinge
d711dcc99d Turn on git revision 2023-01-10 00:46:49 +01:00
Jonas Kvinge
3b72a12540 Release 1.0.13 2023-01-09 22:46:59 +01:00
Strawbs Bot
38a1b7765a Update translations 2023-01-09 01:09:50 +01:00
Jonas Kvinge
02f2b8b6f0 CueParser: Detect encoding 2023-01-08 23:40:56 +01:00
Jonas Kvinge
7bfa75102c Remove QRegularExpressionMatch include 2023-01-08 23:24:25 +01:00
Jonas Kvinge
b0f3e7351c Update Changelog 2023-01-08 18:36:32 +01:00
Jonas Kvinge
b5fa401db9 Collection: Make sure RunQuery does not access collection items
- Rename `QueryOptions` to `CollectionFilterOptions`.
- Create new class `CollectionQueryOptions` for passing options from model to `CollectionQuery`.
- Rename `Directory` to `CollectionDirectory`.

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

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

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

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

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

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

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

This may be confusing for some users, because they might have VLC already installed, but not libvlc. This commit fixes it.
2022-04-26 17:39:07 +02:00
Jonas Kvinge
9024acb16e debian: Add qt6-qpa-plugins to depends
Fixes #937
2022-04-23 23:48:16 +02:00
Jonas Kvinge
7732402122 Add ffmpeg to MSVC 2022-04-23 18:06:38 +02:00
Jonas Kvinge
2059bce6a7 Add Qt 6 support to debian files 2022-04-23 02:15:22 +02:00
Jonas Kvinge
499c86a8b8 Add safe git directory 2022-04-20 01:23:02 +02:00
Strawbs Bot
ef084eb145 Update translations 2022-04-20 01:02:20 +02:00
Jonas Kvinge
3f3ae7c38f SmartPlaylistSearchTerm: Fix filetype search 2022-04-19 23:11:13 +02:00
Strawbs Bot
83d762287f Update translations 2022-04-18 01:01:58 +02:00
Strawbs Bot
5af0acf147 Update translations 2022-04-16 01:05:16 +02:00
Jonas Kvinge
907dfee6f7 Utilities: Use inconv with MSVC 2022-04-15 17:44:04 +02:00
Strawbs Bot
d587d24603 Update translations 2022-04-15 01:03:02 +02:00
Jonas Kvinge
c246b8f164 GstEngine: Show debug information in error dialog 2022-04-14 20:56:57 +02:00
Strawbs Bot
deecafa053 Update translations 2022-04-11 01:02:28 +02:00
Jonas Kvinge
f8810106a2 Turn on git revision 2022-04-10 17:34:26 +02:00
Jonas Kvinge
8e35fbe532 Release 1.0.4 2022-04-10 14:08:25 +02:00
Jonas Kvinge
b1fdccde6e ContextView: Specify alternative fonts for no song playing 2022-04-10 14:05:51 +02:00
Jonas Kvinge
6741f100a1 Update Changelog 2022-04-10 12:19:23 +02:00
Jonas Kvinge
e05e9ea1b2 timeconstants: Use constexpr 2022-04-08 17:35:44 +02:00
Jonas Kvinge
197341de5e Update debian/copyright-scan-patterns.yml 2022-04-08 17:35:31 +02:00
Jonas Kvinge
2933482be3 Update debian/copyright 2022-04-08 17:35:23 +02:00
Jonas Kvinge
c7ce23239f Disable gstwasapi2 in nsi 2022-04-07 23:18:08 +02:00
Jonas Kvinge
79115f7439 Update README and issue template 2022-04-07 01:22:21 +02:00
Jonas Kvinge
4457103672 Add pcre2 to nsi for MSVC 2022-04-06 23:23:20 +02:00
Jonas Kvinge
d204875f72 globalshortcut-x11: Fix minor code issues 2022-04-06 21:22:10 +02:00
Strawbs Bot
c690e73b1a Update translations 2022-04-05 01:02:10 +02:00
Jonas Kvinge
b5d39c5f21 Context: Remove use of custom font
Fixes #932
2022-04-04 20:26:38 +02:00
Strawbs Bot
7f8834cb04 Update translations 2022-04-04 01:02:50 +02:00
Jonas Kvinge
0dab7e293c GstEngine: Append "2" to wasapi2sink output description 2022-04-02 01:37:43 +02:00
Jonas Kvinge
8f016880af globalshortcut-win: Register 0-9 as num keys too 2022-04-02 00:43:41 +02:00
Jonas Kvinge
f471462a84 AnalyzerBase: Refactor code 2022-04-01 22:30:22 +02:00
Strawbs Bot
58eec8df1e Update translations 2022-03-30 01:02:21 +02:00
Jonas Kvinge
2655b8b43a TagReaderTagLib: Replace use of QByteArray::count() 2022-03-29 01:43:07 +02:00
Jonas Kvinge
ea86c043a4 AlsaPCMDeviceFinder: Fix use of deleted memory 2022-03-29 01:23:35 +02:00
Strawbs Bot
c1faa616bc Update translations 2022-03-29 01:04:21 +02:00
Strawbs Bot
a68bf5a30d Update translations 2022-03-28 01:02:14 +02:00
Jonas Kvinge
9568b8e0e5 Add hls to nsi 2022-03-28 00:34:20 +02:00
Jonas Kvinge
b34321ef87 GlobalShortcutsManager: Translate shortcuts
Fixes #928
2022-03-27 14:31:58 +02:00
Strawbs Bot
4971f1c5bf Update translations 2022-03-27 01:04:49 +01:00
Maxime Haselbauer
962b52bd5b Add save all playlists action 2022-03-26 22:38:21 +01:00
Jonas Kvinge
9449bfa414 Update protobuf in nsi 2022-03-26 21:02:56 +01:00
Strawbs Bot
5b8e9066c6 Update translations 2022-03-26 01:03:00 +01:00
Jonas Kvinge
8690be7fd2 Use separate sparkle feed for mingw and msvc 2022-03-25 21:38:37 +01:00
Jonas Kvinge
497267016b Turn on git revision 2022-03-25 01:22:31 +01:00
Jonas Kvinge
0468f850c2 Release 1.0.3 2022-03-24 21:23:36 +01:00
Jonas Kvinge
b9e7d4e30c Update Changelog 2022-03-24 21:21:24 +01:00
Jonas Kvinge
0e7734b555 Update README.md 2022-03-24 20:32:50 +01:00
Jonas Kvinge
e81dcce5b3 Update nsi for msvc dependencies 2022-03-23 19:13:40 +01:00
Strawbs Bot
38bd1f7e1c Update translations 2022-03-23 01:16:48 +01:00
Jonas Kvinge
36ad9704a2 Update libspeex for msvc in nsi 2022-03-22 21:24:54 +01:00
Jonas Kvinge
a6c05df362 Formatting 2022-03-22 21:19:59 +01:00
Jonas Kvinge
f6b70fda71 Formatting 2022-03-22 21:09:05 +01:00
Jonas Kvinge
8cb4e75f70 Update nsi for msvc dependencies 2022-03-22 17:32:49 +01:00
Jonas Kvinge
da1815ac2b Qobuz: Fix albums request limited to 50 albums
Fixes #922
2022-03-21 21:54:27 +01:00
Jonas Kvinge
f7357f2d10 Add libbrotlienc.dll to nsi 2022-03-21 21:30:33 +01:00
Jonas Kvinge
d9c92c5ddd CI: Use new MSVC dependencies 2022-03-21 18:37:31 +01:00
Jonas Kvinge
c82bdb6405 Add musepack, bs2b, faac and faad to nsi for msvc 2022-03-19 20:15:56 +01:00
Jonas Kvinge
eec8ee5830 Add qtsparkle for msvc in nsi 2022-03-17 14:46:12 +01:00
Strawbs Bot
e67eb3c0d8 Update translations 2022-03-17 01:02:02 +01:00
Jonas Kvinge
9c101759f6 CI: Update CI for MSVC dependencies 2022-03-17 00:06:18 +01:00
Jonas Kvinge
a55ee92590 Update nsi for MSVC library changes 2022-03-17 00:05:27 +01:00
Jonas Kvinge
5ccfc97dab Database: Fix schema update with Windows line-endings 2022-03-17 00:04:12 +01:00
Jonas Kvinge
d6dd88ec3d Add registry inetc plugin to nsi 2022-03-14 22:13:14 +01:00
Strawbs Bot
8557d83599 Update translations 2022-03-13 01:02:01 +01:00
Jonas Kvinge
94cf1f8698 macdeployqt: Remove optional plugins 2022-03-11 20:45:15 +01:00
Strawbs Bot
9ada35c3a3 Update translations 2022-03-11 01:03:01 +01:00
Jonas Kvinge
79b0c906fa CI: Fix path to gst-plugin-scanner for macOS 2022-03-10 22:14:51 +01:00
Jonas Kvinge
a0688f1dba CI: Fix path to gst-plugin-scanner for macOS 2022-03-10 21:09:12 +01:00
Jonas Kvinge
f91e8fecee CI: Reduce installed macports packages 2022-03-10 16:24:01 +01:00
Jonas Kvinge
1b363babe2 Use our own macOS dependencies 2022-03-10 15:51:07 +01:00
Jonas Kvinge
73843cb54d Switch back to libsoup 2 in nsi
libsoup 3.0 currently has issues with gstreamer
2022-03-08 21:53:10 +01:00
Jonas Kvinge
a2ccfc2116 Add libgioopenssl.dll to nsi 2022-03-07 22:32:50 +01:00
Jonas Kvinge
fe104e2bad Update gstreamer plugins in nsi 2022-03-07 19:28:38 +01:00
Jonas Kvinge
35e3e9f4ff RPM spec: Update release for OpenMandriva 2022-03-06 14:05:07 +01:00
Jonas Kvinge
b2a1cd9716 CI: Add openSUSE Leap 15.4 2022-03-05 21:26:51 +01:00
Jonas Kvinge
14f58eae4b CI: Add Fedora 36 2022-03-05 21:26:24 +01:00
Jonas Kvinge
5cec000618 Add fdk-aac to nsi 2022-03-05 12:15:48 +01:00
Jonas Kvinge
4805a5287d CI: Remove Ubuntu Hirsute 2022-03-05 03:27:09 +01:00
Jonas Kvinge
4789dc5b30 Add bs2b to nsi 2022-03-05 01:55:05 +01:00
Jonas Kvinge
5a35099043 Add support for bs2b
Improve headphone listening of stereo audio records
2022-03-05 01:30:49 +01:00
Strawbs Bot
4cd0128919 Update translations 2022-03-02 01:02:32 +01:00
Jonas Kvinge
61e9b80f67 Song: Remove playlists from accepted file extensions
Fixes #909
2022-03-01 21:26:08 +01:00
Strawbs Bot
dcd881ba6c Update translations 2022-02-23 01:02:20 +01:00
Strawbs Bot
d40a67ce68 Update translations 2022-02-22 01:02:35 +01:00
Jonas Kvinge
1c1e7ca62a nsi: Move libmpg123-0.dll to common files 2022-02-21 20:47:11 +01:00
Jonas Kvinge
d3831d511b nsi: Move libmpg123-0.dll to common files 2022-02-21 20:45:26 +01:00
Jonas Kvinge
0942e93144 Add mpg123 plugin to nsi 2022-02-21 20:33:10 +01:00
Jonas Kvinge
98d3eba8e8 AlbumCoverLoader: Use char for QString::remove() 2022-02-21 20:22:47 +01:00
Jonas Kvinge
ff3db03696 AlbumCoverLoader: Remove slash and backslash from cover filename
Fixes #903
2022-02-21 20:21:06 +01:00
Strawbs Bot
3608c31d22 Update translations 2022-02-21 01:03:09 +01:00
Jonas Kvinge
8d504d9cee Turn on git revision 2022-02-20 21:47:24 +01:00
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
Jonas Kvinge
a45cb25002 Release 1.0.1 2022-01-08 15:20:32 +01:00
Jonas Kvinge
21ec116769 Update Changelog 2022-01-08 14:42:53 +01:00
Jonas Kvinge
1d4775a94b Simplify stylesheet on QToolButton 2022-01-08 13:18:54 +01:00
Jonas Kvinge
4cde9a7e9e Fix padding on toolbuttons with menu button popup
Fixes #795
2022-01-08 13:10:48 +01:00
Jonas Kvinge
709ba72777 CollectionWatcher: Exclude hidden files 2022-01-07 21:16:38 +01:00
Strawbs Bot
0e56b8c575 Update translations 2022-01-07 01:05:42 +01:00
Jonas Kvinge
558a087e37 CollectionWatcher: Resume collection scan when adding directory 2022-01-06 23:29:20 +01:00
Jonas Kvinge
7d96fe8b65 CollectionWatcher: Abort collection scan on exit 2022-01-06 23:14:10 +01:00
Jonas Kvinge
2f3e8986ab AlbumCoverChoiceController: Clear manually set cover when setting embedded cover
Possible fix for #858
2022-01-06 02:14:33 +01:00
Strawbs Bot
df359ba0fa Update translations 2022-01-06 01:09:25 +01:00
Jonas Kvinge
31fa60884f Tagreader: Fix comment 2022-01-06 00:08:48 +01:00
Jonas Kvinge
15be227920 TagReader: Various fixes to embedded cover handling
- Add support for saving embedded for Opus
- Fix deleting cover for Ogg Vorbis, Opus and Speex
- Don't load empty covers
2022-01-06 00:06:20 +01:00
Jonas Kvinge
fdedfd54c7 Moodbar: Disable moodbar loader for CUE songs 2022-01-05 18:59:14 +01:00
Strawbs Bot
7d55eb4b44 Update translations 2022-01-03 12:42:15 +01:00
Jonas Kvinge
61ac7ae31e GeniusLyricsProvider: Move index past start tag 2022-01-02 21:47:16 +01:00
Jonas Kvinge
353e141036 Add Qt 5 warning 2022-01-02 14:48:45 +01:00
Jonas Kvinge
cb4332842f Save MP4 tags as UTF-8
Fixes #830
2022-01-02 02:47:42 +01:00
Jonas Kvinge
004d219c97 CollectionWatcher: Fix notify on path change, improve debug output
Possible fix for #860
2022-01-01 01:32:41 +01:00
Jonas Kvinge
94561e6815 Windows: Include ibgstxingmux.dll in installer 2021-12-27 18:12:55 +01:00
Jonas Kvinge
ce3af4961b GeniusLyricsProvider: Fix parsing of different HTML pages 2021-12-19 20:59:38 +01:00
Jonas Kvinge
bbd81e7d9c kglobalaccel: Attempt to register media shortcuts too 2021-12-18 20:18:37 +01:00
Jonas Kvinge
8b1d198efd Remove unused Avahi 2021-12-18 19:46:23 +01:00
Jonas Kvinge
7a3bafc961 Add Tumbleweed to CI 2021-12-18 13:00:33 +01:00
Jonas Kvinge
512eed9b04 Remove CMake release config from strawberry.spec 2021-12-14 22:16:44 +01:00
Strawbs Bot
38adf640e9 Update translations 2021-12-13 01:02:34 +01:00
Jonas Kvinge
f4d8d73970 Always save metadata in playlist for Tidal, Qobuz and Subsonic songs
Fixes #851
2021-12-12 01:43:46 +01:00
Strawbs Bot
5a50285dee Update translations 2021-12-08 12:29:11 +01:00
Jonas Kvinge
ca4ea0719f Playlist: Fix updating summary after reloading items
Fixes #848
2021-12-08 01:35:49 +01:00
Strawbs Bot
4c6251bf28 Update translations 2021-11-29 01:02:44 +01:00
Alexey Vazhnov
22c12c7366 Add dist/scripts/import-from-clementine.sh
Shell script for importing database from Clementine.

Fixes #838
Fixes #248
2021-11-28 13:14:45 +01:00
Jonas Kvinge
8f49d1591f Support more CUE filenames
Fixes #835
2021-11-27 20:28:00 +01:00
Jonas Kvinge
a97dbab2ae CollectionWatcher: Rename fileinfo variable 2021-11-27 19:25:25 +01:00
Jonas Kvinge
4cb8261d3b CueParser: Fix parsing tracks with 1-digit minutes
Fixes #836
2021-11-27 18:15:03 +01:00
Strawbs Bot
059e2d740f Update translations 2021-11-22 01:02:26 +01:00
Strawbs Bot
587d1c9d74 Add Spanish (Mexico) 2021-11-20 17:28:02 +01:00
Strawbs Bot
ab56c96170 Add Spanish (Argentina) 2021-11-20 17:27:23 +01:00
Strawbs Bot
efa4270429 Add Spanish/Spain 2021-11-20 17:14:43 +01:00
Strawbs Bot
0fbe5d888a Update translations 2021-11-13 01:02:59 +01:00
Strawbs Bot
b68f81179e Update translations 2021-11-11 01:05:36 +01:00
Jonas Kvinge
6a8c1af5f9 GstEnginePipeline: Set port-pattern for jackaudiosink 2021-11-11 00:58:00 +01:00
Jonas Kvinge
98f287559b GstEngine: Allow custom device for jackaudiosink 2021-11-11 00:58:00 +01:00
Strawbs Bot
1a53d85f6a Update translations 2021-11-10 01:19:03 +01:00
Jonas Kvinge
05b168aa04 Fix incorrect playlist column filesize for streams 2021-11-09 21:16:44 +01:00
Jonas Kvinge
a68d856074 AlbumCoverLoader: Change ID to quint64 2021-11-09 20:48:43 +01:00
Jonas Kvinge
d5dac9c6cc Add musicbrainz icon 2021-11-09 20:07:48 +01:00
Adam Hill
e9f7f42c03 PlaylistView: Fix for currenttrack_bar blocky rendering 2021-11-09 19:45:41 +01:00
Uint
7b8265d4a3 Prevent filtering when filter toolbar is hidden, clear when disabled 2021-11-09 19:41:23 +01:00
Jonas Kvinge
5715f4c2cb Remove use of macros in Song and TagReader 2021-11-09 19:34:43 +01:00
Jonas Kvinge
350debb66c Utilities: Add static_cast in Hmac() 2021-11-09 19:34:43 +01:00
Jonas Kvinge
267cd3660b InternetSearchSortModel: Replace use of macro 2021-11-09 19:34:43 +01:00
Jonas Kvinge
bc1c0c3c6d SqlQuery: Add more BindValue methods 2021-11-09 19:34:43 +01:00
Jonas Kvinge
c420f69da8 SqlRow: Replace class with a new that takes values by column field name 2021-11-09 19:34:43 +01:00
Jonas Kvinge
2151d96303 Use PlaylistItemList 2021-11-09 19:34:43 +01:00
Jonas Kvinge
c48c65d0ce InternetService: Change parameters to const 2021-11-09 19:34:43 +01:00
Jonas Kvinge
1c0b706b94 TranscoderOptionsVorbis: Remove use of macros 2021-11-09 19:34:43 +01:00
Jonas Kvinge
2dca3d6f5a gstfastspectrum: Remove some macros 2021-11-09 19:34:43 +01:00
Jonas Kvinge
0992636f8c playlistparsers: Change qt_endl macro to constexpr 2021-11-09 19:34:43 +01:00
Jonas Kvinge
86d3f2b4ed SliderSlider: Remove unused macros 2021-11-09 19:34:43 +01:00
Jonas Kvinge
b78b4038f6 InternetService: Fix overloaded signal 2021-11-09 19:34:43 +01:00
Jonas Kvinge
84c14349dc ContextAlbumsModel: Remove unused SqlRow 2021-11-09 19:34:43 +01:00
Strawbs Bot
9916e34006 Update translations 2021-11-09 01:05:40 +01:00
Jonas Kvinge
a729b42e5d Tidal: Fix reading keyId 2021-11-08 20:44:12 +01:00
Jonas Kvinge
01f8129ed0 Improve URL handler, return error for encrypted Tidal streams 2021-11-08 20:25:22 +01:00
Jonas Kvinge
fd85763fb4 Tidal: Make sure OAuth is enabled when sending access token 2021-11-08 19:47:17 +01:00
Jonas Kvinge
c278ffe2cb CI: Remove Windows Qt 5 builder 2021-11-05 21:41:30 +01:00
Jonas Kvinge
902c76a781 Remove Qt 5 support from Windows nsi 2021-11-05 21:38:09 +01:00
Jonas Kvinge
4daed0070a WorkerPool: Add missing config.h include 2021-11-04 00:42:49 +01:00
Jonas Kvinge
a4d055b3ac Remove obsolete cmake version check 2021-11-04 00:05:06 +01:00
Jonas Kvinge
e6ae6c6f04 Remove Fedora 33 2021-11-03 22:11:17 +01:00
Jonas Kvinge
de54ceeb40 Add Fedora 35 to CI 2021-11-03 21:21:12 +01:00
Strawbs Bot
77fe00df30 Update translations 2021-11-03 01:02:23 +01:00
Strawbs Bot
4ae3e63dea Update translations 2021-11-01 01:20:05 +01:00
Jonas Kvinge
3329839dbe CollectionWatcher: Add overwrite_rating_ to initialization list 2021-10-31 23:26:22 +01:00
Jonas Kvinge
ca10920bb5 Add option for overwriting database rating 2021-10-31 23:24:32 +01:00
Jonas Kvinge
b41957ce5c Add back css style for QToolButton only on macOS
Fixes #819
2021-10-31 16:55:33 +01:00
Jonas Kvinge
3db6699018 WorkerPool: Use variable 2021-10-31 14:48:42 +01:00
Jonas Kvinge
5284ca90ef Forward messages from tagreader worker process on Windows 2021-10-31 13:51:23 +01:00
Jonas Kvinge
628cdff4fa TagReaderTagParser: Return false from SaveSongPlaycountToFile 2021-10-31 13:19:52 +01:00
Jonas Kvinge
af0c6f9233 Logging: Use stdout unless critical or fatal, and flush stream 2021-10-31 13:18:26 +01:00
Jonas Kvinge
7697bbfa4e Logging: Formatting 2021-10-31 13:18:26 +01:00
buckmelanoma
642a455a9c Add icon mappings for download and scrobble
Adds mappings for download (Cover Manager) and scrobble (Import data from last.fm):
2021-10-31 02:23:15 +01:00
Strawbs Bot
6abfa2859b Update translations 2021-10-31 01:20:21 +02:00
buckmelanoma
20c2225d8f Add icon names for missing Tools menu entries
I noticed the abort_collection_scan and console menu entries were missing matching icons.  This change adds appropriate icons for each action.
2021-10-31 00:37:57 +02:00
Jonas Kvinge
5e7759b697 Utilities: Change return type for GetThreadId and SetThreadIOPriority to long 2021-10-31 00:26:02 +02:00
Jonas Kvinge
1ce8d2b31d RadioView: Remove overloaded signal 2021-10-31 00:24:16 +02:00
Jonas Kvinge
9fbecb5af6 macdeployqt: Use static QFile::exists() 2021-10-30 19:23:08 +02:00
Jonas Kvinge
1223469be9 Song: Add playcount and rating to Song::IsMetadataEqual() 2021-10-30 19:06:46 +02:00
Jonas Kvinge
5eae3ddd8a Use float for rating 2021-10-30 18:53:14 +02:00
Jonas Kvinge
3d0b6e6ea1 TagReader: Check for valid file times
Fixes #815
2021-10-30 17:57:13 +02:00
Jonas Kvinge
c6c53548ac GstEnginePipeline: Return true from BusCallback 2021-10-30 17:55:18 +02:00
Jonas Kvinge
3efe2d1e05 Initialize to 0 2021-10-30 17:10:05 +02:00
buckmelanoma
7c87b53517 PlaylistView: Use SmoothPixmapTransform when drawing play icon
Fixes #794
2021-10-30 03:36:17 +02:00
Jonas Kvinge
a461c97bcf IconLoader: Log when icon fails to load 2021-10-30 03:34:52 +02:00
Jonas Kvinge
67a6d6c1e3 LyricsFetcher: Change request ID to quint64 2021-10-30 03:15:03 +02:00
Jonas Kvinge
8b8e427a2b DeleteFiles: Fix compile with older Qt versions 2021-10-30 03:13:55 +02:00
Jonas Kvinge
7d5c263ab2 FHT: Change to static_cast double 2021-10-30 03:13:12 +02:00
Jonas Kvinge
79ac53b2d9 Fix narrowing conversions 2021-10-30 02:21:29 +02:00
Jonas Kvinge
a704412dee ContextAlbumsModel: Use const_iterator 2021-10-30 02:05:55 +02:00
Jonas Kvinge
24e2338769 ScrobblingAPI20: Add clazy:exclude=range-loop-detach 2021-10-30 02:02:37 +02:00
Jonas Kvinge
bc240f82ef SomaFMService: Add clazy:exclude=function-args-by-ref 2021-10-30 02:01:48 +02:00
Jonas Kvinge
a2ad68406d RadioView: Add clazy:exclude=reserve-candidates 2021-10-30 02:01:14 +02:00
Jonas Kvinge
3d807d2331 FilterParser: Add iter_ and end_ to initialization list 2021-10-30 02:00:26 +02:00
Jonas Kvinge
e6a7b484ba OSDBase: Remove redundant initialization 2021-10-30 01:59:51 +02:00
Jonas Kvinge
a62371829f Add ui_ to initialization list 2021-10-30 01:58:47 +02:00
Jonas Kvinge
fb98336713 Udisks2Lister: Remove redundant initialization 2021-10-30 01:58:01 +02:00
Jonas Kvinge
ebadb4db0a Use const_iterator 2021-10-30 01:57:12 +02:00
Jonas Kvinge
9a480eb710 SqlQuery: Make QSqlDatabase parameter const reference 2021-10-30 01:33:16 +02:00
Jonas Kvinge
03ecde8b83 Add default to switch 2021-10-30 01:08:35 +02:00
Strawbs Bot
0291b78bfa Update translations 2021-10-30 01:02:38 +02:00
Jonas Kvinge
377e6fad25 gstmoodbar: Formatting 2021-10-30 00:48:58 +02:00
Jonas Kvinge
e75c955a68 mac_startup: Remove unused functions 2021-10-30 00:48:58 +02:00
buckmelanoma
6df356327d Add 2px of padding for edit-clear icon
edit-clear icon tends to sit on left side of frame.  adding 2 px makes it look nicer.
2021-10-29 17:52:43 +02:00
buckmelanoma
7a57586f90 Map edit-clear-list system icons
Use system edit-clear-list icons when enabled instead of defaulting to edit-clear-locationbar-ltr.png
2021-10-29 17:52:43 +02:00
Strawbs Bot
1e2bad270d Update translations 2021-10-29 01:02:58 +02:00
Strawbs Bot
688d983b25 Update translations 2021-10-28 01:02:41 +02:00
Jonas Kvinge
fa834a76ef ContextView: Avoid unnecessary album resize 2021-10-27 22:16:48 +02:00
Jonas Kvinge
5cb88efc38 Remove debug line 2021-10-26 23:54:27 +02:00
Jonas Kvinge
6b64c43851 TagReaderTagLib: Read FMPS_Rating for MPEG ID3v2 tag 2021-10-26 01:10:01 +02:00
Jonas Kvinge
704e6c5448 TagReaderTagLib: Use double for ratings to match Song 2021-10-26 00:24:03 +02:00
Jonas Kvinge
072d7379df TagReaderTagLib: Add checks for nullptr 2021-10-26 00:02:36 +02:00
Strawbs Bot
df1b756a43 Update translations 2021-10-25 01:13:11 +02:00
Jonas Kvinge
30269d9d95 Organize: Remove unused "mark as listened" option 2021-10-24 23:19:01 +02:00
Jonas Kvinge
d29a1de980 Allow users to select native notifications on Windows
Setting will fallback to system tray notifications which are
native notifications on Windows.
2021-10-24 23:09:20 +02:00
Jonas Kvinge
57f5ccff81 InternetSearchView: Change tool button popup mode back to InstantPopup 2021-10-24 22:05:10 +02:00
buckmelanoma
69374bfa11 Revert collection options QToolButton mode
Changing this button type fixed the arrow problem but has a side effect of making the button only clickable on the arrow portion.   #795 fixed the issue with styling on QToolButtons and ends up fixing this issue too.  Therefore the change to MenuButtonPopup should be reverted in order to restore the original functionality.
2021-10-24 20:11:27 +02:00
Jonas Kvinge
d9fd330216 Update Changelog 2021-10-24 18:32:14 +02:00
Jonas Kvinge
312f62d98f Fix stop after this track button with Qt 6
Fixes #795
2021-10-24 18:15:42 +02:00
buckmelanoma
0d408055b2 Add settings to enable/disable playlist toolbar 2021-10-24 17:04:35 +02:00
Jonas Kvinge
496ae42d72 EditTagDialog: Change return to continue in EditTagDialog::SongRated 2021-10-24 16:11:53 +02:00
Jonas Kvinge
3ab86543ad Add support for saving playcounts and ratings to tags 2021-10-24 16:08:17 +02:00
Jonas Kvinge
ce7926cfa4 Update libffi in nsi 2021-10-23 11:35:52 +02:00
Strawbs Bot
48c81b188c Update translations 2021-10-23 01:02:17 +02:00
Luna
21b241bbbe add release info 2021-10-22 23:25:19 +02:00
Luna
934d6fc267 add oars content rating 2021-10-22 23:25:19 +02:00
Luna
a0ce2daa2e add type to appdata.xml 2021-10-22 23:25:19 +02:00
Jonas Kvinge
006d77239b Update protobuf in nsi 2021-10-21 18:40:04 +02:00
Jonas Kvinge
303d31bde7 Update Windows dependencies 2021-10-19 23:56:24 +02:00
Strawbs Bot
737fbeccde Update translations 2021-10-19 01:02:20 +02:00
Jonas Kvinge
ec17dc9830 TagReaderClient: Sort functions 2021-10-18 23:15:50 +02:00
Strawbs Bot
0f710ea3be Update translations 2021-10-18 01:01:58 +02:00
Jonas Kvinge
bd4eec4527 Song: Only merge user set playcount and rating if set
Fixes #790
2021-10-18 00:39:26 +02:00
Jonas Kvinge
c78252e0d5 Add dates to Changelog
Fixes #803
2021-10-17 20:30:57 +02:00
Jonas Kvinge
b1f70982bf Make playlist column text elided
Fixes #801
2021-10-17 02:33:26 +02:00
Strawbs Bot
6128fb4f19 Update translations 2021-10-17 01:10:41 +02:00
Jonas Kvinge
ee915254e7 Song: Sort code in Song::ToProtobuf() 2021-10-17 00:34:33 +02:00
Jonas Kvinge
d835d4aae6 Add rating to Song::InitFromProtobuf and Song::ToProtobuf 2021-10-17 00:27:31 +02:00
Jonas Kvinge
5945d0ebee Read rating from tags
Fixes #790
2021-10-16 23:33:03 +02:00
Jonas Kvinge
3d3aacdcb1 InternetSearchView: Change popupmode for toolbutton to QToolButton::MenuButtonPopup 2021-10-16 22:41:14 +02:00
Jonas Kvinge
c3ce6cff72 GstEngine: Move CreateElement() to GstEnginePipeline 2021-10-16 21:28:56 +02:00
Jonas Kvinge
6d7a01fb4e Logging: Remove custom debug level for gst pipeline 2021-10-16 21:25:36 +02:00
Jonas Kvinge
8582e09e73 CI: Remove Ubuntu Groovy and add Impish 2021-10-16 14:30:45 +02:00
buckmelanoma
90744f2965 Fix filter menu button arrow overlap
Change collection filter menu button's popupMode to MenuButtonPopup to prevent arrow overlapping with button icon
2021-10-16 13:21:15 +02:00
Jonas Kvinge
03d0776fdc Turn on git revision 2021-10-15 00:02:06 +02:00
Jonas Kvinge
9d18f40c5f Release 1.0.0 2021-10-14 20:50:41 +02:00
Jonas Kvinge
47e771ee37 Update Changelog 2021-10-14 20:50:20 +02:00
Jonas Kvinge
20760dcf0e Fix FreeBSD CI 2021-10-13 19:30:46 +02:00
Strawbs Bot
2edf12e4cd Update translations 2021-10-13 01:16:38 +02:00
Jonas Kvinge
c946c1d1c4 Player: Don't preload next song while playing module music
Workaround bug in GStreamer

Fixes #787
Fixes #772
2021-10-12 22:59:23 +02:00
Jonas Kvinge
bb5fe5a6d1 Add Song::is_module_music() 2021-10-12 22:58:39 +02:00
Jonas Kvinge
814d2fa9fc MainWindow: Use Song::PrettyTitle() in debug message 2021-10-12 22:57:59 +02:00
Jonas Kvinge
10d89cb6a6 FileView: Add module music formats to file filter 2021-10-12 21:44:30 +02:00
Jonas Kvinge
a6569d09ac Read XM and IT module music 2021-10-12 21:43:46 +02:00
staticssleever668
b38ad81928 Remove use of C-style casts 2021-10-12 18:50:17 +02:00
Jonas Kvinge
637772f8f0 GstEnginePipeline: Convert S24_32LE for analyzer 2021-10-12 18:46:12 +02:00
Jonas Kvinge
0093eb6c2c GstEnginePipeline: Refactor code 2021-10-12 18:36:58 +02:00
Jonas Kvinge
f3b70d1cb2 GstEnginePipeline: Rename variable 2021-10-12 18:36:13 +02:00
Strawbs Bot
5152f57f6e Update translations 2021-10-11 01:02:01 +02:00
Jonas Kvinge
e6112a311d Add openmpt to nsi 2021-10-10 23:31:08 +02:00
Jonas Kvinge
e069d069d2 GstEngine: Remove unused variables 2021-10-10 21:12:31 +02:00
Jonas Kvinge
fd74bbc868 Remove unused GstElementDeleter 2021-10-10 16:33:07 +02:00
Strawbs Bot
3b37aea3da Update translations 2021-10-10 01:02:39 +02:00
Jonas Kvinge
2fd4bbbd49 Update Changelog 2021-10-09 22:25:27 +02:00
Jonas Kvinge
17226b524b SubsonicSettingsPage: Rename HTTP2 to HTTP/2 2021-10-09 16:38:13 +02:00
Jonas Kvinge
f38b33ee50 Scrobbler: Use seconds instead of minutes for submit delay 2021-10-09 14:05:05 +02:00
Jonas Kvinge
0da0e0a6db macdeployqt: Fix typo 2021-10-09 01:50:19 +02:00
Jonas Kvinge
de2b6d1dee macdeployqt: Replace QSet with QList 2021-10-09 01:50:19 +02:00
Jonas Kvinge
c9a501ddc8 Update README.md 2021-10-09 00:39:11 +02:00
Jonas Kvinge
c5babbbb22 Update README.md 2021-10-09 00:34:28 +02:00
Jonas Kvinge
1fd0d1a330 macdeployqt: Remove FinalCheck from header 2021-10-08 23:47:33 +02:00
Jonas Kvinge
84d9b30fec macdeployqt: Replace bearer with tls 2021-10-08 23:40:41 +02:00
Jonas Kvinge
d0f1522f0d GstEnginePipeline: Use gst_bus_remove_watch to remove bus watch 2021-10-08 23:39:29 +02:00
Jonas Kvinge
6b2e25122d nsi: Remove tls dir 2021-10-07 23:48:23 +02:00
Strawbs Bot
ce3026f91c Update translations 2021-10-06 01:02:49 +02:00
Jonas Kvinge
4b384b3b59 Update ccpp.yml 2021-10-04 11:51:16 +02:00
Strawbs Bot
da7605a234 Update translations 2021-10-03 01:08:24 +02:00
Jonas Kvinge
3abdec1b91 Add qopensslbackend.dll to nsi and CI 2021-10-01 23:52:59 +02:00
Strawbs Bot
ef34199887 Update translations 2021-10-01 01:02:14 +02:00
Jonas Kvinge
08eca88e2f Add require for qt6-network-tls to RPM spec 2021-09-30 22:54:08 +02:00
Strawbs Bot
4636cc74dc Update translations 2021-09-29 01:03:09 +02:00
Jonas Kvinge
4cc54a2f05 PlaylistTabBar: Hide star option with clicked outside of a tab 2021-09-28 22:19:31 +02:00
Jonas Kvinge
9bd728889b PlaylistTabBar: Add right click option to star playlist
Fixes #782
2021-09-28 22:14:25 +02:00
Adam Hill
d870115467 Set SmoothPixmapTransform for playing-widget and context album art display 2021-09-28 21:52:31 +02:00
Jonas Kvinge
2b445fb563 StyleSheetLoader: Cleanup code and add workaround for macOS dark theme
Fixes #778
2021-09-28 17:25:22 +02:00
Strawbs Bot
44a3bad278 Update translations 2021-09-28 01:12:34 +02:00
Jonas Kvinge
8d2615547d Add keyboard shortcut for focusing search fields
Fixes #779
2021-09-27 21:42:30 +02:00
Jonas Kvinge
3292db8b77 Add missing override 2021-09-27 21:41:45 +02:00
Jonas Kvinge
8c6ad52437 Organize: Update collection directory ID and song path immediately
Fixes #781
2021-09-27 19:30:31 +02:00
Jonas Kvinge
62e53b53f0 Replace assert with Q_ASSERT 2021-09-27 19:30:31 +02:00
Strawbs Bot
35db157617 Update translations 2021-09-27 01:22:03 +02:00
Jonas Kvinge
cfb137a94b DeviceDatabaseBackend: Fix GetAllDevices() 2021-09-26 21:38:06 +02:00
Jonas Kvinge
9b4a33a612 MPris2: Remove static 2021-09-26 20:14:11 +02:00
Jonas Kvinge
918b7c1e03 Move chrono include 2021-09-26 20:06:04 +02:00
Jonas Kvinge
8fb354705c Update Changelog 2021-09-26 19:03:01 +02:00
Jonas Kvinge
b3826064b7 Bump device schema version 2021-09-26 18:35:03 +02:00
Jonas Kvinge
acba68dab9 MergedProxyModel: Add FIXME 2021-09-26 18:34:44 +02:00
Jonas Kvinge
32ea709350 Subsonic: Turn off HTTP/2 setting by default 2021-09-26 16:50:41 +02:00
Jonas Kvinge
c15dfc7c5d Subsonic: Make HTTP/2 setting visible with Qt 5.15.0 and higher 2021-09-26 16:49:53 +02:00
Jonas Kvinge
92f6a0c6c8 Add mod and s3m to filetypes 2021-09-26 16:23:02 +02:00
Jonas Kvinge
0235be538b Moodbar: Check for nullptr 2021-09-26 14:42:24 +02:00
Jonas Kvinge
abf19e7a27 Moodbar: Use gst_element_link_many 2021-09-26 14:42:05 +02:00
Jonas Kvinge
1d3540dca6 Remove unused MoodbarPipeline::IsAvailable function 2021-09-26 14:41:36 +02:00
Jonas Kvinge
ddfc9d911b Extend unit tests 2021-09-26 01:15:17 +02:00
Strawbs Bot
b952256988 Update translations 2021-09-26 01:02:42 +02:00
Jonas Kvinge
71868936d1 Subsonic: Use common static function CreateUrl() 2021-09-25 01:18:40 +02:00
Strawbs Bot
23ef4fb132 Update translations 2021-09-22 01:04:55 +02:00
Jonas Kvinge
f74f2ca3ef Subsonic: Remove redundant null check 2021-09-21 01:36:38 +02:00
Jonas Kvinge
f4f005cdd6 Subsonic: Fix auth method for URL handler 2021-09-21 01:30:01 +02:00
Jonas Kvinge
3137652280 Use ParamList 2021-09-21 01:30:01 +02:00
Strawbs Bot
88c6f0340a Update translations 2021-09-21 01:01:57 +02:00
Strawbs Bot
86146c7292 Update translations 2021-09-20 01:20:57 +02:00
Tom Kranz
fad39b6d67 Store Tidal MPEG-DASH file in data uri 2021-09-19 19:56:22 +02:00
Jonas Kvinge
09a9330f3e Show error when reading or saving album covers 2021-09-19 19:31:34 +02:00
Jonas Kvinge
d2d7f32c45 Add new method for updating songs based on song ID
Show status updating database.

Fixes #750
2021-09-19 15:43:36 +02:00
Tom Kranz
120b18b399 Use XSPF image elements as manually set artwork 2021-09-19 13:40:42 +02:00
Jonas Kvinge
32b9e6b73d Make error dialog larger 2021-09-18 17:12:59 +02:00
Jonas Kvinge
8d6e5272b9 Update protobuf in nsi 2021-09-17 01:35:20 +02:00
Strawbs Bot
b6f90a9715 Update translations 2021-09-15 01:02:18 +02:00
Jonas Kvinge
e3d0b777fc Add algorithm include 2021-09-14 22:57:09 +02:00
Jonas Kvinge
79a8450462 SpotifyCoverProvider: Fix trying to set timer to minus value 2021-09-14 22:12:28 +02:00
EmmanuelMess
1a967597e8 Fix roundings with lround() 2021-09-14 21:29:29 +02:00
Jonas Kvinge
d5b0794b00 Remove unneeded this 2021-09-13 20:49:33 +02:00
Jonas Kvinge
d78ee3d62b Fix total playlist length for songs without length 2021-09-13 20:46:55 +02:00
Strawbs Bot
03037a9a6b Update translations 2021-09-13 01:12:16 +02:00
Emmanuel
0637b65846 Fix a few narrowing conversions (#761)
* Fix narrowing conversion in album cover loader

* Fix narrowing conversions in discogs cover provider

* Fix narrowing conversions in spotify cover provider

* Add explicit conversion in moodbarbuilder

* Fix narrowing conversions in osd dbus

* Make WordyTimeNanosec use unsigned quint64

* Fix narrowing conversions in song

* Fix narrowing conversions in qobuz stream url request

* Make ConnectionInfo.msgLen use unsigned quint64

* Make AnalizerBase.timeout to signed int

* Fix narrowing conversions in album cover fetcher

* Make fht type be unsigned int

* Correct for type in blockanalizer and use std::fill where possible

* Revert "Fix narrowing conversions in song"

This reverts commit 3de291394d.
2021-09-12 21:24:22 +02:00
Jonas Kvinge
e77e914f44 Escape ampersands in playlist tabs
Fixes #760
2021-09-12 21:19:58 +02:00
EmmanuelMess
68c44daef2 Fix SingleApplication static functions called from instance 2021-09-10 18:44:36 +02:00
Strawbs Bot
8ca0b54b18 Update translations 2021-09-10 01:21:33 +02:00
Jonas Kvinge
b77d01baca CI: Use new image for Windows build 2021-09-09 23:06:59 +02:00
Jonas Kvinge
cd509bbbdc Update nsi for OpenSSL 3 2021-09-09 22:05:53 +02:00
Jonas Kvinge
24a3ac9811 Use static QMetaObject::invokeMethod 2021-09-09 21:53:14 +02:00
Jonas Kvinge
d35d3aabc3 Show error dialog for failed SQL queries 2021-09-09 21:45:46 +02:00
Jonas Kvinge
9e624a6c0d Remove openSUSE 15.2 from CI 2021-09-07 01:16:02 +02:00
Strawbs Bot
9823cd25d2 Update translations 2021-09-07 01:01:55 +02:00
Jonas Kvinge
416a8c8f5d Context: Hide albums widget in constructor 2021-09-07 00:10:05 +02:00
Strawbs Bot
c55bdd423e Update translations 2021-09-06 01:02:08 +02:00
Jonas Kvinge
e45e202c5e Subsonic: Make network replies timeout after 30 seconds
Fixes #754
2021-09-05 21:47:00 +02:00
Jonas Kvinge
2280a30ba9 Subsonic: Minor code style fix 2021-09-05 21:46:41 +02:00
Jonas Kvinge
9ac7518156 Subsonic: Remove obsolete return 2021-09-05 21:46:16 +02:00
Jonas Kvinge
0e6dbaf71a Settings: Fix loading subsonic auth method setting 2021-09-05 21:35:21 +02:00
Strawbs Bot
fe018ff8f7 Update translations 2021-09-02 01:03:13 +02:00
Jonas Kvinge
9b01e09302 GlobalShortcutsManager: Minor code fixes 2021-09-02 00:52:44 +02:00
Jonas Kvinge
3127474fd7 GlobalShortcutsManager: Fix reading settings 2021-09-02 00:52:21 +02:00
Jonas Kvinge
b849edfcca GlobalShortcutsBackend: Fix type return 2021-09-01 22:37:08 +02:00
Jonas Kvinge
20a23c2868 Various cleanup to global shortcuts code 2021-09-01 21:37:11 +02:00
Jonas Kvinge
49d9ded684 Fix null pointer crash
Possible fix for #752
2021-09-01 16:37:34 +02:00
Jonas Kvinge
fc57b437c2 Fix radio items leak 2021-08-31 22:45:28 +02:00
Jonas Kvinge
1ba20561ed Fix global shortcuts memory leak 2021-08-31 21:21:59 +02:00
Strawbs Bot
2c8b26e091 Update translations 2021-08-31 01:02:17 +02:00
Jonas Kvinge
62d2a97f38 Add make deploy to macOS CI 2021-08-30 18:13:29 +02:00
Strawbs Bot
44aa292bb5 Update translations 2021-08-30 01:02:16 +02:00
Strawbs Bot
5273b52c31 Update translations 2021-08-26 01:04:00 +02:00
Jonas Kvinge
f143efb810 Revert "Use std::as_const"
This reverts commit 0b15e29324.
2021-08-25 03:47:50 +02:00
Jonas Kvinge
978fb06349 clazy:exclude=range-loop-reference 2021-08-25 03:45:12 +02:00
Jonas Kvinge
e274e8070d Update Changelog 2021-08-25 03:19:42 +02:00
Jonas Kvinge
46bd5b42fa Use 4arg connect 2021-08-25 03:08:30 +02:00
Jonas Kvinge
0b15e29324 Use std::as_const 2021-08-25 03:00:34 +02:00
Jonas Kvinge
75b6669371 Simplify return 2021-08-25 02:58:54 +02:00
Jonas Kvinge
c1c34017e4 Remove get() 2021-08-25 02:58:20 +02:00
Jonas Kvinge
ed08818b6f Use multi-arg 2021-08-25 02:57:57 +02:00
Jonas Kvinge
71adfc0a74 Use std::chrono_literals 2021-08-25 02:57:09 +02:00
Jonas Kvinge
49ccbddb17 Add Q_DISABLE_COPY 2021-08-25 02:56:30 +02:00
Jonas Kvinge
be3c7eef60 Use default 2021-08-25 02:55:54 +02:00
Jonas Kvinge
336c6cdd9d Use 4arg connect 2021-08-25 02:55:00 +02:00
Jonas Kvinge
709a706853 Delete mimedata when returning early 2021-08-25 02:38:58 +02:00
Jonas Kvinge
dad62faf88 Use fully-qualified parameter for signal 2021-08-25 02:36:18 +02:00
Jonas Kvinge
6e0a5fb5c6 Make const 2021-08-25 02:29:05 +02:00
Jonas Kvinge
4b9551d27f Simplify if statement 2021-08-25 02:28:41 +02:00
Strawbs Bot
2a67bc9926 Update translations 2021-08-25 01:16:47 +02:00
Jonas Kvinge
d02241d32c Fix compile with MSVC 2021-08-24 21:49:06 +02:00
Strawbs Bot
55e038d345 Update translations 2021-08-24 01:08:33 +02:00
Jonas Kvinge
ea2bfbda44 Formatting 2021-08-23 21:21:08 +02:00
Jonas Kvinge
ed7794f396 macdeployqt: Replace foreach with C++11 for loop 2021-08-23 01:44:35 +02:00
Strawbs Bot
086646f311 Update translations 2021-08-23 01:02:20 +02:00
Jonas Kvinge
ad169ca5a5 Remove unneeded namespace prefix 2021-08-22 23:29:44 +02:00
Jonas Kvinge
671e636aef Remove some uses of auto 2021-08-22 23:27:25 +02:00
Jonas Kvinge
72d381e9ed Replace qAsConst with C++17 std::as_const 2021-08-22 23:26:53 +02:00
Jonas Kvinge
c076933b52 Use FREEBSD variable 2021-08-22 23:22:15 +02:00
Jonas Kvinge
fdb5c813ad Use actions/checkout@v1.2.0 for FreeBSD too 2021-08-20 22:36:44 +02:00
Strawbs Bot
1bda6633b1 Update translations 2021-08-20 01:02:15 +02:00
Jonas Kvinge
249a5bf3b7 macOS deploy CI improvements 2021-08-19 22:59:38 +02:00
Jonas Kvinge
679b468618 macdeployqt: Fix QLibraryInfo::LibraryExecutablesPath with Qt 5 2021-08-19 20:27:21 +02:00
Jonas Kvinge
cf2a0af3d9 Fix macdeploycheck link directories 2021-08-19 20:24:11 +02:00
Jonas Kvinge
82be53224d Simplify libgpod link directories 2021-08-19 20:23:20 +02:00
Jonas Kvinge
9cc995cb52 Add macdeploycheck 2021-08-19 19:17:43 +02:00
Jonas Kvinge
42d414797a macdeployqt: Formatting 2021-08-19 19:17:43 +02:00
Jonas Kvinge
b071a4df70 macdeployqt: Simplify code in changeInstallName 2021-08-19 19:17:43 +02:00
Jonas Kvinge
46d927291c macdeployqt: Adapt upstream change 2021-08-19 19:17:43 +02:00
Jonas Kvinge
50ab01d9c9 macdeployqt: Remove unused option to specify plugins dir 2021-08-19 19:17:43 +02:00
Jonas Kvinge
dc8fe63acf Add script to copy gstreamer plugins on macOS 2021-08-19 19:17:43 +02:00
Jonas Kvinge
4fc5863888 Add taglib and tagparser link directories 2021-08-19 19:17:43 +02:00
Jonas Kvinge
e2d8149dcf Formatting 2021-08-19 19:17:43 +02:00
Jonas Kvinge
5f156d6bab Only read local files in SongLoader::EffectiveSongLoad 2021-08-19 19:17:43 +02:00
Strawbs Bot
816cdcf4bf Update translations 2021-08-16 01:01:43 +02:00
Jonas Kvinge
75c94ae092 Always look for qpa/qplatformnativeinterface.h 2021-08-14 20:00:27 +02:00
Jonas Kvinge
ecf2c50a26 Use QX11Application with Qt >= 6.2, use QX11Info with Qt 5 2021-08-14 17:06:40 +02:00
Jonas Kvinge
cecb9293f6 Add QRegularExpression::CaseInsensitiveOption 2021-08-13 23:33:41 +02:00
Jonas Kvinge
1ebfa0ad7e Song::kAlbumRemoveDisc is already QRegularExpression 2021-08-13 23:32:54 +02:00
Jonas Kvinge
35c7b57308 Allow fading when a ALSA PCM device is selected 2021-08-13 22:39:34 +02:00
Strawbs Bot
36bfeffbcc Update translations 2021-08-13 01:03:08 +02:00
Jonas Kvinge
e6858719c9 Reduce network access managers 2021-08-12 23:00:42 +02:00
Strawbs Bot
f2d52f83fe Update translations 2021-08-10 01:02:54 +02:00
Jonas Kvinge
f1d3cadb3b Add better logging for file open and write errors 2021-08-09 23:32:26 +02:00
Jonas Kvinge
7d61d8e646 Replace C-style cast with reinterpret_cast 2021-08-09 23:32:09 +02:00
Jonas Kvinge
6ede400f3a CMakeLists.txt formatting 2021-08-07 03:02:36 +02:00
Strawbs Bot
78de45fee2 Update translations 2021-08-07 01:01:40 +02:00
Jonas Kvinge
4559e33331 Update .github/workflows/ccpp.yml 2021-08-01 15:32:51 +02:00
Jonas Kvinge
43875dd3fe Remove Fedora 35 from CI
It's broken.
2021-08-01 08:41:12 +02:00
Jonas Kvinge
fa10384a92 Add FreeBSD to CI 2021-08-01 08:32:50 +02:00
Strawbs Bot
7e144da6b9 Update translations 2021-07-31 01:02:51 +02:00
Jonas Kvinge
54af17e7bf Remove linker hack 2021-07-30 23:01:44 +02:00
Jonas Kvinge
d4a9f5bb2e Replace Iconv_LIBRARY with Iconv_LIBRARIES 2021-07-30 23:01:07 +02:00
Jonas Kvinge
8040813da8 Remove QUIET from find_package for Backtrace and Iconv 2021-07-30 23:00:34 +02:00
Jonas Kvinge
871e40c5c0 Update Changelog 2021-07-30 21:17:53 +02:00
Jonas Kvinge
7ce922b084 Simplify CMake by using macros 2021-07-30 21:17:50 +02:00
Jonas Kvinge
0c9989695a Subsonic: Use 500 albums per request
Fixes #740
2021-07-30 21:17:44 +02:00
Jonas Kvinge
88d7cb3ed5 Add MD5 token authentication for Subsonic 2021-07-30 21:16:41 +02:00
Strawbs Bot
5b7fc80f26 Update translations 2021-07-29 01:15:44 +02:00
Jonas Kvinge
553e8baa8b Fix async song load
Fixes #739
2021-07-28 22:25:33 +02:00
Jonas Kvinge
62a5031ccf Delay pause on resume playback 2021-07-23 21:54:46 +02:00
Jonas Kvinge
4abac65316 Properly disconnect PlaylistManager::AllPlaylistsLoaded on resume 2021-07-23 21:54:21 +02:00
Jonas Kvinge
c6e42e1032 Reset play offset when switching song while paused
Fixes #735
2021-07-23 21:32:12 +02:00
Jonas Kvinge
a353631892 Code tidy 2021-07-23 21:30:08 +02:00
Jonas Kvinge
f144c982e3 Minor CMakeLists.txt cleanup 2021-07-21 17:45:22 +02:00
Jonas Kvinge
16625b1dc7 Move some files from ext to src 2021-07-21 17:29:16 +02:00
Jonas Kvinge
78ccce7d1a Change USE_BUNDLE default 2021-07-21 17:29:16 +02:00
Strawbs Bot
ffba5f7d31 Update translations 2021-07-19 01:01:56 +02:00
Jonas Kvinge
2cb8fa62df Remove duplicate TAGLIB_LIBRARY_DIRS 2021-07-18 16:38:20 +02:00
Jonas Kvinge
853b936cdd Revert "Add sudo"
This reverts commit 4f0fdbab62.
2021-07-18 15:34:07 +02:00
Jonas Kvinge
4f0fdbab62 Add sudo 2021-07-18 15:33:13 +02:00
Jonas Kvinge
190b23b702 Fix build with macports 2021-07-18 15:23:57 +02:00
Strawbs Bot
e0bb79b2c4 Update translations 2021-07-15 01:03:31 +02:00
Jonas Kvinge
2eab763d74 Check that QIODevice::open() is successful, and explicitly call close() 2021-07-14 20:52:57 +02:00
Jonas Kvinge
f64c1dd9e5 Update Changelog 2021-07-14 13:12:20 +02:00
Jonas Kvinge
fab1d94d34 Delay resume playback on startup to make sure Tidal login is refreshed 2021-07-14 13:02:54 +02:00
Jonas Kvinge
facf49b2b7 Spotify: Decrease login delay on startup 2021-07-14 13:02:12 +02:00
Jonas Kvinge
da86b86776 Rename variable 2021-07-14 12:53:28 +02:00
Jonas Kvinge
a79d9d4e77 Move beginInsertRows() 2021-07-14 12:26:48 +02:00
Jonas Kvinge
d9e378211a Fix sorting of radios 2021-07-14 11:22:24 +02:00
Strawbs Bot
99fbbf70de Update translations 2021-07-14 01:03:06 +02:00
Jonas Kvinge
50a616457d Add missing const 2021-07-13 23:25:44 +02:00
Jonas Kvinge
2ad30ebe88 Add missing Qt::CaseInsensitive 2021-07-13 23:25:36 +02:00
Jonas Kvinge
68dbc29f2c Use QString::compare with Qt::CaseInsensitive to reduce allocations 2021-07-13 23:18:12 +02:00
Strawbs Bot
a87863229f Update translations 2021-07-13 01:07:37 +02:00
Jonas Kvinge
f39ffcb997 Simplify if condition 2021-07-12 13:45:51 +02:00
Jonas Kvinge
f20bb388be Rename variable 2021-07-12 13:27:14 +02:00
Jonas Kvinge
fc45015b13 Remove unused variable 2021-07-12 13:26:41 +02:00
Jonas Kvinge
7a5f047f8e Add parent to RadioMimeData 2021-07-12 13:26:20 +02:00
Jonas Kvinge
4251bee3ca Change some uses of QMap to QHash 2021-07-12 08:28:52 +02:00
Jonas Kvinge
f02741284c Tagparser: Fix reading and writing year/originalyear 2021-07-12 07:54:01 +02:00
Jonas Kvinge
fec7419fcc Make const 2021-07-12 07:38:49 +02:00
Jonas Kvinge
e8694531f6 Iterate QMap values 2021-07-12 07:34:20 +02:00
Jonas Kvinge
461491f742 Use multiarg 2021-07-12 07:33:40 +02:00
Jonas Kvinge
af29acf462 tagparser: Save release and record date 2021-07-12 07:32:41 +02:00
Jonas Kvinge
b47f29e87c tagparser: Parse tracks when saving 2021-07-12 07:32:17 +02:00
Jonas Kvinge
fc8ec6d7fa Replace INSTANTIATE_TEST_CASE_P with INSTANTIATE_TEST_SUITE_P 2021-07-12 05:51:01 +02:00
Jonas Kvinge
1d4c736cfa Initialize container to nullptr 2021-07-12 05:51:01 +02:00
Strawbs Bot
600450082a Update translations 2021-07-12 01:18:19 +02:00
Jonas Kvinge
c6da0864f2 Use std::make_shared 2021-07-11 19:57:18 +02:00
Jonas Kvinge
10fc6b4562 Fix tagreader test compile error with tagparser 2021-07-11 19:56:21 +02:00
Jonas Kvinge
e48b7d83a3 Formatting 2021-07-11 09:49:38 +02:00
Jonas Kvinge
a6742d401c Formatting 2021-07-11 07:40:57 +02:00
Jonas Kvinge
87b9a8c4c8 Use RadioPlaylistItem 2021-07-11 07:39:27 +02:00
Jonas Kvinge
134dc55891 Rename RadioView::SetModel 2021-07-11 05:53:10 +02:00
Jonas Kvinge
295cf98e70 Add missing override 2021-07-11 05:30:35 +02:00
Jonas Kvinge
7333155b8c Edit tab order in scrobbler settings 2021-07-11 05:23:37 +02:00
Jonas Kvinge
3960c7d8e6 Add SomaFM and Radio Paradise to scrobbler sources 2021-07-11 05:18:56 +02:00
Jonas Kvinge
b053f99690 Add Song::is_radio() 2021-07-11 05:18:39 +02:00
Jonas Kvinge
5700c3f72e Change GStreamer text 2021-07-11 05:17:45 +02:00
Jonas Kvinge
cdb3729a88 Use Song::SourceFromURL in SongLoader::AddAsRawStream 2021-07-11 05:17:17 +02:00
Jonas Kvinge
c33f2a1d27 Unref bus in SongLoader::LoadRemote() 2021-07-11 04:58:37 +02:00
Jonas Kvinge
9b9a32b053 tagparser: Fix opening file readonly 2021-07-11 04:36:44 +02:00
Jonas Kvinge
95eec369b5 Fix includes 2021-07-11 02:31:15 +02:00
Jonas Kvinge
5d5860683b Add missing includes 2021-07-11 02:29:24 +02:00
Jonas Kvinge
434b31b932 Formatting 2021-07-11 02:27:26 +02:00
Jonas Kvinge
f69e42e520 Use Q_ASSERT 2021-07-11 02:27:03 +02:00
Jonas Kvinge
c5cadfe0c6 Fix memory leak in InternetSearchView::ResultsContextMenuEvent 2021-07-11 01:52:21 +02:00
Jonas Kvinge
f21be30004 Use static QPixmapCache everywhere 2021-07-11 01:43:52 +02:00
Jonas Kvinge
b8b21d53e1 Use static QPixmapCache 2021-07-11 01:32:51 +02:00
Jonas Kvinge
09ec39c87a Remove unused functions from RadioService 2021-07-11 01:20:42 +02:00
Jonas Kvinge
dbf18db3a3 No need to pass Application to RadioBackend 2021-07-11 01:12:50 +02:00
Jonas Kvinge
d8f0ae0980 Remove unused variable 2021-07-11 01:11:25 +02:00
Jonas Kvinge
09bbf1f4d7 Add radios 2021-07-11 01:08:06 +02:00
Strawbs Bot
d07aff9872 Update translations 2021-07-11 01:02:12 +02:00
Jonas Kvinge
4cb3f9d177 Close files in song loader 2021-07-11 00:45:30 +02:00
Jonas Kvinge
c1a815778b Formatting 2021-07-10 21:52:21 +02:00
Jonas Kvinge
5b003b09ac Make CollectionBackendInterface to PlaylistParser optional 2021-07-10 21:52:01 +02:00
Jonas Kvinge
22d0697c77 Use Song::is_stream 2021-07-10 21:50:23 +02:00
Jonas Kvinge
432b0f3e54 songloader: Make sure timeout timer is started from correct thread 2021-07-10 21:48:31 +02:00
Jonas Kvinge
2bee41e90e Fix compile of Utilities::Hmac with Qt 6.3 2021-07-07 23:54:21 +02:00
Jonas Kvinge
2a7312f2b4 Fix tagreader test 2021-07-07 23:46:21 +02:00
Strawbs Bot
f5091339ad Update translations 2021-07-06 01:02:54 +02:00
Jonas Kvinge
3d06d68196 Fix broken context albums 2021-07-04 17:34:42 +02:00
Strawbs Bot
1a643bfa8c Update translations 2021-07-03 01:20:53 +02:00
Jonas Kvinge
cd82b0a669 Fix spelling and typos 2021-07-02 18:45:53 +02:00
Jonas Kvinge
57312e29e2 Build with tagparser on openSUSE 2021-07-02 11:25:02 +02:00
Jonas Kvinge
592df4819b Update Changelog 2021-07-02 02:26:34 +02:00
Jonas Kvinge
f36997c7c5 Close MediaFileInfo 2021-07-02 01:39:21 +02:00
Jonas Kvinge
b1640d3626 Remove tagparser/abstractattachment.h include 2021-07-02 01:38:56 +02:00
Jonas Kvinge
825c62c62b Fix typo in TagReaderTagLib constructor and destructor 2021-07-02 01:26:48 +02:00
Jonas Kvinge
a4b0c6f37d Remove unused QVector include 2021-07-02 01:26:32 +02:00
Jonas Kvinge
239b88aa3b Add support for TagParser as an alternative to TagLib 2021-07-02 01:16:46 +02:00
Jonas Kvinge
88819611f4 Remove TagLib dependency from Song class 2021-07-02 01:16:46 +02:00
Jonas Kvinge
e6ff8368a9 Fix filefilter 2021-07-02 01:16:46 +02:00
Jonas Kvinge
8315f572ea Remove default parameter 2021-07-02 01:16:46 +02:00
Strawbs Bot
89e2070419 Update translations 2021-07-02 01:04:47 +02:00
Jonas Kvinge
b5f4df0912 Refactor subsonic, tidal and qobuz code 2021-07-01 02:02:02 +02:00
Jonas Kvinge
b9f3f80d50 Use std::make_unique / std::make_shared 2021-07-01 02:02:02 +02:00
Jonas Kvinge
0e8ae1a206 Change to std::shared_ptr 2021-07-01 02:02:02 +02:00
Jonas Kvinge
32729174bb Make CollectionModelTest constructor public 2021-07-01 02:02:02 +02:00
Jonas Kvinge
2cf6fe8da7 Fix ConcurrentRunTest 2021-07-01 02:02:02 +02:00
Strawbs Bot
929b031f09 Update translations 2021-07-01 01:03:41 +02:00
Jonas Kvinge
57a36491ee Remove mpris.cpp and mpris.h 2021-06-30 16:26:07 +02:00
Jonas Kvinge
f3a8dde5f0 Use std::make_shared 2021-06-30 16:15:55 +02:00
Jonas Kvinge
ffa2489998 Formatting 2021-06-30 16:15:55 +02:00
Strawbs Bot
6cd7bcdae6 Update translations 2021-06-28 01:07:32 +02:00
Jonas Kvinge
e4f684f411 Change const_iterator to iterator 2021-06-28 00:27:28 +02:00
Jonas Kvinge
fdc9a71f9e Use protected kApiUrl 2021-06-28 00:21:50 +02:00
Jonas Kvinge
bb134ee7ac Rename NeedLogin to set_need_login 2021-06-28 00:21:50 +02:00
Jonas Kvinge
18dc6f3c88 Remove unused variables in InternetCollectionViewContainer 2021-06-28 00:21:50 +02:00
Jonas Kvinge
9327fd3aa1 Formatting 2021-06-28 00:21:50 +02:00
Jonas Kvinge
aa859b9002 Remove dead code 2021-06-28 00:21:50 +02:00
Jonas Kvinge
20a15ecd35 Replace while with for loop 2021-06-28 00:21:50 +02:00
Jonas Kvinge
062c59b321 Rename FindSongs 2021-06-28 00:21:50 +02:00
Jonas Kvinge
9ace66edb7 Rename CollectionFilterWidget::SetCollectionModel to CollectionFilterWidget::Init 2021-06-28 00:21:50 +02:00
Jonas Kvinge
a97d784f26 Rename filter to search_field 2021-06-28 00:21:50 +02:00
Jonas Kvinge
a2e7173983 Rename filter to filter_widget 2021-06-28 00:21:50 +02:00
Jonas Kvinge
0869651dc3 Change parameter order of CollectionBackend::Init 2021-06-28 00:21:50 +02:00
Strawbs Bot
ca42286354 Update translations 2021-06-26 01:07:31 +02:00
Jonas Kvinge
174bfcc597 Use higher resolution images from last.fm API 2021-06-25 22:41:17 +02:00
Jonas Kvinge
244d25ce53 Fix compile with Qt 5 2021-06-25 18:46:45 +02:00
Jonas Kvinge
8287efd51f Remove silencing -Wclazy-qt6-deprecated-api-fixes to workaround clazy bugs 2021-06-25 18:19:37 +02:00
Jonas Kvinge
df31b5d59f Replace Q_ENUMS with Q_ENUM 2021-06-25 18:06:30 +02:00
Jonas Kvinge
53cc47a8b1 Use localhost directly as redirect for scrobbling API 2.0 2021-06-25 16:04:19 +02:00
Jonas Kvinge
55f8294a38 Remove escape characters from playlist filter string
Fixes #728
2021-06-25 12:01:05 +02:00
Strawbs Bot
67a5e3f37e Update translations 2021-06-23 01:16:19 +02:00
Jonas Kvinge
06cd2f3a57 Remove static from IsMacAccessibilityEnabled 2021-06-22 16:17:51 +02:00
Jonas Kvinge
d614a94203 Remove const from SingleApplication methods 2021-06-22 16:15:04 +02:00
Jonas Kvinge
f66aca2164 Remove static from OSDPretty::current_screen 2021-06-22 14:17:24 +02:00
Jonas Kvinge
b071ecb45e Formatting 2021-06-22 14:04:42 +02:00
Jonas Kvinge
83a70fecca Use QWidget::tr() 2021-06-22 14:04:42 +02:00
Jonas Kvinge
dbc7c224c1 Fix setting PID 2021-06-22 14:04:42 +02:00
Jonas Kvinge
7876f9a8a5 Remove unneeded QFont in parameter initialization list 2021-06-22 14:04:42 +02:00
Jonas Kvinge
215057ce6f Remove unneeded get() 2021-06-22 14:04:42 +02:00
Jonas Kvinge
6d8b0b3ab6 Simplify return 2021-06-22 14:04:42 +02:00
Jonas Kvinge
e5c85ddd32 Pass task ID to SetTaskBlocksCollectionScans 2021-06-22 14:04:42 +02:00
Jonas Kvinge
6bf3c34fe5 Fix parameter name mismatch 2021-06-22 14:04:42 +02:00
Jonas Kvinge
584f5e5935 Change bool/int condition 2021-06-22 14:04:42 +02:00
Jonas Kvinge
58a5367015 Make const 2021-06-22 14:04:42 +02:00
Jonas Kvinge
8c2b907ff5 Make static 2021-06-22 14:04:42 +02:00
Strawbs Bot
e3ab0c0192 Update translations 2021-06-22 01:05:22 +02:00
Jonas Kvinge
8572e3eabb Fix volume slider regression 2021-06-21 20:21:40 +02:00
Jonas Kvinge
d4f10c61ef Change lambda capture 2021-06-21 20:10:02 +02:00
Jonas Kvinge
59e11d6caa Remove reference 2021-06-21 20:00:31 +02:00
Jonas Kvinge
67778198de Formatting 2021-06-21 19:55:47 +02:00
Jonas Kvinge
ebfd8cd6f7 Initialize variables and formatting 2021-06-21 19:55:18 +02:00
Jonas Kvinge
83b54f2ae6 Formatting 2021-06-21 19:54:42 +02:00
Jonas Kvinge
7ea60ed178 Update copyrights 2021-06-21 19:54:12 +02:00
Jonas Kvinge
c61d1ce6b4 Use std::any_of 2021-06-21 19:52:37 +02:00
Jonas Kvinge
6a7959547e Change CoverProvider quality return type to float 2021-06-21 18:16:04 +02:00
Jonas Kvinge
af3834672e Remove unneeded break 2021-06-21 18:14:59 +02:00
Jonas Kvinge
f95ff6cb89 Formatting 2021-06-21 16:08:53 +02:00
Jonas Kvinge
e85c13b3fe Change switch to if statement 2021-06-21 15:44:13 +02:00
Jonas Kvinge
ed09627fdb Use std::make_unique 2021-06-21 15:40:44 +02:00
Jonas Kvinge
99ba2c2e8b Make playlist parameter to queue not optional 2021-06-21 15:40:44 +02:00
Jonas Kvinge
589bdf5dcd Use default 2021-06-21 15:40:44 +02:00
Jonas Kvinge
1abbd5ecbc Pass parent to queue 2021-06-21 15:40:44 +02:00
Strawbs Bot
7619e8427a Update translations 2021-06-21 01:17:51 +02:00
Jonas Kvinge
069e24d713 Fix compile 2021-06-21 00:29:38 +02:00
Jonas Kvinge
8e9b45f80f Add override 2021-06-20 23:57:19 +02:00
Jonas Kvinge
2d604a80c9 Change 0 to nullptr 2021-06-20 23:56:56 +02:00
Jonas Kvinge
1f59a1b952 unsigned long int 2021-06-20 23:56:33 +02:00
Jonas Kvinge
6e5ff01db5 Remove unused variables 2021-06-20 23:55:59 +02:00
Jonas Kvinge
50be44adf8 Add namespace comments 2021-06-20 23:55:02 +02:00
Jonas Kvinge
e1bf4347ab Fix uninitialized variables 2021-06-20 23:53:28 +02:00
Jonas Kvinge
3a3305c020 Uppercase literal suffix 2021-06-20 23:49:04 +02:00
Jonas Kvinge
a83f174e1a Remove unused settingsdialog variable 2021-06-20 19:47:38 +02:00
Jonas Kvinge
1295033fae Clang-Tidy and Clazy fixes 2021-06-20 19:04:08 +02:00
Jonas Kvinge
755abec636 Use QProcess::startCommand with Qt 6 2021-06-20 02:48:58 +02:00
Jonas Kvinge
310995fb87 Use static QFileInfo::exists 2021-06-20 02:26:30 +02:00
Jonas Kvinge
bee30e572f Fix incorrect use of return 2021-06-20 02:25:36 +02:00
Jonas Kvinge
cd37a40bab Only link to chromaprint when song fingerprinting or musicbrainz is enabled 2021-06-16 22:54:23 +02:00
Jonas Kvinge
8699790e78 Always call QFutureWatcher::setFuture after connects 2021-06-16 00:30:21 +02:00
Strawbs Bot
d2d3f58a14 Update translations 2021-06-15 01:03:14 +02:00
Jonas Kvinge
081df59ed7 Only call QSystemTrayIcon::isSystemTrayAvailable once
Workaround file descriptor leak

Fixes #724
2021-06-15 00:25:54 +02:00
Strawbs Bot
ec3bcdcb26 Update translations 2021-06-14 01:02:38 +02:00
Jonas Kvinge
8265cf8a6a Use selected plug devices when loading automatic/custom device 2021-06-14 00:18:14 +02:00
Jonas Kvinge
dfb53fb3dd Change regex for CARD and DEV in ALSA devices 2021-06-13 23:58:47 +02:00
Jonas Kvinge
705fc920e5 Fix 2021-06-13 23:44:15 +02:00
Jonas Kvinge
99764741e4 Fix detecting ALSA PCM devices 2021-06-13 23:42:08 +02:00
Jonas Kvinge
35b3bc4522 Handle some chromaprinter error cases 2021-06-13 23:18:22 +02:00
Jonas Kvinge
91eee99bab Increase pen size for OSD Pretty border
Workaround for QTBUG-93476

Fixes #708
2021-06-13 20:56:14 +02:00
Jonas Kvinge
e56defdc50 Formatting 2021-06-13 20:55:37 +02:00
Jonas Kvinge
fbe4d3ce9f Add Subsonic option to turn off HTTP2
Fixes #718
2021-06-13 19:55:45 +02:00
Strawbs Bot
8cf5707575 Update translations 2021-06-13 01:16:37 +02:00
Jonas Kvinge
f786a17014 Formatting 2021-06-12 20:53:23 +02:00
Jonas Kvinge
427b9c1ebc Formatting 2021-06-12 19:22:38 +02:00
Jonas Kvinge
141957e4b5 Remove godaddy certificate 2021-06-12 19:14:47 +02:00
Jonas Kvinge
b911f4f34e Formatting 2021-06-12 16:06:41 +02:00
Jonas Kvinge
0caf76dfae Remove unneeded includes 2021-06-12 16:06:41 +02:00
Jonas Kvinge
00f09168d7 Update Changelog 2021-06-12 16:06:41 +02:00
Strawbs Bot
d636359c10 Update translations 2021-06-11 01:16:45 +02:00
Jonas Kvinge
8fd32aba4f Improve resume playback on startup, re-request stream URL when unpausing
Fixes #270
2021-06-10 23:14:05 +02:00
Strawbs Bot
9db59d5deb Update translations 2021-06-09 01:03:30 +02:00
Jonas Kvinge
d98321c703 Use newer compiler with Qt 6 on openSUSE Leap 2021-06-08 23:43:14 +02:00
Jonas Kvinge
a6424c005f Add Gui to QT_COMPONENTS 2021-06-08 22:49:34 +02:00
Jonas Kvinge
80d127c277 Use fingerprints from database if available when fetching tags from MusicBrainz 2021-06-08 20:59:56 +02:00
Strawbs Bot
3ca0c828c6 Update translations 2021-06-07 01:01:41 +02:00
Strawbs Bot
d3a8e03b2c Add Portuguese (Brazil) 2021-06-06 01:47:57 +02:00
Strawbs Bot
6e75de0dcb Add Chinese 2021-06-06 01:43:49 +02:00
Strawbs Bot
a7bed9741a Add Catalan 2021-06-06 01:42:38 +02:00
Strawbs Bot
f70e52a7a5 Add Japanese 2021-06-06 01:38:22 +02:00
Strawbs Bot
95d7de0654 Add Dutch 2021-06-06 01:36:50 +02:00
Strawbs Bot
3398d25b35 Add Ukrainian 2021-06-06 01:35:40 +02:00
Strawbs Bot
80a4a43680 Add Finnish 2021-06-06 01:34:54 +02:00
Strawbs Bot
01ac61f38c Update translations 2021-06-06 01:23:21 +02:00
Jonas Kvinge
a98be36684 Set DEFAULT '' for all TEXT 2021-06-06 00:36:35 +02:00
Jonas Kvinge
7f085c4012 Check fingerprint for NULL 2021-06-06 00:26:11 +02:00
Jonas Kvinge
5f008d1560 Edit collection settings tab order 2021-06-05 22:34:32 +02:00
Jonas Kvinge
0782b579d5 Update README and Changelog 2021-06-05 22:30:15 +02:00
Jonas Kvinge
f8ed2afef1 Add song fingerprinting and tracking
Fixes #296
2021-06-05 21:56:40 +02:00
Jonas Kvinge
a883508eca Fix marking CUE songs available 2021-06-05 02:50:20 +02:00
Jonas Kvinge
a4a20ec220 Make sure schedule playlist save timer is started from correct thread 2021-06-05 00:07:15 +02:00
Jonas Kvinge
faed63712f Remove Fedora 32 and CentOS 8 from CI 2021-06-04 00:25:11 +02:00
Jonas Kvinge
0032ec5036 Don't log access tokens 2021-06-04 00:15:35 +02:00
Strawbs Bot
9df24a841f Update translations 2021-06-02 01:01:56 +02:00
Jonas Kvinge
d2aa4ff2bd Remove duplicate line 2021-06-01 23:16:04 +02:00
Jonas Kvinge
171db01401 Set default for original year 2021-05-31 19:07:55 +02:00
Strawbs Bot
0112f1e11d Update translations 2021-05-31 01:01:58 +02:00
Jonas Kvinge
8f7b09b58e Update Changelog 2021-05-30 20:57:54 +02:00
Strawbs Bot
479c2b6cec Update translations 2021-05-30 01:25:46 +02:00
Jonas Kvinge
e6f50e6637 Strip mimetype when downloading covers 2021-05-29 23:27:40 +02:00
Jonas Kvinge
548f8bf23e Fix macOS compile 2021-05-29 22:47:53 +02:00
Jonas Kvinge
b6bfe81f9a Use HAVE_X11_GLOBALSHORTCUTS 2021-05-29 22:20:46 +02:00
Jonas Kvinge
ab95bcc028 Change text PulseAudio 2021-05-29 21:52:52 +02:00
Jonas Kvinge
8b7b3df0a3 Fix Qt 5 compile 2021-05-29 20:54:01 +02:00
Jonas Kvinge
69a6416146 Change to uppercase 2021-05-29 20:37:58 +02:00
Jonas Kvinge
1ced4e277b Add global shortcuts support on MATE 2021-05-29 20:35:55 +02:00
Jonas Kvinge
0c5236ebcb Fix crash when no system tray is available 2021-05-29 18:52:47 +02:00
Jonas Kvinge
66c55c5007 Remove remaining HAVE_X11EXTRAS 2021-05-29 18:36:58 +02:00
Jonas Kvinge
7f5a0f1b0c Update RPM spec, man page and debian control 2021-05-29 00:57:25 +02:00
Jonas Kvinge
0c766938f1 Update appdata 2021-05-29 00:49:27 +02:00
Jonas Kvinge
1455e87aef Update appdata 2021-05-29 00:48:23 +02:00
Jonas Kvinge
7c50eef8ad Add Fedora 35 2021-05-28 23:39:30 +02:00
Jonas Kvinge
aa9f972ccf Update Changelog 2021-05-26 17:05:07 +02:00
Strawbs Bot
45df99bb56 Update translations 2021-05-26 13:00:30 +02:00
Strawbs Bot
a2968e57cf Update translations 2021-05-21 01:15:12 +02:00
Jonas Kvinge
67f831beba Refactor systemtrayicon code 2021-05-20 21:40:08 +02:00
Jonas Kvinge
264d47caf4 Change playlist tabbar favorite tooltip 2021-05-20 17:12:28 +02:00
Jonas Kvinge
ef72b3273e Move private Qt GUI include 2021-05-20 17:10:08 +02:00
jonas@jkvinge.net
7d3ade7ae1 Automatically detect Qt version 2021-05-17 00:56:04 +02:00
Strawbs Bot
59897fdf55 Update translations 2021-05-14 01:02:10 +02:00
jonas@jkvinge.net
0b4ea04c91 Update protobuf dll in nsi 2021-05-13 21:06:43 +02:00
jonas@jkvinge.net
094b3b4636 Update Dmg.cmake: Move depends for macdeployqt 2021-05-13 12:18:06 +02:00
jonas@jkvinge.net
0298beeb06 Fix macOS build 2021-05-13 02:17:58 +02:00
Strawbs Bot
971542d6bc Update translations 2021-05-13 01:26:18 +02:00
jonas@jkvinge.net
5bdbc9f40d Add CMake test for Qt sqlite support 2021-05-13 00:18:06 +02:00
jonas@jkvinge.net
efcd35d4a1 Remove use of X11Extras and WinExtras
Modules are deprecated in Qt 6
See: QTBUG-83251
2021-05-12 23:15:04 +02:00
Strawbs Bot
a01541d7ca Update translations 2021-05-12 01:05:21 +02:00
jonas@jkvinge.net
7d96d7c066 Update README 2021-05-11 22:06:09 +02:00
jonas@jkvinge.net
639ea35921 Use wchar version of GetDiskFreeSpaceEx on Windows Qt 5 2021-05-11 20:32:28 +02:00
jonas@jkvinge.net
dee1905e16 Make the default tabbbar background color lighter
Fixes #711
2021-05-11 20:10:31 +02:00
jonas@jkvinge.net
1803705749 Add option to turn off playlist alternating row colors 2021-05-11 19:40:47 +02:00
jonas@jkvinge.net
5d96ee5492 Add ALSA PCM devices and option to set channels
Fixes #262
2021-05-11 19:14:00 +02:00
jonas@jkvinge.net
4a0a1a32a4 Rename ENABLE_CHROMAPRINT to ENABLE_MUSICBRAINZ 2021-05-10 21:17:50 +02:00
Strawbs Bot
c2108a35d0 Update translations 2021-05-09 01:01:51 +02:00
jonas@jkvinge.net
31ecdbae18 Update protobuf dll in nsi 2021-05-08 01:56:42 +02:00
jonas@jkvinge.net
e9c733e78f Turn off -Werror for Windows build in CI 2021-05-08 01:56:42 +02:00
Strawbs Bot
2320c5e04c Update translations 2021-05-08 01:01:55 +02:00
Jonas Kvinge
fb7b3b0295 Revert "Shuffle all songs instead of from the current to the end"
This reverts commit 316a3d51ee.
2021-05-04 23:16:18 +02:00
Jonas Kvinge
316a3d51ee Shuffle all songs instead of from the current to the end
Fixes #707
2021-05-04 22:48:18 +02:00
Jonas Kvinge
240dcf2e5c Improve device icon loading 2021-05-04 21:55:19 +02:00
Strawbs Bot
5fbdbffa23 Update translations 2021-05-04 01:04:38 +02:00
Jonas Kvinge
932c8b65fb Add Ubuntu Hirsute to CI 2021-05-03 23:33:59 +02:00
Strawbs Bot
e18e174947 Update translations 2021-05-02 01:02:16 +02:00
Jonas Kvinge
f2c7df3a3b Build on macOS with libgpod 2021-05-01 22:12:13 +02:00
Jonas Kvinge
2b15dae806 Strip misc from song title when sending now playing 2021-05-01 18:19:08 +02:00
Jonas Kvinge
2625d72818 Don't strip off "Live" from song title 2021-05-01 18:03:26 +02:00
Strawbs Bot
a8b4d72421 Update translations 2021-04-27 01:06:58 +02:00
Jonas Kvinge
88562890ae Use int in MainWindow::UpdateTrackSliderPosition 2021-04-26 23:36:59 +02:00
Jonas Kvinge
86c267eb89 Seconds is already qint64 2021-04-26 23:13:37 +02:00
Jonas Kvinge
3d1928cca9 Fix typo 2021-04-26 23:12:59 +02:00
Jonas Kvinge
8c64d3b55c Do most item reloading in the background, schedule playlist saving 2021-04-26 22:57:08 +02:00
Jonas Kvinge
41b238e87b Formatting 2021-04-26 22:56:14 +02:00
Jonas Kvinge
da83025fb0 Update temporary metadata when reloading song
Possible fix for #697
2021-04-26 20:33:57 +02:00
Jonas Kvinge
84d3b190c8 Update Changelog 2021-04-25 21:20:43 +02:00
Strawbs Bot
272fc5a72d Update translations 2021-04-25 01:04:39 +02:00
Strawbs Bot
0f709059e3 Update translations 2021-04-24 01:02:19 +02:00
Jonas Kvinge
0f91bb28a9 Remove CircleCI 2021-04-23 21:09:11 +02:00
Jonas Kvinge
63d75a8e17 Build common DMG for all macOS versions 2021-04-23 21:08:23 +02:00
Strawbs Bot
be95d8409b Update translations 2021-04-23 01:02:57 +02:00
Jonas Kvinge
9d3000498b Add setting for setting reply gain fallback gain 2021-04-22 21:55:26 +02:00
Jonas Kvinge
48f8468e65 Change direction to out for signals 2021-04-22 21:54:45 +02:00
Jonas Kvinge
9b60559855 Use QFile::encodeName() in Song::InitFromFilePartial
Fixes #693
2021-04-21 20:11:37 +02:00
Jonas Kvinge
e97acf7938 Fix errors in D-Bus XMLs 2021-04-21 16:05:23 +02:00
Jonas Kvinge
1cfb92e75c Remove quotation mark from org.gnome.SettingsDaemon.MediaKeys.xml 2021-04-21 16:00:34 +02:00
Strawbs Bot
4c617ccd49 Update translations 2021-04-19 01:01:46 +02:00
Jonas Kvinge
494517e767 Turn back git revision 2021-04-18 22:07:43 +02:00
Jonas Kvinge
655c872ac9 Release 0.9.3 2021-04-18 18:44:43 +02:00
Strawbs Bot
cb0f2b48fd Update translations 2021-04-18 01:03:10 +02:00
Strawbs Bot
20a84bdefc Update translations 2021-04-17 01:02:28 +02:00
Jonas Kvinge
83ad7d4935 Set exit before quit is called 2021-04-16 18:34:38 +02:00
Jonas Kvinge
ae2ca175d3 Fix remembering hidden state
Prevent SetHiddenInTray() or Exit() from being called again after
qApp->quit() in MainWindow::closeEvent()
2021-04-16 18:27:24 +02:00
Jonas Kvinge
c855108b94 Update Changelog 2021-04-15 21:06:19 +02:00
Strawbs Bot
5e80b694c2 Update translations 2021-04-15 01:02:00 +02:00
Jonas Kvinge
99640aa2ad Add Windows Qt 6 build to CI 2021-04-14 21:11:01 +02:00
Jonas Kvinge
4c0f7c3dd4 Add commandline option to resize window 2021-04-14 19:50:38 +02:00
Jonas Kvinge
2a8490ef31 Use modern user interface and locked list also for uninstalling 2021-04-14 18:07:23 +02:00
Jonas Kvinge
43dc694963 Include gst-discoverer-1.0.exe in windows setup 2021-04-14 16:56:30 +02:00
Strawbs Bot
e03ee00554 Update translations 2021-04-14 01:02:25 +02:00
Jonas Kvinge
01a07ec0e8 Enable stream discoverer on all systems
Fixes #689
2021-04-14 00:16:37 +02:00
Jonas Kvinge
74b7738a9d Create GLib main event loop on non-glib systems 2021-04-14 00:16:07 +02:00
Jonas Kvinge
10aaaebc38 Enable stream discoverer on all Unix except macOS 2021-04-13 22:11:44 +02:00
Jonas Kvinge
a8d072150d Remove avresample-4.dll from nsi 2021-04-13 19:11:48 +02:00
Jonas Kvinge
7877bb7956 Add setting for OSD Pretty fading 2021-04-13 17:27:10 +02:00
Strawbs Bot
bd31e3df89 Update translations 2021-04-13 01:01:55 +02:00
Jonas Kvinge
531e97b499 Only use QPlatformNativeInterface on X11 2021-04-12 19:40:34 +02:00
Jonas Kvinge
43876e967a Enable Qt6WinExtras.dll in nsi 2021-04-12 15:41:28 +02:00
Jonas Kvinge
efaf917939 Add pragma unused 2021-04-11 19:16:07 +02:00
Jonas Kvinge
7d3ceb7d8c Fix Tidal authentication on macOS 2021-04-11 18:33:35 +02:00
Jonas Kvinge
201ac47943 Add new screenshot 2021-04-11 09:11:24 +02:00
Jonas Kvinge
5a70285c10 Update Changelog 2021-04-11 03:24:21 +02:00
Jonas Kvinge
e13c27d32c Allow editing of playlist metadata for streams 2021-04-11 02:01:53 +02:00
Strawbs Bot
9c9b673eeb Update translations 2021-04-11 01:13:36 +02:00
Jonas Kvinge
7323fe0000 Fix queued item painting 2021-04-11 01:03:02 +02:00
Jonas Kvinge
460d045cbe Fix rescan when collection directory is removed and added 2021-04-11 01:01:57 +02:00
Jonas Kvinge
4983c1cfc9 FIx tidal search field not showing on macOS 2021-04-10 09:56:59 +02:00
Jonas Kvinge
c7bc9d471a Allow keep running option on macOS too 2021-04-10 08:22:08 +02:00
Jonas Kvinge
a36b91ffe8 Cast to quint32 2021-04-10 08:21:58 +02:00
Jonas Kvinge
88da0db0f7 Update copyrights 2021-04-10 07:32:38 +02:00
Jonas Kvinge
816c2b0ca8 Use qint32 for unique worker number 2021-04-10 07:20:36 +02:00
Jonas Kvinge
d6ff68339b Use qint64 for unique worker number 2021-04-10 07:02:08 +02:00
Jonas Kvinge
fdf483c98b Update README.md 2021-04-10 06:36:18 +02:00
Jonas Kvinge
eb020c1cb8 Register tidal URL scheme on macOS 2021-04-10 06:04:31 +02:00
Jonas Kvinge
6fa331ad06 Make macdeployqt work with Qt 5 too 2021-04-10 03:28:38 +02:00
Jonas Kvinge
5a58ac2845 Make CollectionQuery subclass QSqlQuery, don't copy QSqlQuery 2021-04-10 03:21:05 +02:00
Strawbs Bot
0c4edc4d17 Update translations 2021-04-09 01:02:09 +02:00
Jonas Kvinge
b5cea4c27e Make enabling FTS3 non-fatal 2021-04-08 22:33:43 +02:00
Jonas Kvinge
b7de5d6df3 Only enable FTS3 when schema needs upgrading 2021-04-08 22:13:21 +02:00
Strawbs Bot
d7310ba307 Update translations 2021-04-07 01:03:08 +02:00
Jonas Kvinge
cabb94b856 Move taglib include dir to system include dirs 2021-04-05 22:25:52 +02:00
Jonas Kvinge
82b649f67d Move taglib include dir to system include dirs 2021-04-05 22:22:25 +02:00
Strawbs Bot
8753782a0c Update translations 2021-04-04 01:02:57 +02:00
Strawbs Bot
566a139edc Update translations 2021-04-02 01:03:04 +02:00
Jonas Kvinge
39dda0f16b Check that rating position is to the right or left of the rectangle.
Adapted from Clementine.

Author: Jim Broadus
2021-04-02 00:47:53 +02:00
Jonas Kvinge
bddb371e31 Fix open in file browser when inode/directory mimetype is set to thunar
Fixes #677
2021-04-01 18:31:19 +02:00
Jonas Kvinge
128223a28a Add setting for configuring the color for the currently playing song
Fixes #676
2021-04-01 02:18:15 +02:00
Jonas Kvinge
45b9d0553f Update FUNDING.yml 2021-04-01 00:27:54 +02:00
Jonas Kvinge
a87f0e0475 Also strip variables with uppercase letters in OpenInFileManager() 2021-03-31 23:14:16 +02:00
Jonas Kvinge
beacea0482 Improve macdeployqt patch 2021-03-31 01:00:51 +02:00
Jonas Kvinge
85b59e79d3 Update ccpp.yml 2021-03-30 20:41:13 +02:00
Jonas Kvinge
9a947c5544 Use LockedList nsis plugin 2021-03-30 20:35:48 +02:00
Strawbs Bot
e4cebf4cbe Update translations 2021-03-30 01:03:27 +02:00
Jonas Kvinge
f63e05b7d4 Use QString::SkipEmptyParts for older Qt versions 2021-03-29 22:45:01 +02:00
Jonas Kvinge
84b7fa02bb Strip all variables from command in OpenInFileManager
Fixes #674
2021-03-29 22:37:55 +02:00
Strawbs Bot
36e597a045 Update translations 2021-03-29 01:28:10 +02:00
Strawbs Bot
f760b3f271 Update translations 2021-03-27 01:12:06 +01:00
Jonas Kvinge
d4c8fa6a24 Use const QJsonValueRef 2021-03-26 23:55:55 +01:00
Jonas Kvinge
c6604734c9 Remove using std::placeholders 2021-03-26 23:33:56 +01:00
Jonas Kvinge
91ab8e22b7 Use QJsonValueRef 2021-03-26 22:10:43 +01:00
Jonas Kvinge
14fb647647 Fix uninitialized variables 2021-03-26 21:30:13 +01:00
Jonas Kvinge
8a39a43ad5 Make sure QCache::insert is successful
Otherwise object is deleted by QCache::insert
2021-03-26 21:07:47 +01:00
Jonas Kvinge
a3d23a6f57 Turn back git revision 2021-03-26 20:35:18 +01:00
973 changed files with 126383 additions and 50418 deletions

View File

@@ -1,417 +0,0 @@
version: 2.1
commands:
cmake:
description: Configure build
steps:
- run:
name: Configure build
command: cmake ..
working_directory: build
build_source:
description: Create source tarball
steps:
- run:
name: Create source tarball
command: ../dist/scripts/maketarball.sh
working_directory: build
build_rpm:
description: Build RPM
steps:
- run:
name: Create RPM build sources directories
command: mkdir -p ~/rpmbuild/SOURCES /usr/src/packages/SOURCES
- run:
name: Copy source tarball 1
command: cp strawberry-*.tar.xz ~/rpmbuild/SOURCES/
working_directory: build
- run:
name: Copy source tarball 2
command: cp strawberry-*.tar.xz /usr/src/packages/SOURCES/
working_directory: build
- run:
name: Build RPM
command: rpmbuild -ba ../dist/unix/strawberry.spec
working_directory: build
build_deb:
description: Build Deb
steps:
- run:
name: make deb
command: dpkg-buildpackage -b -d -uc -us -nc -j2
install_opensuse_dependencies:
description: Install openSUSE dependencies
steps:
- run:
name: Update packages
command: zypper --non-interactive --gpg-auto-import-keys ref
- run:
name: Install openSUSE dependencies
command: >
zypper --non-interactive --gpg-auto-import-keys install
lsb-release
rpm-build
git
tar
make
cmake
gcc
gcc-c++
gettext-tools
glibc-devel
libboost_headers-devel
boost-devel
glib2-devel
glib2-tools
dbus-1-devel
alsa-devel
libnotify-devel
libgnutls-devel
protobuf-devel
sqlite3-devel
libpulse-devel
gstreamer-devel
gstreamer-plugins-base-devel
taglib-devel
vlc-devel
libQt5Core-devel
libQt5Gui-devel
libQt5Widgets-devel
libQt5Concurrent-devel
libQt5Network-devel
libQt5Sql-devel
libQt5DBus-devel
libQt5Test-devel
libqt5-qtx11extras-devel
libqt5-qtbase-common-devel
libQt5Sql5-sqlite
libqt5-linguist-devel
libcdio-devel
libgpod-devel
libmtp-devel
libchromaprint-devel
desktop-file-utils
update-desktop-files
appstream-glib
hicolor-icon-theme
install_fedora_dependencies:
description: Install Fedora dependencies
steps:
- run:
name: Update packages
command: yum update --assumeyes
- run:
name: Upgrade packages
command: yum upgrade --assumeyes
- run:
name: Install Fedora dependencies
command: >
dnf install --assumeyes
@development-tools
redhat-lsb-core
git
glibc
gcc-c++
rpmdevtools
make
cmake
pkgconfig
glib
man
tar
gettext
openssh
boost-devel
dbus-devel
protobuf-devel
protobuf-compiler
sqlite-devel
alsa-lib-devel
pulseaudio-libs-devel
libnotify-devel
gnutls-devel
qt5-qtbase-devel
qt5-qtx11extras-devel
qt5-qttools-devel
gstreamer1-devel
gstreamer1-plugins-base-devel
taglib-devel
libcdio-devel
libgpod-devel
libmtp-devel
libchromaprint-devel
fftw-devel
desktop-file-utils
libappstream-glib
hicolor-icon-theme
install_debian_dependencies:
description: Install Debian dependencies
steps:
- run:
name: Install Debian dependencies
command: >
apt-get update && apt-get install -y
build-essential
dh-make
ssh
git
make
cmake
gcc
pkg-config
fakeroot
gettext
lsb-release
libglib2.0-dev
dpkg-dev
libdbus-1-dev
libboost-dev
libprotobuf-dev
protobuf-compiler
libsqlite3-dev
libgnutls28-dev
libasound2-dev
libpulse-dev
libtag1-dev
qtbase5-dev
qtbase5-dev-tools
qtbase5-private-dev
libqt5x11extras5-dev
qttools5-dev
libgstreamer1.0-dev
libgstreamer-plugins-base1.0-dev
gstreamer1.0-alsa
gstreamer1.0-pulseaudio
libchromaprint-dev
libfftw3-dev
libcdio-dev
libmtp-dev
libgpod-dev
install_ubuntu_dependencies:
description: Install Ubuntu dependencies
steps:
- run:
name: Setup environment
command: |
echo 'export DEBIAN_FRONTEND=noninteractive' >> $BASH_ENV
source $BASH_ENV
- run:
name: Install Ubuntu dependencies
command: >
apt-get update && apt-get install -y
build-essential
dh-make
ssh
git
make
cmake
pkg-config
gcc
fakeroot
wget
curl
gettext
lsb-release
dpkg-dev
libglib2.0-dev
libboost-dev
libdbus-1-dev
libprotobuf-dev
protobuf-compiler
libsqlite3-dev
libgnutls28-dev
libasound2-dev
libpulse-dev
libtag1-dev
qtbase5-dev
qtbase5-dev-tools
qtbase5-private-dev
libqt5x11extras5-dev
qttools5-dev
libgstreamer1.0-dev
libgstreamer-plugins-base1.0-dev
libgstreamer-plugins-good1.0-dev
gstreamer1.0-alsa
gstreamer1.0-pulseaudio
libchromaprint-dev
libfftw3-dev
libcdio-dev
libmtp-dev
libgpod-dev
jobs:
build_source:
docker:
- image: opensuse/leap:15.2
steps:
- install_opensuse_dependencies
- checkout
- cmake
- build_source
build_opensuse_lp151:
docker:
- image: opensuse/leap:15.1
environment:
RPM_BUILD_NCPUS: "2"
steps:
- install_opensuse_dependencies
- checkout
- cmake
- build_source
- build_rpm
build_opensuse_lp152:
docker:
- image: opensuse/leap:15.2
environment:
RPM_BUILD_NCPUS: "2"
steps:
- install_opensuse_dependencies
- checkout
- cmake
- build_source
- build_rpm
build_fedora_32:
docker:
- image: fedora:32
environment:
RPM_BUILD_NCPUS: "2"
steps:
- install_fedora_dependencies
- checkout
- cmake
- build_source
- build_rpm
build_fedora_33:
docker:
- image: fedora:33
environment:
RPM_BUILD_NCPUS: "2"
steps:
- install_fedora_dependencies
- checkout
- cmake
- build_source
- build_rpm
build_debian_buster:
docker:
- image: debian:buster
steps:
- install_debian_dependencies
- checkout
- cmake
- build_deb
build_debian_bullseye:
docker:
- image: debian:bullseye
steps:
- install_debian_dependencies
- checkout
- cmake
- build_deb
build_ubuntu_bionic:
docker:
- image: ubuntu:bionic
steps:
- install_ubuntu_dependencies
- checkout
- cmake
- build_deb
build_ubuntu_focal:
docker:
- image: ubuntu:focal
steps:
- install_ubuntu_dependencies
- checkout
- cmake
- build_deb
build_ubuntu_groovy:
docker:
- image: ubuntu:groovy
steps:
- install_ubuntu_dependencies
- checkout
- cmake
- build_deb
workflows:
version: 2
build_all:
jobs:
- build_source:
filters:
tags:
only: /.*/
- build_opensuse_lp151:
filters:
tags:
only: /.*/
- build_opensuse_lp152:
filters:
tags:
only: /.*/
- build_fedora_32:
filters:
tags:
only: /.*/
- build_fedora_33:
filters:
tags:
only: /.*/
- build_debian_buster:
filters:
tags:
only: /.*/
- build_debian_bullseye:
filters:
tags:
only: /.*/
- build_ubuntu_bionic:
filters:
tags:
only: /.*/
- build_ubuntu_focal:
filters:
tags:
only: /.*/
- build_ubuntu_groovy:
filters:
tags:
only: /.*/

View File

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

1
.github/FUNDING.yml vendored
View File

@@ -1,2 +1,3 @@
github: jonaski
patreon: jonaskvinge
custom: https://paypal.me/jonaskvinge

View File

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

6
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: daily

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

41
.gitignore vendored
View File

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

View File

@@ -1,46 +0,0 @@
sudo: required
language: C++
os: osx
osx_image: xcode11.3
compiler: clang
before_install:
- if ! [ "$DEPLOY_KEY_ENC" == "" ]; then
echo $DEPLOY_KEY_ENC | base64 --decode | openssl aes-256-cbc -K $encrypted_83a41ac424a6_key -iv $encrypted_83a41ac424a6_iv -out ~/.ssh/id_rsa -d ;
chmod 600 ~/.ssh/id_rsa ;
fi
- git fetch --unshallow
- git pull
- brew update
- travis_wait 400 brew upgrade || echo "Failed"
- travis_wait 400 brew upgrade || echo "Failed"
- brew install glib pkgconfig libffi protobuf protobuf-c qt gettext gnutls fftw sqlite chromaprint zlib taglib
- brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav
- brew install libcdio libmtp
- brew install create-dmg
- brew install --cask sparkle
- sudo ln -s /usr/local/Caskroom/sparkle/$(ls /usr/local/Caskroom/sparkle | head -n1) /usr/local/opt/sparkle
- export Qt6_DIR=/usr/local/opt/qt6/lib/cmake
- export Qt6LinguistTools_DIR=/usr/local/opt/qt6/lib/cmake/Qt6LinguistTools
- ls /usr/local/lib/gstreamer-1.0
before_script:
- mkdir build
- cd build
- cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_WITH_QT6=ON -DBUILD_WERROR=ON -DUSE_BUNDLE=ON
script:
- make -j8
- make install
- make dmg2
after_success:
- ls -lh strawberry*.dmg
- if [[ "$TRAVIS_OS_NAME" == "osx" ]] && [ -f ~/.ssh/id_rsa ]; then
if [[ "$TRAVIS_BRANCH" == "master" ]] || [[ "$TRAVIS_BRANCH" == "travis" ]]; then
rsync -e "ssh -o StrictHostKeyChecking=no" -va strawberry*.dmg travis@echoes.jkvinge.net:/home/travis/builds/macos/mojave/;
fi
fi
branches:
except:
- # Do not build tags that we create when we upload to GitHub Releases
- /^(?i:continuous)$/

13
3rdparty/README.md vendored
View File

@@ -1,15 +1,13 @@
3rdparty libraries located in this directory
============================================
singleapplication
KDSingleApplication
-----------------
This is a small static library used by Strawberry to prevent it from starting twice per user session.
If the user tries to start strawberry twice, the main window will maximize instead of starting another instance.
If you dynamically link to your systems version, you'll need two versions, one defined as QApplication and
one as a QCoreApplication.
It is included here because it is not packed by distros and is also used on macOS and Windows.
It is also used to pass command-line options through to the first instance.
URL: https://github.com/itay-grudev/SingleApplication
URL: https://github.com/KDAB/KDSingleApplication/
SPMediaKeyTap
@@ -23,3 +21,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 on Windows.

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

@@ -0,0 +1,3 @@
add_library(getopt STATIC getopt.cpp)
target_compile_definitions(getopt PRIVATE -DSTATIC_GETOPT -D_UNICODE)
target_include_directories(getopt PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

753
3rdparty/getopt/getopt.cpp vendored Normal file
View File

@@ -0,0 +1,753 @@
/* Getopt for Microsoft C
This code is a modification of the Free Software Foundation, Inc.
Getopt library for parsing command line argument the purpose was
to provide a Microsoft Visual C friendly derivative. This code
provides functionality for both Unicode and Multibyte builds.
Date: 02/03/2011 - Ludvik Jerabek - Initial Release
Version: 1.1
Comment: Supports getopt, getopt_long, and getopt_long_only
and POSIXLY_CORRECT environment flag
License: LGPL
Revisions:
02/03/2011 - Ludvik Jerabek - Initial Release
02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4
07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs
08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception
08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB
02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file
08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi
10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features
06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable
09/24/2022 - Ludvik Jerabek - Updated to match most recent getopt release
09/25/2022 - Ludvik Jerabek - Fixed memory allocation (malloc call) issue for wchar_t*
**DISCLAIMER**
THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#define _CRT_SECURE_NO_WARNINGS
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include "getopt.h"
#ifdef __cplusplus
# define _GETOPT_THROW throw()
#else
# define _GETOPT_THROW
#endif
int optind = 1;
int opterr = 1;
int optopt = '?';
enum ENUM_ORDERING {
REQUIRE_ORDER,
PERMUTE,
RETURN_IN_ORDER
};
//
//
// Ansi structures and functions follow
//
//
static struct _getopt_data_a {
int optind;
int opterr;
int optopt;
char *optarg;
int __initialized;
char *__nextchar;
enum ENUM_ORDERING __ordering;
int __first_nonopt;
int __last_nonopt;
} getopt_data_a;
char *optarg_a;
static void exchange_a(char **argv, struct _getopt_data_a *d) {
int bottom = d->__first_nonopt;
int middle = d->__last_nonopt;
int top = d->optind;
char *tem;
while (top > middle && middle > bottom) {
if (top - middle > middle - bottom) {
int len = middle - bottom;
int i;
for (i = 0; i < len; i++) {
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
}
top -= len;
}
else {
int len = top - middle;
int i;
for (i = 0; i < len; i++) {
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
}
bottom += len;
}
}
d->__first_nonopt += (d->optind - d->__last_nonopt);
d->__last_nonopt = d->optind;
}
static int process_long_option_a(int argc, char **argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int print_errors, const char *prefix);
static int process_long_option_a(int argc, char **argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int print_errors, const char *prefix) {
assert(longopts != NULL);
char *nameend;
size_t namelen;
const struct option_a *p;
const struct option_a *pfound = NULL;
int n_options;
int option_index = 0;
for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++)
;
namelen = nameend - d->__nextchar;
for (p = longopts, n_options = 0; p->name; p++, n_options++)
if (!strncmp(p->name, d->__nextchar, namelen) && namelen == strlen(p->name)) {
pfound = p;
option_index = n_options;
break;
}
if (pfound == NULL) {
unsigned char *ambig_set = NULL;
int ambig_fallback = 0;
int indfound = -1;
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp(p->name, d->__nextchar, namelen)) {
if (pfound == NULL) {
pfound = p;
indfound = option_index;
}
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) {
if (!ambig_fallback) {
if (!print_errors)
ambig_fallback = 1;
else if (!ambig_set) {
if ((ambig_set = reinterpret_cast<unsigned char *>(malloc(n_options * sizeof(char)))) == NULL)
ambig_fallback = 1;
if (ambig_set) {
memset(ambig_set, 0, n_options * sizeof(char));
ambig_set[indfound] = 1;
}
}
if (ambig_set)
ambig_set[option_index] = 1;
}
}
}
if (ambig_set || ambig_fallback) {
if (print_errors) {
if (ambig_fallback)
fprintf(stderr, "%s: option '%s%s' is ambiguous\n", argv[0], prefix, d->__nextchar);
else {
_lock_file(stderr);
fprintf(stderr, "%s: option '%s%s' is ambiguous; possibilities:", argv[0], prefix, d->__nextchar);
for (option_index = 0; option_index < n_options; option_index++)
if (ambig_set[option_index])
fprintf(stderr, " '%s%s'", prefix, longopts[option_index].name);
fprintf(stderr, "\n");
_unlock_file(stderr);
}
}
free(ambig_set);
d->__nextchar += strlen(d->__nextchar);
d->optind++;
d->optopt = 0;
return '?';
}
option_index = indfound;
}
if (pfound == NULL) {
if (!long_only || argv[d->optind][1] == '-' || strchr(optstring, *d->__nextchar) == NULL) {
if (print_errors)
fprintf(stderr, "%s: unrecognized option '%s%s'\n", argv[0], prefix, d->__nextchar);
d->__nextchar = NULL;
d->optind++;
d->optopt = 0;
return '?';
}
return -1;
}
d->optind++;
d->__nextchar = NULL;
if (*nameend) {
if (pfound->has_arg)
d->optarg = nameend + 1;
else {
if (print_errors)
fprintf(stderr, "%s: option '%s%s' doesn't allow an argument\n", argv[0], prefix, pfound->name);
d->optopt = pfound->val;
return '?';
}
}
else if (pfound->has_arg == 1) {
if (d->optind < argc)
d->optarg = argv[d->optind++];
else {
if (print_errors)
fprintf(stderr, "%s: option '%s%s' requires an argument\n", argv[0], prefix, pfound->name);
d->optopt = pfound->val;
return optstring[0] == ':' ? ':' : '?';
}
}
if (longind != NULL)
*longind = option_index;
if (pfound->flag) {
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
static const char *_getopt_initialize_a(const char *optstring, struct _getopt_data_a *d, int posixly_correct) {
if (d->optind == 0)
d->optind = 1;
d->__first_nonopt = d->__last_nonopt = d->optind;
d->__nextchar = NULL;
if (optstring[0] == '-') {
d->__ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+') {
d->__ordering = REQUIRE_ORDER;
++optstring;
}
else if (posixly_correct | !!getenv("POSIXLY_CORRECT"))
d->__ordering = REQUIRE_ORDER;
else
d->__ordering = PERMUTE;
d->__initialized = 1;
return optstring;
}
int _getopt_internal_r_a(int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int posixly_correct);
int _getopt_internal_r_a(int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int posixly_correct) {
int print_errors = d->opterr;
if (argc < 1)
return -1;
d->optarg = NULL;
if (d->optind == 0 || !d->__initialized)
optstring = _getopt_initialize_a(optstring, d, posixly_correct);
else if (optstring[0] == '-' || optstring[0] == '+')
optstring++;
if (optstring[0] == ':')
print_errors = 0;
if (d->__nextchar == NULL || *d->__nextchar == '\0') {
if (d->__last_nonopt > d->optind)
d->__last_nonopt = d->optind;
if (d->__first_nonopt > d->optind)
d->__first_nonopt = d->optind;
if (d->__ordering == PERMUTE) {
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
exchange_a(const_cast<char **>(argv), d);
else if (d->__last_nonopt != d->optind)
d->__first_nonopt = d->optind;
while (d->optind < argc && (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
d->optind++;
d->__last_nonopt = d->optind;
}
if (d->optind != argc && !strcmp(argv[d->optind], "--")) {
d->optind++;
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
exchange_a(const_cast<char **>(argv), d);
else if (d->__first_nonopt == d->__last_nonopt)
d->__first_nonopt = d->optind;
d->__last_nonopt = argc;
d->optind = argc;
}
if (d->optind == argc) {
if (d->__first_nonopt != d->__last_nonopt)
d->optind = d->__first_nonopt;
return -1;
}
if (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0') {
if (d->__ordering == REQUIRE_ORDER)
return -1;
d->optarg = argv[d->optind++];
return 1;
}
if (longopts) {
if (argv[d->optind][1] == '-') {
d->__nextchar = argv[d->optind] + 2;
return process_long_option_a(argc, const_cast<char **>(argv), optstring, longopts, longind, long_only, d, print_errors, "--");
}
if (long_only && (argv[d->optind][2] || !strchr(optstring, argv[d->optind][1]))) {
int code;
d->__nextchar = argv[d->optind] + 1;
code = process_long_option_a(argc, const_cast<char **>(argv), optstring, longopts,
longind, long_only, d,
print_errors, "-");
if (code != -1)
return code;
}
}
d->__nextchar = argv[d->optind] + 1;
}
{
char c = *d->__nextchar++;
const char *temp = strchr(optstring, c);
if (*d->__nextchar == '\0')
++d->optind;
if (temp == NULL || c == ':' || c == ';') {
if (print_errors)
fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], c);
d->optopt = c;
return '?';
}
if (temp[0] == 'W' && temp[1] == ';' && longopts != NULL) {
if (*d->__nextchar != '\0')
d->optarg = d->__nextchar;
else if (d->optind == argc) {
if (print_errors)
fprintf(stderr, "%s: option requires an argument -- '%c'\n", argv[0], c);
d->optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
return c;
}
else
d->optarg = argv[d->optind];
d->__nextchar = d->optarg;
d->optarg = NULL;
return process_long_option_a(argc, const_cast<char **>(argv), optstring, longopts, longind, 0, d, print_errors, "-W ");
}
if (temp[1] == ':') {
if (temp[2] == ':') {
if (*d->__nextchar != '\0') {
d->optarg = d->__nextchar;
d->optind++;
}
else
d->optarg = NULL;
d->__nextchar = NULL;
}
else {
if (*d->__nextchar != '\0') {
d->optarg = d->__nextchar;
d->optind++;
}
else if (d->optind == argc) {
if (print_errors)
fprintf(stderr, "%s: option requires an argument -- '%c'\n", argv[0], c);
d->optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
}
else
d->optarg = argv[d->optind++];
d->__nextchar = NULL;
}
}
return c;
}
}
int _getopt_internal_a(int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, int posixly_correct);
int _getopt_internal_a(int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, int posixly_correct) {
int result;
getopt_data_a.optind = optind;
getopt_data_a.opterr = opterr;
result = _getopt_internal_r_a(argc, argv, optstring, longopts, longind, long_only, &getopt_data_a, posixly_correct);
optind = getopt_data_a.optind;
optarg_a = getopt_data_a.optarg;
optopt = getopt_data_a.optopt;
return result;
}
int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW {
return _getopt_internal_a(argc, argv, optstring, static_cast<const struct option_a *>(0), static_cast<int *>(0), 0, 0);
}
int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW {
return _getopt_internal_a(argc, argv, options, long_options, opt_index, 0, 0);
}
int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW {
return _getopt_internal_a(argc, argv, options, long_options, opt_index, 1, 0);
}
int _getopt_long_r_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d);
int _getopt_long_r_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d) {
return _getopt_internal_r_a(argc, argv, options, long_options, opt_index, 0, d, 0);
}
int _getopt_long_only_r_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d);
int _getopt_long_only_r_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d) {
return _getopt_internal_r_a(argc, argv, options, long_options, opt_index, 1, d, 0);
}
//
//
// Unicode Structures and Functions
//
//
static struct _getopt_data_w {
int optind;
int opterr;
int optopt;
wchar_t *optarg;
int __initialized;
wchar_t *__nextchar;
enum ENUM_ORDERING __ordering;
int __first_nonopt;
int __last_nonopt;
} getopt_data_w;
wchar_t *optarg_w;
static void exchange_w(wchar_t **argv, struct _getopt_data_w *d) {
int bottom = d->__first_nonopt;
int middle = d->__last_nonopt;
int top = d->optind;
wchar_t *tem;
while (top > middle && middle > bottom) {
if (top - middle > middle - bottom) {
int len = middle - bottom;
int i;
for (i = 0; i < len; i++) {
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
}
top -= len;
}
else {
int len = top - middle;
int i;
for (i = 0; i < len; i++) {
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
}
bottom += len;
}
}
d->__first_nonopt += (d->optind - d->__last_nonopt);
d->__last_nonopt = d->optind;
}
static int process_long_option_w(int argc, wchar_t **argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int print_errors, const wchar_t *prefix) {
assert(longopts != NULL);
wchar_t *nameend;
size_t namelen;
const struct option_w *p;
const struct option_w *pfound = NULL;
int n_options;
int option_index = 0;
for (nameend = d->__nextchar; *nameend && *nameend != L'='; nameend++)
;
namelen = nameend - d->__nextchar;
for (p = longopts, n_options = 0; p->name; p++, n_options++)
if (!wcsncmp(p->name, d->__nextchar, namelen) && namelen == wcslen(p->name)) {
pfound = p;
option_index = n_options;
break;
}
if (pfound == NULL) {
wchar_t *ambig_set = NULL;
int ambig_fallback = 0;
int indfound = -1;
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!wcsncmp(p->name, d->__nextchar, namelen)) {
if (pfound == NULL) {
pfound = p;
indfound = option_index;
}
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) {
if (!ambig_fallback) {
if (!print_errors)
ambig_fallback = 1;
else if (!ambig_set) {
if ((ambig_set = reinterpret_cast<wchar_t *>(malloc(n_options * sizeof(wchar_t)))) == NULL)
ambig_fallback = 1;
if (ambig_set) {
memset(ambig_set, 0, n_options * sizeof(wchar_t));
ambig_set[indfound] = 1;
}
}
if (ambig_set)
ambig_set[option_index] = 1;
}
}
}
if (ambig_set || ambig_fallback) {
if (print_errors) {
if (ambig_fallback)
fwprintf(stderr, L"%s: option '%s%s' is ambiguous\n", argv[0], prefix, d->__nextchar);
else {
_lock_file(stderr);
fwprintf(stderr, L"%s: option '%s%s' is ambiguous; possibilities:", argv[0], prefix, d->__nextchar);
for (option_index = 0; option_index < n_options; option_index++)
if (ambig_set[option_index])
fwprintf(stderr, L" '%s%s'", prefix, longopts[option_index].name);
fwprintf(stderr, L"\n");
_unlock_file(stderr);
}
}
free(ambig_set);
d->__nextchar += wcslen(d->__nextchar);
d->optind++;
d->optopt = 0;
return L'?';
}
option_index = indfound;
}
if (pfound == NULL) {
if (!long_only || argv[d->optind][1] == L'-' || wcschr(optstring, *d->__nextchar) == NULL) {
if (print_errors)
fwprintf(stderr, L"%s: unrecognized option '%s%s'\n", argv[0], prefix, d->__nextchar);
d->__nextchar = NULL;
d->optind++;
d->optopt = 0;
return L'?';
}
return -1;
}
d->optind++;
d->__nextchar = NULL;
if (*nameend) {
if (pfound->has_arg)
d->optarg = nameend + 1;
else {
if (print_errors)
fwprintf(stderr, L"%s: option '%s%s' doesn't allow an argument\n", argv[0], prefix, pfound->name);
d->optopt = pfound->val;
return L'?';
}
}
else if (pfound->has_arg == 1) {
if (d->optind < argc)
d->optarg = argv[d->optind++];
else {
if (print_errors)
fwprintf(stderr, L"%s: option '%s%s' requires an argument\n", argv[0], prefix, pfound->name);
d->optopt = pfound->val;
return optstring[0] == L':' ? L':' : L'?';
}
}
if (longind != NULL)
*longind = option_index;
if (pfound->flag) {
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
static const wchar_t *_getopt_initialize_w(const wchar_t *optstring, struct _getopt_data_w *d, int posixly_correct) {
if (d->optind == 0)
d->optind = 1;
d->__first_nonopt = d->__last_nonopt = d->optind;
d->__nextchar = NULL;
if (optstring[0] == L'-') {
d->__ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == L'+') {
d->__ordering = REQUIRE_ORDER;
++optstring;
}
else if (posixly_correct | !!_wgetenv(L"POSIXLY_CORRECT"))
d->__ordering = REQUIRE_ORDER;
else
d->__ordering = PERMUTE;
d->__initialized = 1;
return optstring;
}
int _getopt_internal_r_w(int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int posixly_correct);
int _getopt_internal_r_w(int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int posixly_correct) {
int print_errors = d->opterr;
if (argc < 1)
return -1;
d->optarg = NULL;
if (d->optind == 0 || !d->__initialized)
optstring = _getopt_initialize_w(optstring, d, posixly_correct);
else if (optstring[0] == L'-' || optstring[0] == L'+')
optstring++;
if (optstring[0] == L':')
print_errors = 0;
#define NONOPTION_P (argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0')
if (d->__nextchar == NULL || *d->__nextchar == L'\0') {
if (d->__last_nonopt > d->optind)
d->__last_nonopt = d->optind;
if (d->__first_nonopt > d->optind)
d->__first_nonopt = d->optind;
if (d->__ordering == PERMUTE) {
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
exchange_w(const_cast<wchar_t **>(argv), d);
else if (d->__last_nonopt != d->optind)
d->__first_nonopt = d->optind;
while (d->optind < argc && NONOPTION_P)
d->optind++;
d->__last_nonopt = d->optind;
}
if (d->optind != argc && !wcscmp(argv[d->optind], L"--")) {
d->optind++;
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
exchange_w(const_cast<wchar_t **>(argv), d);
else if (d->__first_nonopt == d->__last_nonopt)
d->__first_nonopt = d->optind;
d->__last_nonopt = argc;
d->optind = argc;
}
if (d->optind == argc) {
if (d->__first_nonopt != d->__last_nonopt)
d->optind = d->__first_nonopt;
return -1;
}
if (NONOPTION_P) {
if (d->__ordering == REQUIRE_ORDER)
return -1;
d->optarg = argv[d->optind++];
return 1;
}
if (longopts) {
if (argv[d->optind][1] == L'-') {
d->__nextchar = argv[d->optind] + 2;
return process_long_option_w(argc, const_cast<wchar_t **>(argv), optstring, longopts, longind, long_only, d, print_errors, L"--");
}
if (long_only && (argv[d->optind][2] || !wcschr(optstring, argv[d->optind][1]))) {
int code;
d->__nextchar = argv[d->optind] + 1;
code = process_long_option_w(argc, const_cast<wchar_t **>(argv), optstring, longopts, longind, long_only, d, print_errors, L"-");
if (code != -1)
return code;
}
}
d->__nextchar = argv[d->optind] + 1;
}
{
wchar_t c = *d->__nextchar++;
const wchar_t *temp = wcschr(optstring, c);
if (*d->__nextchar == L'\0')
++d->optind;
if (temp == NULL || c == L':' || c == L';') {
if (print_errors)
fwprintf(stderr, L"%s: invalid option -- '%c'\n", argv[0], c);
d->optopt = c;
return L'?';
}
if (temp[0] == L'W' && temp[1] == L';' && longopts != NULL) {
if (*d->__nextchar != L'\0')
d->optarg = d->__nextchar;
else if (d->optind == argc) {
if (print_errors)
fwprintf(stderr, L"%s: option requires an argument -- '%c'\n", argv[0], c);
d->optopt = c;
if (optstring[0] == L':')
c = L':';
else
c = L'?';
return c;
}
else
d->optarg = argv[d->optind];
d->__nextchar = d->optarg;
d->optarg = NULL;
return process_long_option_w(argc, const_cast<wchar_t **>(argv), optstring, longopts, longind,
0, d, print_errors, L"-W ");
}
if (temp[1] == L':') {
if (temp[2] == L':') {
if (*d->__nextchar != L'\0') {
d->optarg = d->__nextchar;
d->optind++;
}
else
d->optarg = NULL;
d->__nextchar = NULL;
}
else {
if (*d->__nextchar != L'\0') {
d->optarg = d->__nextchar;
d->optind++;
}
else if (d->optind == argc) {
if (print_errors)
fwprintf(stderr, L"%s: option requires an argument -- '%c'\n", argv[0], c);
d->optopt = c;
if (optstring[0] == L':')
c = L':';
else
c = L'?';
}
else
d->optarg = argv[d->optind++];
d->__nextchar = NULL;
}
}
return c;
}
}
int _getopt_internal_w(int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, int posixly_correct);
int _getopt_internal_w(int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, int posixly_correct) {
int result;
getopt_data_w.optind = optind;
getopt_data_w.opterr = opterr;
result = _getopt_internal_r_w(argc, argv, optstring, longopts, longind, long_only, &getopt_data_w, posixly_correct);
optind = getopt_data_w.optind;
optarg_w = getopt_data_w.optarg;
optopt = getopt_data_w.optopt;
return result;
}
int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW {
return _getopt_internal_w(argc, argv, optstring, static_cast<const struct option_w *>(0), static_cast<int *>(0), 0, 0);
}
int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW {
return _getopt_internal_w(argc, argv, options, long_options, opt_index, 0, 0);
}
int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW {
return _getopt_internal_w(argc, argv, options, long_options, opt_index, 1, 0);
}
int _getopt_long_r_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d);
int _getopt_long_r_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d) {
return _getopt_internal_r_w(argc, argv, options, long_options, opt_index, 0, d, 0);
}
int _getopt_long_only_r_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d);
int _getopt_long_only_r_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d) {
return _getopt_internal_r_w(argc, argv, options, long_options, opt_index, 1, d, 0);
}

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

@@ -0,0 +1,135 @@
/* Getopt for Microsoft C
This code is a modification of the Free Software Foundation, Inc.
Getopt library for parsing command line argument the purpose was
to provide a Microsoft Visual C friendly derivative. This code
provides functionality for both Unicode and Multibyte builds.
Date: 02/03/2011 - Ludvik Jerabek - Initial Release
Version: 1.1
Comment: Supports getopt, getopt_long, and getopt_long_only
and POSIXLY_CORRECT environment flag
License: LGPL
Revisions:
02/03/2011 - Ludvik Jerabek - Initial Release
02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4
07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs
08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception
08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB
02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file
08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi
10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features
06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable
09/24/2022 - Ludvik Jerabek - Updated to match most recent getopt release
09/25/2022 - Ludvik Jerabek - Fixed memory allocation (malloc call) issue for wchar_t*
**DISCLAIMER**
THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef __GETOPT_H_
#define __GETOPT_H_
#ifdef _GETOPT_API
# undef _GETOPT_API
#endif
#if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT)
# error "The preprocessor definitions of EXPORTS_GETOPT and STATIC_GETOPT can only be used individually"
#elif defined(STATIC_GETOPT)
# define _GETOPT_API
#elif defined(EXPORTS_GETOPT)
# pragma message("Exporting getopt library")
# define _GETOPT_API __declspec(dllexport)
#else
# pragma message("Importing getopt library")
# define _GETOPT_API __declspec(dllimport)
#endif
// Change behavior for C\C++
#ifdef __cplusplus
# define _BEGIN_EXTERN_C extern "C" {
# define _END_EXTERN_C }
# define _GETOPT_THROW throw()
#else
# define _BEGIN_EXTERN_C
# define _END_EXTERN_C
# define _GETOPT_THROW
#endif
// Standard GNU options
#define null_argument 0 /*Argument Null*/
#define no_argument 0 /*Argument Switch Only*/
#define required_argument 1 /*Argument Required*/
#define optional_argument 2 /*Argument Optional*/
// Shorter Options
#define ARG_NULL 0 /*Argument Null*/
#define ARG_NONE 0 /*Argument Switch Only*/
#define ARG_REQ 1 /*Argument Required*/
#define ARG_OPT 2 /*Argument Optional*/
#include <string.h>
#include <wchar.h>
_BEGIN_EXTERN_C
extern _GETOPT_API int optind;
extern _GETOPT_API int opterr;
extern _GETOPT_API int optopt;
// Ansi
struct option_a {
const char *name;
int has_arg;
int *flag;
int val;
};
extern _GETOPT_API char *optarg_a;
extern _GETOPT_API int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW;
extern _GETOPT_API int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW;
extern _GETOPT_API int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW;
// Unicode
struct option_w {
const wchar_t *name;
int has_arg;
int *flag;
int val;
};
extern _GETOPT_API wchar_t *optarg_w;
extern _GETOPT_API int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW;
extern _GETOPT_API int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW;
extern _GETOPT_API int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW;
_END_EXTERN_C
#undef _BEGIN_EXTERN_C
#undef _END_EXTERN_C
#undef _GETOPT_THROW
#undef _GETOPT_API
#ifdef _UNICODE
# define getopt getopt_w
# define getopt_long getopt_long_w
# define getopt_long_only getopt_long_only_w
# define option option_w
# define optarg optarg_w
#else
# define getopt getopt_a
# define getopt_long getopt_long_a
# define getopt_long_only getopt_long_only_a
# define option option_a
# define optarg optarg_a
#endif
#endif // __GETOPT_H_

View File

@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.7)
set(SOURCES kdsingleapplication.cpp kdsingleapplication_localsocket.cpp)
set(HEADERS kdsingleapplication.h kdsingleapplication_localsocket_p.h)
qt_wrap_cpp(MOC ${HEADERS})
add_library(kdsingleapplication STATIC ${SOURCES} ${MOC})
target_compile_definitions(kdsingleapplication PRIVATE -DKDSINGLEAPPLICATION_STATIC_BUILD)
target_include_directories(kdsingleapplication PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(kdsingleapplication PUBLIC ${QtCore_LIBRARIES} ${QtNetwork_LIBRARIES} )

6
3rdparty/kdsingleapplication/LICENSE vendored Normal file
View File

@@ -0,0 +1,6 @@
KDSingleApplication is (C) 2019-2023, Klarälvdalens Datakonsult AB,
and is available under the terms of the MIT license.
See the full license text in the LICENSES folder.
Contact KDAB at <info@kdab.com> to inquire about commercial licensing.

53
3rdparty/kdsingleapplication/README.md vendored Normal file
View File

@@ -0,0 +1,53 @@
# KDSingleApplication
`KDSingleApplication` is a helper class for single-instance policy applications
written by [KDAB](https://www.kdab.com).
## Usage
Currently the documentation is woefully lacking, but see the examples or tests
for inspiration. Basically it involves:
1. Create a `Q(Core|Gui)Application` object.
2. Create a `KDSingleApplication` object.
3. Check if the current instance is *primary* (or "master") or
*secondary* (or "slave") by calling `isPrimaryInstance`:
* the *primary* instance needs to listen from messages coming from the
secondary instances, by connecting a slot to the `messageReceived` signal;
* the *secondary* instances can send messages to the primary instance
by calling `sendMessage`.
## Licensing
KDSingleApplication is (C) 2019-2023, Klarälvdalens Datakonsult AB, and is available
under the terms of the [MIT license](LICENSES/MIT.txt).
Contact KDAB at <info@kdab.com> if you need different licensing options.
## Get Involved
KDAB will happily accept external contributions.
Please submit your contributions or issue reports from our GitHub space at
<https://github.com/KDAB/KDSingleApplication>.
## About KDAB
KDSingleApplication is supported and maintained by Klarälvdalens Datakonsult AB (KDAB).
The KDAB Group is the global No.1 software consultancy for Qt, C++ and
OpenGL applications across desktop, embedded and mobile platforms.
The KDAB Group provides consulting and mentoring for developing Qt applications
from scratch and in porting from all popular and legacy frameworks to Qt.
We continue to help develop parts of Qt and are one of the major contributors
to the Qt Project. We can give advanced or standard trainings anywhere
around the globe on Qt as well as C++, OpenGL, 3D and more.
Please visit <https://www.kdab.com> to meet the people who write code like this.
Stay up-to-date with KDAB product announcements:
* [KDAB Newsletter](https://news.kdab.com)
* [KDAB Blogs](https://www.kdab.com/category/blogs)
* [KDAB on Twitter](https://twitter.com/KDABQt)

View File

@@ -0,0 +1,106 @@
/*
This file is part of KDSingleApplication.
SPDX-FileCopyrightText: 2019-2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
SPDX-License-Identifier: MIT
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#include "kdsingleapplication.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QFileInfo>
// TODO: make this pluggable.
#include "kdsingleapplication_localsocket_p.h"
// Avoiding dragging in Qt private APIs for now, so this does not inherit
// from QObjectPrivate.
class KDSingleApplicationPrivate
{
public:
explicit KDSingleApplicationPrivate(const QString &name, KDSingleApplication *q);
QString name() const
{
return m_name;
}
bool isPrimaryInstance() const
{
return m_impl.isPrimaryInstance();
}
bool sendMessage(const QByteArray &message, int timeout)
{
return m_impl.sendMessage(message, timeout);
}
private:
Q_DECLARE_PUBLIC(KDSingleApplication)
KDSingleApplication *q_ptr;
QString m_name;
KDSingleApplicationLocalSocket m_impl;
};
KDSingleApplicationPrivate::KDSingleApplicationPrivate(const QString &name, KDSingleApplication *q)
: q_ptr(q)
, m_name(name)
, m_impl(name)
{
if (Q_UNLIKELY(name.isEmpty()))
qFatal("KDSingleApplication requires a non-empty application name");
if (isPrimaryInstance()) {
QObject::connect(&m_impl, &KDSingleApplicationLocalSocket::messageReceived,
q, &KDSingleApplication::messageReceived);
}
}
static QString extractExecutableName(const QString &applicationFilePath)
{
return QFileInfo(applicationFilePath).fileName();
}
KDSingleApplication::KDSingleApplication(QObject *parent)
: KDSingleApplication(extractExecutableName(QCoreApplication::applicationFilePath()), parent)
{
}
KDSingleApplication::KDSingleApplication(const QString &name, QObject *parent)
: QObject(parent)
, d_ptr(new KDSingleApplicationPrivate(name, this))
{
}
QString KDSingleApplication::name() const
{
Q_D(const KDSingleApplication);
return d->name();
}
bool KDSingleApplication::isPrimaryInstance() const
{
Q_D(const KDSingleApplication);
return d->isPrimaryInstance();
}
bool KDSingleApplication::sendMessage(const QByteArray &message)
{
return sendMessageWithTimeout(message, 5000);
}
bool KDSingleApplication::sendMessageWithTimeout(const QByteArray &message, int timeout)
{
Q_ASSERT(!isPrimaryInstance());
Q_D(KDSingleApplication);
return d->sendMessage(message, timeout);
}
KDSingleApplication::~KDSingleApplication() = default;

View File

@@ -0,0 +1,48 @@
/*
This file is part of KDSingleApplication.
SPDX-FileCopyrightText: 2019-2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
SPDX-License-Identifier: MIT
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#ifndef KDSINGLEAPPLICATION_H
#define KDSINGLEAPPLICATION_H
#include <QtCore/QObject>
#include <memory>
#include "kdsingleapplication_lib.h"
class KDSingleApplicationPrivate;
class KDSINGLEAPPLICATION_EXPORT KDSingleApplication : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(bool isPrimaryInstance READ isPrimaryInstance CONSTANT)
public:
explicit KDSingleApplication(QObject *parent = nullptr);
explicit KDSingleApplication(const QString &name, QObject *parent = nullptr);
~KDSingleApplication();
QString name() const;
bool isPrimaryInstance() const;
public Q_SLOTS:
// avoid default arguments and overloads, as they don't mix with connections
bool sendMessage(const QByteArray &message);
bool sendMessageWithTimeout(const QByteArray &message, int timeout);
Q_SIGNALS:
void messageReceived(const QByteArray &message);
private:
Q_DECLARE_PRIVATE(KDSingleApplication)
std::unique_ptr<KDSingleApplicationPrivate> d_ptr;
};
#endif // KDSINGLEAPPLICATION_H

View File

@@ -0,0 +1,23 @@
/*
This file is part of KDSingleApplication.
SPDX-FileCopyrightText: 2019-2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
SPDX-License-Identifier: MIT
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#ifndef KDSINGLEAPPLICATION_LIB_H
#define KDSINGLEAPPLICATION_LIB_H
#include <QtCore/QtGlobal>
#if defined(KDSINGLEAPPLICATION_STATIC_BUILD)
#define KDSINGLEAPPLICATION_EXPORT
#elif defined(KDSINGLEAPPLICATION_SHARED_BUILD)
#define KDSINGLEAPPLICATION_EXPORT Q_DECL_EXPORT
#else
#define KDSINGLEAPPLICATION_EXPORT Q_DECL_IMPORT
#endif
#endif // KDSINGLEAPPLICATION_LIB_H

View File

@@ -0,0 +1,315 @@
/*
This file is part of KDSingleApplication.
SPDX-FileCopyrightText: 2019-2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
SPDX-License-Identifier: MIT
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#include "kdsingleapplication_localsocket_p.h"
#include <QtCore/QDir>
#include <QtCore/QDeadlineTimer>
#include <QtCore/QTimer>
#include <QtCore/QLockFile>
#include <QtCore/QDataStream>
#include <QtCore/QtDebug>
#include <QtCore/QLoggingCategory>
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket>
#include <chrono>
#include <algorithm>
#ifdef Q_OS_UNIX
// for ::getuid()
# include <sys/types.h>
# include <unistd.h>
#endif
#ifdef Q_OS_WIN
# include <qt_windows.h>
#endif
namespace {
static constexpr auto LOCALSOCKET_CONNECTION_TIMEOUT = std::chrono::seconds(5);
static constexpr char LOCALSOCKET_PROTOCOL_VERSION = 2;
} // namespace
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-declarations"
#endif
Q_LOGGING_CATEGORY(kdsaLocalSocket, "kdsingleapplication.localsocket", QtWarningMsg)
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
KDSingleApplicationLocalSocket::KDSingleApplicationLocalSocket(const QString &name, QObject *parent)
: QObject(parent)
{
#if defined(Q_OS_UNIX)
/* cppcheck-suppress useInitializationList */
m_socketName = QStringLiteral("kdsingleapp-%1-%2")
.arg(::getuid())
.arg(name);
#elif defined(Q_OS_WIN)
// I'm not sure of a "global session identifier" on Windows; are
// multiple logins from the same user a possibility? For now, following this:
// https://docs.microsoft.com/en-us/windows/desktop/devnotes/getting-the-session-id-of-the-current-process
DWORD sessionId;
BOOL haveSessionId = ProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
m_socketName = QString::fromUtf8("kdsingleapp-%1-%2")
.arg(haveSessionId ? sessionId : 0)
.arg(name);
#else
#error "KDSingleApplication has not been ported to this platform"
#endif
const QString lockFilePath =
QDir::tempPath() + QLatin1Char('/') + m_socketName + QLatin1String(".lock");
qCDebug(kdsaLocalSocket) << "Socket name is" << m_socketName;
qCDebug(kdsaLocalSocket) << "Lock file path is" << lockFilePath;
std::unique_ptr<QLockFile> lockFile(new QLockFile(lockFilePath));
lockFile->setStaleLockTime(0);
if (!lockFile->tryLock()) {
// someone else has the lock => we're secondary
qCDebug(kdsaLocalSocket) << "Secondary instance";
return;
}
qCDebug(kdsaLocalSocket) << "Primary instance";
std::unique_ptr<QLocalServer> server = std::make_unique<QLocalServer>();
if (!server->listen(m_socketName)) {
// maybe the primary crashed, leaving a stale socket; delete it and try again
QLocalServer::removeServer(m_socketName);
if (!server->listen(m_socketName)) {
// TODO: better error handling.
qWarning("KDSingleApplication: unable to make the primary instance listen on %ls: %ls",
qUtf16Printable(m_socketName),
qUtf16Printable(server->errorString()));
return;
}
}
connect(server.get(), &QLocalServer::newConnection,
this, &KDSingleApplicationLocalSocket::handleNewConnection);
m_lockFile = std::move(lockFile);
m_localServer = std::move(server);
}
KDSingleApplicationLocalSocket::~KDSingleApplicationLocalSocket() = default;
bool KDSingleApplicationLocalSocket::isPrimaryInstance() const
{
return m_localServer != nullptr;
}
bool KDSingleApplicationLocalSocket::sendMessage(const QByteArray &message, int timeout)
{
Q_ASSERT(!isPrimaryInstance());
QLocalSocket socket;
qCDebug(kdsaLocalSocket) << "Preparing to send message" << message << "with timeout" << timeout;
QDeadlineTimer deadline(timeout);
// There is an inherent race here with the setup of the server side.
// Even if the socket lock is held by the server, the server may not
// be listening yet. So this connection may fail; keep retrying
// until we hit the timeout.
do {
socket.connectToServer(m_socketName);
if (socket.waitForConnected(static_cast<int>(deadline.remainingTime())))
break;
} while (!deadline.hasExpired());
qCDebug(kdsaLocalSocket) << "Socket state:" << socket.state() << "Timer remaining" << deadline.remainingTime() << "Expired?" << deadline.hasExpired();
if (deadline.hasExpired()) {
qCWarning(kdsaLocalSocket) << "Connection timed out";
return false;
}
socket.write(&LOCALSOCKET_PROTOCOL_VERSION, 1);
{
QByteArray encodedMessage;
QDataStream ds(&encodedMessage, QIODevice::WriteOnly);
ds << message;
socket.write(encodedMessage);
}
qCDebug(kdsaLocalSocket) << "Wrote message in the socket"
<< "Timer remaining" << deadline.remainingTime() << "Expired?" << deadline.hasExpired();
// There is no acknowledgement mechanism here.
// Should there be one?
while (socket.bytesToWrite() > 0) {
if (!socket.waitForBytesWritten(static_cast<int>(deadline.remainingTime()))) {
qCWarning(kdsaLocalSocket) << "Message to primary timed out";
return false;
}
}
qCDebug(kdsaLocalSocket) << "Bytes written, now disconnecting"
<< "Timer remaining" << deadline.remainingTime() << "Expired?" << deadline.hasExpired();
socket.disconnectFromServer();
if (socket.state() == QLocalSocket::UnconnectedState) {
qCDebug(kdsaLocalSocket) << "Disconnected -- success!";
return true;
}
if (!socket.waitForDisconnected(static_cast<int>(deadline.remainingTime()))) {
qCWarning(kdsaLocalSocket) << "Disconnection from primary timed out";
return false;
}
qCDebug(kdsaLocalSocket) << "Disconnected -- success!";
return true;
}
void KDSingleApplicationLocalSocket::handleNewConnection()
{
Q_ASSERT(m_localServer);
QLocalSocket *socket = nullptr;
while ((socket = m_localServer->nextPendingConnection())) {
qCDebug(kdsaLocalSocket) << "Got new connection on" << m_socketName << "state" << socket->state();
Connection c(socket);
socket = c.socket.get();
c.readDataConnection = QObjectConnectionHolder(
connect(socket, &QLocalSocket::readyRead,
this, &KDSingleApplicationLocalSocket::readDataFromSecondary));
c.secondaryDisconnectedConnection = QObjectConnectionHolder(
connect(socket, &QLocalSocket::disconnected,
this, &KDSingleApplicationLocalSocket::secondaryDisconnected));
c.abortConnection = QObjectConnectionHolder(
connect(c.timeoutTimer.get(), &QTimer::timeout,
this, &KDSingleApplicationLocalSocket::abortConnectionToSecondary));
m_clients.push_back(std::move(c));
// Note that by the time we get here, the socket could've already been closed,
// and no signals emitted (hello, Windows!). Read what's already in the socket.
if (readDataFromSecondarySocket(socket))
return;
if (socket->state() == QLocalSocket::UnconnectedState)
secondarySocketDisconnected(socket);
}
}
template<typename Container>
static auto findConnectionBySocket(Container &container, QLocalSocket *socket)
{
auto i = std::find_if(container.begin(),
container.end(),
[socket](const auto &c) { return c.socket.get() == socket; });
Q_ASSERT(i != container.end());
return i;
}
template<typename Container>
static auto findConnectionByTimer(Container &container, QTimer *timer)
{
auto i = std::find_if(container.begin(),
container.end(),
[timer](const auto &c) { return c.timeoutTimer.get() == timer; });
Q_ASSERT(i != container.end());
return i;
}
void KDSingleApplicationLocalSocket::readDataFromSecondary()
{
QLocalSocket *socket = static_cast<QLocalSocket *>(sender());
readDataFromSecondarySocket(socket);
}
bool KDSingleApplicationLocalSocket::readDataFromSecondarySocket(QLocalSocket *socket)
{
auto i = findConnectionBySocket(m_clients, socket);
Connection &c = *i;
c.readData.append(socket->readAll());
qCDebug(kdsaLocalSocket) << "Got more data from a secondary. Data read so far:" << c.readData;
const QByteArray &data = c.readData;
if (data.size() >= 1) {
if (data[0] != LOCALSOCKET_PROTOCOL_VERSION) {
qCDebug(kdsaLocalSocket) << "Got an invalid protocol version";
m_clients.erase(i);
return true;
}
}
QDataStream ds(data);
ds.skipRawData(1);
ds.startTransaction();
QByteArray message;
ds >> message;
if (ds.commitTransaction()) {
qCDebug(kdsaLocalSocket) << "Got a complete message:" << message;
Q_EMIT messageReceived(message);
m_clients.erase(i);
return true;
}
return false;
}
void KDSingleApplicationLocalSocket::secondaryDisconnected()
{
QLocalSocket *socket = static_cast<QLocalSocket *>(sender());
secondarySocketDisconnected(socket);
}
void KDSingleApplicationLocalSocket::secondarySocketDisconnected(QLocalSocket *socket)
{
auto i = findConnectionBySocket(m_clients, socket);
Connection c = std::move(*i);
m_clients.erase(i);
qCDebug(kdsaLocalSocket) << "Secondary disconnected. Data read:" << c.readData;
}
void KDSingleApplicationLocalSocket::abortConnectionToSecondary()
{
QTimer *timer = static_cast<QTimer *>(sender());
auto i = findConnectionByTimer(m_clients, timer);
Connection c = std::move(*i);
m_clients.erase(i);
qCDebug(kdsaLocalSocket) << "Secondary timed out. Data read:" << c.readData;
}
KDSingleApplicationLocalSocket::Connection::Connection(QLocalSocket *_socket)
: socket(_socket)
, timeoutTimer(new QTimer)
{
timeoutTimer->start(LOCALSOCKET_CONNECTION_TIMEOUT);
}

View File

@@ -0,0 +1,126 @@
/*
This file is part of KDSingleApplication.
SPDX-FileCopyrightText: 2019-2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
SPDX-License-Identifier: MIT
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#ifndef KDSINGLEAPPLICATION_LOCALSOCKET_P_H
#define KDSINGLEAPPLICATION_LOCALSOCKET_P_H
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QString>
QT_BEGIN_NAMESPACE
class QLockFile;
class QLocalServer;
class QLocalSocket;
class QTimer;
QT_END_NAMESPACE
#include <memory>
#include <vector>
struct QObjectDeleteLater
{
void operator()(QObject *o)
{
o->deleteLater();
}
};
class QObjectConnectionHolder
{
Q_DISABLE_COPY(QObjectConnectionHolder)
QMetaObject::Connection c;
public:
QObjectConnectionHolder()
{
}
explicit QObjectConnectionHolder(QMetaObject::Connection _c)
: c(std::move(_c))
{
}
~QObjectConnectionHolder()
{
QObject::disconnect(c);
}
QObjectConnectionHolder(QObjectConnectionHolder &&other) noexcept
: c(std::exchange(other.c, {}))
{
}
QObjectConnectionHolder &operator=(QObjectConnectionHolder &&other) noexcept
{
QObjectConnectionHolder moved(std::move(other));
swap(moved);
return *this;
}
void swap(QObjectConnectionHolder &other) noexcept
{
using std::swap;
swap(c, other.c);
}
};
class KDSingleApplicationLocalSocket : public QObject
{
Q_OBJECT
public:
explicit KDSingleApplicationLocalSocket(const QString &name,
QObject *parent = nullptr);
~KDSingleApplicationLocalSocket();
bool isPrimaryInstance() const;
public Q_SLOTS:
bool sendMessage(const QByteArray &message, int timeout);
Q_SIGNALS:
void messageReceived(const QByteArray &message);
private:
void handleNewConnection();
void readDataFromSecondary();
bool readDataFromSecondarySocket(QLocalSocket *socket);
void secondaryDisconnected();
void secondarySocketDisconnected(QLocalSocket *socket);
void abortConnectionToSecondary();
QString m_socketName;
std::unique_ptr<QLockFile> m_lockFile; // protects m_localServer
std::unique_ptr<QLocalServer> m_localServer;
struct Connection
{
explicit Connection(QLocalSocket *s);
std::unique_ptr<QLocalSocket, QObjectDeleteLater> socket;
std::unique_ptr<QTimer, QObjectDeleteLater> timeoutTimer;
QByteArray readData;
// socket/timeoutTimer are deleted via deleteLater (as we delete them
// in slots connected to their signals). Before the deleteLater is acted upon,
// they may emit further signals, triggering logic that it's not supposed
// to be triggered (as the Connection has already been destroyed).
// Use this Holder to break the connections.
QObjectConnectionHolder readDataConnection;
QObjectConnectionHolder secondaryDisconnectedConnection;
QObjectConnectionHolder abortConnection;
};
std::vector<Connection> m_clients;
};
#endif // KDSINGLEAPPLICATION_LOCALSOCKET_P_H

View File

@@ -64,7 +64,6 @@ int main(int argc, char **argv)
qDebug() << " -appstore-compliant : Skip deployment of components that use private API";
qDebug() << " -libpath=<path> : Add the given path to the library search path";
qDebug() << " -fs=<filesystem> : Set the filesystem used for the .dmg disk image (defaults to HFS+)";
qDebug() << " -plugins-dir=<path> : Set plugins directory";
qDebug() << "";
qDebug() << "macdeployqt takes an application bundle as input and makes it";
qDebug() << "self-contained by copying in the Qt frameworks and plugins that";
@@ -88,7 +87,7 @@ int main(int argc, char **argv)
appBundlePath = QDir::cleanPath(appBundlePath);
if (QDir().exists(appBundlePath) == false) {
if (!QDir(appBundlePath).exists()) {
qDebug() << "Error: Could not find app bundle" << appBundlePath;
return 1;
}
@@ -110,7 +109,6 @@ int main(int argc, char **argv)
extern bool appstoreCompliant;
extern bool deployFramework;
extern bool secureTimestamp;
QString plugin_dir;
for (int i = 2; i < argc; ++i) {
QByteArray argument = QByteArray(argv[i]);
@@ -198,7 +196,7 @@ int main(int argc, char **argv)
LogDebug() << "Argument found:" << argument;
appstoreCompliant = true;
// Undocumented option, may not work as intented
// Undocumented option, may not work as intended
} else if (argument == QByteArray("-deploy-framework")) {
LogDebug() << "Argument found:" << argument;
deployFramework = true;
@@ -210,13 +208,6 @@ int main(int argc, char **argv)
LogError() << "Missing filesystem type";
else
filesystem = argument.mid(index+1);
} else if (argument.startsWith(QByteArray("-plugins-dir"))) {
LogDebug() << "Argument found:" << argument;
int index = argument.indexOf('=');
if (index == -1)
LogError() << "Missing filesystem type";
else
plugin_dir = argument.mid(index+1);
} else if (argument.startsWith("-")) {
LogError() << "Unknown argument" << argument << "\n";
return 1;
@@ -231,7 +222,7 @@ int main(int argc, char **argv)
if (deployFramework && deploymentInfo.isFramework)
fixupFramework(appBundlePath);
// Convenience: Look for .qml files in the current directoty if no -qmldir specified.
// Convenience: Look for .qml files in the current directory if no -qmldir specified.
if (qmlDirs.isEmpty()) {
QDir dir;
if (!dir.entryList(QStringList() << QStringLiteral("*.qml")).isEmpty()) {
@@ -252,36 +243,37 @@ int main(int argc, char **argv)
deploymentInfo.deployedFrameworks.end()).values();
}
// Handle plugins
if (plugins) {
if (plugin_dir.isEmpty()) {
// Set the plugins search directory
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
deploymentInfo.pluginPath = QLibraryInfo::path(QLibraryInfo::PluginsPath);
}
else {
deploymentInfo.pluginPath = plugin_dir;
}
if (deploymentInfo.pluginPath.isEmpty()) {
LogError() << "Missing Qt plugins path\n";
return 1;
}
if (!QDir(deploymentInfo.pluginPath).exists()) {
LogError() << "Plugins path does not exist\n" << deploymentInfo.pluginPath;
return 1;
}
Q_ASSERT(!deploymentInfo.pluginPath.isEmpty());
if (!deploymentInfo.pluginPath.isEmpty()) {
LogNormal();
deployPlugins(appBundlePath, deploymentInfo, useDebugLibs);
createQtConf(appBundlePath);
}
#else
deploymentInfo.pluginPath = QLibraryInfo::location(QLibraryInfo::PluginsPath);
#endif
// Sanity checks
if (deploymentInfo.pluginPath.isEmpty()) {
LogError() << "Missing Qt plugins path\n";
return 1;
}
if (!QDir(deploymentInfo.pluginPath).exists()) {
LogError() << "Plugins path does not exist" << deploymentInfo.pluginPath << "\n";
return 1;
}
// Deploy plugins
Q_ASSERT(!deploymentInfo.pluginPath.isEmpty());
if (!deploymentInfo.pluginPath.isEmpty()) {
LogNormal();
deployPlugins(appBundlePath, deploymentInfo, useDebugLibs);
createQtConf(appBundlePath);
}
}
if (runStripEnabled)
stripAppBinary(appBundlePath);
if (!FinalCheck(appBundlePath)) {
return 1;
}
if (runCodesign)
codesign(codesignIdentiy, appBundlePath);

View File

@@ -35,9 +35,13 @@
#include <QStringList>
#include <QDebug>
#include <iostream>
#include <utility>
#include <QProcess>
#include <QDir>
#include <QSet>
#include <QList>
#include <QVariant>
#include <QVariantMap>
#include <QStack>
#include <QDirIterator>
#include <QLibraryInfo>
@@ -102,7 +106,7 @@ inline QDebug operator<<(QDebug debug, const ApplicationBundleInfo &info)
bool copyFilePrintStatus(const QString &from, const QString &to)
{
if (QFile(to).exists()) {
if (QFile::exists(to)) {
if (alwaysOwerwriteEnabled) {
QFile(to).remove();
} else {
@@ -139,7 +143,7 @@ bool copyFilePrintStatus(const QString &from, const QString &to)
bool linkFilePrintStatus(const QString &file, const QString &link)
{
if (QFile(link).exists()) {
if (QFile::exists(link)) {
if (QFile(link).symLinkTarget().isEmpty())
LogError() << link << "exists but it's a file.";
else
@@ -185,9 +189,7 @@ OtoolInfo findDependencyInfo(const QString &binaryPath)
return info;
}
static const QRegularExpression regexp(QStringLiteral(
"^\\t(.+) \\(compatibility version (\\d+\\.\\d+\\.\\d+), "
"current version (\\d+\\.\\d+\\.\\d+)(, weak)?\\)$"));
static const QRegularExpression regexp(QStringLiteral("^\\t(.+) \\(compatibility version (\\d+\\.\\d+\\.\\d+), current version (\\d+\\.\\d+\\.\\d+)(, weak|, reexport)?\\)$"));
QString output = otool.readAllStandardOutput();
QStringList outputLines = output.split("\n", Qt::SkipEmptyParts);
@@ -200,18 +202,26 @@ OtoolInfo findDependencyInfo(const QString &binaryPath)
if (binaryPath.contains(".framework/") || binaryPath.endsWith(".dylib")) {
const auto match = regexp.match(outputLines.first());
if (match.hasMatch()) {
info.installName = match.captured(1);
info.compatibilityVersion = QVersionNumber::fromString(match.captured(2));
info.currentVersion = QVersionNumber::fromString(match.captured(3));
QString installname = match.captured(1);
if (QFileInfo(binaryPath).fileName() == QFileInfo(installname).fileName()) {
info.installName = installname;
info.compatibilityVersion = QVersionNumber::fromString(match.captured(2));
info.currentVersion = QVersionNumber::fromString(match.captured(3));
outputLines.removeFirst();
} else {
info.installName = binaryPath;
}
} else {
LogError() << "Could not parse otool output line:" << outputLines.first();
outputLines.removeFirst();
}
//outputLines.removeFirst();
}
for (const QString &outputLine : outputLines) {
const auto match = regexp.match(outputLine);
if (match.hasMatch()) {
if (match.captured(1) == info.installName)
continue; // Another arch reference to the same binary
DylibInfo dylib;
dylib.binaryPath = match.captured(1);
dylib.compatibilityVersion = QVersionNumber::fromString(match.captured(2));
@@ -225,7 +235,7 @@ OtoolInfo findDependencyInfo(const QString &binaryPath)
return info;
}
FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs)
FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs)
{
FrameworkInfo info;
QString trimmed = line.trimmed();
@@ -243,7 +253,7 @@ FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundl
if (trimmed.startsWith("@rpath/")) {
QString rpathRelativePath = trimmed.mid(QStringLiteral("@rpath/").length());
bool foundInsideBundle = false;
foreach (const QString &rpath, rpaths) {
for (const QString &rpath : std::as_const(rpaths)) {
QString path = QDir::cleanPath(rpath + "/" + rpathRelativePath);
// Skip paths already inside the bundle.
if (!appBundlePath.isEmpty()) {
@@ -284,7 +294,7 @@ FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundl
// Split the line into [Qt-path]/lib/qt[Module].framework/Versions/[Version]/
QStringList parts = trimmed.split("/");
while (part < parts.count()) {
const QString currentPart = parts.at(part).simplified() ;
const QString currentPart = parts.at(part).simplified();
++part;
if (currentPart == "")
continue;
@@ -292,17 +302,17 @@ FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundl
if (state == QtPath) {
// Check for library name part
if (part < parts.count() && parts.at(part).contains(".dylib")) {
info.frameworkDirectory += "/" + (qtPath + currentPart + "/").simplified();
info.frameworkDirectory += "/" + QString(qtPath + currentPart + "/").simplified();
state = DylibName;
continue;
} else if (part < parts.count() && parts.at(part).endsWith(".framework")) {
info.frameworkDirectory += "/" + (qtPath + "lib/").simplified();
info.frameworkDirectory += "/" + QString(qtPath + "lib/").simplified();
state = FrameworkName;
continue;
} else if (trimmed.startsWith("/") == false) { // If the line does not contain a full path, the app is using a binary Qt package.
QStringList partsCopy = parts;
partsCopy.removeLast();
foreach (QString path, librarySearchPath) {
for (QString &path : librarySearchPath) {
if (!path.endsWith("/"))
path += '/';
QString nameInPath = path + parts.join(QLatin1Char('/'));
@@ -496,7 +506,7 @@ QString findEntitlementsFile(const QString& path)
return QString();
}
QList<FrameworkInfo> getQtFrameworks(const QList<DylibInfo> &dependencies, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs)
QList<FrameworkInfo> getQtFrameworks(const QList<DylibInfo> &dependencies, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs)
{
QList<FrameworkInfo> libraries;
for (const DylibInfo &dylibInfo : dependencies) {
@@ -536,9 +546,9 @@ QString resolveDyldPrefix(const QString &path, const QString &loaderPath, const
return path;
}
QSet<QString> getBinaryRPaths(const QString &path, bool resolve = true, QString executablePath = QString())
QList<QString> getBinaryRPaths(const QString &path, bool resolve = true, QString executablePath = QString())
{
QSet<QString> rpaths;
QList<QString> rpaths;
QProcess otool;
otool.start("otool", QStringList() << "-l" << path);
@@ -575,18 +585,20 @@ QSet<QString> getBinaryRPaths(const QString &path, bool resolve = true, QString
return rpaths;
}
QList<FrameworkInfo> getQtFrameworks(const QString &path, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs)
QList<FrameworkInfo> getQtFrameworks(const QString &path, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs)
{
const OtoolInfo info = findDependencyInfo(path);
return getQtFrameworks(info.dependencies, appBundlePath, rpaths + getBinaryRPaths(path), useDebugLibs);
QList<QString> allRPaths = rpaths + getBinaryRPaths(path);
allRPaths.removeDuplicates();
return getQtFrameworks(info.dependencies, appBundlePath, allRPaths, useDebugLibs);
}
QList<FrameworkInfo> getQtFrameworksForPaths(const QStringList &paths, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs)
QList<FrameworkInfo> getQtFrameworksForPaths(const QStringList &paths, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs)
{
QList<FrameworkInfo> result;
QSet<QString> existing;
foreach (const QString &path, paths) {
foreach (const FrameworkInfo &info, getQtFrameworks(path, appBundlePath, rpaths, useDebugLibs)) {
for (const QString &path : paths) {
for (const FrameworkInfo &info : getQtFrameworks(path, appBundlePath, rpaths, useDebugLibs)) {
if (!existing.contains(info.frameworkPath)) { // avoid duplicates
existing.insert(info.frameworkPath);
result << info;
@@ -605,10 +617,10 @@ QStringList getBinaryDependencies(const QString executablePath,
const auto dependencies = findDependencyInfo(path).dependencies;
bool rpathsLoaded = false;
QSet<QString> rpaths;
QList<QString> rpaths;
// return bundle-local dependencies. (those starting with @executable_path)
foreach (const DylibInfo &info, dependencies) {
for (const DylibInfo &info : dependencies) {
QString trimmedLine = info.binaryPath;
if (trimmedLine.startsWith("@executable_path/")) {
QString binary = QDir::cleanPath(executablePath + trimmedLine.mid(QStringLiteral("@executable_path/").length()));
@@ -617,14 +629,14 @@ QStringList getBinaryDependencies(const QString executablePath,
} else if (trimmedLine.startsWith("@rpath/")) {
if (!rpathsLoaded) {
rpaths = getBinaryRPaths(path, true, executablePath);
foreach (const QString &binaryPath, additionalBinariesContainingRpaths) {
QSet<QString> binaryRpaths = getBinaryRPaths(binaryPath, true);
rpaths += binaryRpaths;
for (const QString &binaryPath : additionalBinariesContainingRpaths) {
rpaths += getBinaryRPaths(binaryPath, true);
}
rpaths.removeDuplicates();
rpathsLoaded = true;
}
bool resolved = false;
foreach (const QString &rpath, rpaths) {
for (const QString &rpath : std::as_const(rpaths)) {
QString binary = QDir::cleanPath(rpath + "/" + trimmedLine.mid(QStringLiteral("@rpath/").length()));
LogDebug() << "Checking for" << binary;
if (QFile::exists(binary)) {
@@ -653,20 +665,20 @@ bool recursiveCopy(const QString &sourcePath, const QString &destinationPath)
LogNormal() << "copy:" << sourcePath << destinationPath;
QStringList files = QDir(sourcePath).entryList(QStringList() << "*", QDir::Files | QDir::NoDotAndDotDot);
foreach (QString file, files) {
for (const QString &file : files) {
const QString fileSourcePath = sourcePath + "/" + file;
const QString fileDestinationPath = destinationPath + "/" + file;
copyFilePrintStatus(fileSourcePath, fileDestinationPath);
}
QStringList subdirs = QDir(sourcePath).entryList(QStringList() << "*", QDir::Dirs | QDir::NoDotAndDotDot);
foreach (QString dir, subdirs) {
for (const QString &dir : subdirs) {
recursiveCopy(sourcePath + "/" + dir, destinationPath + "/" + dir);
}
return true;
}
void recursiveCopyAndDeploy(const QString &appBundlePath, const QSet<QString> &rpaths, const QString &sourcePath, const QString &destinationPath)
void recursiveCopyAndDeploy(const QString &appBundlePath, const QList<QString> &rpaths, const QString &sourcePath, const QString &destinationPath)
{
QDir().mkpath(destinationPath);
@@ -674,7 +686,7 @@ void recursiveCopyAndDeploy(const QString &appBundlePath, const QSet<QString> &r
const bool isDwarfPath = sourcePath.endsWith("DWARF");
QStringList files = QDir(sourcePath).entryList(QStringList() << QStringLiteral("*"), QDir::Files | QDir::NoDotAndDotDot);
foreach (QString file, files) {
for (const QString &file : files) {
const QString fileSourcePath = sourcePath + QLatin1Char('/') + file;
if (file.endsWith("_debug.dylib")) {
@@ -720,7 +732,7 @@ void recursiveCopyAndDeploy(const QString &appBundlePath, const QSet<QString> &r
}
QStringList subdirs = QDir(sourcePath).entryList(QStringList() << QStringLiteral("*"), QDir::Dirs | QDir::NoDotAndDotDot);
foreach (QString dir, subdirs) {
for (const QString &dir : subdirs) {
recursiveCopyAndDeploy(appBundlePath, rpaths, sourcePath + QLatin1Char('/') + dir, destinationPath + QLatin1Char('/') + dir);
}
}
@@ -743,8 +755,8 @@ QString copyDylib(const FrameworkInfo &framework, const QString path)
return QString();
}
// Retrun if the dylib has aleardy been deployed
if (QFileInfo(dylibDestinationBinaryPath).exists() && !alwaysOwerwriteEnabled)
// Return if the dylib has already been deployed
if (QFileInfo::exists(dylibDestinationBinaryPath) && !alwaysOwerwriteEnabled)
return dylibDestinationBinaryPath;
// Copy dylib binary
@@ -777,13 +789,13 @@ QString copyFramework(const FrameworkInfo &framework, const QString path)
// Now copy the framework. Some parts should be left out (headers/, .prl files).
// Some parts should be included (Resources/, symlink structure). We want this
// function to make as few assumtions about the framework as possible while at
// function to make as few assumptions about the framework as possible while at
// the same time producing a codesign-compatible framework.
// Copy framework binary
copyFilePrintStatus(framework.sourceFilePath, frameworkDestinationBinaryPath);
// Copy Resouces/, Libraries/ and Helpers/
// Copy Resources/, Libraries/ and Helpers/
const QString resourcesSourcePath = framework.frameworkPath + "/Resources";
const QString resourcesDestianationPath = frameworkDestinationDirectory + "/Versions/" + framework.version + "/Resources";
recursiveCopy(resourcesSourcePath, resourcesDestianationPath);
@@ -811,7 +823,7 @@ QString copyFramework(const FrameworkInfo &framework, const QString path)
// Contents/Info.plist should be Versions/5/Resources/Info.plist
const QString legacyInfoPlistPath = framework.frameworkPath + "/Contents/Info.plist";
const QString correctInfoPlistPath = frameworkDestinationDirectory + "/Resources/Info.plist";
if (QFile(legacyInfoPlistPath).exists()) {
if (QFile::exists(legacyInfoPlistPath)) {
copyFilePrintStatus(legacyInfoPlistPath, correctInfoPlistPath);
patch_debugInInfoPlist(correctInfoPlistPath);
}
@@ -841,7 +853,7 @@ void changeIdentification(const QString &id, const QString &binaryPath)
void changeInstallName(const QString &bundlePath, const FrameworkInfo &framework, const QStringList &binaryPaths, bool useLoaderPath)
{
const QString absBundlePath = QFileInfo(bundlePath).absoluteFilePath();
foreach (const QString &binary, binaryPaths) {
for (const QString &binary : binaryPaths) {
QString deployedInstallName;
if (useLoaderPath) {
deployedInstallName = QLatin1String("@loader_path/")
@@ -849,17 +861,23 @@ void changeInstallName(const QString &bundlePath, const FrameworkInfo &framework
} else {
deployedInstallName = framework.deployedInstallName;
}
changeInstallName(framework.installName, deployedInstallName, binary);
if (!framework.sourceFilePath.isEmpty()) {
changeInstallName(framework.sourceFilePath, deployedInstallName, binary);
}
if (!framework.installName.isEmpty() && framework.installName != framework.sourceFilePath) {
changeInstallName(framework.installName, deployedInstallName, binary);
}
// Workaround for the case when the library ID name is a symlink, while the dependencies
// specified using the canonical path to the library (QTBUG-56814)
QString canonicalInstallName = QFileInfo(framework.installName).canonicalFilePath();
QFileInfo fileInfo= QFileInfo(framework.installName);
QString canonicalInstallName = fileInfo.canonicalFilePath();
if (!canonicalInstallName.isEmpty() && canonicalInstallName != framework.installName) {
changeInstallName(canonicalInstallName, deployedInstallName, binary);
}
// Homebrew workaround, resolve symlink /usr/local/opt/library to /usr/local/Cellar/library
if (framework.installName.startsWith("/usr/local/opt/") && framework.installName.count('/') >= 5) {
canonicalInstallName = QFileInfo(framework.installName.section('/', 0, 4)).canonicalFilePath() + "/" + framework.installName.section('/', 5);
changeInstallName(canonicalInstallName, deployedInstallName, binary);
// some libraries' inner dependencies (such as ffmpeg, nettle) use symbol link (QTBUG-100093)
QString innerDependency = fileInfo.canonicalPath() + "/" + fileInfo.fileName();
if (innerDependency != canonicalInstallName && innerDependency != framework.installName) {
changeInstallName(innerDependency, deployedInstallName, binary);
}
}
}
}
@@ -869,7 +887,7 @@ void addRPath(const QString &rpath, const QString &binaryPath)
runInstallNameTool(QStringList() << "-add_rpath" << rpath << binaryPath);
}
void deployRPaths(const QString &bundlePath, const QSet<QString> &rpaths, const QString &binaryPath, bool useLoaderPath)
void deployRPaths(const QString &bundlePath, const QList<QString> &rpaths, const QString &binaryPath, bool useLoaderPath)
{
const QString absFrameworksPath = QFileInfo(bundlePath).absoluteFilePath()
+ QLatin1String("/Contents/Frameworks");
@@ -877,7 +895,8 @@ void deployRPaths(const QString &bundlePath, const QSet<QString> &rpaths, const
const QString loaderPathToFrameworks = QLatin1String("@loader_path/") + relativeFrameworkPath;
bool rpathToFrameworksFound = false;
QStringList args;
foreach (const QString &rpath, getBinaryRPaths(binaryPath, false)) {
QList<QString> binaryRPaths = getBinaryRPaths(binaryPath, false);
for (const QString &rpath : std::as_const(binaryRPaths)) {
if (rpath == "@executable_path/../Frameworks" ||
rpath == loaderPathToFrameworks) {
rpathToFrameworksFound = true;
@@ -903,9 +922,9 @@ void deployRPaths(const QString &bundlePath, const QSet<QString> &rpaths, const
runInstallNameTool(QStringList() << args << binaryPath);
}
void deployRPaths(const QString &bundlePath, const QSet<QString> &rpaths, const QStringList &binaryPaths, bool useLoaderPath)
void deployRPaths(const QString &bundlePath, const QList<QString> &rpaths, const QStringList &binaryPaths, bool useLoaderPath)
{
foreach (const QString &binary, binaryPaths) {
for (const QString &binary : binaryPaths) {
deployRPaths(bundlePath, rpaths, binary, useLoaderPath);
}
}
@@ -971,7 +990,7 @@ DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks,
deploymentInfo.useLoaderPath = useLoaderPath;
deploymentInfo.isFramework = bundlePath.contains(".framework");
deploymentInfo.isDebug = false;
QSet<QString> rpathsUsed;
QList<QString> rpathsUsed;
while (frameworks.isEmpty() == false) {
const FrameworkInfo framework = frameworks.takeFirst();
@@ -983,16 +1002,22 @@ DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks,
if (framework.isDebugLibrary())
deploymentInfo.isDebug = true;
if (deploymentInfo.qtPath.isNull())
if (deploymentInfo.qtPath.isNull()) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
deploymentInfo.qtPath = QLibraryInfo::path(QLibraryInfo::PrefixPath);
#else
deploymentInfo.qtPath = QLibraryInfo::location(QLibraryInfo::PrefixPath);
#endif
}
if (framework.frameworkDirectory.startsWith(bundlePath)) {
LogError() << framework.frameworkName << "already deployed, skipping.";
continue;
}
if (!framework.rpathUsed.isEmpty())
rpathsUsed << framework.rpathUsed;
if (!framework.rpathUsed.isEmpty() && !rpathsUsed.contains(framework.rpathUsed)) {
rpathsUsed.append(framework.rpathUsed);
}
// Copy the framework/dylib to the app bundle.
const QString deployedBinaryPath = framework.isDylib ? copyDylib(framework, bundlePath)
@@ -1015,11 +1040,11 @@ DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks,
// Check for framework dependencies
QList<FrameworkInfo> dependencies = getQtFrameworks(deployedBinaryPath, bundlePath, rpathsUsed, useDebugLibs);
foreach (FrameworkInfo dependency, dependencies) {
for (const FrameworkInfo &dependency : dependencies) {
if (dependency.rpathUsed.isEmpty()) {
changeInstallName(bundlePath, dependency, QStringList() << deployedBinaryPath, useLoaderPath);
} else {
rpathsUsed << dependency.rpathUsed;
rpathsUsed.append(dependency.rpathUsed);
}
// Deploy framework if necessary.
@@ -1031,6 +1056,7 @@ DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks,
deploymentInfo.deployedFrameworks = copiedFrameworks;
deployRPaths(bundlePath, rpathsUsed, binaryPaths, useLoaderPath);
deploymentInfo.rpathsUsed += rpathsUsed;
deploymentInfo.rpathsUsed.removeDuplicates();
return deploymentInfo;
}
@@ -1042,8 +1068,14 @@ DeploymentInfo deployQtFrameworks(const QString &appBundlePath, const QStringLis
applicationBundle.libraryPaths = findAppLibraries(appBundlePath);
QStringList allBinaryPaths = QStringList() << applicationBundle.binaryPath << applicationBundle.libraryPaths
<< additionalExecutables;
QSet<QString> allLibraryPaths = getBinaryRPaths(applicationBundle.binaryPath, true);
allLibraryPaths.insert(QLibraryInfo::path(QLibraryInfo::LibrariesPath));
QList<QString> allLibraryPaths = getBinaryRPaths(applicationBundle.binaryPath, true);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
allLibraryPaths.append(QLibraryInfo::path(QLibraryInfo::LibrariesPath));
#else
allLibraryPaths.append(QLibraryInfo::location(QLibraryInfo::LibrariesPath));
#endif
allLibraryPaths.removeDuplicates();
QList<FrameworkInfo> frameworks = getQtFrameworksForPaths(allBinaryPaths, appBundlePath, allLibraryPaths, useDebugLibs);
if (frameworks.isEmpty() && !alwaysOwerwriteEnabled) {
LogWarning();
@@ -1059,8 +1091,8 @@ DeploymentInfo deployQtFrameworks(const QString &appBundlePath, const QStringLis
QString getLibInfix(const QStringList &deployedFrameworks)
{
QString libInfix;
foreach (const QString &framework, deployedFrameworks) {
if (framework.startsWith(QStringLiteral("QtCore")) && framework.endsWith(QStringLiteral(".framework"))) {
for (const QString &framework : deployedFrameworks) {
if (framework.startsWith(QStringLiteral("QtCore")) && framework.endsWith(QStringLiteral(".framework")) && !framework.contains(QStringLiteral("5Compat"))) {
Q_ASSERT(framework.length() >= 16);
// 16 == "QtCore" + ".framework"
const int lengthOfLibInfix = framework.length() - 16;
@@ -1114,7 +1146,7 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
// Network
if (deploymentInfo.containsModule("Network", libInfix))
addPlugins(QStringLiteral("bearer"));
addPlugins(QStringLiteral("tls"));
// All image formats (svg if QtSvg is used)
const bool usesSvg = deploymentInfo.containsModule("Svg", libInfix);
@@ -1181,7 +1213,7 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
}
}
foreach (const QString &plugin, pluginList) {
for (const QString &plugin : pluginList) {
QString sourcePath = pluginSourcePath + "/" + plugin;
const QString destinationPath = pluginDestinationPath + "/" + plugin;
QDir dir;
@@ -1196,27 +1228,57 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
// GIO modules
{
QString sourcePath = qgetenv("GIO_EXTRA_MODULES");
if (sourcePath.isEmpty()) {
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 (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
{
QString sourcePath = qgetenv("GST_PLUGIN_SCANNER");
if (sourcePath.isEmpty()) {
sourcePath = "/usr/local/opt/gstreamer/libexec/gstreamer-1.0/gst-plugin-scanner";
if (QFileInfo::exists("/usr/local/opt/gstreamer/libexec/gstreamer-1.0/gst-plugin-scanner")) {
sourcePath = "/usr/local/opt/gstreamer/libexec/gstreamer-1.0/gst-plugin-scanner";
}
else if (QFileInfo::exists("/opt/local/libexec/gstreamer-1.0/gst-plugin-scanner")) {
sourcePath = "/opt/local/libexec/gstreamer-1.0/gst-plugin-scanner";
}
else {
qFatal("Missing GST_PLUGIN_SCANNER.");
}
}
const QString destinationPath = appBundleInfo.path + "/" + "Contents/PlugIns/gst-plugin-scanner";
QDir dir;
@@ -1228,8 +1290,13 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
}
// GStreamer plugins.
QStringList gstreamer_plugins = QStringList() << "libgstapetag.dylib"
QStringList gstreamer_plugins = QStringList()
<< "libgstaes.dylib"
<< "libgstaiff.dylib"
<< "libgstapetag.dylib"
<< "libgstapp.dylib"
<< "libgstasf.dylib"
<< "libgstasfmux.dylib"
<< "libgstaudioconvert.dylib"
<< "libgstaudiofx.dylib"
<< "libgstaudiomixer.dylib"
@@ -1237,61 +1304,88 @@ 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"
<< "libgstgio.dylib"
<< "libgsticydemux.dylib"
<< "libgstid3demux.dylib"
<< "libgstlevel.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"
<< "libgstrtp.dylib"
<< "libgstrtsp.dylib"
<< "libgstflac.dylib"
<< "libgstwavparse.dylib"
<< "libgstfaac.dylib"
<< "libgstfaad.dylib"
<< "libgstfdkaac.dylib"
<< "libgstflac.dylib"
<< "libgstgio.dylib"
//<< "libgstgme.dylib"
<< "libgsthls.dylib"
<< "libgsticydemux.dylib"
<< "libgstid3demux.dylib"
<< "libgstid3tag.dylib"
<< "libgstisomp4.dylib"
<< "libgstlame.dylib"
<< "libgstlibav.dylib"
<< "libgstmpg123.dylib"
<< "libgstmusepack.dylib"
<< "libgstogg.dylib"
<< "libgstopenmpt.dylib"
<< "libgstopus.dylib"
<< "libgstopusparse.dylib"
<< "libgstasf.dylib"
<< "libgstosxaudio.dylib"
<< "libgstpbtypes.dylib"
<< "libgstplayback.dylib"
<< "libgstreplaygain.dylib"
<< "libgstrtp.dylib"
<< "libgstrtsp.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"
<< "libgstmusepack.dylib";
<< "libgstwavenc.dylib"
<< "libgstwavpack.dylib"
<< "libgstwavparse.dylib"
<< "libgstxingmux.dylib";
QString gstreamer_plugins_dir = qgetenv("GST_PLUGIN_PATH");
if (gstreamer_plugins_dir.isEmpty()) {
gstreamer_plugins_dir = "/usr/local/lib/gstreamer-1.0";
}
QString gstreamer_plugins_dir = qgetenv("GST_PLUGIN_PATH");
if (gstreamer_plugins_dir.isEmpty()) {
if (QDir().exists("/usr/local/lib/gstreamer-1.0")) {
gstreamer_plugins_dir = "/usr/local/lib/gstreamer-1.0";
}
else if (QDir().exists("/opt/local/lib/gstreamer-1.0")) {
gstreamer_plugins_dir = "/opt/local/lib/gstreamer-1.0";
}
else {
qFatal("Missing GST_PLUGIN_PATH.");
}
}
QStringList missing_gst_plugins;
for (const QString &plugin : gstreamer_plugins) {
const QString sourcePath = gstreamer_plugins_dir + "/" + plugin;
const QString destinationPath = appBundleInfo.path + "/Contents/PlugIns/gstreamer/" + plugin;
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);
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();
missing_gst_plugins << 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;
}
}
@@ -1337,7 +1431,7 @@ void deployPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo,
deployPlugins(applicationBundle, deploymentInfo.pluginPath, pluginDestinationPath, deploymentInfo, useDebugLibs);
}
void deployQmlImport(const QString &appBundlePath, const QSet<QString> &rpaths, const QString &importSourcePath, const QString &importName)
void deployQmlImport(const QString &appBundlePath, const QList<QString> &rpaths, const QString &importSourcePath, const QString &importName)
{
QString importDestinationPath = appBundlePath + "/Contents/Resources/qml/" + importName;
@@ -1366,15 +1460,19 @@ bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInf
LogNormal() << "Application QML file path(s) is" << qmlDirs;
LogNormal() << "QML module search path(s) is" << qmlImportPaths;
// Use qmlimportscanner from QLibraryInfo::BinariesPath
QString qmlImportScannerPath = QDir::cleanPath(QLibraryInfo::path(QLibraryInfo::BinariesPath) + "/qmlimportscanner");
// Use qmlimportscanner from QLibraryInfo::LibraryExecutablesPath
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QString qmlImportScannerPath = QDir::cleanPath(QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath) + "/qmlimportscanner");
#else
QString qmlImportScannerPath = QDir::cleanPath(QLibraryInfo::location(QLibraryInfo::LibraryExecutablesPath) + "/qmlimportscanner");
#endif
// Fallback: Look relative to the macdeployqt binary
if (!QFile(qmlImportScannerPath).exists())
if (!QFile::exists(qmlImportScannerPath))
qmlImportScannerPath = QCoreApplication::applicationDirPath() + "/qmlimportscanner";
// Verify that we found a qmlimportscanner binary
if (!QFile(qmlImportScannerPath).exists()) {
if (!QFile::exists(qmlImportScannerPath)) {
LogError() << "qmlimportscanner not found at" << qmlImportScannerPath;
LogError() << "Rebuild qtdeclarative/tools/qmlimportscanner";
return false;
@@ -1383,13 +1481,17 @@ bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInf
// build argument list for qmlimportsanner: "-rootPath foo/ -rootPath bar/ -importPath path/to/qt/qml"
// ("rootPath" points to a directory containing app qml, "importPath" is where the Qt imports are installed)
QStringList argumentList;
foreach (const QString &qmlDir, qmlDirs) {
for (const QString &qmlDir : qmlDirs) {
argumentList.append("-rootPath");
argumentList.append(qmlDir);
}
for (const QString &importPath : qmlImportPaths)
argumentList << "-importPath" << importPath;
QString qmlImportsPath = QLibraryInfo::path(QLibraryInfo::Qml2ImportsPath);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QString qmlImportsPath = QLibraryInfo::path(QLibraryInfo::QmlImportsPath);
#else
QString qmlImportsPath = QLibraryInfo::location(QLibraryInfo::QmlImportsPath);
#endif
argumentList.append( "-importPath");
argumentList.append(qmlImportsPath);
@@ -1400,7 +1502,7 @@ bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInf
LogError() << "Could not start qmlimpoortscanner. Process error is" << qmlImportScanner.errorString();
return false;
}
qmlImportScanner.waitForFinished();
qmlImportScanner.waitForFinished(-1);
// log qmlimportscanner errors
qmlImportScanner.setReadChannel(QProcess::StandardError);
@@ -1427,7 +1529,7 @@ bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInf
std::sort(array.begin(), array.end(), importLessThan);
// deploy each import
foreach (const QVariant &importValue, array) {
for (const QVariant &importValue : array) {
QVariantMap import = importValue.toMap();
QString name = import["name"].toString();
QString path = import["path"].toString();
@@ -1524,7 +1626,7 @@ QSet<QString> codesignBundle(const QString &identity,
QString appBundleAbsolutePath = QFileInfo(appBundlePath).absoluteFilePath();
QString rootBinariesPath = appBundleAbsolutePath + "/Contents/MacOS/";
QStringList foundRootBinaries = QDir(rootBinariesPath).entryList(QStringList() << "*", QDir::Files);
foreach (const QString &binary, foundRootBinaries) {
for (const QString &binary : foundRootBinaries) {
QString binaryPath = rootBinariesPath + binary;
pendingBinaries.push(binaryPath);
pendingBinariesSet.insert(binaryPath);
@@ -1533,14 +1635,14 @@ QSet<QString> codesignBundle(const QString &identity,
bool getAbsoltuePath = true;
QStringList foundPluginBinaries = findAppBundleFiles(appBundlePath + "/Contents/PlugIns/", getAbsoltuePath);
foreach (const QString &binary, foundPluginBinaries) {
for (const QString &binary : foundPluginBinaries) {
pendingBinaries.push(binary);
pendingBinariesSet.insert(binary);
}
// Add frameworks for processing.
QStringList frameworkPaths = findAppFrameworkPaths(appBundlePath);
foreach (const QString &frameworkPath, frameworkPaths) {
for (const QString &frameworkPath : frameworkPaths) {
// Prioritise first to sign any additional inner bundles found in the Helpers folder (e.g
// used by QtWebEngine).
@@ -1549,7 +1651,7 @@ QSet<QString> codesignBundle(const QString &identity,
helpersIterator.next();
QString helpersPath = helpersIterator.filePath();
QStringList innerBundleNames = QDir(helpersPath).entryList(QStringList() << "*.app", QDir::Dirs);
foreach (const QString &innerBundleName, innerBundleNames)
for (const QString &innerBundleName : innerBundleNames)
signedBinaries += codesignBundle(identity,
helpersPath + "/" + innerBundleName,
additionalBinariesContainingRpaths);
@@ -1562,7 +1664,7 @@ QSet<QString> codesignBundle(const QString &identity,
librariesIterator.next();
QString librariesPath = librariesIterator.filePath();
QStringList bundleFiles = findAppBundleFiles(librariesPath, getAbsoltuePath);
foreach (const QString &binary, bundleFiles) {
for (const QString &binary : bundleFiles) {
pendingBinaries.push(binary);
pendingBinariesSet.insert(binary);
}
@@ -1587,7 +1689,7 @@ QSet<QString> codesignBundle(const QString &identity,
pendingBinaries.push(binary);
pendingBinariesSet.insert(binary);
int dependenciesSkipped = 0;
foreach (const QString &dependency, dependencies) {
for (const QString &dependency : std::as_const(dependencies)) {
// Skip dependencies that are outside the current app bundle, because this might
// cause a codesign error if the current bundle is part of the dependency (e.g.
// a bundle is part of a framework helper, and depends on that framework).
@@ -1698,109 +1800,3 @@ void fixupFramework(const QString &frameworkName)
addRPath("@loader_path/../../Contents/Frameworks/", frameworkBinary);
}
bool FinalCheck(const QString &appBundlePath) {
bool success = true;
QDirIterator iter(appBundlePath, QDir::Files | QDir::NoSymLinks, QDirIterator::Subdirectories);
while (iter.hasNext()) {
iter.next();
QString filepath = iter.fileInfo().filePath();
if (filepath.endsWith(".plist") ||
filepath.endsWith(".icns") ||
filepath.endsWith(".prl") ||
filepath.endsWith(".conf") ||
filepath.endsWith(".h") ||
filepath.endsWith(".nib") ||
filepath.endsWith(".strings") ||
filepath.endsWith(".css") ||
filepath.endsWith("CodeResources") ||
filepath.endsWith("PkgInfo") ||
filepath.endsWith(".modulemap")) {
continue;
}
//qDebug() << "Final check on" << filepath;
QProcess otool;
otool.start("otool", QStringList() << "-L" << filepath);
otool.waitForFinished();
if (otool.exitStatus() != QProcess::NormalExit || otool.exitCode() != 0) {
LogError() << otool.readAllStandardError();
success = false;
continue;
}
QString output = otool.readAllStandardOutput();
QStringList output_lines = output.split("\n", Qt::SkipEmptyParts);
if (output_lines.size() < 2) {
LogError() << "Could not parse otool output:" << output;
success = false;
continue;
}
QString first_line = output_lines.first();
if (first_line.endsWith(':')) first_line.chop(1);
if (first_line == filepath) {
output_lines.removeFirst();
}
else {
LogError() << "First line" << first_line << "does not match" << filepath;
success = false;
}
static const QRegularExpression regexp(QStringLiteral("^\\t(.+) \\(compatibility version (\\d+\\.\\d+\\.\\d+), current version (\\d+\\.\\d+\\.\\d+)(, weak)?\\)$"));
for (const QString &output_line : output_lines) {
//qDebug() << "Final check on" << filepath << output_line;
const auto match = regexp.match(output_line);
if (match.hasMatch()) {
QString library = match.captured(1);
if (QFileInfo(library).fileName() == QFileInfo(filepath).fileName()) { // It's this.
continue;
}
else if (library.startsWith("@executable_path")) {
QString real_path = library;
real_path = real_path.replace("@executable_path", appBundlePath + "/Contents/MacOS");
if (!QFile(real_path).exists()) {
LogError() << real_path << "does not exist for" << filepath;
success = false;
}
}
else if (library.startsWith("@rpath")) {
QString real_path = library;
real_path = real_path.replace("@rpath", appBundlePath + "/Contents/Frameworks");
if (!QFile(real_path).exists() && !real_path.endsWith("QtSvg")) { // FIXME: Ignore broken svg image plugin.
LogError() << real_path << "does not exist for" << filepath;
success = false;
}
}
else if (library.startsWith("@loader_path")) {
QString loader_path = QFileInfo(filepath).path();
QString real_path = library;
real_path = real_path.replace("@loader_path", loader_path);
if (!QFile(real_path).exists()) {
LogError() << real_path << "does not exist for" << filepath;
success = false;
}
}
else if (library.startsWith("/System/Library/") || library.startsWith("/usr/lib/")) { // System library
continue;
}
else if (library.endsWith("libgcc_s.1.dylib")) { // fftw points to it for some reason.
continue;
}
else {
LogError() << "File" << filepath << "points to" << library;
success = false;
}
}
else {
LogError() << "Could not parse otool output line:" << output_line;
success = false;
}
}
}
return success;
}

View File

@@ -62,7 +62,7 @@ public:
bool isDebugLibrary() const
{
return binaryName.contains(QLatin1String("_debug"));
return binaryName.endsWith(QStringLiteral("_debug"));
}
};
@@ -101,7 +101,7 @@ public:
QString qtPath;
QString pluginPath;
QStringList deployedFrameworks;
QSet<QString> rpathsUsed;
QList<QString> rpathsUsed;
bool useLoaderPath;
bool isFramework;
bool isDebug;
@@ -112,10 +112,10 @@ public:
inline QDebug operator<<(QDebug debug, const ApplicationBundleInfo &info);
OtoolInfo findDependencyInfo(const QString &binaryPath);
FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs);
FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs);
QString findAppBinary(const QString &appBundlePath);
QList<FrameworkInfo> getQtFrameworks(const QString &path, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs);
QList<FrameworkInfo> getQtFrameworks(const QStringList &otoolLines, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs);
QList<FrameworkInfo> getQtFrameworks(const QString &path, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs);
QList<FrameworkInfo> getQtFrameworks(const QStringList &otoolLines, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs);
QString copyFramework(const FrameworkInfo &framework, const QString path);
DeploymentInfo deployQtFrameworks(const QString &appBundlePath, const QStringList &additionalExecutables, bool useDebugLibs);
DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks,const QString &bundlePath, const QStringList &binaryPaths, bool useDebugLibs, bool useLoaderPath);
@@ -136,6 +136,6 @@ QSet<QString> codesignBundle(const QString &identity,
void codesign(const QString &identity, const QString &appBundlePath);
void createDiskImage(const QString &appBundlePath, const QString &filesystemType);
void fixupFramework(const QString &appBundlePath);
bool FinalCheck(const QString &appBundlePath);
#endif

View File

@@ -1,46 +0,0 @@
cmake_minimum_required(VERSION 3.0)
include(CheckIncludeFiles)
include(CheckFunctionExists)
if(CMAKE_VERSION VERSION_GREATER 3.0)
check_function_exists(geteuid HAVE_GETEUID)
check_function_exists(getpwuid HAVE_GETPWUID)
endif()
set(SINGLEAPP-SOURCES singleapplication.cpp singleapplication_p.cpp)
set(SINGLEAPP-MOC-HEADERS singleapplication.h singleapplication_p.h)
if(BUILD_WITH_QT6)
qt6_wrap_cpp(SINGLEAPP-SOURCES-MOC ${SINGLEAPP-MOC-HEADERS})
else()
qt5_wrap_cpp(SINGLEAPP-SOURCES-MOC ${SINGLEAPP-MOC-HEADERS})
endif()
add_library(singleapplication STATIC ${SINGLEAPP-SOURCES} ${SINGLEAPP-SOURCES-MOC})
target_include_directories(singleapplication PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
target_link_libraries(singleapplication PRIVATE
${QtCore_LIBRARIES}
${QtWidgets_LIBRARIES}
${QtNetwork_LIBRARIES}
)
set(SINGLECOREAPP-SOURCES singlecoreapplication.cpp singlecoreapplication_p.cpp)
set(SINGLECOREAPP-MOC-HEADERS singlecoreapplication.h singlecoreapplication_p.h)
if(BUILD_WITH_QT6)
qt6_wrap_cpp(SINGLECOREAPP-SOURCES-MOC ${SINGLECOREAPP-MOC-HEADERS})
else()
qt5_wrap_cpp(SINGLECOREAPP-SOURCES-MOC ${SINGLECOREAPP-MOC-HEADERS})
endif()
add_library(singlecoreapplication STATIC ${SINGLECOREAPP-SOURCES} ${SINGLECOREAPP-SOURCES-MOC})
target_include_directories(singlecoreapplication PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
target_link_libraries(singlecoreapplication PRIVATE
${QtCore_LIBRARIES}
${QtNetwork_LIBRARIES}
)
configure_file(config.h.in "${CMAKE_CURRENT_BINARY_DIR}/config.h")

View File

@@ -1,24 +0,0 @@
The MIT License (MIT)
Copyright (c) Itay Grudev 2015 - 2016
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Note: Some of the examples include code not distributed under the terms of the
MIT License.

View File

@@ -1,265 +0,0 @@
SingleApplication
=================
This is a replacement of the QtSingleApplication for `Qt5`.
Keeps the Primary Instance of your Application and kills each subsequent
instances. It can (if enabled) spawn secondary (non-related to the primary)
instances and can send data to the primary instance from secondary instances.
Usage
-----
The `SingleApplication` class inherits from whatever `Q[Core|Gui]Application`
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:
```cpp
#include <QApplication>
#include <SingleApplication.h>
int main( int argc, char* argv[] )
{
SingleApplication app( argc, argv );
return app.exec();
}
```
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:
```bash
git submodule add git@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
include(singleapplication/singleapplication.pri)
DEFINES += QAPPLICATION_CLASS=QApplication
```
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
been started, for example.
```cpp
// window is a QWindow instance
QObject::connect(
&app,
&SingleApplication::instanceStarted,
&window,
&QWindow::raise
);
```
Using `SingleApplication::instance()` is a neat way to get the
`SingleApplication` instance for binding to it's signals anywhere in your
program.
__Note:__ On Windows the ability to bring the application windows to the
foreground is restricted. See [Windows specific implementations](Windows.md)
for a workaround and an example implementation.
Secondary Instances
-------------------
If you want to be able to launch additional Secondary Instances (not related to
your Primary Instance) you have to enable that with the third parameter of the
`SingleApplication` constructor. The default is `false` meaning no Secondary
Instances. Here is an example of how you would start a Secondary Instance send
a message with the command line arguments to the primary instance and then shut
down.
```cpp
int main(int argc, char *argv[])
{
SingleApplication app( argc, argv, true );
if( app.isSecondary() ) {
app.sendMessage( app.arguments().join(' ')).toUtf8() );
app.exit( 0 );
}
return app.exec();
}
```
*__Note:__ A secondary instance won't cause the emission of the
`instanceStarted()` signal by default. See `SingleApplication::Mode` for more
details.*
You can check whether your instance is a primary or secondary with the following
methods:
```cpp
app.isPrimary();
// or
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.*
API
---
### Members
```cpp
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100 )
```
Depending on whether `allowSecondary` is set, this constructor may terminate
your app if there is already a primary instance running. Additional `Options`
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.
*__Note:__ `argc` and `argv` may be changed as Qt removes arguments that it
recognizes.*
*__Note:__ `Mode::SecondaryNotification` only works if set on both the primary
and the secondary instance.*
*__Note:__ Operating system can restrict the shared memory blocks to the same
user, in which case the User/System modes will have no effect and the block will
be user wide.*
---
```cpp
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
---
```cpp
bool SingleApplication::isPrimary()
```
Returns if the instance is the primary instance.
---
```cpp
bool SingleApplication::isSecondary()
```
Returns if the instance is a secondary instance.
---
```cpp
quint32 SingleApplication::instanceId()
```
Returns a unique identifier for the current instance.
---
```cpp
qint64 SingleApplication::primaryPid()
```
Returns the process ID (PID) of the primary instance.
### Signals
```cpp
void SingleApplication::instanceStarted()
```
Triggered whenever a new instance had been started, except for secondary
instances if the `Mode::SecondaryNotification` flag is not specified.
---
```cpp
void SingleApplication::receivedMessage( quint32 instanceId, QByteArray message )
```
Triggered whenever there is a message received from a secondary instance.
---
### Flags
```cpp
enum SingleApplication::Mode
```
* `Mode::User` - The SingleApplication block should apply user wide. This adds
user specific data to the key used for the shared memory and server name.
This is the default functionality.
* `Mode::System` The SingleApplication block applies system-wide.
* `Mode::SecondaryNotification` Whether to trigger `instanceStarted()` even
whenever secondary instances are started.
* `Mode::ExcludeAppPath` Excludes the application path from the server name
(and memory block) hash.
* `Mode::ExcludeAppVersion` Excludes the application version from the server
name (and memory block) hash.
*__Note:__ `Mode::SecondaryNotification` only works if set on both the primary
and the secondary instance.*
*__Note:__ Operating system can restrict the shared memory blocks to the same
user, in which case the User/System modes will have no effect and the block will
be user wide.*
---
Versioning
----------
Each major version introduces either very significant changes or is not
backwards compatible with the previous version. Minor versions only add
additional features, bug fixes or performance improvements and are backwards
compatible with the previous release. See [`CHANGELOG.md`](CHANGELOG.md) for
more details.
Implementation
--------------
The library is implemented with a QSharedMemory block which is thread safe and
guarantees a race condition will not occur. It also uses a QLocalSocket to
notify the main process that a new instance had been spawned and thus invoke the
`instanceStarted()` signal and for messaging the primary instance.
Additionally the library can recover from being forcefully killed on *nix
systems and will reset the memory block given that there are no other
instances running.
License
-------
This library and it's supporting documentation are released under
`The MIT License (MIT)` with the exception of the Qt calculator examples which
is distributed under the BSD license.

View File

@@ -1,2 +0,0 @@
#cmakedefine HAVE_GETEUID
#cmakedefine HAVE_GETPWUID

View File

@@ -1,269 +0,0 @@
// The MIT License (MIT)
//
// 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
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// W A R N I N G !!!
// -----------------
//
// This is a modified version of SingleApplication,
// The original version is at:
//
// https://github.com/itay-grudev/SingleApplication
//
//
#include <cstdlib>
#include <limits>
#include <QtGlobal>
#include <QApplication>
#include <QThread>
#include <QSharedMemory>
#include <QLocalSocket>
#include <QByteArray>
#include <QElapsedTimer>
#include <QtDebug>
#include "singleapplication.h"
#include "singleapplication_p.h"
/**
* @brief Constructor. Checks and fires up LocalServer or closes the program if another instance already exists
* @param argc
* @param argv
* @param allowSecondary Whether to enable secondary instance support
* @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)
: app_t(argc, argv),
d_ptr(new SingleApplicationPrivate(this)) {
Q_D(SingleApplication);
// Store the current mode of the program
d->options_ = options;
// Generating an application ID used for identifying the shared memory block and QLocalServer
d->genBlockServerName();
// To mitigate QSharedMemory issues with large amount of processes attempting to attach at the same time
d->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.
d->memory_ = new QSharedMemory(d->blockServerName_);
d->memory_->attach();
delete d->memory_;
#endif
// Guarantee thread safe behaviour with a shared memory block.
d->memory_ = new QSharedMemory(d->blockServerName_);
// Create a shared memory block
if (d->memory_->create(sizeof(InstancesInfo))) {
// Initialize the shared memory block
if (!d->memory_->lock()) {
qCritical() << "SingleApplication: Unable to lock memory block after create.";
abortSafely();
}
d->initializeMemoryBlock();
}
else {
if (d->memory_->error() == QSharedMemory::AlreadyExists) {
// Attempt to attach to the memory segment
if (!d->memory_->attach()) {
qCritical() << "SingleApplication: Unable to attach to shared memory block.";
abortSafely();
}
if (!d->memory_->lock()) {
qCritical() << "SingleApplication: Unable to lock memory block after attach.";
abortSafely();
}
}
else {
qCritical() << "SingleApplication: Unable to create block.";
abortSafely();
}
}
InstancesInfo *inst = 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 more than 5s have elapsed, assume the primary instance crashed and assume it's position
if (time.elapsed() > 5000) {
qWarning() << "SingleApplication: Shared memory block has been in an inconsistent state from more than 5s. Assuming primary instance failure.";
d->initializeMemoryBlock();
}
// Otherwise wait for a random period and try again.
// The random sleep here limits the probability of a collision between two racing apps and allows the app to initialise faster
if (!d->memory_->unlock()) {
qDebug() << "SingleApplication: Unable to unlock memory for random wait.";
qDebug() << d->memory_->errorString();
}
d->randomSleep();
if (!d->memory_->lock()) {
qCritical() << "SingleApplication: Unable to lock memory after random wait.";
abortSafely();
}
}
if (inst->primary == false) {
d->startPrimary();
if (!d->memory_->unlock()) {
qDebug() << "SingleApplication: Unable to unlock memory after primary start.";
qDebug() << d->memory_->errorString();
}
return;
}
// Check if another instance can be started
if (allowSecondary) {
d->startSecondary();
if (d->options_ & Mode::SecondaryNotification) {
d->connectToPrimary(timeout, SingleApplicationPrivate::SecondaryInstance);
}
if (!d->memory_->unlock()) {
qDebug() << "SingleApplication: Unable to unlock memory after secondary start.";
qDebug() << d->memory_->errorString();
}
return;
}
if (!d->memory_->unlock()) {
qDebug() << "SingleApplication: Unable to unlock memory at end of execution.";
qDebug() << d->memory_->errorString();
}
d->connectToPrimary(timeout, SingleApplicationPrivate::NewInstance);
delete d;
::exit(EXIT_SUCCESS);
}
SingleApplication::~SingleApplication() {
Q_D(SingleApplication);
delete d;
}
/**
* Checks if the current application instance is primary.
* @return Returns true if the instance is primary, false otherwise.
*/
bool SingleApplication::isPrimary() {
Q_D(SingleApplication);
return d->server_ != nullptr;
}
/**
* Checks if the current application instance is secondary.
* @return Returns true if the instance is secondary, false otherwise.
*/
bool SingleApplication::isSecondary() {
Q_D(SingleApplication);
return d->server_ == nullptr;
}
/**
* Allows you to identify an instance by returning unique consecutive instance ids.
* 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);
return d->instanceNumber_;
}
/**
* Returns the OS PID (Process Identifier) of the process running the primary instance.
* Especially useful when SingleApplication is coupled with OS. specific APIs.
* @return Returns the primary instance PID.
*/
qint64 SingleApplication::primaryPid() {
Q_D(SingleApplication);
return d->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);
return d->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();
}
/**
* Sends message to the Primary Instance.
* @param message The message to send.
* @param timeout the maximum timeout in milliseconds for blocking functions.
* @return true if the message was sent successfuly, false otherwise.
*/
bool SingleApplication::sendMessage(QByteArray message, int timeout) {
Q_D(SingleApplication);
// Nobody to connect to
if (isPrimary()) return false;
// Make sure the socket is connected
if (!d->connectToPrimary(timeout, SingleApplicationPrivate::Reconnect))
return false;
d->socket_->write(message);
const bool dataWritten = d->socket_->waitForBytesWritten(timeout);
d->socket_->flush();
return dataWritten;
}
/**
* Cleans up the shared memory block and exits with a failure.
* This function halts program execution.
*/
void SingleApplication::abortSafely() {
Q_D(SingleApplication);
qCritical() << "SingleApplication: " << d->memory_->error() << d->memory_->errorString();
delete d;
::exit(EXIT_FAILURE);
}

View File

@@ -1,153 +0,0 @@
// The MIT License (MIT)
//
// 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
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// W A R N I N G !!!
// -----------------
//
// This is a modified version of SingleApplication,
// The original version is at:
//
// https://github.com/itay-grudev/SingleApplication
//
//
#ifndef SINGLEAPPLICATION_H
#define SINGLEAPPLICATION_H
#include <QtGlobal>
#include <QApplication>
#include <QFlags>
#include <QByteArray>
class SingleApplicationPrivate;
/**
* @brief The SingleApplication class handles multipe instances of the same Application
* @see QApplication
*/
class SingleApplication : public QApplication {
Q_OBJECT
typedef QApplication app_t;
public:
/**
* @brief Mode of operation of SingleApplication.
* Whether the block should be user-wide or system-wide and whether the
* primary instance should be notified when a secondary instance had been
* started.
* @note Operating system can restrict the shared memory blocks to the same
* user, in which case the User/System modes will have no effect and the
* block will be user wide.
* @enum
*/
enum Mode {
User = 1 << 0,
System = 1 << 1,
SecondaryNotification = 1 << 2,
ExcludeAppVersion = 1 << 3,
ExcludeAppPath = 1 << 4
};
Q_DECLARE_FLAGS(Options, Mode)
/**
* @brief Intitializes a SingleApplication instance with argc command line
* arguments in argv
* @arg {int &} argc - Number of arguments in argv
* @arg {const char *[]} argv - Supplied command line arguments
* @arg {bool} allowSecondary - Whether to start the instance as secondary
* if there is already a primary instance.
* @arg {Mode} mode - Whether for the SingleApplication block to be applied
* User wide or System wide.
* @arg {int} timeout - Timeout to wait in milliseconds.
* @note argc and argv may be changed as Qt removes arguments that it
* recognizes
* @note Mode::SecondaryNotification only works if set on both the primary
* instance and the secondary instance.
* @note The timeout is just a hint for the maximum time of blocking
* 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);
~SingleApplication() override;
/**
* @brief Returns if the instance is the primary instance
* @returns {bool}
*/
bool isPrimary();
/**
* @brief Returns if the instance is a secondary instance
* @returns {bool}
*/
bool isSecondary();
/**
* @brief Returns a unique identifier for the current instance
* @returns {qint32}
*/
quint32 instanceId();
/**
* @brief Returns the process ID (PID) of the primary instance
* @returns {qint64}
*/
qint64 primaryPid();
/**
* @brief Returns the username of the user running the primary instance
* @returns {QString}
*/
QString primaryUser();
/**
* @brief Returns the username of the current user
* @returns {QString}
*/
QString currentUser();
/**
* @brief Sends a message to the primary instance. Returns true on success.
* @param {int} timeout - Timeout for connecting
* @returns {bool}
* @note sendMessage() will return false if invoked from the primary
* instance.
*/
bool sendMessage(QByteArray message, int timeout = 1000);
signals:
void instanceStarted();
void receivedMessage(quint32 instanceId, QByteArray message);
private:
SingleApplicationPrivate *d_ptr;
Q_DECLARE_PRIVATE(SingleApplication)
void abortSafely();
};
Q_DECLARE_OPERATORS_FOR_FLAGS(SingleApplication::Options)
#endif // SINGLEAPPLICATION_H

View File

@@ -1,470 +0,0 @@
// The MIT License (MIT)
//
// 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
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// W A R N I N G !!!
// -----------------
//
// This is a modified version of SingleApplication,
// The original version is at:
//
// https://github.com/itay-grudev/SingleApplication
//
//
#include "config.h"
#include <QtGlobal>
#include <cstdlib>
#include <cstddef>
#ifdef Q_OS_UNIX
# include <unistd.h>
# include <sys/types.h>
# include <pwd.h>
#endif
#include <QObject>
#include <QThread>
#include <QIODevice>
#include <QSharedMemory>
#include <QByteArray>
#include <QDataStream>
#include <QCryptographicHash>
#include <QLocalServer>
#include <QLocalSocket>
#include <QDir>
#include <QElapsedTimer>
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
# include <QRandomGenerator>
#else
# include <QDateTime>
#endif
#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),
socket_(nullptr),
server_(nullptr),
instanceNumber_(-1) {}
SingleApplicationPrivate::~SingleApplicationPrivate() {
if (socket_ != nullptr) {
socket_->close();
delete socket_;
socket_ = nullptr;
}
if (memory_ != nullptr) {
memory_->lock();
InstancesInfo *inst = 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();
}
memory_->unlock();
delete memory_;
memory_ = nullptr;
}
}
QString SingleApplicationPrivate::getUsername() {
#ifdef Q_OS_UNIX
QString username;
#if defined(HAVE_GETEUID) && defined(HAVE_GETPWUID)
struct passwd *pw = getpwuid(geteuid());
if (pw) {
username = QString::fromLocal8Bit(pw->pw_name);
}
#endif
if (username.isEmpty()) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
username = qEnvironmentVariable("USER");
#else
username = QString::fromLocal8Bit(qgetenv("USER"));
#endif
}
return username;
#endif
#ifdef Q_OS_WIN
wchar_t username[UNLEN + 1];
// Specifies size of the buffer on input
DWORD usernameLength = UNLEN + 1;
if (GetUserNameW(username, &usernameLength)) {
return QString::fromWCharArray(username);
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
return qEnvironmentVariable("USERNAME");
#else
return QString::fromLocal8Bit(qgetenv("USERNAME"));
#endif
#endif
}
void SingleApplicationPrivate::genBlockServerName() {
QCryptographicHash appData(QCryptographicHash::Sha256);
appData.addData("SingleApplication", 17);
appData.addData(SingleApplication::app_t::applicationName().toUtf8());
appData.addData(SingleApplication::app_t::organizationName().toUtf8());
appData.addData(SingleApplication::app_t::organizationDomain().toUtf8());
if (!(options_ & SingleApplication::Mode::ExcludeAppVersion)) {
appData.addData(SingleApplication::app_t::applicationVersion().toUtf8());
}
if (!(options_ & SingleApplication::Mode::ExcludeAppPath)) {
#ifdef Q_OS_WIN
appData.addData(SingleApplication::app_t::applicationFilePath().toLower().toUtf8());
#else
appData.addData(SingleApplication::app_t::applicationFilePath().toUtf8());
#endif
}
// User level block requires a user specific data in the hash
if (options_ & SingleApplication::Mode::User) {
appData.addData(getUsername().toUtf8());
}
// Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with server naming requirements.
blockServerName_ = appData.result().toBase64().replace("/", "_");
}
void SingleApplicationPrivate::initializeMemoryBlock() {
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
inst->primary = false;
inst->secondary = 0;
inst->primaryPid = -1;
inst->primaryUser[0] = '\0';
inst->checksum = blockChecksum();
}
void SingleApplicationPrivate::startPrimary() {
Q_Q(SingleApplication);
// Reset the number of connections
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
inst->primary = true;
inst->primaryPid = q->applicationPid();
qstrncpy(inst->primaryUser, getUsername().toUtf8().data(), sizeof(inst->primaryUser));
inst->checksum = blockChecksum();
instanceNumber_ = 0;
// Successful creation means that no main process exists
// So we start a QLocalServer to listen for connections
QLocalServer::removeServer(blockServerName_);
server_ = new QLocalServer();
// Restrict access to the socket according to the SingleApplication::Mode::User flag on User level or no restrictions
if (options_ & SingleApplication::Mode::User) {
server_->setSocketOptions(QLocalServer::UserAccessOption);
}
else {
server_->setSocketOptions(QLocalServer::WorldAccessOption);
}
server_->listen(blockServerName_);
QObject::connect(server_, &QLocalServer::newConnection, this, &SingleApplicationPrivate::slotConnectionEstablished);
}
void SingleApplicationPrivate::startSecondary() {
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
inst->secondary += 1;
inst->checksum = blockChecksum();
instanceNumber_ = inst->secondary;
}
bool SingleApplicationPrivate::connectToPrimary(const int timeout, const ConnectionType connectionType) {
QElapsedTimer time;
time.start();
// Connect to the Local Server of the Primary Instance if not already connected.
if (socket_ == nullptr) {
socket_ = new QLocalSocket();
}
if (socket_->state() == QLocalSocket::ConnectedState) return true;
if (socket_->state() != QLocalSocket::ConnectedState) {
forever {
randomSleep();
if (socket_->state() != QLocalSocket::ConnectingState)
socket_->connectToServer(blockServerName_);
if (socket_->state() == QLocalSocket::ConnectingState) {
socket_->waitForConnected(static_cast<int>(timeout - time.elapsed()));
}
// If connected break out of the loop
if (socket_->state() == QLocalSocket::ConnectedState) break;
// If elapsed time since start is longer than the method timeout return
if (time.elapsed() >= timeout) return false;
}
}
// Initialisation message according to the SingleApplication protocol
QByteArray initMsg;
QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
writeStream.setVersion(QDataStream::Qt_5_8);
writeStream << blockServerName_.toLatin1();
writeStream << static_cast<quint8>(connectionType);
writeStream << instanceNumber_;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
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
QByteArray header;
QDataStream headerStream(&header, QIODevice::WriteOnly);
headerStream.setVersion(QDataStream::Qt_5_8);
headerStream << static_cast<quint64>(initMsg.length());
socket_->write(header);
socket_->write(initMsg);
bool result = socket_->waitForBytesWritten(static_cast<int>(timeout - time.elapsed()));
socket_->flush();
return result;
}
quint16 SingleApplicationPrivate::blockChecksum() {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
quint16 checksum = qChecksum(QByteArray(static_cast<const char*>(memory_->constData()), offsetof(InstancesInfo, checksum)));
#else
quint16 checksum = qChecksum(static_cast<const char*>(memory_->constData()), offsetof(InstancesInfo, checksum));
#endif
return checksum;
}
qint64 SingleApplicationPrivate::primaryPid() {
memory_->lock();
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
qint64 pid = inst->primaryPid;
memory_->unlock();
return pid;
}
QString SingleApplicationPrivate::primaryUser() {
memory_->lock();
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
QByteArray username = inst->primaryUser;
memory_->unlock();
return QString::fromUtf8(username);
}
/**
* @brief Executed when a connection has been made to the LocalServer
*/
void SingleApplicationPrivate::slotConnectionEstablished() {
QLocalSocket *nextConnSocket = server_->nextPendingConnection();
connectionMap_.insert(nextConnSocket, ConnectionInfo());
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this, [nextConnSocket, this]() {
auto &info = connectionMap_[nextConnSocket];
slotClientConnectionClosed(nextConnSocket, info.instanceId);
});
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, this, [nextConnSocket, this]() {
connectionMap_.remove(nextConnSocket);
nextConnSocket->deleteLater();
});
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this, [nextConnSocket, this]() {
auto &info = connectionMap_[nextConnSocket];
switch (info.stage) {
case StageHeader:
readInitMessageHeader(nextConnSocket);
break;
case StageBody:
readInitMessageBody(nextConnSocket);
break;
case StageConnected:
slotDataAvailable(nextConnSocket, info.instanceId);
break;
default:
break;
};
});
}
void SingleApplicationPrivate::readInitMessageHeader(QLocalSocket *sock) {
if (!connectionMap_.contains(sock)) {
return;
}
if (sock->bytesAvailable() < static_cast<qint64>(sizeof(quint64))) {
return;
}
QDataStream headerStream(sock);
headerStream.setVersion(QDataStream::Qt_5_8);
// Read the header to know the message length
quint64 msgLen = 0;
headerStream >> msgLen;
ConnectionInfo &info = connectionMap_[sock];
info.stage = StageBody;
info.msgLen = msgLen;
if (sock->bytesAvailable() >= static_cast<qint64>(msgLen)) {
readInitMessageBody(sock);
}
}
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)) {
return;
}
// Read the message body
QByteArray msgBytes = sock->read(info.msgLen);
QDataStream readStream(msgBytes);
readStream.setVersion(QDataStream::Qt_5_8);
// server name
QByteArray latin1Name;
readStream >> latin1Name;
// connection type
ConnectionType connectionType = InvalidConnection;
quint8 connTypeVal = InvalidConnection;
readStream >> connTypeVal;
connectionType = static_cast<ConnectionType>(connTypeVal);
// instance id
quint32 instanceId = 0;
readStream >> instanceId;
// checksum
quint16 msgChecksum = 0;
readStream >> msgChecksum;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
const quint16 actualChecksum = qChecksum(QByteArray(msgBytes, static_cast<quint32>(msgBytes.length() - sizeof(quint16))));
#else
const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length() - sizeof(quint16)));
#endif
bool isValid = readStream.status() == QDataStream::Ok && QLatin1String(latin1Name) == blockServerName_ && msgChecksum == actualChecksum;
if (!isValid) {
sock->close();
return;
}
info.instanceId = instanceId;
info.stage = StageConnected;
if (connectionType == NewInstance || (connectionType == SecondaryInstance && options_ & SingleApplication::Mode::SecondaryNotification)) {
Q_EMIT q->instanceStarted();
}
if (sock->bytesAvailable() > 0) {
slotDataAvailable(sock, instanceId);
}
}
void SingleApplicationPrivate::slotDataAvailable(QLocalSocket *dataSocket, const quint32 instanceId) {
Q_Q(SingleApplication);
Q_EMIT q->receivedMessage(instanceId, dataSocket->readAll());
}
void SingleApplicationPrivate::slotClientConnectionClosed(QLocalSocket *closedSocket, const quint32 instanceId) {
if (closedSocket->bytesAvailable() > 0) {
slotDataAvailable(closedSocket, instanceId);
}
}
void SingleApplicationPrivate::randomSleep() {
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
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));
#endif
}

View File

@@ -1,111 +0,0 @@
// The MIT License (MIT)
//
// 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
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// W A R N I N G !!!
// -----------------
//
// This is a modified version of SingleApplication,
// The original version is at:
//
// https://github.com/itay-grudev/SingleApplication
//
//
#ifndef SINGLEAPPLICATION_P_H
#define SINGLEAPPLICATION_P_H
#include <QtGlobal>
#include <QObject>
#include <QString>
#include <QMap>
#include "singleapplication.h"
class QLocalServer;
class QLocalSocket;
class QSharedMemory;
struct InstancesInfo {
bool primary;
quint32 secondary;
qint64 primaryPid;
char primaryUser[128];
quint16 checksum;
};
struct ConnectionInfo {
explicit ConnectionInfo() : msgLen(0), instanceId(0), stage(0) {}
qint64 msgLen;
quint32 instanceId;
quint8 stage;
};
class SingleApplicationPrivate : public QObject {
Q_OBJECT
public:
enum ConnectionType : quint8 {
InvalidConnection = 0,
NewInstance = 1,
SecondaryInstance = 2,
Reconnect = 3
};
enum ConnectionStage : quint8 {
StageHeader = 0,
StageBody = 1,
StageConnected = 2,
};
Q_DECLARE_PUBLIC(SingleApplication)
explicit SingleApplicationPrivate(SingleApplication *ptr);
~SingleApplicationPrivate() override;
QString getUsername();
void genBlockServerName();
void initializeMemoryBlock();
void startPrimary();
void startSecondary();
bool connectToPrimary(const int timeout, const ConnectionType connectionType);
quint16 blockChecksum();
qint64 primaryPid();
QString primaryUser();
void readInitMessageHeader(QLocalSocket *socket);
void readInitMessageBody(QLocalSocket *socket);
void randomSleep();
SingleApplication *q_ptr;
QSharedMemory *memory_;
QLocalSocket *socket_;
QLocalServer *server_;
quint32 instanceNumber_;
QString blockServerName_;
SingleApplication::Options options_;
QMap<QLocalSocket*, ConnectionInfo> connectionMap_;
public slots:
void slotConnectionEstablished();
void slotDataAvailable(QLocalSocket*, const quint32);
void slotClientConnectionClosed(QLocalSocket*, const quint32);
};
#endif // SINGLEAPPLICATION_P_H

View File

@@ -1,269 +0,0 @@
// The MIT License (MIT)
//
// 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
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// W A R N I N G !!!
// -----------------
//
// This is a modified version of SingleApplication,
// The original version is at:
//
// https://github.com/itay-grudev/SingleApplication
//
//
#include <cstdlib>
#include <limits>
#include <QtGlobal>
#include <QCoreApplication>
#include <QThread>
#include <QSharedMemory>
#include <QLocalSocket>
#include <QByteArray>
#include <QElapsedTimer>
#include <QtDebug>
#include "singlecoreapplication.h"
#include "singlecoreapplication_p.h"
/**
* @brief Constructor. Checks and fires up LocalServer or closes the program if another instance already exists
* @param argc
* @param argv
* @param allowSecondary Whether to enable secondary instance support
* @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)
: app_t(argc, argv),
d_ptr(new SingleCoreApplicationPrivate(this)) {
Q_D(SingleCoreApplication);
// Store the current mode of the program
d->options_ = options;
// Generating an application ID used for identifying the shared memory block and QLocalServer
d->genBlockServerName();
// To mitigate QSharedMemory issues with large amount of processes attempting to attach at the same time
d->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.
d->memory_ = new QSharedMemory(d->blockServerName_);
d->memory_->attach();
delete d->memory_;
#endif
// Guarantee thread safe behaviour with a shared memory block.
d->memory_ = new QSharedMemory(d->blockServerName_);
// Create a shared memory block
if (d->memory_->create(sizeof(InstancesInfo))) {
// Initialize the shared memory block
if (!d->memory_->lock()) {
qCritical() << "SingleCoreApplication: Unable to lock memory block after create.";
abortSafely();
}
d->initializeMemoryBlock();
}
else {
if (d->memory_->error() == QSharedMemory::AlreadyExists) {
// Attempt to attach to the memory segment
if (!d->memory_->attach()) {
qCritical() << "SingleCoreApplication: Unable to attach to shared memory block.";
abortSafely();
}
if (!d->memory_->lock()) {
qCritical() << "SingleCoreApplication: Unable to lock memory block after attach.";
abortSafely();
}
}
else {
qCritical() << "SingleCoreApplication: Unable to create block.";
abortSafely();
}
}
InstancesInfo *inst = 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 more than 5s have elapsed, assume the primary instance crashed and assume it's position
if (time.elapsed() > 5000) {
qWarning() << "SingleCoreApplication: Shared memory block has been in an inconsistent state from more than 5s. Assuming primary instance failure.";
d->initializeMemoryBlock();
}
// Otherwise wait for a random period and try again.
// The random sleep here limits the probability of a collision between two racing apps and allows the app to initialise faster
if (!d->memory_->unlock()) {
qDebug() << "SingleCoreApplication: Unable to unlock memory for random wait.";
qDebug() << d->memory_->errorString();
}
d->randomSleep();
if (!d->memory_->lock()) {
qCritical() << "SingleCoreApplication: Unable to lock memory after random wait.";
abortSafely();
}
}
if (inst->primary == false) {
d->startPrimary();
if (!d->memory_->unlock()) {
qDebug() << "SingleCoreApplication: Unable to unlock memory after primary start.";
qDebug() << d->memory_->errorString();
}
return;
}
// Check if another instance can be started
if (allowSecondary) {
d->startSecondary();
if (d->options_ & Mode::SecondaryNotification) {
d->connectToPrimary(timeout, SingleCoreApplicationPrivate::SecondaryInstance);
}
if (!d->memory_->unlock()) {
qDebug() << "SingleCoreApplication: Unable to unlock memory after secondary start.";
qDebug() << d->memory_->errorString();
}
return;
}
if (!d->memory_->unlock()) {
qDebug() << "SingleCoreApplication: Unable to unlock memory at end of execution.";
qDebug() << d->memory_->errorString();
}
d->connectToPrimary(timeout, SingleCoreApplicationPrivate::NewInstance);
delete d;
::exit(EXIT_SUCCESS);
}
SingleCoreApplication::~SingleCoreApplication() {
Q_D(SingleCoreApplication);
delete d;
}
/**
* Checks if the current application instance is primary.
* @return Returns true if the instance is primary, false otherwise.
*/
bool SingleCoreApplication::isPrimary() {
Q_D(SingleCoreApplication);
return d->server_ != nullptr;
}
/**
* Checks if the current application instance is secondary.
* @return Returns true if the instance is secondary, false otherwise.
*/
bool SingleCoreApplication::isSecondary() {
Q_D(SingleCoreApplication);
return d->server_ == nullptr;
}
/**
* Allows you to identify an instance by returning unique consecutive instance ids.
* 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);
return d->instanceNumber_;
}
/**
* Returns the OS PID (Process Identifier) of the process running the primary instance.
* Especially useful when SingleCoreApplication is coupled with OS. specific APIs.
* @return Returns the primary instance PID.
*/
qint64 SingleCoreApplication::primaryPid() {
Q_D(SingleCoreApplication);
return d->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);
return d->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();
}
/**
* Sends message to the Primary Instance.
* @param message The message to send.
* @param timeout the maximum timeout in milliseconds for blocking functions.
* @return true if the message was sent successfuly, false otherwise.
*/
bool SingleCoreApplication::sendMessage(QByteArray message, int timeout) {
Q_D(SingleCoreApplication);
// Nobody to connect to
if (isPrimary()) return false;
// Make sure the socket is connected
if (!d->connectToPrimary(timeout, SingleCoreApplicationPrivate::Reconnect))
return false;
d->socket_->write(message);
const bool dataWritten = d->socket_->waitForBytesWritten(timeout);
d->socket_->flush();
return dataWritten;
}
/**
* Cleans up the shared memory block and exits with a failure.
* This function halts program execution.
*/
void SingleCoreApplication::abortSafely() {
Q_D(SingleCoreApplication);
qCritical() << "SingleCoreApplication: " << d->memory_->error() << d->memory_->errorString();
delete d;
::exit(EXIT_FAILURE);
}

View File

@@ -1,152 +0,0 @@
// The MIT License (MIT)
//
// 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
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// W A R N I N G !!!
// -----------------
//
// This is a modified version of SingleApplication,
// The original version is at:
//
// https://github.com/itay-grudev/SingleApplication
//
//
#ifndef SINGLECOREAPPLICATION_H
#define SINGLECOREAPPLICATION_H
#include <QtGlobal>
#include <QCoreApplication>
#include <QFlags>
#include <QByteArray>
class SingleCoreApplicationPrivate;
/**
* @brief The SingleCoreApplication class handles multipe instances of the same Application
* @see QCoreApplication
*/
class SingleCoreApplication : public QCoreApplication {
Q_OBJECT
typedef QCoreApplication app_t;
public:
/**
* @brief Mode of operation of SingleCoreApplication.
* Whether the block should be user-wide or system-wide and whether the
* primary instance should be notified when a secondary instance had been
* started.
* @note Operating system can restrict the shared memory blocks to the same
* user, in which case the User/System modes will have no effect and the
* block will be user wide.
* @enum
*/
enum Mode {
User = 1 << 0,
System = 1 << 1,
SecondaryNotification = 1 << 2,
ExcludeAppVersion = 1 << 3,
ExcludeAppPath = 1 << 4
};
Q_DECLARE_FLAGS(Options, Mode)
/**
* @brief Intitializes a SingleCoreApplication instance with argc command line
* arguments in argv
* @arg {int &} argc - Number of arguments in argv
* @arg {const char *[]} argv - Supplied command line arguments
* @arg {bool} allowSecondary - Whether to start the instance as secondary
* if there is already a primary instance.
* @arg {Mode} mode - Whether for the SingleCoreApplication block to be applied
* User wide or System wide.
* @arg {int} timeout - Timeout to wait in milliseconds.
* @note argc and argv may be changed as Qt removes arguments that it
* recognizes
* @note Mode::SecondaryNotification only works if set on both the primary
* instance and the secondary instance.
* @note The timeout is just a hint for the maximum time of blocking
* operations. It does not guarantee that the SingleCoreApplication
* initialisation will be completed in given time, though is a good hint.
* Usually 4*timeout would be the worst case (fail) scenario.
*/
explicit SingleCoreApplication(int &argc, char *argv[], const bool allowSecondary = false, const Options options = Mode::User, const int timeout = 1000);
~SingleCoreApplication() override;
/**
* @brief Returns if the instance is the primary instance
* @returns {bool}
*/
bool isPrimary();
/**
* @brief Returns if the instance is a secondary instance
* @returns {bool}
*/
bool isSecondary();
/**
* @brief Returns a unique identifier for the current instance
* @returns {qint32}
*/
quint32 instanceId();
/**
* @brief Returns the process ID (PID) of the primary instance
* @returns {qint64}
*/
qint64 primaryPid();
/**
* @brief Returns the username of the user running the primary instance
* @returns {QString}
*/
QString primaryUser();
/**
* @brief Returns the username of the current user
* @returns {QString}
*/
QString currentUser();
/**
* @brief Sends a message to the primary instance. Returns true on success.
* @param {int} timeout - Timeout for connecting
* @returns {bool}
* @note sendMessage() will return false if invoked from the primary
* instance.
*/
bool sendMessage(QByteArray message, int timeout = 1000);
signals:
void instanceStarted();
void receivedMessage(quint32 instanceId, QByteArray message);
private:
SingleCoreApplicationPrivate *d_ptr;
Q_DECLARE_PRIVATE(SingleCoreApplication)
void abortSafely();
};
Q_DECLARE_OPERATORS_FOR_FLAGS(SingleCoreApplication::Options)
#endif // SINGLECOREAPPLICATION_H

View File

@@ -1,470 +0,0 @@
// The MIT License (MIT)
//
// 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
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// W A R N I N G !!!
// -----------------
//
// This is a modified version of SingleApplication,
// The original version is at:
//
// https://github.com/itay-grudev/SingleApplication
//
//
#include "config.h"
#include <QtGlobal>
#include <cstdlib>
#include <cstddef>
#ifdef Q_OS_UNIX
# include <unistd.h>
# include <sys/types.h>
# include <pwd.h>
#endif
#include <QObject>
#include <QThread>
#include <QIODevice>
#include <QSharedMemory>
#include <QByteArray>
#include <QDataStream>
#include <QCryptographicHash>
#include <QLocalServer>
#include <QLocalSocket>
#include <QDir>
#include <QElapsedTimer>
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
# include <QRandomGenerator>
#else
# include <QDateTime>
#endif
#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),
socket_(nullptr),
server_(nullptr),
instanceNumber_(-1) {}
SingleCoreApplicationPrivate::~SingleCoreApplicationPrivate() {
if (socket_ != nullptr) {
socket_->close();
delete socket_;
socket_ = nullptr;
}
if (memory_ != nullptr) {
memory_->lock();
InstancesInfo *inst = 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();
}
memory_->unlock();
delete memory_;
memory_ = nullptr;
}
}
QString SingleCoreApplicationPrivate::getUsername() {
#ifdef Q_OS_UNIX
QString username;
#if defined(HAVE_GETEUID) && defined(HAVE_GETPWUID)
struct passwd *pw = getpwuid(geteuid());
if (pw) {
username = QString::fromLocal8Bit(pw->pw_name);
}
#endif
if (username.isEmpty()) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
username = qEnvironmentVariable("USER");
#else
username = QString::fromLocal8Bit(qgetenv("USER"));
#endif
}
return username;
#endif
#ifdef Q_OS_WIN
wchar_t username[UNLEN + 1];
// Specifies size of the buffer on input
DWORD usernameLength = UNLEN + 1;
if (GetUserNameW(username, &usernameLength)) {
return QString::fromWCharArray(username);
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
return qEnvironmentVariable("USERNAME");
#else
return QString::fromLocal8Bit(qgetenv("USERNAME"));
#endif
#endif
}
void SingleCoreApplicationPrivate::genBlockServerName() {
QCryptographicHash appData(QCryptographicHash::Sha256);
appData.addData("SingleApplication", 17);
appData.addData(SingleCoreApplication::app_t::applicationName().toUtf8());
appData.addData(SingleCoreApplication::app_t::organizationName().toUtf8());
appData.addData(SingleCoreApplication::app_t::organizationDomain().toUtf8());
if (!(options_ & SingleCoreApplication::Mode::ExcludeAppVersion)) {
appData.addData(SingleCoreApplication::app_t::applicationVersion().toUtf8());
}
if (!(options_ & SingleCoreApplication::Mode::ExcludeAppPath)) {
#ifdef Q_OS_WIN
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toLower().toUtf8());
#else
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toUtf8());
#endif
}
// User level block requires a user specific data in the hash
if (options_ & SingleCoreApplication::Mode::User) {
appData.addData(getUsername().toUtf8());
}
// Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with server naming requirements.
blockServerName_ = appData.result().toBase64().replace("/", "_");
}
void SingleCoreApplicationPrivate::initializeMemoryBlock() {
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
inst->primary = false;
inst->secondary = 0;
inst->primaryPid = -1;
inst->primaryUser[0] = '\0';
inst->checksum = blockChecksum();
}
void SingleCoreApplicationPrivate::startPrimary() {
Q_Q(SingleCoreApplication);
// Reset the number of connections
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
inst->primary = true;
inst->primaryPid = q->applicationPid();
qstrncpy(inst->primaryUser, getUsername().toUtf8().data(), sizeof(inst->primaryUser));
inst->checksum = blockChecksum();
instanceNumber_ = 0;
// Successful creation means that no main process exists
// So we start a QLocalServer to listen for connections
QLocalServer::removeServer(blockServerName_);
server_ = new QLocalServer();
// Restrict access to the socket according to the SingleCoreApplication::Mode::User flag on User level or no restrictions
if (options_ & SingleCoreApplication::Mode::User) {
server_->setSocketOptions(QLocalServer::UserAccessOption);
}
else {
server_->setSocketOptions(QLocalServer::WorldAccessOption);
}
server_->listen(blockServerName_);
QObject::connect(server_, &QLocalServer::newConnection, this, &SingleCoreApplicationPrivate::slotConnectionEstablished);
}
void SingleCoreApplicationPrivate::startSecondary() {
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
inst->secondary += 1;
inst->checksum = blockChecksum();
instanceNumber_ = inst->secondary;
}
bool SingleCoreApplicationPrivate::connectToPrimary(const int timeout, const ConnectionType connectionType) {
QElapsedTimer time;
time.start();
// Connect to the Local Server of the Primary Instance if not already connected.
if (socket_ == nullptr) {
socket_ = new QLocalSocket();
}
if (socket_->state() == QLocalSocket::ConnectedState) return true;
if (socket_->state() != QLocalSocket::ConnectedState) {
forever {
randomSleep();
if (socket_->state() != QLocalSocket::ConnectingState)
socket_->connectToServer(blockServerName_);
if (socket_->state() == QLocalSocket::ConnectingState) {
socket_->waitForConnected(static_cast<int>(timeout - time.elapsed()));
}
// If connected break out of the loop
if (socket_->state() == QLocalSocket::ConnectedState) break;
// If elapsed time since start is longer than the method timeout return
if (time.elapsed() >= timeout) return false;
}
}
// Initialisation message according to the SingleCoreApplication protocol
QByteArray initMsg;
QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
writeStream.setVersion(QDataStream::Qt_5_8);
writeStream << blockServerName_.toLatin1();
writeStream << static_cast<quint8>(connectionType);
writeStream << instanceNumber_;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
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
QByteArray header;
QDataStream headerStream(&header, QIODevice::WriteOnly);
headerStream.setVersion(QDataStream::Qt_5_8);
headerStream << static_cast<quint64>(initMsg.length());
socket_->write(header);
socket_->write(initMsg);
bool result = socket_->waitForBytesWritten(timeout - static_cast<int>(time.elapsed()));
socket_->flush();
return result;
}
quint16 SingleCoreApplicationPrivate::blockChecksum() {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
quint16 checksum = qChecksum(QByteArray(static_cast<const char*>(memory_->constData()), offsetof(InstancesInfo, checksum)));
#else
quint16 checksum = qChecksum(static_cast<const char*>(memory_->constData()), offsetof(InstancesInfo, checksum));
#endif
return checksum;
}
qint64 SingleCoreApplicationPrivate::primaryPid() {
memory_->lock();
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
qint64 pid = inst->primaryPid;
memory_->unlock();
return pid;
}
QString SingleCoreApplicationPrivate::primaryUser() {
memory_->lock();
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
QByteArray username = inst->primaryUser;
memory_->unlock();
return QString::fromUtf8(username);
}
/**
* @brief Executed when a connection has been made to the LocalServer
*/
void SingleCoreApplicationPrivate::slotConnectionEstablished() {
QLocalSocket *nextConnSocket = server_->nextPendingConnection();
connectionMap_.insert(nextConnSocket, ConnectionInfo());
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this, [nextConnSocket, this]() {
auto &info = connectionMap_[nextConnSocket];
slotClientConnectionClosed(nextConnSocket, info.instanceId);
});
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, this, [nextConnSocket, this]() {
connectionMap_.remove(nextConnSocket);
nextConnSocket->deleteLater();
});
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this, [nextConnSocket, this]() {
auto &info = connectionMap_[nextConnSocket];
switch (info.stage) {
case StageHeader:
readInitMessageHeader(nextConnSocket);
break;
case StageBody:
readInitMessageBody(nextConnSocket);
break;
case StageConnected:
slotDataAvailable(nextConnSocket, info.instanceId);
break;
default:
break;
};
});
}
void SingleCoreApplicationPrivate::readInitMessageHeader(QLocalSocket *sock) {
if (!connectionMap_.contains(sock)) {
return;
}
if (sock->bytesAvailable() < static_cast<qint64>(sizeof(quint64))) {
return;
}
QDataStream headerStream(sock);
headerStream.setVersion(QDataStream::Qt_5_8);
// Read the header to know the message length
quint64 msgLen = 0;
headerStream >> msgLen;
ConnectionInfo &info = connectionMap_[sock];
info.stage = StageBody;
info.msgLen = msgLen;
if (sock->bytesAvailable() >= static_cast<qint64>(msgLen)) {
readInitMessageBody(sock);
}
}
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)) {
return;
}
// Read the message body
QByteArray msgBytes = sock->read(info.msgLen);
QDataStream readStream(msgBytes);
readStream.setVersion(QDataStream::Qt_5_8);
// server name
QByteArray latin1Name;
readStream >> latin1Name;
// connection type
ConnectionType connectionType = InvalidConnection;
quint8 connTypeVal = InvalidConnection;
readStream >> connTypeVal;
connectionType = static_cast<ConnectionType>(connTypeVal);
// instance id
quint32 instanceId = 0;
readStream >> instanceId;
// checksum
quint16 msgChecksum = 0;
readStream >> msgChecksum;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
const quint16 actualChecksum = qChecksum(QByteArray(msgBytes, static_cast<quint32>(msgBytes.length() - sizeof(quint16))));
#else
const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length() - sizeof(quint16)));
#endif
bool isValid = readStream.status() == QDataStream::Ok && QLatin1String(latin1Name) == blockServerName_ && msgChecksum == actualChecksum;
if (!isValid) {
sock->close();
return;
}
info.instanceId = instanceId;
info.stage = StageConnected;
if (connectionType == NewInstance || (connectionType == SecondaryInstance && options_ & SingleCoreApplication::Mode::SecondaryNotification)) {
Q_EMIT q->instanceStarted();
}
if (sock->bytesAvailable() > 0) {
slotDataAvailable(sock, instanceId);
}
}
void SingleCoreApplicationPrivate::slotDataAvailable(QLocalSocket *dataSocket, const quint32 instanceId) {
Q_Q(SingleCoreApplication);
Q_EMIT q->receivedMessage(instanceId, dataSocket->readAll());
}
void SingleCoreApplicationPrivate::slotClientConnectionClosed(QLocalSocket *closedSocket, const quint32 instanceId) {
if (closedSocket->bytesAvailable() > 0) {
slotDataAvailable(closedSocket, instanceId);
}
}
void SingleCoreApplicationPrivate::randomSleep() {
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
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));
#endif
}

View File

@@ -1,111 +0,0 @@
// The MIT License (MIT)
//
// 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
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// W A R N I N G !!!
// -----------------
//
// This is a modified version of SingleApplication,
// The original version is at:
//
// https://github.com/itay-grudev/SingleApplication
//
//
#ifndef SINGLECOREAPPLICATION_P_H
#define SINGLECOREAPPLICATION_P_H
#include <QtGlobal>
#include <QObject>
#include <QString>
#include <QMap>
#include "singlecoreapplication.h"
class QLocalServer;
class QLocalSocket;
class QSharedMemory;
struct InstancesInfo {
bool primary;
quint32 secondary;
qint64 primaryPid;
char primaryUser[128];
quint16 checksum;
};
struct ConnectionInfo {
explicit ConnectionInfo() : msgLen(0), instanceId(0), stage(0) {}
qint64 msgLen;
quint32 instanceId;
quint8 stage;
};
class SingleCoreApplicationPrivate : public QObject {
Q_OBJECT
public:
enum ConnectionType : quint8 {
InvalidConnection = 0,
NewInstance = 1,
SecondaryInstance = 2,
Reconnect = 3
};
enum ConnectionStage : quint8 {
StageHeader = 0,
StageBody = 1,
StageConnected = 2,
};
Q_DECLARE_PUBLIC(SingleCoreApplication)
explicit SingleCoreApplicationPrivate(SingleCoreApplication *ptr);
~SingleCoreApplicationPrivate() override;
QString getUsername();
void genBlockServerName();
void initializeMemoryBlock();
void startPrimary();
void startSecondary();
bool connectToPrimary(const int timeout, const ConnectionType connectionType);
quint16 blockChecksum();
qint64 primaryPid();
QString primaryUser();
void readInitMessageHeader(QLocalSocket *socket);
void readInitMessageBody(QLocalSocket *socket);
void randomSleep();
SingleCoreApplication *q_ptr;
QSharedMemory *memory_;
QLocalSocket *socket_;
QLocalServer *server_;
quint32 instanceNumber_;
QString blockServerName_;
SingleCoreApplication::Options options_;
QMap<QLocalSocket*, ConnectionInfo> connectionMap_;
public slots:
void slotConnectionEstablished();
void slotDataAvailable(QLocalSocket*, const quint32);
void slotClientConnectionClosed(QLocalSocket*, const quint32);
};
#endif // SINGLECOREAPPLICATION_P_H

View File

@@ -1,7 +1,13 @@
cmake_minimum_required(VERSION 3.7)
project(strawberry)
cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0054 NEW)
if(POLICY CMP0054)
cmake_policy(SET CMP0054 NEW)
endif()
if(POLICY CMP0074)
cmake_policy(SET CMP0074 NEW)
endif()
include(CheckCXXCompilerFlag)
include(CheckCXXSourceRuns)
@@ -12,13 +18,13 @@ include(cmake/Summary.cmake)
include(cmake/OptionalSource.cmake)
include(cmake/ParseArguments.cmake)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(LINUX ON)
endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
set(FREEBSD ON)
endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
set(OPENBSD ON)
endif()
@@ -32,78 +38,102 @@ 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)
list(APPEND COMPILE_OPTIONS
$<$<COMPILE_LANGUAGE:C>:-std=c99>
$<$<COMPILE_LANGUAGE:CXX>:-std=c++17>
-Wall
-Wextra
-Wpedantic
-Wunused
-Wshadow
-Wundef
-Wuninitialized
-Wredundant-decls
-Wcast-align
-Winit-self
-Wmissing-include-dirs
-Wmissing-declarations
-Wstrict-overflow=2
-Wunused-parameter
-Wformat=2
-Wdisabled-optimization
$<$<COMPILE_LANGUAGE:CXX>:-Woverloaded-virtual>
$<$<COMPILE_LANGUAGE:CXX>:-Wno-old-style-cast>
$<$<COMPILE_LANGUAGE:CXX>:-fpermissive>
)
option(BUILD_WERROR "Build with -Werror" OFF)
if(BUILD_WERROR)
list(APPEND COMPILE_OPTIONS -Werror)
endif(BUILD_WERROR)
if(MSVC)
list(APPEND COMPILE_OPTIONS /MP)
else()
list(APPEND COMPILE_OPTIONS
$<$<COMPILE_LANGUAGE:C>:-std=c11>
$<$<COMPILE_LANGUAGE:CXX>:-std=c++17>
-Wall
-Wextra
-Wpedantic
-Wunused
-Wshadow
-Wundef
-Wuninitialized
-Wredundant-decls
-Wcast-align
-Winit-self
-Wmissing-include-dirs
-Wmissing-declarations
-Wstrict-overflow=2
-Wunused-parameter
-Wformat=2
-Wdisabled-optimization
$<$<COMPILE_LANGUAGE:CXX>:-Woverloaded-virtual>
$<$<COMPILE_LANGUAGE:CXX>:-Wold-style-cast>
)
option(BUILD_WERROR "Build with -Werror" OFF)
if(BUILD_WERROR)
list(APPEND COMPILE_OPTIONS -Werror)
endif()
endif()
add_compile_options(${COMPILE_OPTIONS})
if(${CMAKE_BUILD_TYPE} MATCHES "Release")
if(CMAKE_BUILD_TYPE MATCHES "Release")
add_definitions(-DNDEBUG)
add_definitions(-DQT_NO_DEBUG_OUTPUT)
endif()
if(APPLE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks")
option(USE_RPATH "Use RPATH" APPLE)
if(USE_RPATH)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
endif()
find_program(CCACHE_EXECUTABLE NAMES ccache)
if (CCACHE_EXECUTABLE)
if(CCACHE_EXECUTABLE)
message(STATUS "ccache found: will be used for compilation and linkage")
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_EXECUTABLE})
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_EXECUTABLE})
endif ()
endif()
option(USE_ICU "Use ICU" ON)
find_package(PkgConfig REQUIRED)
find_package(Boost REQUIRED)
find_package(Threads)
find_package(Backtrace QUIET)
find_package(Backtrace)
if(Backtrace_FOUND)
set(HAVE_BACKTRACE ON)
endif()
find_package(Iconv QUIET)
if(USE_ICU)
find_package(ICU COMPONENTS uc i18n REQUIRED)
if(ICU_FOUND)
set(HAVE_ICU ON)
endif()
else()
find_package(Iconv)
endif()
find_package(GnuTLS REQUIRED)
find_package(Protobuf REQUIRED)
if (NOT Protobuf_PROTOC_EXECUTABLE)
message(FATAL_ERROR "Missing protobuf compiler.")
if(NOT APPLE)
find_package(Protobuf CONFIG)
endif()
if(NOT Protobuf_FOUND)
find_package(Protobuf REQUIRED)
endif()
if(NOT TARGET protobuf::protoc)
message(FATAL_ERROR "Missing Protobuf compiler.")
endif()
if(LINUX)
find_package(ALSA REQUIRED)
pkg_check_modules(DBUS REQUIRED dbus-1)
else(LINUX)
else()
find_package(ALSA)
pkg_check_modules(DBUS dbus-1)
endif(LINUX)
if (UNIX AND NOT APPLE)
endif()
if(UNIX AND NOT APPLE)
find_package(X11)
pkg_check_modules(XCB xcb)
endif()
@@ -113,6 +143,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)
@@ -123,7 +156,7 @@ pkg_check_modules(GSTREAMER_PBUTILS gstreamer-pbutils-1.0)
pkg_check_modules(LIBVLC libvlc)
pkg_check_modules(SQLITE REQUIRED sqlite3>=3.9)
pkg_check_modules(LIBPULSE libpulse)
pkg_check_modules(CHROMAPRINT libchromaprint)
pkg_check_modules(CHROMAPRINT libchromaprint>=1.4)
pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92)
pkg_check_modules(LIBMTP libmtp>=1.0)
pkg_check_modules(GDK_PIXBUF gdk-pixbuf-2.0)
@@ -132,81 +165,99 @@ find_package(FFTW3)
find_package(GTest)
find_library(GMOCK_LIBRARY gmock)
if(NOT QT_DEFAULT_MAJOR_VERSION)
set(QT_DEFAULT_MAJOR_VERSION 5)
endif()
set(QT_MAJOR_VERSION ${QT_DEFAULT_MAJOR_VERSION} CACHE STRING "Qt version to use (5 or 6), defaults to ${QT_DEFAULT_MAJOR_VERSION}")
option(BUILD_WITH_QT5 "Use Qt 5" OFF)
option(BUILD_WITH_QT6 "Use Qt 6" OFF)
option(QT_VERSION_MAJOR "Qt version to use (5 or 6)")
option(BUILD_WITH_QT5 "Build with Qt 5" OFF)
option(BUILD_WITH_QT6 "Build with Qt 6" OFF)
if(WITH_QT6)
set(BUILD_WITH_QT6 ON)
endif()
if(BUILD_WITH_QT5)
set(QT_MAJOR_VERSION 5)
elseif(BUILD_WITH_QT6)
set(QT_MAJOR_VERSION 6)
else()
if(QT_MAJOR_VERSION EQUAL 5)
set(BUILD_WITH_QT5 ON)
elseif(QT_MAJOR_VERSION EQUAL 6)
set(BUILD_WITH_QT6 ON)
else()
set(BUILD_WITH_QT5 ON)
set(QT_MAJOR_VERSION 5)
endif()
if(QT_MAJOR_VERSION)
set(QT_VERSION_MAJOR ${QT_MAJOR_VERSION})
endif()
set(QT_COMPONENTS Core Concurrent Widgets Network Sql)
set(QT_OPTIONAL_COMPONENTS Test)
if(QT_MAJOR_VERSION EQUAL 5)
set(QT_MIN_VERSION 5.8)
if(QT_VERSION_MAJOR)
set(QT_DEFAULT_MAJOR_VERSION ${QT_VERSION_MAJOR})
endif()
set(QT_COMPONENTS Core Concurrent Gui Widgets Network Sql)
if(DBUS_FOUND AND NOT WIN32)
list(APPEND QT_COMPONENTS DBus)
endif()
if(X11_FOUND)
set(QT_OPTIONAL_COMPONENTS Test)
set(QT_MIN_VERSION 5.12)
if(BUILD_WITH_QT6 OR QT_VERSION_MAJOR EQUAL 6)
set(QT_VERSION_MAJOR 6 CACHE STRING "" FORCE)
set(BUILD_WITH_QT6 ON CACHE BOOL "" FORCE)
elseif(BUILD_WITH_QT5 OR QT_VERSION_MAJOR EQUAL 5)
set(QT_VERSION_MAJOR 5 CACHE STRING "" FORCE)
set(BUILD_WITH_QT5 ON CACHE BOOL "" FORCE)
else()
# Automatically detect Qt version.
find_package(QT NAMES Qt6 Qt5 COMPONENTS ${QT_COMPONENTS} REQUIRED)
if(QT_FOUND AND QT_VERSION_MAJOR EQUAL 6)
set(BUILD_WITH_QT6 ON CACHE BOOL "" FORCE)
set(QT_VERSION_MAJOR 6 CACHE STRING "" FORCE)
elseif(QT_FOUND AND QT_VERSION_MAJOR EQUAL 5)
set(BUILD_WITH_QT5 ON CACHE BOOL "" FORCE)
set(QT_VERSION_MAJOR 5 CACHE STRING "" FORCE)
else()
message(FATAL_ERROR "Missing Qt.")
endif()
endif()
if(QT_VERSION_MAJOR)
set(QT_DEFAULT_MAJOR_VERSION ${QT_VERSION_MAJOR})
endif()
if(X11_FOUND AND BUILD_WITH_QT5)
list(APPEND QT_OPTIONAL_COMPONENTS X11Extras)
endif()
if(WIN32)
list(APPEND QT_OPTIONAL_COMPONENTS WinExtras)
endif()
find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} REQUIRED COMPONENTS ${QT_COMPONENTS} OPTIONAL_COMPONENTS ${QT_OPTIONAL_COMPONENTS})
find_package(Qt${QT_VERSION_MAJOR} ${QT_MIN_VERSION} REQUIRED COMPONENTS ${QT_COMPONENTS} OPTIONAL_COMPONENTS ${QT_OPTIONAL_COMPONENTS})
set(QtCore_LIBRARIES Qt${QT_MAJOR_VERSION}::Core)
set(QtConcurrent_LIBRARIES Qt${QT_MAJOR_VERSION}::Concurrent)
set(QtGui_LIBRARIES Qt${QT_MAJOR_VERSION}::Gui)
set(QtWidgets_LIBRARIES Qt${QT_MAJOR_VERSION}::Widgets)
set(QtNetwork_LIBRARIES Qt${QT_MAJOR_VERSION}::Network)
set(QtSql_LIBRARIES Qt${QT_MAJOR_VERSION}::Sql)
set(QT_LIBRARIES Qt${QT_MAJOR_VERSION}::Core Qt${QT_MAJOR_VERSION}::Concurrent Qt${QT_MAJOR_VERSION}::Gui Qt${QT_MAJOR_VERSION}::Widgets Qt${QT_MAJOR_VERSION}::Network Qt${QT_MAJOR_VERSION}::Sql)
if(Qt${QT_MAJOR_VERSION}DBus_FOUND)
set(QtDBus_LIBRARIES Qt${QT_MAJOR_VERSION}::DBus)
list(APPEND QT_LIBRARIES Qt${QT_MAJOR_VERSION}::DBus)
get_target_property(QT_DBUSXML2CPP_EXECUTABLE Qt${QT_MAJOR_VERSION}::qdbusxml2cpp LOCATION)
set(QtCore_LIBRARIES Qt${QT_VERSION_MAJOR}::Core)
set(QtConcurrent_LIBRARIES Qt${QT_VERSION_MAJOR}::Concurrent)
set(QtGui_LIBRARIES Qt${QT_VERSION_MAJOR}::Gui)
set(QtWidgets_LIBRARIES Qt${QT_VERSION_MAJOR}::Widgets)
set(QtNetwork_LIBRARIES Qt${QT_VERSION_MAJOR}::Network)
set(QtSql_LIBRARIES Qt${QT_VERSION_MAJOR}::Sql)
set(QT_LIBRARIES Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Concurrent Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Sql)
if(Qt${QT_VERSION_MAJOR}DBus_FOUND)
set(QtDBus_LIBRARIES Qt${QT_VERSION_MAJOR}::DBus)
list(APPEND QT_LIBRARIES Qt${QT_VERSION_MAJOR}::DBus)
get_target_property(QT_DBUSXML2CPP_EXECUTABLE Qt${QT_VERSION_MAJOR}::qdbusxml2cpp LOCATION)
endif()
if(Qt${QT_MAJOR_VERSION}X11Extras_FOUND)
set(QtX11Extras_LIBRARIES Qt${QT_MAJOR_VERSION}::X11Extras)
list(APPEND QT_LIBRARIES Qt${QT_MAJOR_VERSION}::X11Extras)
if(BUILD_WITH_QT5 AND Qt5X11Extras_FOUND)
set(HAVE_X11EXTRAS ON)
set(QtX11Extras_LIBRARIES Qt5::X11Extras)
list(APPEND QT_LIBRARIES Qt5::X11Extras)
endif()
if(Qt${QT_MAJOR_VERSION}WinExtras_FOUND)
set(QtWinExtras_LIBRARIES Qt${QT_MAJOR_VERSION}::WinExtras)
list(APPEND QT_LIBRARIES Qt${QT_MAJOR_VERSION}::WinExtras)
set(HAVE_WINEXTRAS ON)
endif()
if(Qt${QT_MAJOR_VERSION}Test_FOUND)
set(QtTest_LIBRARIES Qt${QT_MAJOR_VERSION}::Test)
if(Qt${QT_VERSION_MAJOR}Test_FOUND)
set(QtTest_LIBRARIES Qt${QT_VERSION_MAJOR}::Test)
endif()
find_package(Qt${QT_MAJOR_VERSION} QUIET COMPONENTS LinguistTools CONFIG)
if(Qt${QT_MAJOR_VERSION}LinguistTools_FOUND)
set(QT_LCONVERT_EXECUTABLE Qt${QT_MAJOR_VERSION}::lconvert)
find_package(Qt${QT_VERSION_MAJOR} QUIET COMPONENTS LinguistTools CONFIG)
if(Qt${QT_VERSION_MAJOR}LinguistTools_FOUND)
set(QT_LCONVERT_EXECUTABLE Qt${QT_VERSION_MAJOR}::lconvert)
endif()
if(BUILD_WITH_QT5 AND Qt5Core_VERSION VERSION_LESS 5.15.0)
macro(qt_add_resources)
qt5_add_resources(${ARGN})
endmacro()
macro(qt_wrap_cpp)
qt5_wrap_cpp(${ARGN})
endmacro()
macro(qt_wrap_ui)
qt5_wrap_ui(${ARGN})
endmacro()
macro(qt_add_dbus_adaptor)
qt5_add_dbus_adaptor(${ARGN})
endmacro()
macro(qt_add_dbus_interface)
qt5_add_dbus_interface(${ARGN})
endmacro()
endif()
if(X11_FOUND)
@@ -222,43 +273,80 @@ if(X11_FOUND)
else()
message(WARNING, "Missing X11/XF86keysym.h")
endif()
find_path(QPA_QPLATFORMNATIVEINTERFACE_H qpa/qplatformnativeinterface.h PATHS ${Qt${QT_VERSION_MAJOR}Gui_PRIVATE_INCLUDE_DIRS})
if(QPA_QPLATFORMNATIVEINTERFACE_H)
set(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H ON)
message(STATUS "Have qpa/qplatformnativeinterface.h header.")
else()
message(STATUS "Missing qpa/qplatformnativeinterface.h header.")
endif()
# Check for QX11Application (Qt 6 compiled with XCB).
if(BUILD_WITH_QT6 AND Qt6Gui_VERSION VERSION_GREATER_EQUAL 6.2.0)
set(CMAKE_REQUIRED_FLAGS "-std=c++17")
set(CMAKE_REQUIRED_LIBRARIES ${QtCore_LIBRARIES} ${QtGui_LIBRARIES})
check_cxx_source_compiles("
#include <QGuiApplication>
int main() {
(void)qApp->nativeInterface<QNativeInterface::QX11Application>();
return 0;
}
"
HAVE_QX11APPLICATION
)
unset(CMAKE_REQUIRED_FLAGS)
unset(CMAKE_REQUIRED_LIBRARIES)
endif()
endif(X11_FOUND)
find_path(QPA_QPLATFORMNATIVEINTERFACE_H qpa/qplatformnativeinterface.h PATHS ${Qt${QT_MAJOR_VERSION}Gui_PRIVATE_INCLUDE_DIRS})
if(QPA_QPLATFORMNATIVEINTERFACE_H)
set(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H ON)
include_directories(${Qt${QT_MAJOR_VERSION}Gui_PRIVATE_INCLUDE_DIRS})
message(STATUS "Have qpa/qplatformnativeinterface.h header.")
else()
message(STATUS "Missing qpa/qplatformnativeinterface.h header.")
option(USE_TAGLIB "Build with TagLib" OFF)
option(USE_TAGPARSER "Build with TagParser" OFF)
if(NOT USE_TAGLIB AND NOT USE_TAGPARSER)
set(USE_TAGLIB ON)
endif()
# TAGLIB
pkg_check_modules(TAGLIB REQUIRED taglib>=1.11.1)
find_path(HAVE_TAGLIB_DSFFILE_H taglib/dsffile.h)
find_path(HAVE_TAGLIB_DSDIFFFILE_H taglib/dsdifffile.h)
if(HAVE_TAGLIB_DSFFILE_H)
set(HAVE_TAGLIB_DSFFILE ON)
endif(HAVE_TAGLIB_DSFFILE_H)
if(HAVE_TAGLIB_DSDIFFFILE_H)
set(HAVE_TAGLIB_DSDIFFFILE ON)
endif(HAVE_TAGLIB_DSDIFFFILE_H)
if(USE_TAGLIB)
pkg_check_modules(TAGLIB REQUIRED taglib>=1.11.1)
if(TAGLIB_FOUND)
find_path(HAVE_TAGLIB_DSFFILE_H taglib/dsffile.h)
find_path(HAVE_TAGLIB_DSDIFFFILE_H taglib/dsdifffile.h)
if(HAVE_TAGLIB_DSFFILE_H)
set(HAVE_TAGLIB_DSFFILE ON)
endif(HAVE_TAGLIB_DSFFILE_H)
if(HAVE_TAGLIB_DSDIFFFILE_H)
set(HAVE_TAGLIB_DSDIFFFILE ON)
endif(HAVE_TAGLIB_DSDIFFFILE_H)
endif()
endif()
# TAGPARSER
if(USE_TAGPARSER)
pkg_check_modules(TAGPARSER REQUIRED tagparser)
endif()
if(NOT TAGLIB_FOUND AND NOT TAGPARSER_FOUND)
message(FATAL_ERROR "You need either TagLib or TagParser!")
endif()
# SingleApplication
add_subdirectory(3rdparty/singleapplication)
set(SINGLEAPPLICATION_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/singleapplication)
set(SINGLEAPPLICATION_LIBRARIES singleapplication)
set(SINGLECOREAPPLICATION_LIBRARIES singlecoreapplication)
add_subdirectory(3rdparty/kdsingleapplication)
set(SINGLEAPPLICATION_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/kdsingleapplication)
set(SINGLEAPPLICATION_LIBRARIES kdsingleapplication)
add_definitions(-DKDSINGLEAPPLICATION_STATIC_BUILD)
if(APPLE)
find_library(SPARKLE Sparkle PATHS "/usr/local/opt/sparkle")
add_subdirectory(3rdparty/macdeployqt)
add_subdirectory(3rdparty/SPMediaKeyTap)
set(SPMEDIAKEYTAP_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/SPMediaKeyTap)
set(SPMEDIAKEYTAP_LIBRARIES SPMediaKeyTap)
endif(APPLE)
add_subdirectory(3rdparty/macdeployqt)
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()
@@ -269,23 +357,29 @@ if(NOT SPARKLE AND (APPLE OR WIN32))
endif()
endif()
if (WIN32)
if(WIN32)
add_subdirectory(3rdparty/getopt)
set(GETOPT_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/getopt)
set(GETOPT_LIBRARIES getopt)
add_definitions(-DSTATIC_GETOPT -D_UNICODE)
endif()
if(WIN32 AND NOT MSVC)
# RC compiler
string(REPLACE "gcc" "windres" CMAKE_RC_COMPILER_INIT ${CMAKE_C_COMPILER})
enable_language(RC)
SET(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> -O coff -o <OBJECT> <SOURCE> -I ${CMAKE_SOURCE_DIR}/dist/windows")
endif(WIN32)
endif()
# Optional bits
if(WIN32)
option(ENABLE_WIN32_CONSOLE "Show the windows console even outside Debug mode" OFF)
endif(WIN32)
endif()
optional_component(ALSA ON "ALSA integration"
DEPENDS "alsa" ALSA_FOUND
)
optional_component(LIBPULSE ON "Pulse audio integration"
optional_component(LIBPULSE ON "PulseAudio integration"
DEPENDS "libpulse" LIBPULSE_FOUND
)
@@ -306,11 +400,17 @@ optional_component(VLC ON "Engine: VLC backend"
DEPENDS "libvlc" LIBVLC_FOUND
)
optional_component(CHROMAPRINT ON "Chromaprint (Tag fetching from Musicbrainz)"
optional_component(SONGFINGERPRINTING ON "Song fingerprinting and tracking"
DEPENDS "chromaprint" CHROMAPRINT_FOUND
DEPENDS "gstreamer" HAVE_GSTREAMER
)
if (X11_FOUND OR HAVE_DBUS OR APPLE OR WIN32)
optional_component(MUSICBRAINZ ON "MusicBrainz integration"
DEPENDS "chromaprint" CHROMAPRINT_FOUND
DEPENDS "gstreamer" HAVE_GSTREAMER
)
if(X11_FOUND OR HAVE_DBUS OR APPLE OR WIN32)
set(HAVE_GLOBALSHORTCUTS_SUPPORT ON)
endif()
@@ -318,12 +418,17 @@ optional_component(GLOBALSHORTCUTS ON "Global shortcuts"
DEPENDS "D-Bus, X11, Windows or macOS" HAVE_GLOBALSHORTCUTS_SUPPORT
)
if(HAVE_QX11APPLICATION OR HAVE_X11EXTRAS OR HAVE_QPA_QPLATFORMNATIVEINTERFACE_H)
set(X11_GLOBALSHORTCUTS_REQUIREMENT_FOUND ON)
endif()
optional_component(X11_GLOBALSHORTCUTS ON "X11 global shortcuts"
DEPENDS "X11Extras" Qt${QT_MAJOR_VERSION}X11Extras_FOUND
DEPENDS "X11" X11_FOUND
DEPENDS "QX11Application, X11Extras or qpa/qplatformnativeinterface.h header" X11_GLOBALSHORTCUTS_REQUIREMENT_FOUND
)
optional_component(AUDIOCD ON "Devices: Audio CD support"
DEPENDS "libcdio" LIBCDIO_FOUND
DEPENDS "gstreamer" HAVE_GSTREAMER
)
optional_component(UDISKS2 ON "Devices: UDisks2 backend"
@@ -335,6 +440,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
@@ -344,11 +454,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
@@ -363,33 +468,32 @@ 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
DEPENDS "gstreamer" HAVE_GSTREAMER
)
if(LINUX OR APPLE)
option(USE_BUNDLE "Bundle dependencies" OFF)
elseif(WIN32)
if(APPLE OR WIN32)
option(USE_BUNDLE "Bundle dependencies" ON)
else()
option(USE_BUNDLE "Bundle dependencies" OFF)
endif()
if (USE_BUNDLE AND NOT USE_BUNDLE_DIR)
if(LINUX)
set(USE_BUNDLE_DIR "../plugins")
endif(LINUX)
if(APPLE)
set(USE_BUNDLE_DIR "../PlugIns")
endif(APPLE)
endif(USE_BUNDLE AND NOT USE_BUNDLE_DIR)
# Check that we have sqlite3 with FTS5
if(USE_BUNDLE AND NOT USE_BUNDLE_DIR)
if(LINUX)
set(USE_BUNDLE_DIR "../plugins")
endif()
if(APPLE)
set(USE_BUNDLE_DIR "../PlugIns")
endif()
endif()
if(NOT CMAKE_CROSSCOMPILING)
# Check that we have Qt with sqlite driver
set(CMAKE_REQUIRED_FLAGS "-std=c++17")
set(CMAKE_REQUIRED_LIBRARIES ${QtCore_LIBRARIES} ${QtSql_LIBRARIES})
check_cxx_source_runs("
@@ -400,22 +504,52 @@ if(NOT CMAKE_CROSSCOMPILING)
db.setDatabaseName(\":memory:\");
if (!db.open()) { return 1; }
QSqlQuery q(db);
q.prepare(\"CREATE VIRTUAL TABLE test_fts USING fts5(test, tokenize = 'unicode61 remove_diacritics 0');\");
q.prepare(\"CREATE TABLE test (test TEXT);\");
if (!q.exec()) return 1;
}
"
SQLITE3_FTS5
QT_SQLITE_TEST
)
if(QT_SQLITE_TEST)
# Check that we have sqlite3 with FTS5
check_cxx_source_runs("
#include <QSqlDatabase>
#include <QSqlQuery>
int main() {
QSqlDatabase db = QSqlDatabase::addDatabase(\"QSQLITE\");
db.setDatabaseName(\":memory:\");
if (!db.open()) { return 1; }
QSqlQuery q(db);
q.prepare(\"CREATE VIRTUAL TABLE test_fts USING fts5(test, tokenize = 'unicode61 remove_diacritics 0');\");
if (!q.exec()) return 1;
}
"
SQLITE_FTS5_TEST
)
endif()
unset(CMAKE_REQUIRED_FLAGS)
unset(CMAKE_REQUIRED_LIBRARIES)
endif()
# Set up definitions
add_definitions(-DBOOST_BIND_NO_PLACEHOLDERS)
add_definitions(${QT_DEFINITIONS})
add_definitions(-DQT_STRICT_ITERATORS)
add_definitions(-DQT_USE_QSTRINGBUILDER)
add_definitions(-DQT_NO_URL_CAST_FROM_STRING)
add_definitions(-DQT_NO_CAST_TO_ASCII)
add_definitions(
-DBOOST_BIND_NO_PLACEHOLDERS
-DQT_STRICT_ITERATORS
-DQT_NO_CAST_FROM_BYTEARRAY
-DQT_USE_QSTRINGBUILDER
-DQT_NO_URL_CAST_FROM_STRING
-DQT_NO_CAST_TO_ASCII
-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT
-DQT_NO_FOREACH
)
if(WIN32)
add_definitions(-DUNICODE)
if(MSVC)
add_definitions(-DPROTOBUF_USE_DLLS)
endif()
endif()
# Subdirectories
add_subdirectory(src)
@@ -431,27 +565,37 @@ if(GTest_FOUND AND GMOCK_LIBRARY AND QtTest_LIBRARIES)
add_subdirectory(tests)
endif()
# Uninstall support
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
if(LINUX AND LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
add_subdirectory(debian)
endif()
add_custom_target(uninstall
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
# Uninstall support
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
# 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()
if(NOT SQLITE3_FTS5 AND NOT CMAKE_CROSSCOMPILING)
message(WARNING "sqlite3 must be enabled with FTS5. See: https://www.sqlite.org/fts5.html")
if(QT_VERSION_MAJOR EQUAL 5)
message(WARNING "It is detected that Strawberry is being built with Qt 5. There are no bugfix releases for the latest minor LTS version of Qt 5 available to open-source users, only commercial users. Therefore Strawberry should be built with Qt 6 when possible. Building with Qt 6 will also take advantage of improvements and new features not available in Qt 5. To build with Qt 6 specify -DBUILD_WITH_QT6=ON to automatically detect Qt 6, or for example -DCMAKE_PREFIX_PATH=/usr/local/lib64/cmake to manually specify the Qt 6 directory.")
endif()
if(NOT TAGLIB_VERSION VERSION_GREATER_EQUAL 1.12)
if(NOT CMAKE_CROSSCOMPILING)
if(QT_SQLITE_TEST)
if(NOT SQLITE_FTS5_TEST)
message(WARNING "sqlite must be enabled with FTS5. See: https://www.sqlite.org/fts5.html")
endif()
else()
message(WARNING "The Qt sqlite driver test failed.")
endif()
endif()
if(USE_TAGLIB AND TAGLIB_FOUND AND NOT TAGLIB_VERSION VERSION_GREATER_EQUAL 1.12)
message(WARNING "There is a critical bug in TagLib (1.11.1) that can result in corrupt Ogg files, see: https://github.com/taglib/taglib/issues/864, please consider updating TagLib to the newest version.")
endif()

112
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,112 @@
# Contribution guidelines
Strawberry is an free and open-source project, it is possible and encouraged to participate in the development.
You can also participate by answering questions, reporting bugs or helping with documentation.
## Submitting a pull request
You should start by creating a fork of the Strawberry repository using the GitHub
fork button, after that you can clone the repository from your fork.
Replace "username" with your own.
### Clone the repository
git clone git@github.com:username/strawberry.git
cd strawberry
### Setup the remote
git remote add upstream git@github.com:strawberrymusicplayer/strawberry.git
### Create a new branch
This creates a new branch from the master branch that you use for specific
changes.
git checkout -b your-branch
### Stage changes
Once you've finished working on a specific change, stage the changes for
a specific commit.
Always keep your commits relevant to the pull request, and each commit as
small as possible.
git add -p
### Commit changes
git commit
### Commit messages
The first line should start with "Class:", which referer to the class
that is changed. Don't use a trailing period after the first line.
If this change affects more than one class, omit the class and write a
more general message.
You only need to include a main description (body) for larger changes
where the one line is not enough to describe everything.
The main description starts after two newlines, it is normal prose and
should use normal punctuation and capital letters where appropriate.
An example of the expected format for git commit messages is as follows:
```
class: Short explanation of the commit
Longer explanation explaining exactly what's changed, why it's changed,
and what bugs were fixed.
Fixes #1234
```
### Push the changes to GitHub
Once you've finished working on the changes, push the branch
to the Git repository and open a new pull request.
git push origin your-branch
### Update your fork's master branch
git checkout master
git pull --rebase origin master
git fetch upstream
git merge upstream/master
git push origin master
### Update your branch
git checkout your-branch
git fetch upstream
git rebase upstream/master
git push origin your-branch --force-with-lease
### Rebase your branch
If you need fix any issues with your commits, you need to rebase your
branch to squash any commits, or to change the commit message.
git checkout your-branch
git log
git rebase -i commit_sha~
git push origin your-branch --force-with-lease
### Delete your fork
If you do not plan to work more on Strawberry, please delete your fork from GitHub
once the pull requests are merged.

537
Changelog
View File

@@ -2,7 +2,411 @@ Strawberry Music Player
=======================
ChangeLog
0.9.2:
Version 1.0.18 (2023.07.02):
Bugfixes:
* Fixed reading disc from QObuz songs (#1168).
* Fixed volume being reset on playback with PulseAudio (#1174).
* Fixed <br> tags in SQL query error message.
* Fixed compile with Qt 6 without XCB (QX11Application).
* Fixed smart playlist editor not properly loading search terms (#1172).
* Fixed use of fixed icon for playlist favorite star icon (#1178).
* Possible fix for collection thumbnails using disk cache having identical covers for albums with hashtag (#) in the album title (#1183).
* Fixed listenbrainz scrobbling for songs with multiple artist mbids.
* Fixed listenbrainz scrobbling for songs without duration.
* Fixed gapless playback sometimes not working.
* Fixed writing PNG images as embedded covers (#1209).
* Fixed greyscale album covers not working in OSD D-Bus (#1205).
* Fixed collection thumbnail disk cache with Qt 6.5.1 and newer.
* Fixed moodbar disk cache with Qt 6.5.1 and newer.
* Fixed playlist edit tag F2 shortcut only working for title tag (#1210).
* Append number to filename if the destination file already exist when transcoding audio (#1200).
* Fixed abseil linking issues with protobuf 1.22.0 and newer.
* (macOS) Fixed "Show this message" checkbox having no affect on Rosetta warning dialog (#1180).
* (macOS) Disable unused D-Bus.
* (Windows) Fixed command line options not working with diacritics (#1191).
* (Windows) Fixed issue with saving album covers in album directory being saved in temp directory instead.
* (Windows) Fixed crash when trying a play a song which doesn't exist, gstreamer issue #1683 (#1214).
Enhancements:
* Reduce memory overhead with album cover handling (#1046).
* Improved listenbrainz error handling.
* Show error dialog for listenbrainz errors similar to last.fm/libre.fm.
* Reduce NetworkAccessManager instances.
* Replace SingleApplication with KDSingleApplication.
* Require Qt 5.12 or higher.
* Add new database fields for art_embedded and art_unset.
* Rewrite album cover loader.
* Move cover filename settings from collection to covers settings.
* Add setting to set priorities for album cover types.
* Add rating filtering to playlist search (#1212).
* (Windows|MSVC) Add WSAPI2 plugin.
Version 1.0.17 (2023.03.29):
Bugfixes:
* Fixed over-sized context album cover with device pixel ratio higher than 1.0 (#1166).
* Fixed playing widget fading from a blurry previous cover with device pixel ratio higher than 1.0.
* Made playlist source icon, album cover manager and OSD pretty cover respect device pixel ratio.
Version 1.0.16 (2023.03.27):
Bugfixes:
* Fixed lyrics from Musixmatch.
* Fixed possible file corruption when saving both tags and embedded cover using the tag editor (#1158).
* Fixed compile without GStreamer.
* Fixed context and playing now album art rendering on High DPI displays (#1161).
* Fixed setting source properties (device, user-agent, ssl-strict) with GStreamer 1.22 (playbin3) and higher (#1148).
* Fixed rescan songs feature not ignoring mtime.
* Search lyrics by artist instead of album artist by default.
Code improvements:
* Replace use of deprecated QSqlDatabase::exec().
Added features:
* Added backend setting for strict SSL mode.
* Read AcoustID and MusicBrainz tags.
* Submit MusicBrainz tags with ListenBrainz.
Version 1.0.15 (2023.03.04):
Bugfixes:
* Fixed playlist column showing invalid last played date for streams.
* Fixed crash when the audio bin failed to initialize (#1123, #1133).
* Fixed duplicated filename when organizing files using dot in the filename (#1136).
* Fixed tag inline editing for streams (#1130).
* Fixed resetting play statistics using tag edit dialog (#1124).
* Fixed compilation songs not showing if group by was set to other than (Album) Artist / Album (#1140).
Enhancements:
* Added lyrics from stands4 (lyrics.com).
* Added Sonogram analyzer.
* Use GStreamer playbin3 with GStreamer 1.22.0 and higher.
Code improvements:
* Made use of C++11 enum class where possible.
* Use new QNativeIpcKey based QSharedMemory constructor with Qt 6.6 and higher.
Version 1.0.14 (2023.01.13):
Bugfixes:
* Fix initial volume not set when using Auto as output (#1104).
* Fix saving moodbar if the URL contains host, ie.: UNC paths for SMB (#1101).
* Fix CollectionBackendTest compile error (#1100).
* Remove explicitly enabling debug messages (#1106).
Version 1.0.13 (2023.01.09):
Bugfixes:
* Fixed volume synchronization leading to infinite loop resulting in crash when adjusting volume while playing (#1089).
* Fixed incorrect volume.
* Fixed collection organizing incorrectly handling slashes inside {} brackets for variables (#1091).
* Fixed saving relative playlists to non-existing playlist files (#1092).
* Fixed intermittent crash on collection model query (#1095).
* Require system icons for fancy tabbar and settings sidebar to be larger than 22x22 (#1084).
Version 1.0.12 (2023.01.02):
Bugfixes:
* Fixed crash when adjusting volume with mouse wheel (#1089).
* Fixed playback stopping in certain cases where the next track was unavailable (#958).
* (Windows) Apply patch for fonts too large on High DPI screen (QTBUG-108593).
Removed features:
* Removed appearance settings for changing palette colors, it was never properly implemented.
Version 1.0.11 (2022.12.30):
Bugfixes:
* Capitalize GLib application name so it appears nicely in GNOME and PulseAudio Volume Control (#1066).
* Fixed missing application icon for PulseAudio Volume Control (#1066).
* Ignore errors for missing albums when updating Tidal collection if there are results (#1061).
* Only run periodic collection scan when moitoring collection setting is on.
* Fixed an edge case where the context headline text was being cut short (#1067).
* Made "Show in file browser" support SpaceFM filemanager (#1073).
* Fixed incorrect tab order in edit tag dialog (#1075).
* Changed "FMPS_PlayCount" to "FMPS_Playcount" when saving tag (#1074).
* Fixed compilation tag read and write for MP4 (#1076).
* Removed incorrect use of "TPE1" for performer when reading ID3 tags (#1076).
* Disable tag fields for unsupported tags in tag editor.
* Don't allow organizing files without unique tags (track or title) for filename (#1077).
* Don't remove disc from album title when creating cover hash to allow different covers for each disc on an album (#1069).
* Fixed incorrect relative paths for song filenames when saving playlists if the saved playlist location is a symablic link to the song filename (#1071).
* Scrobble "Various Artists" as album artist (#1082).
Enhancements:
* Use system volume instead of own software volume when available (#1037).
* Improved Tidal and Qobuz support with timed requests.
* Support MPRIS2 xesam:userRating.
Version 1.0.10 (2022.10.21):
Bugfixes:
* Fixed "Could not open settings file for writing: No such file or directory" error before settings file is created.
* Fixed visual glitch on currently playing track (#1051).
* Fixed "Unknown error" on Tidal search (#1047).
* Fixed incomplete lyrics from Genius.
* Fixed icons not showing in the file view on some systems (#1024).
* Fixed issues with context and playing widget stopping when using VLC (#1054).
* (macOS) Fixed search field related crash when playlist toolbar is turned off.
Enhancements:
* Fixed narrowing conversions in connects.
* Fixed casts from QByteArray.
* Removed subdir for generated dbus files
* Removed use of fixed font in context (#1040).
* Improve Musixmatch lyrics search.
Version 1.0.9 (2022.09.03):
Bugfixes:
* Fixed parsing album title from radio stream metadata (#1023).
* (macOS) Fixed Strawberry not starting, incorrect rpath for libgcc_s.1.1.dylib (#1025).
* (macOS) Fixed HTTP streaming.
Version 1.0.8 (2022.08.29):
Bugfixes:
* Fixed backslash being appended to filter text when switching playlist (#1005).
* Fixed OSD notifications service registering taking too long to timeout when not available.
* Fixed radio stream added twice when double-clicked (#1015).
* Fixed translating undo and redo buttons (#1017).
Enhancements:
* Use ICU instead of iconv to transliterate characters for filenames.
* Make separating albums by grouping tag optional in collection group by album.
* Added support for video game music formats VGM and SPC.
* Added setting for explicitly turning on HTTP/2 for streaming. Strawberry will set the
libsoup SOUP_FORCE_HTTP1 environment variable when the HTTP/2 is not checked (#1016).
* (Windows|MSVC) Install Visual C++ runtime redistributable automatically in installer.
Version 1.0.7 (2022.07.25)
Bugfixes:
* Fixed checking file extension case-insensitive when loading and saving playlists.
* Fixed reading and saving rating with TagParser.
* (macOS/Windows) Fixed playlist column alignment. Applied patch for Qt bug QTBUG-103576 (#999).
* (Windows|MinGW) Fixed HLS streaming.
* (Windows|MSVC) Fixed MP3 encoding.
Enhancements
* Added option for selecting file extension when saving all playlists.
Version 1.0.6 (2022.07.17)
Bugfixes:
* Fixed certain albums not added to playlist in correct track order from search for Tidal and QObuz.
* Fixed songs not added to playlist in numeric order when added from file view with right click (#977).
* Fixed "Stop after this track" graying out next track in dynamic mode (#912).
* Fixed a gstreamer caps leak when transcoding songs.
* Fixed errors in translation files (#994).
Enhancements
* Add songs to the collection even when they have invalid ctime or mtime.
* Made ListenBrainz scrobbler respect "Prefer album artist" option (#989).
* Send track duration, number, player name and version when scrobbling to ListenBrainz (#995).
* (macOS) Added missing HLS streaming plugin.
Version 1.0.5 (2022.06.10)
Bugfixes:
* Fixed smart playlist filetype search.
* Fixed Radio Paradise URLs to use HTTPS instead of HTTP.
* Fixed horizontal scrolling not affecting currently playing track (#952).
* Fixed keep running in the background when window is closed with Wayland (#964).
* Fixed percent-encoding of URLs when loading and saving XSPF playlists (#821).
* Fixed fancy tabbar context menu showing on right clicks outside of tabbar when a song is playing.
* Fixed possible duplicating songs in the database when moving songs to the collection using the organize feature.
* (Windows|MSVC) Fixed moodbar fftw3 crash with (older) CPU's that does not support AVX2 (#944).
* (Windows|MSVC) Fixed using libiconv for converting characters when organizing files like with MinGW.
Enhancements
* Show more details in error dialog on GStreamer errors (#958).
* Allow setting blur amount of playlist background image up to 100px (#939).
* Include 128x128 icon sizes (#954).
* Show right click copy context menu in context view on top text and lyrics (#965).
* Improve fading between album covers in context view.
* Added option for overwriting database playcounts in collection settings (#962).
* Added option for disabling bar on currently playing track (#972).
* (Debian) Added Qt 6 support to debian files and build with Qt 6 for Debian Bookworm, Ubuntu Jammy and newer.
* (Windows|MSVC) Added libav/ffmpeg plugin.
Version 1.0.4 (2022.04.10)
Bugfixes:
* Fixed use-after-free memory in ALSA PCM device finder.
* Translate global shortcuts.
* (Windows) Fixed registering 0-9 numpad keys in global shortcuts.
Enhancements
* Added save all playlists action.
* (Windows) Made updater support both MSVC and MinGW.
* (Windows) Added HLS support.
Other:
* Removed use of custom font in context.
Version 1.0.3 (2022.03.24)
Bugfixes:
* Remove slash and backslash from filenames when saving album covers using album directory cover filenames (#903).
* Remove playlist file-extensions from accepted audio file extensions (#909).
* Fixed Qobuz requests only receiving the first 50 albums (#922).
* (Windows|MinGW) Fixed streaming stopping at the end of each track. libsoup downgraded from 3.0 to 2.74.
* (Windows|MSVC) Fixed initial database schema failure caused by CRLF line-endings in schema files.
New features
* Added support for bs2b (Improved headphone listening of stereo audio records using Bauer stereophonic-to-binaural DSP) (#249).
Version 1.0.2 (2022.02.20)
Bugfixes:
* 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:
* Fixed collection and internet search filter tool button menu arrow overlap (#796).
* Fixed stop after this track button with Qt 6 (#795).
* Fixed not updating the URL when songs were moved on disk when the fingerprinting feature is enabled.
* Fixed SQL query error for songs with an invalid modification time (#815).
* Fixed blocky rendering of the currently playing track with high resolution screens (#794).
* Fixed incorrect playlist column filesize for radio streams.
* Fixed deleting embedded album cover from Ogg songs.
* Fixed parsing of Cue tracks with 1-digit minutes (#836).
* Fixed updating of playlist summary after reloading items when adding songs from files outside of the collection (#848).
* Fixed always saving metadata when saving playlists for Tidal, Qobuz and Subsonic songs independent of playlist setting (#851).
* Fixed setting media shortcuts when using kglobalaccel (#849).
* Fixed parsing of Genius lyrics when they are sometimes received in a different HTML format.
* Fixed saving MP4 specific tags as UTF-8 (#830).
* Fixed clearing "manually set" cover when saving album covers embedded from outside of the tag editor (#858).
* Fixed aborting collection scan when Strawberry exists to avoid hang on exit.
* Fixed resuming collection scan when adding a new directory after collection scan was aborted.
* Fixed excluding hidden songs from the collection.
* Disabled moodbar for CUE songs since they can not be supported properly (#865).
* (Windows) Added gstreamer gstxingmux plugin to fix transcoding to MP3 (#856).
Enhancements:
* Made playlist header column text elided (#801).
* Added support for reading and writing playcounts and ratings from/to tags.
* Added support for setting rating using the edit tag dialog.
* Added setting to enable/disable playlist toolbar (#809).
* Added component type, content_rating type and releases to AppStream data file (#806).
* Removed unused "mark as listened" option in organize dialog.
* Fixed some clazy warnings and narrowing conversions in the source code.
* Replaced uses of macros in the source code.
* Added a more user-friendly error message when receiving encrypted streams from Tidal (#824).
* Added support for port-pattern entered in the device textbox when using Jack as output (#828).
* Added Spanish (Spain) translation.
* Added support for more CUE filenames (#835).
* (Windows) Add gstreamer dash plugin.
Version 1.0.0 (2021.10.14)
Bugfixes:
* Fix updating temporary metadata when reloading songs outside of the collection.
* Don't strip off "Live" from song title when sending scrobbles.
* Fix incorrect use of QFutureWatcher.
* Fix compile of Utilities::Hmac with Qt 6.2.
* Fix a memory leak when using right click context menu in internet search.
* Fix a gstreamer bus leak when adding streams and remote playlists.
* Fix "Source ID x was not found when attempting to remove it" error.
* Escape ampersands in playlist tabs.
* Fix analyzer with S24_32LE audio format.
* (macOS) Fix incorrect playlist alternating row colors with dark theme.
* (Windows) Fix adding songs with Japanese characters from the files tab.
Enhancements:
* Add replaygain fallback gain setting.
* Add option to turn off playlist alternating row colors.
* Make the default tabbbar background color lighter.
* Remove use of deprecated WinExtras Qt module.
* Add CMake test for Qt sqlite support.
* Automatically detect Qt version if BUILD_WITH_QT5 or BUILD_WITH_QT6 is not specified.
* Correct playlist tabbar favorite tooltip from "click" to "double-click".
* Remove scroll over icon to change track option since it does not work reliable.
* Improve resume playback on startup.
* Re-request stream URL for Tidal and QObuz when resuming playback after pausing for more than 30 seconds.
* Add Finnish, Ukrainian, Dutch, Japanese, Chinese, Catalan and Portuguese (Brazil).
* Add support for TagParser (https://github.com/Martchus/tagparser) as an alternative to TagLib.
* Add Subsonic option to turn off HTTP/2.
* Fix minor Clang-Tidy and Clazy warnings.
* Use higher resolution images from last.fm API.
* Add MD5 token authentication for Subsonic.
* Use 500 albums per request when receiving albums from Subsonic.
* Use QX11Application with Qt >= 6.2 for X11 global shortcuts.
* Allow fading when a ALSA PCM device is selected.
* Store Tidal MPEG-DASH file in data uri.
* Use XSPF image elements as manually set artwork.
* Make error dialog larger.
* Show error dialog for failed SQL queries.
* Show error dialog when failing to read or write album covers.
* Add module music formats (mod, s3m, xm, it) to detected filetypes.
* Disable gapless playback for module music formats to workaround gstreamer bug.
* Update directory ID and song path immediately when organizing collection songs.
* Add right click option to star a playlist in playlist tabs.
* Use seconds instead of minutes for scrobble submit delay.
* (macOS) Build with libgpod.
* (Windows) Fix compile with MSVC.
New features:
* Add ALSA PCM devices.
* Add song fingerprinting and tracking.
* Add support for native global shortcuts on MATE.
* Add radios view with channels from Radio Paradise and SomaFM.
Version 0.9.3 (2021.04.18)
Bugfixes:
* Fix "Show in file browser" to work with thunar.
* Check that the clicked rating position is to the right or left of the rectangle.
* Fix rescan when collection directory is removed and re-added.
* Create GLib main event loop on non-glib systems to fix stream discoverer.
* (macOS) Fix intermittent abort on startup.
* (macOS) Fix Tidal and Qobuz search field not showing.
* (macOS) Add tidal URL scheme to Info.plist.
* (macOS) Fix Tidal OAuth authentication.
Enhancements:
* Allow editing playlist metadata for radio streams.
* Make CollectionQuery subclass QSqlQuery, avoid copying QSqlQuery.
* Only enable FTS3 when schema needs upgrading, since FTS5 is used for search.
* Add setting for configuring the color for the currently playing song.
* Add setting to turn on OSD Pretty fading.
* Add commandline option to resize window.
* (Windows) Show dialog with programs that needs to close in nsis installer.
* (macOS) Make macdeployqt work with Qt 5 too.
* (macOS) Show keep running option in behaviour settings.
Version 0.9.2 (2021.03.25)
Bugfixes:
* Fix marking songs available.
@@ -13,7 +417,8 @@ ChangeLog
* (macOS) Fix crash when opening cover manager.
* (macOS) Fix broken Qt plugins resulting in album covers not showing.
0.9.1:
Version 0.9.1 (2021.03.13)
Bugfixes:
* Fix duplicating songs in the DB when organizing songs between 2 different collection directories.
@@ -48,7 +453,8 @@ ChangeLog
New features:
* Add option and support for saving embedded covers for FLAC, Ogg Vorbis, MP3 and MP4/AAC.
0.8.5:
Version 0.8.5 (2020.12.19)
Bugfixes:
* Fix return type of SmartPlaylistQueryWizardPlugin::type().
@@ -67,7 +473,8 @@ ChangeLog
* Add command line option to play a playlist based on name.
* Change double-click behaviour in cover manager to open fullsize cover.
0.8.4:
Version 0.8.4 (2020.11.15)
Bugfixes:
* Fix preventing session logout when window is maxmimized.
@@ -85,15 +492,16 @@ ChangeLog
* Add support for native global shortcuts on KDE.
* Add track progress in system tray icon as an option.
* Only strip problematic characters in suggested filename when saving a playlist to file.
* Change star/unstar playlist to doubleclick instead of singleclick.
* Don't edit playlist name on doubleclick in playlists view.
* Change star/unstar playlist to double-click instead of singleclick.
* Don't edit playlist name on double-click in playlists view.
* Make context view top label text selectable.
* Add setting to change Qt style.
* Clear ID3v3 tags that are empty, and clear ID3v1 tags when setting ID3v3 tags.
* Remove remaining uses of QTextCodec.
* Remove Core5Compat dependency.
0.8.3:
Version 0.8.3 (2020.10.24)
Bugfixes:
* Fixed updating playing widget song details in small cover mode.
@@ -108,7 +516,8 @@ ChangeLog
Enhancements:
* (Windows) Added WASAPI plugin.
0.8.2:
Version 0.8.2 (2020.10.13)
Bugfixes:
* Fixed broken transition to next song for CUE files with certain audio formats (regression since version 0.6.13).
@@ -120,7 +529,8 @@ ChangeLog
* Removed use of HTML in system tray icon tooltip for all desktop environments instead of just KDE and Cinnamon.
* (Windows) Ignore "IDirectSoundBuffer_GetStatus The operation completed successfully" false error when switching device while playing.
0.8.1:
Version 0.8.1 (2020.10.09)
Bugfixes:
* Fixed engine selection in backend settings with Qt 6.
@@ -167,14 +577,15 @@ ChangeLog
* Added Subsonic server side scrobbling support.
* Load thumbnails from iPods to show under device collection.
0.7.2:
Version 0.7.2 (2020.08.15)
Bugfixes:
* Fixed installation directory for translations.
* Fixed collection sorting for non-ASCII characters.
* Fixed closing connected devices on exit.
0.7.1:
Version 0.7.1 (2020.08.15)
Bugfixes:
* Fixed incorrectly mapped global shortcuts keys "2" and "3".
@@ -213,7 +624,8 @@ ChangeLog
* Removed Xine engine support.
* Removed broken imobiledevice (iPhone) support.
0.6.13:
Version 0.6.13 (2020.07.13)
Bugfixes:
* Fixed cut-off text in about dialog.
@@ -239,7 +651,8 @@ ChangeLog
* Fixed unit test for testing playlist model.
* Added new unit tests for tagreader.
0.6.12:
Version 0.6.12 (2020.06.07)
Bugfixes:
* Fixed height of about dialog.
@@ -252,7 +665,8 @@ ChangeLog
* Sort folders added from file view.
* Changed default collection grouping to album - disc.
0.6.11:
Version 0.6.11 (2020.05.16)
Bugfixes:
* Fixed MPRIS missing art url when playing albums with embedded cover.
@@ -278,10 +692,11 @@ ChangeLog
* Added album covers from Musixmatch and Spotify.
* Added lyrics from Genius, Musixmatch and ChartLyrics.
0.6.10:
Version 0.6.10 (2020.05.01)
Bugfixes:
* Fixed Subsonic album covers not working for albums with non ASCII charcters.
* Fixed Subsonic album covers not working for albums with non ASCII characters.
* Fixed reading date and genre from individual tracks in CUE sheets.
* Fixed resume playback on startup for CUE songs.
* Fixed album cover manager not showing complete album titles in the list of album covers.
@@ -290,7 +705,7 @@ ChangeLog
* Fixed engine and device in context using too large icons when icons were loaded from the system theme.
* Fixed "Secure connection setup failed" problem on Windows when playing streams.
* Fixed margin for song title text in context.
* Fixed UNC paths with non ASCII charcters not working.
* Fixed UNC paths with non ASCII characters not working.
Enhancements:
* Allowing all characters except slash and backslash when organising music unless options to strip characters is checked.
@@ -305,11 +720,11 @@ ChangeLog
* Only showing song length in context when available.
* Sort album cover search results by score and pick the best 3 first before trying others to improve album cover search speed.
* Make scrobbler work for streams.
* Added search for lyrics as a seperate option in context.
* Added search for lyrics as a separate option in context.
* Made font and font sizes in context configurable.
* Splitting artist and song title to the relevant metadata when artist and song title is sent as title seperated by a dash in streams.
* Splitting artist and song title to the relevant metadata when artist and song title is sent as title separated by a dash in streams.
* Added label to show collection pixmap disk cache used in settings.
* Icreased default collection pixmap disk cache to 360.
* Increased default collection pixmap disk cache to 360.
New features:
* Added back Tidal streaming support.
@@ -318,7 +733,8 @@ ChangeLog
Removed features:
* Removed Phonon engine support.
Version 0.6.9:
Version 0.6.9 (2020.03.09)
BugFixes:
* Fixed playlist metadata updating interfering with manual tag editing.
@@ -350,7 +766,8 @@ Version 0.6.9:
* Tidal support (No agreement).
* QObuz support (No agreement).
Version 0.6.8:
Version 0.6.8 (2020.01.05)
* Fixed stuck tabbar and collection GUI with some themes.
* Fixed possible crashes related to QProxyStyle.
@@ -367,14 +784,15 @@ Version 0.6.8:
* (macOS) Fixed filesystem watcher to correctly pick up changed collection directories.
* (Windows) Fixed translations not being included.
Version 0.6.7:
Version 0.6.7 (2019.11.27)
* Fixed crash when cancelling scrobbler authentication
* Fixed "Double clicking a song in the playlist" behaviour setting
* Fixed "Pressing Previous in player" behaviour setting
* Fixed updating compilations where there are spaces or special characters in filenames
* Fixed cases where songs were stuck in "Various Artists" because not all songs in
the same compilation was removed from the model before readded with actual artist.
the same compilation was removed from the model before re-added with actual artist.
* Fixed a bug when importing playlists where metadata was reset
* Fixed scrobbler to also scrobble songs without album title
* Fixed text for replay gain setting not loading in backend setting
@@ -384,7 +802,8 @@ Version 0.6.7:
* Removed left click on analyzer to popup menu
* (Windows) Added killproc executable to terminate running process before uninstalling
Version 0.6.6:
Version 0.6.6 (2019.11.09)
* Fixed lowercased album artist in playlist column
* Fixed compiling with different optional features turned off
@@ -402,7 +821,8 @@ Version 0.6.6:
* Added option to automatically select current playing track
* (Windows) Added support for WASAPI
Version 0.6.5:
Version 0.6.5 (2019.09.30)
* Fixed scrobbler not to send scrobbles multiple times when metadata is updated
* Fixed Listenbrainz scrobbler not don't send "various artists" as album artist
@@ -411,7 +831,8 @@ Version 0.6.5:
* Fixed OSD pretty positioning on Windows on screens with negative geometry
* Fixed appdata file to pass full validation
Version 0.6.4:
Version 0.6.4 (2019.09.25)
* Added setting for fancy tabbar background color
* Added setting to make marking songs unavailable optional
@@ -438,18 +859,21 @@ Version 0.6.4:
* Fixed restoring to original window size when restoring from system tray
* Updated 3rdparty taglib
Version 0.6.3:
Version 0.6.3 (2019.08.05)
* Fixed crash when using internet services.
* Fixed musicbrainz tagfetcher only showing 1 result per song.
* Fixed collection watcher to unwatch deleted directories.
* Added "album - disc" grouping.
Version 0.6.2:
Version 0.6.2 (2019.08.03)
* Disabled fatal error for FTS5 cmake test.
Version 0.6.1:
Version 0.6.1 (2019.08.03)
* Compare artist and album case-insensitive when generating score for album covers.
* Fixed broken return value of sendMessage() in SingleApplication causing application to be started twice.
@@ -495,11 +919,13 @@ Version 0.6.1:
* Fixed certain cases where the playing widget gets stuck when switching fast between context and other widgets.
* Removed ChartLyrics provider (service have been down for a long time).
Version 0.5.5:
Version 0.5.5 (2019.05.05)
* Fixed Tidal API url
Version 0.5.4:
Version 0.5.4 (2019.05.05)
* Changed description for offline mode scrobbling for less confusion
* Fixed scrobbler to not send "playing now" when in offline mode
@@ -530,7 +956,8 @@ Version 0.5.4:
* Fixed and improved snap including upgrading to core18 and adding proper alsa support
* Fixed resume playback on startup not working for other than the first playlist
Version 0.5.3:
Version 0.5.3 (2019.03.02)
* Changed default tagging to albumartist in organise dialog
* Removed support for older taglib in tagreader
@@ -570,7 +997,8 @@ Version 0.5.3:
* Added group by format
* Fixed gstreamer leaks
Version 0.5.2:
Version 0.5.2 (2019.01.26)
* Added error handling and message for URL handler
* Added SingleCoreApplication secondary check
@@ -587,7 +1015,8 @@ Version 0.5.2:
* Added option to copy album cover in organise dialog (filesystem and libgpod devices)
* Added raise() to make sure window is on top when strawberry is started twice
Version 0.5.1:
Version 0.5.1 (2019.01.12)
* Added scrobbler with support for Last.fm, Libre.fm and ListenBrainz
* Fixed key up causing playback to reset
@@ -618,7 +1047,8 @@ Version 0.5.1:
* Added debian copyright file
* Fixed some compile errors
Version 0.4.2:
Version 0.4.2 (2018.11.28)
* Updated AppStream data file to newer specifications
* Fixed Deezer engine to use quality setting
@@ -632,7 +1062,8 @@ Version 0.4.2:
* (Windows) Corrected uninstalled files on x64 installer
* (macOS) Fixed poor performance
Version 0.4.1:
Version 0.4.1 (2018.11.01)
* Fixed crash in analyzer
* Fixed trying to use systray even if the desktop had no systray
@@ -650,11 +1081,13 @@ Version 0.4.1:
* Added AppStream data file
* Fixed compiling with Qt 5 versions of system QtSingleApplication and Qxt library
Version 0.3.3:
Version 0.3.3 (2018.09.24)
* Fixed Tidal login
Version 0.3.2:
Version 0.3.2 (2018.09.24)
* Fixed search error not shown in Tidal search
* Added URL handler for Tidal, now retrieving URL's when playing instead of when searching
@@ -666,7 +1099,8 @@ Version 0.3.2:
* Added encoding of Tidal token in the source code
* Added encoding of Tidal password in the configuration
Version 0.3.1:
Version 0.3.1 (2018.09.15)
* Added new lyrics provider with lyrics from AudD and API Seeds
* New improved context widget with albums and lyrics
@@ -688,7 +1122,8 @@ Version 0.3.1:
* Added support for reading/writing lyrics to tags
* Fixed saving tags (APE) for WavPack files
Version 0.2.1:
Version 0.2.1 (2018.07.05)
* Fixed crash with newer Qt
* Fixed setting output/device for Xine and VLC backend
@@ -698,19 +1133,23 @@ Version 0.2.1:
* Fixed device selection on macOS
* Added xine on to windows build
Version 0.1.6:
Version 0.1.6 (2018.06.07)
* Fixed crash on exit caused by NVIDIA driver
* Fixed PulseAudio device selection
* Improvements to device selection
Version 0.1.5:
Version 0.1.5 (2018.05.16)
* Makefile fixes for building
Version 0.1.4:
* Fixed compliation with clang compiler
Version 0.1.4 (2018.05.14)
* Fixed compilation with clang compiler
* This release is mainly to get it working on openbsd and freebsd.
Version 0.1.3:
Version 0.1.3 (2018.05.12)
* Audio file detection by content
* Added builtin taglib to 3rdparty to support detecting audio by content instead of just file extension
* Removed unneeded qsqlite from 3rdparty
@@ -718,7 +1157,8 @@ Version 0.1.3:
* Replaced incorrect DLL libgstdirectsoundsink.dll (from gst 1.12.4) instead of libgstdirectsound.dll (from gst 1.14.0) for windows build
* Fixed git versioning
Version 0.1.2:
Version 0.1.2 (2018.05.02)
* Fixed playback of WavPack files
* Fixed musicbrainz tagfetcher
* Use common regex (Song::kCoverRemoveDisc) for removing Disc/CD from album
@@ -728,5 +1168,6 @@ Version 0.1.2:
* Fixed problems with windows build missing some DLL's, only supplying required gstreamer-plugins now
* Removed redundant code
Version 0.1.1:
Version 0.1.1 (2018.04.07)
* Initial release

View File

@@ -1,27 +1,32 @@
:strawberry: Strawberry Music Player [![Build Status](https://github.com/strawberrymusicplayer/strawberry/workflows/C/C++%20CI/badge.svg)](https://github.com/strawberrymusicplayer/strawberry/actions)
[![PayPal](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://paypal.me/jonaskvinge)
[![Patreon](https://img.shields.io/badge/patreon-donate-green.svg)](https://patreon.com/jonaskvinge)
:strawberry: Strawberry Music Player [![Build Status](https://github.com/strawberrymusicplayer/strawberry/workflows/build/badge.svg)](https://github.com/strawberrymusicplayer/strawberry/actions)
=======================
[![Sponsor](https://img.shields.io/badge/-Sponsor-green?logo=github)](https://github.com/sponsors/jonaski)
[![Patreon](https://img.shields.io/badge/patreon-donate-green.svg)](https://patreon.com/jonaskvinge)
[![PayPal](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://paypal.me/jonaskvinge)
Strawberry is a music player and music collection organizer. It is a fork of Clementine released in 2018 aimed at music collectors and audiophiles. It's written in C++ using the Qt toolkit.
![Browse](https://www.strawberrymusicplayer.org/pictures/screenshot-002-large.png)
![Browse](https://raw.githubusercontent.com/strawberrymusicplayer/strawberry/master/data/screenshot/screenshot.png)
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/
* Latest builds: https://builds.strawberrymusicplayer.org/
* openSUSE buildservice: https://build.opensuse.org/package/show/home:jonaski:audio/strawberry
* PPA: https://launchpad.net/~jonaski/+archive/ubuntu/strawberry
* Ubuntu PPA: https://launchpad.net/~jonaski/+archive/ubuntu/strawberry
* Ubuntu Unstable PPA: https://launchpad.net/~jonaski/+archive/ubuntu/strawberry-unstable
* Translations: https://translate.zanata.org/iteration/view/strawberry/master
### :bangbang: Opening an issue:
* Read the FAQ: https://wiki.strawberrymusicplayer.org/wiki/FAQ
* Search for the issue to see if it is already solved, or if there is an open issue for it already. If there is an open issue already, you can comment on it if you have additional information that could be useful to us.
* For technical problems, questions and feature requests please use our forum on https://forum.strawberrymusicplayer.org/ that is better suited for discussion. It also better allows answers from the community instead of just the developers on GitHub.
* For technical problems, discussion, questions and feature suggestions use the forum (https://forum.strawberrymusicplayer.org/) instead. The forum is better suited for discussion.
* We do not take feature requests from users on GitHub. Any issues related to feature requests will be closed. This does not necessarily mean that we won't add new features, but we don't have time to take feature requests or answer questions about new features from users. It is still possible to suggest or discuss new features on the forum (https://forum.strawberrymusicplayer.org/).
### :moneybag: Sponsoring:
@@ -43,14 +48,14 @@ Funding developers is a way to contribute to open source projects you appreciate
* Playlist management
* Smart and dynamic playlists
* Advanced audio output and device configuration for bit-perfect playback on Linux
* Edit tags on music files
* Edit tags on audio files
* Fetch tags from MusicBrainz
* Album cover art from [Last.fm](https://www.last.fm/), [Musicbrainz](https://musicbrainz.org/), [Discogs](https://www.discogs.com/), [Musixmatch](https://www.musixmatch.com/), [Deezer](https://www.deezer.com/), [Tidal](https://www.tidal.com/), [Qobuz](https://www.qobuz.com/) and [Spotify](https://www.spotify.com/)
* Song lyrics from [AudD](https://audd.io/), [Genius](https://genius.com/), [Musixmatch](https://www.musixmatch.com/), [ChartLyrics](http://www.chartlyrics.com/), [lyrics.ovh](https://lyrics.ovh/) and [lololyrics.com](https://www.lololyrics.com/)
* Song lyrics from [Lyrics.com](https://www.lyrics.com/), [Genius](https://genius.com/), [Musixmatch](https://www.musixmatch.com/), [ChartLyrics](http://www.chartlyrics.com/), [lyrics.ovh](https://lyrics.ovh/) and [lololyrics.com](https://www.lololyrics.com/)
* Support for multiple backends
* Audio analyzer
* Audio equalizer
* Transfer music to iPod, MTP or mass-storage USB player
* Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
* Scrobbler with support for [Last.fm](https://www.last.fm/), [Libre.fm](https://libre.fm/) and [ListenBrainz](https://listenbrainz.org/)
* Subsonic, Tidal and Qobuz streaming support
@@ -63,32 +68,31 @@ 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 and Make tools](https://cmake.org/)
* [GCC](https://gcc.gnu.org/) or [clang](https://clang.llvm.org/) compiler
* [CMake](https://cmake.org/)
* C/C++ compiler ([GCC](https://gcc.gnu.org/), [Clang](https://clang.llvm.org/) or [MSVC](https://visualstudio.microsoft.com/vs/features/cplusplus/))
* [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) or [pkgconf](https://github.com/pkgconf/pkgconf)
* [Boost](https://www.boost.org/)
* [POSIX thread (pthread)](http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html)
* [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 components X11Extras and D-Bus for Linux/BSD and WinExtras for Windows](https://www.qt.io/)
* [Qt 6 or Qt 5.12 or higher with components Core, Gui, Widgets, Concurrent, Network and Sql](https://www.qt.io/)
* [SQLite 3.9 or newer with FTS5](https://www.sqlite.org)
* [Chromaprint](https://acoustid.org/chromaprint)
* [ALSA (linux)](https://www.alsa-project.org/)
* [D-Bus (linux)](https://www.freedesktop.org/wiki/Software/dbus/)
* [PulseAudio (linux optional)](https://www.freedesktop.org/wiki/Software/PulseAudio/?)
* [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](https://www.taglib.org/)
* [TagLib 1.11.1 or higher](https://www.taglib.org/) or [TagParser](https://github.com/Martchus/tagparser)
* [ICU](https://unicode-org.github.io/icu/)
Optional dependencies:
* Song fingerprinting and MusicBrainz tagging: [Chromaprint](https://acoustid.org/chromaprint)
* Moodbar: [fftw3](http://www.fftw.org/)
* PulseAudio integration: [PulseAudio](https://www.freedesktop.org/wiki/Software/PulseAudio/?)
* Audio CD: [libcdio](https://www.gnu.org/software/libcdio/)
* MTP devices: [libmtp](http://libmtp.sourceforge.net/)
* iPod Classic devices: [libgpod](http://www.gtkpod.org/libgpod/)
* Moodbar: [fftw3](http://www.fftw.org/)
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
@@ -99,16 +103,18 @@ You should also install the gstreamer plugins base and good, and optionally bad,
### Compile and install:
cd strawberry
mkdir build && cd build
cmake ..
make -j$(nproc)
sudo make install
To compile with Qt 6 use:
mkdir build
cd build
cmake .. -DBUILD_WITH_QT6=ON
make -j $(nproc)
sudo make install
Strawberry is backwards compatible with Qt 5, to compile with Qt 5 use:
cmake .. -DBUILD_WITH_QT5=ON
To compile on Windows with Visual Studio 2019 or 2022, see https://github.com/strawberrymusicplayer/strawberry-msvc
### :penguin: Packaging status
[![Packaging status](https://repology.org/badge/vertical-allrepos/strawberry.svg)](https://repology.org/metapackage/strawberry/versions)
[![Packaging status](https://repology.org/badge/vertical-allrepos/strawberry.svg?exclude_unsupported=1)](https://repology.org/metapackage/strawberry/versions)

View File

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

View File

@@ -1,11 +1,10 @@
#find_program(MACDEPLOYQT_EXECUTABLE NAMES macdeployqt PATHS /usr/local/opt/qt6/bin /usr/local/opt/qt5/bin /usr/local/bin REQUIRED)
#if(MACDEPLOYQT_EXECUTABLE)
# message(STATUS "Found macdeployqt: ${MACDEPLOYQT_EXECUTABLE}")
#else()
# message(WARNING "Missing macdeployqt executable.")
#endif()
set(MACDEPLOYQT_EXECUTABLE "${CMAKE_BINARY_DIR}/3rdparty/macdeployqt/macdeployqt")
if(MACDEPLOYQT_EXECUTABLE)
message(STATUS "Found macdeployqt: ${MACDEPLOYQT_EXECUTABLE}")
else()
message(WARNING "Missing macdeployqt executable.")
endif()
find_program(CREATEDMG_EXECUTABLE NAMES create-dmg REQUIRED)
if(CREATEDMG_EXECUTABLE)
@@ -14,24 +13,27 @@ else()
message(WARNING "Missing create-dmg executable.")
endif()
execute_process(COMMAND ${CMAKE_SOURCE_DIR}/dist/macos/macversion.sh OUTPUT_VARIABLE MACOS_VERSION_PACKAGE OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT MACOS_VERSION_PACKAGE)
message(WARNING "Could not set macOS version.")
endif()
if(MACDEPLOYQT_EXECUTABLE AND CREATEDMG_EXECUTABLE AND MACOS_VERSION_PACKAGE)
add_custom_target(dmg
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/
COMMAND cp -r /usr/local/opt/sparkle/Sparkle.framework ${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/
COMMAND ${MACDEPLOYQT_EXECUTABLE} strawberry.app -verbose=3 -executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/strawberry-tagreader
COMMAND ${CREATEDMG_EXECUTABLE} --volname strawberry --background "${CMAKE_SOURCE_DIR}/dist/macos/dmg_background.png" --app-drop-link 450 218 --icon strawberry.app 150 218 --window-size 600 450 strawberry-${STRAWBERRY_VERSION_PACKAGE}-${MACOS_VERSION_PACKAGE}-${CMAKE_HOST_SYSTEM_PROCESSOR}.dmg strawberry.app
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
if(MACDEPLOYQT_EXECUTABLE)
add_custom_target(copy_gstreamer_plugins
#COMMAND ${CMAKE_SOURCE_DIR}/dist/macos/macgstcopy.sh strawberry.app
)
add_custom_target(dmg2
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/
COMMAND cp -r /usr/local/opt/sparkle/Sparkle.framework ${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/
add_custom_target(deploy
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
COMMAND ${CREATEDMG_EXECUTABLE} --skip-jenkins --volname strawberry --background "${CMAKE_SOURCE_DIR}/dist/macos/dmg_background.png" --app-drop-link 450 218 --icon strawberry.app 150 218 --window-size 600 450 strawberry-${STRAWBERRY_VERSION_PACKAGE}-${MACOS_VERSION_PACKAGE}-${CMAKE_HOST_SYSTEM_PROCESSOR}.dmg strawberry.app
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS strawberry strawberry-tagreader copy_gstreamer_plugins macdeployqt
)
add_custom_target(deploycheck
COMMAND ${CMAKE_BINARY_DIR}/ext/macdeploycheck/macdeploycheck strawberry.app
DEPENDS macdeploycheck
)
if(CREATEDMG_EXECUTABLE)
add_custom_target(dmg
COMMAND ${CREATEDMG_EXECUTABLE} --volname strawberry --background "${CMAKE_SOURCE_DIR}/dist/macos/dmg_background.png" --app-drop-link 450 218 --icon strawberry.app 150 218 --window-size 600 450 strawberry-${STRAWBERRY_VERSION_PACKAGE}-${CMAKE_HOST_SYSTEM_PROCESSOR}.dmg strawberry.app
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS deploy deploycheck
)
endif()
endif()

View File

@@ -15,11 +15,7 @@ macro(optional_source TOGGLE)
list(APPEND OTHER_SOURCES ${OPTIONAL_SOURCE_HEADERS})
set(_uic_sources)
if(BUILD_WITH_QT6)
qt6_wrap_ui(_uic_sources ${OPTIONAL_SOURCE_UI})
else()
qt5_wrap_ui(_uic_sources ${OPTIONAL_SOURCE_UI})
endif()
qt_wrap_ui(_uic_sources ${OPTIONAL_SOURCE_UI})
list(APPEND OTHER_SOURCES ${_uic_sources})
list(APPEND OTHER_UIC_SOURCES ${_uic_sources})
endif(${TOGGLE})

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

@@ -24,7 +24,7 @@ macro(summary_show)
list(SORT summary_willbuild)
list(SORT summary_willnotbuild)
message("")
message("Building strawberry version: ${STRAWBERRY_VERSION_DISPLAY}")
message("Building strawberry version: ${STRAWBERRY_VERSION_DISPLAY}, Qt version ${Qt${QT_VERSION_MAJOR}Core_VERSION}")
summary_show_part(summary_willbuild "The following components will be built:")
summary_show_part(summary_willnotbuild "The following components WILL NOT be built:")
message("")

View File

@@ -75,10 +75,6 @@ macro(add_po outfiles po_prefix)
file(APPEND ${_qrc} "<file>${po_prefix}${_lang}.qm</file>")
endforeach(_lang)
file(APPEND ${_qrc} "</qresource></RCC>")
if(BUILD_WITH_QT6)
qt6_add_resources(${outfiles} ${_qrc})
else()
qt5_add_resources(${outfiles} ${_qrc})
endif()
qt_add_resources(${outfiles} ${_qrc})
endif()
endmacro(add_po)

View File

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

View File

@@ -1,19 +1,14 @@
<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>
<file>schema/schema-13.sql</file>
<file>schema/schema-14.sql</file>
<file>schema/schema-15.sql</file>
<file>schema/schema-16.sql</file>
<file>schema/schema-17.sql</file>
<file>schema/device-schema.sql</file>
<file>style/strawberry.css</file>
<file>style/smartplaylistsearchterm.css</file>
@@ -44,7 +39,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>
@@ -92,6 +93,10 @@
<file>icons/128x128/tidal.png</file>
<file>icons/128x128/qobuz.png</file>
<file>icons/128x128/multimedia-player-ipod-standard-black.png</file>
<file>icons/128x128/radio.png</file>
<file>icons/128x128/somafm.png</file>
<file>icons/128x128/radioparadise.png</file>
<file>icons/128x128/musicbrainz.png</file>
<file>icons/64x64/albums.png</file>
<file>icons/64x64/alsa.png</file>
<file>icons/64x64/application-exit.png</file>
@@ -116,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>
@@ -185,6 +191,10 @@
<file>icons/64x64/tidal.png</file>
<file>icons/64x64/qobuz.png</file>
<file>icons/64x64/multimedia-player-ipod-standard-black.png</file>
<file>icons/64x64/radio.png</file>
<file>icons/64x64/somafm.png</file>
<file>icons/64x64/radioparadise.png</file>
<file>icons/64x64/musicbrainz.png</file>
<file>icons/48x48/albums.png</file>
<file>icons/48x48/alsa.png</file>
<file>icons/48x48/application-exit.png</file>
@@ -210,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>
@@ -282,6 +293,10 @@
<file>icons/48x48/tidal.png</file>
<file>icons/48x48/qobuz.png</file>
<file>icons/48x48/multimedia-player-ipod-standard-black.png</file>
<file>icons/48x48/radio.png</file>
<file>icons/48x48/somafm.png</file>
<file>icons/48x48/radioparadise.png</file>
<file>icons/48x48/musicbrainz.png</file>
<file>icons/32x32/albums.png</file>
<file>icons/32x32/alsa.png</file>
<file>icons/32x32/application-exit.png</file>
@@ -307,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>
@@ -379,6 +395,10 @@
<file>icons/32x32/tidal.png</file>
<file>icons/32x32/qobuz.png</file>
<file>icons/32x32/multimedia-player-ipod-standard-black.png</file>
<file>icons/32x32/radio.png</file>
<file>icons/32x32/somafm.png</file>
<file>icons/32x32/radioparadise.png</file>
<file>icons/32x32/musicbrainz.png</file>
<file>icons/22x22/albums.png</file>
<file>icons/22x22/alsa.png</file>
<file>icons/22x22/application-exit.png</file>
@@ -404,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>
@@ -476,5 +497,9 @@
<file>icons/22x22/tidal.png</file>
<file>icons/22x22/qobuz.png</file>
<file>icons/22x22/multimedia-player-ipod-standard-black.png</file>
<file>icons/22x22/radio.png</file>
<file>icons/22x22/somafm.png</file>
<file>icons/22x22/radioparadise.png</file>
<file>icons/22x22/musicbrainz.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
data/icons/22x22/radio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
data/icons/22x22/somafm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 B

BIN
data/icons/32x32/radio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
data/icons/32x32/somafm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
data/icons/48x48/radio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
data/icons/48x48/somafm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
data/icons/64x64/radio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
data/icons/64x64/somafm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -47,24 +47,43 @@ CREATE TABLE device_%deviceid_songs (
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
lastseen 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_embedded INTEGER DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
art_unset INTEGER DEFAULT 0,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT,
rating INTEGER DEFAULT -1
rating INTEGER DEFAULT -1,
acoustid_id TEXT,
acoustid_fingerprint TEXT,
musicbrainz_album_artist_id TEXT,
musicbrainz_artist_id TEXT,
musicbrainz_original_artist_id TEXT,
musicbrainz_album_id TEXT,
musicbrainz_original_album_id TEXT,
musicbrainz_recording_id TEXT,
musicbrainz_track_id TEXT,
musicbrainz_disc_id TEXT,
musicbrainz_release_group_id TEXT,
musicbrainz_work_id TEXT
);
@@ -77,4 +96,4 @@ CREATE VIRTUAL TABLE device_%deviceid_fts USING fts5(
tokenize = "unicode61 remove_diacritics 1"
);
UPDATE devices SET schema_version=2 WHERE ROWID=%deviceid;
UPDATE devices SET schema_version=4 WHERE ROWID=%deviceid;

View File

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

View File

@@ -0,0 +1,5 @@
ALTER TABLE %allsongstables ADD COLUMN fingerprint TEXT;
ALTER TABLE %allsongstables ADD COLUMN lastseen INTEGER NOT NULL DEFAULT -1;
UPDATE schema_version SET version=14;

View File

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

217
data/schema/schema-16.sql Normal file
View File

@@ -0,0 +1,217 @@
ALTER TABLE songs ADD COLUMN acoustid_id TEXT;
ALTER TABLE songs ADD COLUMN acoustid_fingerprint TEXT;
ALTER TABLE songs ADD COLUMN musicbrainz_album_artist_id TEXT;
ALTER TABLE songs ADD COLUMN musicbrainz_artist_id TEXT;
ALTER TABLE songs ADD COLUMN musicbrainz_original_artist_id TEXT;
ALTER TABLE songs ADD COLUMN musicbrainz_album_id TEXT;
ALTER TABLE songs ADD COLUMN musicbrainz_original_album_id TEXT;
ALTER TABLE songs ADD COLUMN musicbrainz_recording_id TEXT;
ALTER TABLE songs ADD COLUMN musicbrainz_track_id TEXT;
ALTER TABLE songs ADD COLUMN musicbrainz_disc_id TEXT;
ALTER TABLE songs ADD COLUMN musicbrainz_release_group_id TEXT;
ALTER TABLE songs ADD COLUMN musicbrainz_work_id TEXT;
ALTER TABLE subsonic_songs ADD COLUMN acoustid_id TEXT;
ALTER TABLE subsonic_songs ADD COLUMN acoustid_fingerprint TEXT;
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_album_artist_id TEXT;
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_artist_id TEXT;
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_original_artist_id TEXT;
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_album_id TEXT;
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_original_album_id TEXT;
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_recording_id TEXT;
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_track_id TEXT;
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_disc_id TEXT;
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_release_group_id TEXT;
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_work_id TEXT;
ALTER TABLE tidal_artists_songs ADD COLUMN acoustid_id TEXT;
ALTER TABLE tidal_artists_songs ADD COLUMN acoustid_fingerprint TEXT;
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_album_artist_id TEXT;
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_artist_id TEXT;
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_original_artist_id TEXT;
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_album_id TEXT;
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_original_album_id TEXT;
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_recording_id TEXT;
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_track_id TEXT;
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_disc_id TEXT;
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_release_group_id TEXT;
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_work_id TEXT;
ALTER TABLE tidal_albums_songs ADD COLUMN acoustid_id TEXT;
ALTER TABLE tidal_albums_songs ADD COLUMN acoustid_fingerprint TEXT;
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_album_artist_id TEXT;
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_artist_id TEXT;
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_original_artist_id TEXT;
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_album_id TEXT;
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_original_album_id TEXT;
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_recording_id TEXT;
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_track_id TEXT;
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_disc_id TEXT;
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_release_group_id TEXT;
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_work_id TEXT;
ALTER TABLE tidal_songs ADD COLUMN acoustid_id TEXT;
ALTER TABLE tidal_songs ADD COLUMN acoustid_fingerprint TEXT;
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_album_artist_id TEXT;
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_artist_id TEXT;
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_original_artist_id TEXT;
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_album_id TEXT;
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_original_album_id TEXT;
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_recording_id TEXT;
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_track_id TEXT;
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_disc_id TEXT;
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_release_group_id TEXT;
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_work_id TEXT;
ALTER TABLE qobuz_artists_songs ADD COLUMN acoustid_id TEXT;
ALTER TABLE qobuz_artists_songs ADD COLUMN acoustid_fingerprint TEXT;
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_album_artist_id TEXT;
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_artist_id TEXT;
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_original_artist_id TEXT;
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_album_id TEXT;
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_original_album_id TEXT;
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_recording_id TEXT;
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_track_id TEXT;
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_disc_id TEXT;
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_release_group_id TEXT;
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_work_id TEXT;
ALTER TABLE qobuz_albums_songs ADD COLUMN acoustid_id TEXT;
ALTER TABLE qobuz_albums_songs ADD COLUMN acoustid_fingerprint TEXT;
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_album_artist_id TEXT;
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_artist_id TEXT;
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_original_artist_id TEXT;
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_album_id TEXT;
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_original_album_id TEXT;
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_recording_id TEXT;
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_track_id TEXT;
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_disc_id TEXT;
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_release_group_id TEXT;
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_work_id TEXT;
ALTER TABLE qobuz_songs ADD COLUMN acoustid_id TEXT;
ALTER TABLE qobuz_songs ADD COLUMN acoustid_fingerprint TEXT;
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_album_artist_id TEXT;
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_artist_id TEXT;
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_original_artist_id TEXT;
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_album_id TEXT;
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_original_album_id TEXT;
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_recording_id TEXT;
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_track_id TEXT;
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_disc_id TEXT;
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_release_group_id TEXT;
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_work_id TEXT;
ALTER TABLE playlist_items ADD COLUMN acoustid_id TEXT;
ALTER TABLE playlist_items ADD COLUMN acoustid_fingerprint TEXT;
ALTER TABLE playlist_items ADD COLUMN musicbrainz_album_artist_id TEXT;
ALTER TABLE playlist_items ADD COLUMN musicbrainz_artist_id TEXT;
ALTER TABLE playlist_items ADD COLUMN musicbrainz_original_artist_id TEXT;
ALTER TABLE playlist_items ADD COLUMN musicbrainz_album_id TEXT;
ALTER TABLE playlist_items ADD COLUMN musicbrainz_original_album_id TEXT;
ALTER TABLE playlist_items ADD COLUMN musicbrainz_recording_id TEXT;
ALTER TABLE playlist_items ADD COLUMN musicbrainz_track_id TEXT;
ALTER TABLE playlist_items ADD COLUMN musicbrainz_disc_id TEXT;
ALTER TABLE playlist_items ADD COLUMN musicbrainz_release_group_id TEXT;
ALTER TABLE playlist_items ADD COLUMN musicbrainz_work_id TEXT;
UPDATE schema_version SET version=16;

45
data/schema/schema-17.sql Normal file
View File

@@ -0,0 +1,45 @@
ALTER TABLE songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
ALTER TABLE songs ADD COLUMN art_unset INTEGER DEFAULT 0;
ALTER TABLE subsonic_songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
ALTER TABLE subsonic_songs ADD COLUMN art_unset INTEGER DEFAULT 0;
ALTER TABLE tidal_artists_songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
ALTER TABLE tidal_artists_songs ADD COLUMN art_unset INTEGER DEFAULT 0;
ALTER TABLE tidal_albums_songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
ALTER TABLE tidal_albums_songs ADD COLUMN art_unset INTEGER DEFAULT 0;
ALTER TABLE tidal_songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
ALTER TABLE tidal_songs ADD COLUMN art_unset INTEGER DEFAULT 0;
ALTER TABLE qobuz_artists_songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
ALTER TABLE qobuz_artists_songs ADD COLUMN art_unset INTEGER DEFAULT 0;
ALTER TABLE qobuz_albums_songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
ALTER TABLE qobuz_albums_songs ADD COLUMN art_unset INTEGER DEFAULT 0;
ALTER TABLE qobuz_songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
ALTER TABLE qobuz_songs ADD COLUMN art_unset INTEGER DEFAULT 0;
ALTER TABLE playlist_items ADD COLUMN art_embedded INTEGER DEFAULT 0;
ALTER TABLE playlist_items ADD COLUMN art_unset INTEGER DEFAULT 0;
UPDATE songs SET art_embedded = 1 WHERE art_automatic = 'file:(embedded)';
UPDATE songs SET art_automatic = '' WHERE art_automatic = 'file:(embedded)';
UPDATE songs SET art_unset = 1 WHERE art_manual = 'file:(unset)';
UPDATE songs SET art_manual = '' WHERE art_manual = 'file:(unset)';
UPDATE schema_version SET version=17;

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

@@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS schema_version (
DELETE FROM schema_version;
INSERT INTO schema_version (version) VALUES (13);
INSERT INTO schema_version (version) VALUES (17);
CREATE TABLE IF NOT EXISTS directories (
path TEXT NOT NULL,
@@ -55,24 +55,43 @@ CREATE TABLE IF NOT EXISTS songs (
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
lastseen 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_embedded INTEGER DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
art_unset INTEGER DEFAULT 0,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT,
rating INTEGER DEFAULT -1
rating INTEGER DEFAULT -1,
acoustid_id TEXT,
acoustid_fingerprint TEXT,
musicbrainz_album_artist_id TEXT,
musicbrainz_artist_id TEXT,
musicbrainz_original_artist_id TEXT,
musicbrainz_album_id TEXT,
musicbrainz_original_album_id TEXT,
musicbrainz_recording_id TEXT,
musicbrainz_track_id TEXT,
musicbrainz_disc_id TEXT,
musicbrainz_release_group_id TEXT,
musicbrainz_work_id TEXT
);
@@ -114,24 +133,43 @@ CREATE TABLE IF NOT EXISTS subsonic_songs (
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
lastseen 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_embedded INTEGER DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
art_unset INTEGER DEFAULT 0,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT,
rating INTEGER DEFAULT -1
rating INTEGER DEFAULT -1,
acoustid_id TEXT,
acoustid_fingerprint TEXT,
musicbrainz_album_artist_id TEXT,
musicbrainz_artist_id TEXT,
musicbrainz_original_artist_id TEXT,
musicbrainz_album_id TEXT,
musicbrainz_original_album_id TEXT,
musicbrainz_recording_id TEXT,
musicbrainz_track_id TEXT,
musicbrainz_disc_id TEXT,
musicbrainz_release_group_id TEXT,
musicbrainz_work_id TEXT
);
@@ -173,24 +211,43 @@ CREATE TABLE IF NOT EXISTS tidal_artists_songs (
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
lastseen 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_embedded INTEGER DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
art_unset INTEGER DEFAULT 0,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT,
rating INTEGER DEFAULT -1
rating INTEGER DEFAULT -1,
acoustid_id TEXT,
acoustid_fingerprint TEXT,
musicbrainz_album_artist_id TEXT,
musicbrainz_artist_id TEXT,
musicbrainz_original_artist_id TEXT,
musicbrainz_album_id TEXT,
musicbrainz_original_album_id TEXT,
musicbrainz_recording_id TEXT,
musicbrainz_track_id TEXT,
musicbrainz_disc_id TEXT,
musicbrainz_release_group_id TEXT,
musicbrainz_work_id TEXT
);
@@ -232,24 +289,43 @@ CREATE TABLE IF NOT EXISTS tidal_albums_songs (
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
lastseen 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_embedded INTEGER DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
art_unset INTEGER DEFAULT 0,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT,
rating INTEGER DEFAULT -1
rating INTEGER DEFAULT -1,
acoustid_id TEXT,
acoustid_fingerprint TEXT,
musicbrainz_album_artist_id TEXT,
musicbrainz_artist_id TEXT,
musicbrainz_original_artist_id TEXT,
musicbrainz_album_id TEXT,
musicbrainz_original_album_id TEXT,
musicbrainz_recording_id TEXT,
musicbrainz_track_id TEXT,
musicbrainz_disc_id TEXT,
musicbrainz_release_group_id TEXT,
musicbrainz_work_id TEXT
);
@@ -291,24 +367,43 @@ CREATE TABLE IF NOT EXISTS tidal_songs (
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
lastseen 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_embedded INTEGER DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
art_unset INTEGER DEFAULT 0,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT,
rating INTEGER DEFAULT -1
rating INTEGER DEFAULT -1,
acoustid_id TEXT,
acoustid_fingerprint TEXT,
musicbrainz_album_artist_id TEXT,
musicbrainz_artist_id TEXT,
musicbrainz_original_artist_id TEXT,
musicbrainz_album_id TEXT,
musicbrainz_original_album_id TEXT,
musicbrainz_recording_id TEXT,
musicbrainz_track_id TEXT,
musicbrainz_disc_id TEXT,
musicbrainz_release_group_id TEXT,
musicbrainz_work_id TEXT
);
@@ -350,24 +445,43 @@ CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
lastseen 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_embedded INTEGER DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
art_unset INTEGER DEFAULT 0,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT,
rating INTEGER DEFAULT -1
rating INTEGER DEFAULT -1,
acoustid_id TEXT,
acoustid_fingerprint TEXT,
musicbrainz_album_artist_id TEXT,
musicbrainz_artist_id TEXT,
musicbrainz_original_artist_id TEXT,
musicbrainz_album_id TEXT,
musicbrainz_original_album_id TEXT,
musicbrainz_recording_id TEXT,
musicbrainz_track_id TEXT,
musicbrainz_disc_id TEXT,
musicbrainz_release_group_id TEXT,
musicbrainz_work_id TEXT
);
@@ -409,24 +523,43 @@ CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
lastseen 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_embedded INTEGER DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
art_unset INTEGER DEFAULT 0,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT,
rating INTEGER DEFAULT -1
rating INTEGER DEFAULT -1,
acoustid_id TEXT,
acoustid_fingerprint TEXT,
musicbrainz_album_artist_id TEXT,
musicbrainz_artist_id TEXT,
musicbrainz_original_artist_id TEXT,
musicbrainz_album_id TEXT,
musicbrainz_original_album_id TEXT,
musicbrainz_recording_id TEXT,
musicbrainz_track_id TEXT,
musicbrainz_disc_id TEXT,
musicbrainz_release_group_id TEXT,
musicbrainz_work_id TEXT
);
@@ -468,24 +601,43 @@ CREATE TABLE IF NOT EXISTS qobuz_songs (
ctime INTEGER NOT NULL DEFAULT -1,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT -1,
lastseen 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_embedded INTEGER DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
art_unset INTEGER DEFAULT 0,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT,
rating INTEGER DEFAULT -1
rating INTEGER DEFAULT -1,
acoustid_id TEXT,
acoustid_fingerprint TEXT,
musicbrainz_album_artist_id TEXT,
musicbrainz_artist_id TEXT,
musicbrainz_original_artist_id TEXT,
musicbrainz_album_id TEXT,
musicbrainz_original_album_id TEXT,
musicbrainz_recording_id TEXT,
musicbrainz_track_id TEXT,
musicbrainz_disc_id TEXT,
musicbrainz_release_group_id TEXT,
musicbrainz_work_id TEXT
);
@@ -540,31 +692,50 @@ CREATE TABLE IF NOT EXISTS playlist_items (
source INTEGER,
directory_id INTEGER,
url TEXT,
url TEXT NOT NULL,
filetype INTEGER,
filesize INTEGER,
mtime INTEGER,
ctime INTEGER,
unavailable INTEGER DEFAULT 0,
fingerprint TEXT,
playcount INTEGER DEFAULT 0,
skipcount INTEGER DEFAULT 0,
lastplayed INTEGER DEFAULT 0,
lastplayed INTEGER DEFAULT -1,
lastseen INTEGER DEFAULT -1,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER DEFAULT 0,
compilation_off INTEGER DEFAULT 0,
compilation_effective INTEGER DEFAULT 0,
art_embedded INTEGER DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
art_unset INTEGER DEFAULT 0,
effective_albumartist TEXT,
effective_originalyear INTEGER,
cue_path TEXT,
rating INTEGER DEFAULT -1
rating INTEGER DEFAULT -1,
acoustid_id TEXT,
acoustid_fingerprint TEXT,
musicbrainz_album_artist_id TEXT,
musicbrainz_artist_id TEXT,
musicbrainz_original_artist_id TEXT,
musicbrainz_album_id TEXT,
musicbrainz_original_album_id TEXT,
musicbrainz_recording_id TEXT,
musicbrainz_track_id TEXT,
musicbrainz_disc_id TEXT,
musicbrainz_release_group_id TEXT,
musicbrainz_work_id TEXT
);
@@ -578,6 +749,13 @@ CREATE TABLE IF NOT EXISTS devices (
transcode_format NOT NULL DEFAULT 5
);
CREATE TABLE IF NOT EXISTS radio_channels (
source INTEGER NOT NULL DEFAULT 0,
name TEXT,
url TEXT NOT NULL,
thumbnail_url TEXT
);
CREATE INDEX IF NOT EXISTS idx_url ON songs (url);
CREATE INDEX IF NOT EXISTS idx_comp_artist ON songs (compilation_effective, artist);

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 KiB

View File

@@ -19,47 +19,6 @@
background-clip: content;
}
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"] {
padding-right: 16px;
}
macos {
font-size: 11pt;
}
macos QMenu {
font-size: 13pt;
}
#context-layout-container {
background-color: %palette-base;
}
@@ -71,3 +30,37 @@ macos QMenu {
#context-layout-scrollarea {
background-color: %palette-base;
}
#context-scrollarea {
background-color: %palette-base;
}
QToolButton {
border: 2px solid transparent;
border-radius: 3px;
padding: 1px;
}
QToolButton:hover {
border: 2px solid %palette-highlight;
background-color: %palette-highlight-lighter;
}
QToolButton:pressed {
border: 2px solid %palette-highlight-darker;
background-color: %palette-highlight-lighter;
}
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;
}

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

@@ -3,9 +3,11 @@ Section: sound
Priority: optional
Maintainer: Jonas Kvinge <jonas@jkvinge.net>
Build-Depends: debhelper (>= 11),
git,
make,
cmake,
gcc,
g++,
protobuf-compiler,
libglib2.0-dev,
libdbus-1-dev,
@@ -16,10 +18,8 @@ Build-Depends: debhelper (>= 11),
libasound2-dev,
libpulse-dev,
libtag1-dev,
qtbase5-dev,
qtbase5-dev-tools,
qttools5-dev,
libqt5x11extras5-dev,
libicu-dev,
@DEBIAN_BUILD_DEPENDS_QT_PACKAGES@,
libgstreamer1.0-dev,
libgstreamer-plugins-base1.0-dev,
libcdio-dev,
@@ -27,38 +27,38 @@ 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
Strawberry is a music player aimed at music collectors, audio enthusiasts and audiophiles.
Description: music player and music collection organizer
Strawberry is a music player aimed at music collectors and audiophiles.
.
Features:
- Play and organize music
- Supports WAV, FLAC, WavPack, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF
- Audio CD playback
- Native desktop notifications
- 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 music files
- Fetch tags from MusicBrainz
- 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
- Song lyrics from Lyrics.com, Genius, Musixmatch, ChartLyrics, lyrics.ovh and lololyrics.com
- Audio analyzer
- Audio equalizer
- Transfer music to iPod, iPhone, MTP or mass-storage USB player
- Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
- Scrobbler with support for Last.fm, Libre.fm and ListenBrainz
- Streaming support for Subsonic
- Streaming support for Subsonic-compatible servers
- Unofficial streaming support for Tidal and Qobuz
.
It is a fork of Clementine. The name is inspired by the band Strawbs.

205
debian/copyright vendored
View File

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

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