62 Commits

Author SHA1 Message Date
Bart De Vries
e6fee85f4e Solve issues with playback signals firing while changing tracks 2023-02-20 11:34:49 +01:00
Bart De Vries
780e63c2f2 [KMediaSession] Allow app and desktop entry name to be set in constructor 2023-02-16 13:32:52 +01:00
Bart De Vries
acd1a55aae Fix minor issue with network connect check in AudioManager
AudioManager was reporting no connectivity in case the networkstatus was
reported as being "Unknown".  We might as well attempt to stream in that
case.  If there is no connectivity, it will fail anyway with another
useful error message.
2023-01-19 20:43:27 +01:00
Bart De Vries
eb07e67f70 [KMediaSession] Implement dynamic audio backend framework
KMediaSession is an audio player library that has an API which is close
to QMediaPlayer and which allows to use --- and dynamically switch
between --- different audio backends. At this moment there is
implementation for libVLC, gstreamer and QtMultimedia. Only QtMultimedia
is a hard dependency in order to at least have one functional backend on
all platforms; all other dependencies are optional.

KMediaSession has out-of-the-box, built-in MPRIS2 support, sleep inhibit,
and basic metadata support.

BUG: 462358

Closes #35
2023-01-16 15:36:54 +01:00
Bart De Vries
562c76c799 Implement streaming support
This implements support for streaming episodes rather than downloading them
first.
This introduces a new setting: prioritizeStreaming. If it's set to false
(default) then a streaming play button is only added to the EntryPage.  If
it is set to true, then the streaming play button will also appear on the
Entry delegates instead of the download button.
There is a separate setting to decide if streaming is also allowed on
metered connections.

FEATURE: 438864
2022-10-19 14:49:56 +02:00
Bart De Vries
5f94b4a357 Add sleep timer
FEATURE: 443400
2022-06-30 08:21:09 +00:00
Bart De Vries
e62d17f9b0 Adjust time left on episodes according to current playback rate
This new feature is implemented behind a switch in the settings (default
is off).

FEATURE: 452135
2022-06-01 21:08:27 +02:00
Bart De Vries
f861f4e802 Add podcast subscription and episode play state synchronization
This implements the gpodder API from scratch.  It turned out that
libmygpo-qt has several critical bugs, and there's no response to pull
requests upstream.  So using that library was not an option.

The implementation into kasts consists of the following:
- Can sync with gpodder.net or with a nextcloud server that has the
  nextcloud-gpodder app installed.  (This app is mostly API compatible
  with gpodder.)
- Passwords are stored using qtkeychain.  If the keychain is
  unavailable it will fallback to file.
- It syncs podcast subscriptions and episode play positions, including
  marking episodes as played. Episodes that have a non-zero play
  position will be added to the queue automatically.
- It will check for a metered connection before syncing.  This is
  coupled to the allowMeteredFeedUpdates setting.
- Full synchronization can be performed either manually (from the
  settings page) or through automatic triggers: on startup and/or on
  feed refresh.
- There is an additional possibility to trigger quick upload-only syncs
  to make sure that the local changes are immediately uploaded to the
  server (if the connection allows).  This will trigger when
  subscriptions are added or removed, when the pause/play button is
  toggled or an episode is marked as played.
- This implements a few safeguards to avoid having multiple feed URLS
  pointing to the same underlying feed (e.g. http vs https).  This
  solves part of #17

Solves #13
2021-10-29 18:47:55 +02:00
Bart De Vries
117f314d0d Move models to dedicated directory 2021-09-18 19:07:15 +02:00
Yuri Chornoivan
9384f3c073 Fix minor typo 2021-07-27 12:53:21 +03:00
Bart De Vries
a15e2dbe5d Make storage path configurable
This adds a new setting to the Settings page.
Existing enclosures and images will be moved to the new location
(first copied, then deleted in the original location).  If any of
the copy actions fail, the operation is aborted and the original
path is restored.
The StorageMoveJob is set up in such a way that it's easy to add other
files or subfolders in the future.

Solves #15
2021-07-24 20:43:11 +02:00
Bart De Vries
b9b82d783f Also add title argument to Error elsewhere 2021-07-14 22:32:14 +02:00
Bart De Vries
8cd1237540 Mark another TODO as solved: make a setting for removing played episodes from queue 2021-07-06 22:36:51 +02:00
Bart De Vries
73b2cf565c Fix recursive loop when last track finishes playing 2021-07-06 19:21:57 +02:00
Bart De Vries
9731795e62 Solve deadlock in startup between ErrorLogModel and AudioManager 2021-07-06 17:03:25 +02:00
Bart De Vries
d2cee8a066 Add error overlay for Invalid Media
This implements a TODO mentioned in the sources.
2021-07-04 16:52:05 +02:00
Bart De Vries
a331366d41 Replace Audio prepare hack by nicer, asynchronous solution
The main bits of this implementation are:
- Start a new track in paused state.  We don't care about the actual
  media state or player state that QMediaPlayer is reporting.  We will
  deal with that when the audio actually starts playing.
- If a player position needs to be restored, we set d->m_pendingSeek to
  the position that needs to be seeked.  We don't actually seek because
  we have no idea what state the player is in yet.
- On the positionChanged signal of QMP, and if the media is buffered, we
  check if there is pendingSeek value set which is set to a different
  value than the current player position.  If so, we call
  d->m_player.setPosition().  If we have arrived at the correct
  position, then we reset d->m_pendingSeek to -1.
- In the position(), duration() and seek() methods, we return sensible
  values, even QMP is not.  So, we report the duration from the
  enclosure, the position from d->m_pendingSeek, and let seek() change
  the value of d->m_PendingSeek (if it's not -1) to the new seek
  position.
- When there's a pending seek, we set the notifyInterval to shorter
  interval to reduce the startup audio glitch as much as possible.  We
  then reset it to the default of 1000 msec.

This was tested on linux and android.
2021-06-20 19:14:07 +02:00
Bart De Vries
8437a44a7b Remove obsolete timeString method 2021-06-05 11:59:57 +02:00
Tobias Fella
3f1f3045ec Port away from KDeclarative 2021-06-03 16:23:06 +02:00
Bart De Vries
9d78b5b488 Run clang-format 2021-05-28 23:16:35 +02:00
Bart De Vries
3983e09634 Use qCDebug in AudioManager 2021-05-28 22:55:18 +02:00
Bart De Vries
b776dd22cb Contextualize singleShots 2021-05-28 16:54:00 +02:00
Bart De Vries
858601aec3 Change from old style connects to function pointers 2021-05-28 16:49:55 +02:00
Bart De Vries
99c1424327 Add setting to continue playback after end of current track 2021-05-23 21:35:38 +02:00
Swapnil Tripathi
21e9d0b9a7 Fix segfault when removing feeds with currently playing entries 2021-05-22 09:05:33 +00:00
Bart De Vries
34c5e5309c Implement timeString method to create HH:mm:ss strings from qint64
This method is now used in all places where a HH:mm:ss string is
required.
2021-05-02 09:42:49 +02:00
Bart De Vries
1b1654d1f4 Apply clang-format 2021-05-01 21:35:37 +02:00
Bart De Vries
d1618943f5 Update based on review by Tobias Fella 2021-05-01 21:09:07 +02:00
Bart De Vries
6edbd91f18 Set setPreventSleep in play() and pause()
Making it toggle based on the playerState did not work properly because
the stream is toggling between pause and play several times in the
prepareAudioStream method.
2021-04-30 21:45:11 +02:00
Bart De Vries
cbf0d9c622 Comment out some qDebug() statements 2021-04-30 19:13:43 +02:00
Bart De Vries
ead73ac2fe Safeguard against QMediaPlayer::InvalidMedia
In case of the InvalidMedia status, skip to next track and delete the
invalid enclosure.
2021-04-30 11:57:39 +02:00
Bart De Vries
36ad248e55 Do some additional checks on entry before loading in AudioManager 2021-04-29 11:28:59 +02:00
Bart De Vries
51db7ea1cf Only use custom gst-pipeline on linux
GStreamer is not used as QMediaPlayer backend on other platforms, so
audio will not start with a custom gst-pipeline on Android and Windows.
Still needs a solution to get rid of the horrible pitch change on
Android and Windows, though.
2021-04-23 10:55:59 +02:00
Bart De Vries
e2d59a69b0 Move audio positioning hack into a separate method
This allows the hack to be re-used in the play() method.  Apparently on
some systems the stream becomes unresponsive again after pausing.  So
probably it's required to ensure that the stream is fully seekable and
buffered before restarting playback.
2021-04-22 16:48:13 +02:00
Bart De Vries
6c7a271970 Use custom gst-pipeline to avoid pitch changes when audio is sped up 2021-04-21 20:25:01 +02:00
Bart De Vries
7be1ed28ec Disable debug output in audiomanager 2021-04-21 14:53:03 +02:00
Bart De Vries
7a900b5921 Update enclosure duration if needed
If the duration that is mentioned in the enclosure doesn't correspond to
the real duration then update to the real duration in the database.
2021-04-21 14:53:03 +02:00
Bart De Vries
4fa45b0075 Save last playing track in database instead of config file 2021-04-21 14:53:03 +02:00
Bart De Vries
23b6b68500 Make sure that canGoNext is accurate when changing anything in queue 2021-04-21 14:53:02 +02:00
Bart De Vries
5f4a24a11d Refactor adding/removing to queue
All adding and removing should now go through the entry itself, using
queueStatus.
2021-04-21 14:53:02 +02:00
Bart De Vries
2e118d9a7e Make sure that canGoNext status is still accurate when queue items have been moved around 2021-04-21 14:53:02 +02:00
Bart De Vries
364dd52f9a Implement swipe to open/close miniplayer/full player 2021-04-21 14:53:02 +02:00
Bart De Vries
49baa7915b More elegant solution for setting MPRIS2 audio duration when changing tracks 2021-04-21 14:53:02 +02:00
Bart De Vries
a624040ef3 Make player robust against having no track loaded at end of queue 2021-04-21 14:53:02 +02:00
Bart De Vries
f85dbd0572 Remove episodes from queue once they've been fully played 2021-04-21 14:53:02 +02:00
Bart De Vries
b2ba953a33 Mark fully played episodes as read 2021-04-21 14:53:02 +02:00
Bart De Vries
32f01b03bd Enable next button in Player
This functionality has safeguards built in, including a canGoNext
property.
This can be extended with streaming playing in the future.
2021-04-21 14:53:02 +02:00
Bart De Vries
7c4658db2d Change implementation of seekable in AudioManager
We cannot simply pass on the value from the underlying QMediaPlayer,
since it is not reliable (see hacks concerning restoring startup player
position).  Instead we keep track of it ourselves and send out the
signal in the proper places.
2021-04-21 14:53:02 +02:00
Bart De Vries
21feef8ce0 Refactor to use skipForward and skipBackward
This is done to make the distinction between skipping time and changing
track.
2021-04-21 14:53:02 +02:00
Bart De Vries
791c25ad19 Use next() and previous() in PlayerControl
Also change to std::min and std::max for the implementation of next and
previous.
2021-04-21 14:53:02 +02:00