Merge lp:~dano6/podbird/podbird into lp:podbird

Proposed by Daniel Kutka
Status: Merged
Approved by: Michael Sheldon
Approved revision: no longer in the source branch.
Merged at revision: 210
Proposed branch: lp:~dano6/podbird/podbird
Merge into: lp:podbird
Diff against target: 273 lines (+84/-38)
6 files modified
app/podbird.qml (+31/-26)
app/podcasts.js (+4/-0)
app/ui/EpisodesPage.qml (+2/-2)
app/ui/EpisodesTab.qml (+5/-5)
app/ui/FullPlayingView.qml (+28/-5)
app/ui/SettingsPage.qml (+14/-0)
To merge this branch: bzr merge lp:~dano6/podbird/podbird
Reviewer Review Type Date Requested Status
Michael Sheldon Approve
Daniel Kutka (community) Needs Resubmitting
Review via email: mp+387072@code.launchpad.net

Commit message

Implemented restoring queue, resuming of episode where stopped and fixed some playback issues

Description of the change

This MR brings restoring queue after restart and restoring playback position (optional). Seeking slider behavior was ported from music-app, that fixes some playback issues - sluggish seeking, getting weird loop after seeking, brings overall better responsiveness of controlling audio.

To post a comment you must log in.
Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

Overall this has some excellent improvements, thanks very much! There's a couple of minor things to address that I've added as diff comments

review: Needs Fixing
Revision history for this message
Daniel Kutka (dano6) :
review: Needs Resubmitting
Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

Excellent, thanks very much!

review: Approve
lp:~dano6/podbird/podbird updated
210. By Michael Sheldon

Merge lp:~dano6/podbird/podbird:

* Restore queue after restart
* Fix resuming playback
* Fix some playback/seeking issues

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'app/podbird.qml'
2--- app/podbird.qml 2020-06-30 11:10:05 +0000
3+++ app/podbird.qml 2020-07-09 11:20:38 +0000
4@@ -42,13 +42,6 @@
5 theme.name: settings.themeName == "Dark.qml" ? "Ubuntu.Components.Themes.SuruDark"
6 : "Ubuntu.Components.Themes.Ambiance"
7
8- Component.onDestruction: {
9- var db = Podcasts.init()
10- db.transaction(function (tx) {
11- tx.executeSql('UPDATE Episode SET queued=0 WHERE queued=1');
12- })
13- Podcasts.clearQueue()
14- }
15
16 // RefreshModel function to call refreshModel() function of the tab currently
17 // visible on application start.
18@@ -62,9 +55,6 @@
19
20 Component.onCompleted: {
21 var db = Podcasts.init()
22- db.transaction(function (tx) {
23- tx.executeSql('UPDATE Episode SET queued=0 WHERE queued=1');
24- })
25
26 var today = new Date()
27 // Only automatically check for podcasts on launch once every 12 hours
28@@ -126,6 +116,8 @@
29 property bool showListView: true
30 property int skipForward: 30
31 property int skipBack: 10
32+ property bool continueWhereStopped: true
33+ property int playlistIndex: -1
34 property bool downloadOverWifiOnly: true
35 }
36
37@@ -232,14 +224,15 @@
38 // but media-hub doesn't report it correctly
39 console.log("Starting playback")
40 player.play()
41- player.restorePosition()
42 }
43 }
44
45 MediaPlayer {
46 id: player
47
48- onPositionChanged: console.log("DEBUG: player position changed to: ", position)
49+ onPositionChanged: {
50+ restorePosition()
51+ }
52
53 // Wrapper function around decodeURIComponent() to prevent exceptions
54 // from bubbling up to the app.
55@@ -277,26 +270,41 @@
56 savePosition()
57 } else {
58 play()
59- // Clear the last saved position when we start playing again
60- clearPosition()
61 }
62 }
63
64 function savePosition() {
65+ podbird.settings.playlistIndex = playlist.currentIndex
66 if (currentGuid) {
67 var db = Podcasts.init()
68 db.transaction(function (tx) {
69 tx.executeSql("UPDATE Episode SET position=? WHERE guid=?", [player.position, currentGuid])
70 tx.executeSql("UPDATE Queue SET position=? WHERE guid=?", [player.position, currentGuid])
71+ if(player.position / player.duration > 0.90)
72+ tx.executeSql("UPDATE Episode SET listened=1 WHERE guid=?", [currentGuid])
73 })
74 }
75 }
76
77+ function restoreFromQueue() {
78+ var db = Podcasts.init()
79+ db.transaction(function (tx) {
80+ var rs = tx.executeSql("SELECT * FROM Queue")
81+ for (var i=0; i<rs.rows.length;i++) {
82+ var episode = rs.rows.item(i)
83+ player.playlist.addItem(episode.url)
84+ }
85+ })
86+ if(playlist.itemCount > podbird.settings.playlistIndex)
87+ playlist.currentIndex = podbird.settings.playlistIndex
88+ }
89+
90 function restorePosition() {
91- if (playbackState === MediaPlayer.PlayingState && pendingSeek !== 0) {
92- player.seek(pendingSeek)
93- player.clearPosition()
94- pendingSeek = 0;
95+ if(playbackState === MediaPlayer.PlayingState && status === MediaPlayer.Loaded && pendingSeek){
96+ //ugly hack because seek function does not seems to work async
97+ var p = pendingSeek
98+ pendingSeek = 0
99+ player.seek(p)
100 }
101 }
102
103@@ -345,7 +353,6 @@
104 }
105
106 property bool endOfMedia: false
107- property double progress: 0
108 property int pendingSeek: 0
109
110 playlist: Playlist {
111@@ -361,16 +368,10 @@
112 currentArtist = meta.artist
113 currentImage = meta.image
114 currentGuid = meta.guid
115- player.pendingSeek = meta.position
116- console.log("DEBUG: player.pendingSeek: ", player.pendingSeek, " meta.position ", meta.position)
117+ player.pendingSeek = podbird.settings.continueWhereStopped && meta.position > 5000 ? meta.position : 0
118 }
119 }
120
121- onPlaybackStateChanged: {
122- console.log("DEBUG: Restoring Position to: ", player.position)
123- restorePosition()
124- }
125-
126 onStatusChanged: {
127 if (status === MediaPlayer.EndOfMedia) {
128 console.log("[LOG]: End of Media. Stopping.")
129@@ -399,6 +400,10 @@
130 Component.onDestruction: {
131 savePosition()
132 }
133+
134+ Component.onCompleted: {
135+ restoreFromQueue()
136+ }
137 }
138
139 PageStack {
140
141=== modified file 'app/podcasts.js'
142--- app/podcasts.js 2017-01-03 00:02:16 +0000
143+++ app/podcasts.js 2020-07-09 11:20:38 +0000
144@@ -104,6 +104,10 @@
145 db.transaction(function(tx) {
146 tx.executeSql("DELETE FROM Queue");
147 });
148+
149+ db.transaction(function (tx) {
150+ tx.executeSql('UPDATE Episode SET queued=0 WHERE queued=1');
151+ });
152 }
153
154 function lookup(source) {
155
156=== modified file 'app/ui/EpisodesPage.qml'
157--- app/ui/EpisodesPage.qml 2019-10-18 11:56:16 +0000
158+++ app/ui/EpisodesPage.qml 2020-07-09 11:20:38 +0000
159@@ -574,8 +574,8 @@
160
161 subtitle.text: model.duration === 0 || model.duration === undefined ? model.downloadedfile ? "📎 " + Qt.formatDate(new Date(model.published), "MMM d, yyyy")
162 : Qt.formatDate(new Date(model.published), "MMM d, yyyy")
163- : model.downloadedfile ? "📎 " + Podcasts.formatEpisodeTime(model.duration) + " | " + Qt.formatDate(new Date(model.published), "MMM d, yyyy")
164- : Podcasts.formatEpisodeTime(model.duration) + " | " + Qt.formatDate(new Date(model.published), "MMM d, yyyy")
165+ : model.downloadedfile ? "📎 " + (model.position ? Podcasts.formatEpisodeTime(model.position/1000) + "/" : "") + Podcasts.formatEpisodeTime(model.duration) + " | " + Qt.formatDate(new Date(model.published), "MMM d, yyyy")
166+ : (model.position ? Podcasts.formatEpisodeTime(model.position/1000) + "/" : "") + Podcasts.formatEpisodeTime(model.duration) + " | " + Qt.formatDate(new Date(model.published), "MMM d, yyyy")
167 subtitle.color: podbird.appTheme.baseSubText
168
169 padding.top: units.gu(1)
170
171=== modified file 'app/ui/EpisodesTab.qml'
172--- app/ui/EpisodesTab.qml 2019-03-26 10:39:53 +0000
173+++ app/ui/EpisodesTab.qml 2020-07-09 11:20:38 +0000
174@@ -544,8 +544,8 @@
175
176 subtitle.text: model.duration === 0 || model.duration === undefined ? model.downloadedfile ? "📎 " + model.artist
177 : model.artist
178- : model.downloadedfile ? "📎 " + Podcasts.formatEpisodeTime(model.duration) + " | " + model.artist
179- : Podcasts.formatEpisodeTime(model.duration) + " | " + model.artist
180+ : model.downloadedfile ? "📎 " + (model.position ? Podcasts.formatEpisodeTime(model.position/1000) + "/" : "") + Podcasts.formatEpisodeTime(model.duration) + " | " + model.artist
181+ : (model.position ? Podcasts.formatEpisodeTime(model.position/1000) + "/" : "") + Podcasts.formatEpisodeTime(model.duration) + " | " + model.artist
182 subtitle.color: podbird.appTheme.baseSubText
183
184 Image {
185@@ -747,9 +747,9 @@
186 episodesModel.append({"guid" : episode.guid, "listened" : episode.listened, "published": episode.published, "name" : episode.name, "description" : episode.description, "duration" : episode.duration, "position" : episode.position, "downloadedfile" : episode.downloadedfile, "image" : podcast.image, "artist" : podcast.artist, "audiourl" : episode.audiourl, "queued": episode.queued, "favourited": episode.favourited, "diff": "Older"})
187 }
188 } else if (diff >= 7) {
189- if (episode.downloadedfile != null) {
190- episodesModel.append({"guid" : episode.guid, "listened" : episode.listened, "published": episode.published, "name" : episode.name, "description" : episode.description, "duration" : episode.duration, "position" : episode.position, "downloadedfile" : episode.downloadedfile, "image" : podcast.image, "artist" : podcast.artist, "audiourl" : episode.audiourl, "queued": episode.queued, "favourited": episode.favourited, "diff": "Older"})
191- }
192+ if (episode.downloadedfile != null) {
193+ episodesModel.append({"guid" : episode.guid, "listened" : episode.listened, "published": episode.published, "name" : episode.name, "description" : episode.description, "duration" : episode.duration, "position" : episode.position, "downloadedfile" : episode.downloadedfile, "image" : podcast.image, "artist" : podcast.artist, "audiourl" : episode.audiourl, "queued": episode.queued, "favourited": episode.favourited, "diff": "Older"})
194+ }
195 }
196 }
197
198
199=== modified file 'app/ui/FullPlayingView.qml'
200--- app/ui/FullPlayingView.qml 2017-01-01 14:28:51 +0000
201+++ app/ui/FullPlayingView.qml 2020-07-09 11:20:38 +0000
202@@ -133,10 +133,24 @@
203 maximumValue: player.duration
204 value: player.position
205 height: units.gu(2)
206-
207- onValueChanged: {
208- if (pressed) {
209- player.seek(value);
210+
211+ property bool seeking: false
212+ property bool seeked: false
213+
214+ onSeekingChanged: {
215+ if (seeking === false) {
216+ startTime.text = Podcasts.formatTime(player.position / 1000)
217+ }
218+ }
219+
220+ onPressedChanged: {
221+ seeking = pressed
222+
223+ if (!pressed) {
224+ seeked = true
225+ player.seek(value)
226+
227+ startTime.text = Podcasts.formatTime(value / 1000)
228 }
229 }
230
231@@ -146,7 +160,16 @@
232
233 Connections {
234 target: player
235- onPositionChanged: scrubber.value = player.position
236+ onPositionChanged: {
237+ // seeked is a workaround for bug 1310706 as the first position after a seek is sometimes invalid (0)
238+ if (scrubber.seeking === false && !scrubber.seeked) {
239+ startTime.text = Podcasts.formatTime(player.position / 1000)
240+ endTime.text = Podcasts.formatTime(player.duration / 1000)
241+
242+ scrubber.value = player.position
243+ }
244+ scrubber.seeked = false;
245+ }
246 }
247
248 Label {
249
250=== modified file 'app/ui/SettingsPage.qml'
251--- app/ui/SettingsPage.qml 2016-12-11 21:23:21 +0000
252+++ app/ui/SettingsPage.qml 2020-07-09 11:20:38 +0000
253@@ -180,6 +180,20 @@
254 onClicked: PopupUtils.open(skipBackDialog, settingsPage);
255 }
256
257+ ListItem {
258+ ListItemLayout {
259+ id: continueWhereStopped
260+ title.text: i18n.tr("Continue where stopped")
261+ Switch {
262+ SlotsLayout.position: SlotsLayout.Last
263+ checked: podbird.settings.continueWhereStopped
264+ onClicked: podbird.settings.continueWhereStopped = checked
265+ }
266+ }
267+ divider.visible: false
268+ height: gridViewLayout.height
269+ }
270+
271 HeaderListItem {
272 title.text: i18n.tr("Podcast Episode Settings")
273 }

Subscribers

People subscribed via source and target branches

to status/vote changes: