Add support for chapters in episodes
This commit is contained in:
parent
bb20181a77
commit
69c803ab5c
7 changed files with 160 additions and 0 deletions
|
@ -26,6 +26,7 @@ MediaPlayer {
|
|||
|
||||
property int episode: 0
|
||||
property string episode_title: ''
|
||||
property var episode_chapters: ([])
|
||||
property string podcast_title: ''
|
||||
signal playerCreated()
|
||||
|
||||
|
@ -62,6 +63,7 @@ MediaPlayer {
|
|||
var old_episode = player.episode;
|
||||
player.episode = episode_id;
|
||||
player.episode_title = episode.title;
|
||||
player.episode_chapters = episode.chapters;
|
||||
player.podcast_title = episode.podcast_title;
|
||||
player.source = episode.source;
|
||||
player.seekTargetSeconds = episode.position;
|
||||
|
|
2
main.py
2
main.py
|
@ -327,6 +327,7 @@ class gPotherSide:
|
|||
'position': episode.current_position,
|
||||
'total': episode.total_time,
|
||||
'video': episode.file_type() == 'video',
|
||||
'chapters': getattr(episode, 'chapters', []),
|
||||
}
|
||||
|
||||
def report_playback_event(self, episode_id, position_from, position_to, duration):
|
||||
|
@ -345,6 +346,7 @@ class gPotherSide:
|
|||
'description': util.remove_html_tags(episode.description),
|
||||
'metadata': ' | '.join(self._format_metadata(episode)),
|
||||
'link': episode.link if episode.link != episode.url else '',
|
||||
'chapters': getattr(episode, 'chapters', []),
|
||||
}
|
||||
|
||||
def _format_metadata(self, episode):
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
import QtQuick 2.0
|
||||
|
||||
import 'common/constants.js' as Constants
|
||||
import 'common/util.js' as Util
|
||||
import 'icons/icons.js' as Icons
|
||||
|
||||
SlidePage {
|
||||
|
@ -30,6 +31,7 @@ SlidePage {
|
|||
property string title
|
||||
property string link
|
||||
property bool ready: false
|
||||
property var chapters: ([])
|
||||
|
||||
hasMenuButton: detailPage.link != ''
|
||||
menuButtonIcon: Icons.link
|
||||
|
@ -47,6 +49,7 @@ SlidePage {
|
|||
metadataLabel.text = episode.metadata;
|
||||
detailPage.link = episode.link;
|
||||
detailPage.ready = true;
|
||||
detailPage.chapters = episode.chapters;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -87,6 +90,45 @@ SlidePage {
|
|||
color: Constants.colors.placeholder
|
||||
}
|
||||
|
||||
PExpander {
|
||||
visible: detailPage.chapters.length > 0
|
||||
|
||||
width: parent.width
|
||||
expandedHeight: chaptersColumn.childrenRect.height
|
||||
|
||||
Column {
|
||||
id: chaptersColumn
|
||||
width: parent.width
|
||||
|
||||
PLabel {
|
||||
text: 'Chapters'
|
||||
color: Constants.colors.secondaryHighlight
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: detailPage.chapters
|
||||
|
||||
delegate: Column {
|
||||
width: parent.width
|
||||
|
||||
PLabel {
|
||||
width: parent.width
|
||||
text: Util.formatDuration(modelData.start)
|
||||
font.pixelSize: 20 * pgst.scalef
|
||||
color: Constants.colors.secondaryHighlight
|
||||
}
|
||||
|
||||
PLabel {
|
||||
width: parent.width
|
||||
text: modelData.title
|
||||
font.pixelSize: 20 * pgst.scalef
|
||||
color: Constants.colors.placeholder
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PLabel {
|
||||
id: descriptionLabel
|
||||
width: parent.width
|
||||
|
|
88
touch/PExpander.qml
Normal file
88
touch/PExpander.qml
Normal file
|
@ -0,0 +1,88 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* gPodder QML UI Reference Implementation
|
||||
* Copyright (c) 2014, Thomas Perl <m@thp.io>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
|
||||
import 'common/constants.js' as Constants
|
||||
import 'common/util.js' as Util
|
||||
|
||||
|
||||
Item {
|
||||
id: expander
|
||||
|
||||
property bool expanded: false
|
||||
property bool canExpand: expandedHeight > contractedHeight
|
||||
|
||||
property real contractedHeight: 100 * pgst.scalef
|
||||
property real expandedHeight: childrenRect.height
|
||||
property color backgroundColor: Constants.colors.page
|
||||
|
||||
height: expanded ? expandedHeight : contractedHeight
|
||||
clip: true
|
||||
|
||||
Behavior on height { PropertyAnimation { } }
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
if (expander.canExpand) {
|
||||
expander.expanded = !expander.expanded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
z: 100
|
||||
|
||||
opacity: chapterExpander.opacity
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
|
||||
height: expander.contractedHeight * 0.6
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0; color: '#00000000' }
|
||||
GradientStop { position: 1; color: expander.backgroundColor }
|
||||
}
|
||||
}
|
||||
|
||||
PLabel {
|
||||
id: chapterExpander
|
||||
|
||||
z: 200
|
||||
|
||||
anchors {
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
|
||||
text: '...'
|
||||
font.pixelSize: 60 * pgst.scalef
|
||||
|
||||
color: Constants.colors.highlight
|
||||
opacity: !expander.expanded
|
||||
|
||||
Behavior on opacity { PropertyAnimation { } }
|
||||
}
|
||||
}
|
|
@ -135,6 +135,29 @@ Dialog {
|
|||
icon: Icons.last
|
||||
onClicked: player.seekAndSync(player.position + 60 * 1000);
|
||||
}
|
||||
|
||||
IconMenuItem {
|
||||
text: 'Chapters'
|
||||
color: Constants.colors.playback
|
||||
icon: Icons.tag_fill
|
||||
visible: player.episode_chapters.length > 0
|
||||
onClicked: {
|
||||
var items = [];
|
||||
|
||||
for (var i in player.episode_chapters) {
|
||||
(function (items, chapter) {
|
||||
items.push({
|
||||
label: chapter.title + ' (' + Util.formatDuration(chapter.start) + ')',
|
||||
callback: function () {
|
||||
player.seekAndSync(chapter.start * 1000);
|
||||
}
|
||||
});
|
||||
})(items, player.episode_chapters[i]);
|
||||
}
|
||||
|
||||
pgst.showSelection(items, 'Chapters');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ Dialog {
|
|||
PLabel {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
margins: 20 * pgst.scalef
|
||||
}
|
||||
|
@ -74,6 +75,7 @@ Dialog {
|
|||
text: modelData
|
||||
color: (index == selectionDialog.selectedIndex || buttonArea.pressed) ? Constants.colors.dialogHighlight : Constants.colors.dialogText
|
||||
font.pixelSize: 30 * pgst.scalef
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
|
|
|
@ -21,3 +21,4 @@ var cog = '\u2699';
|
|||
var link = '\ue077';
|
||||
var vellipsis = '\u22ee';
|
||||
var paperclip = '\ue08a';
|
||||
var tag_fill = '\ue02b';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue