Hello community,

here is the log from the commit of package orion for openSUSE:Factory checked 
in at 2017-06-20 09:40:02
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/orion (Old)
 and      /work/SRC/openSUSE:Factory/.orion.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "orion"

Tue Jun 20 09:40:02 2017 rev:7 rq:504466 version:1.5.1+git~20170612

Changes:
--------
--- /work/SRC/openSUSE:Factory/orion/orion.changes      2017-06-04 
02:01:37.648969159 +0200
+++ /work/SRC/openSUSE:Factory/.orion.new/orion.changes 2017-06-20 
09:40:04.466782845 +0200
@@ -1,0 +2,13 @@
+Tue Jun 13 13:19:06 UTC 2017 - [email protected]
+
+- Update to version 1.5.1+git~20170612:
+  * explicitly percent-encode HLS token (#175)
+  * VOD resume at last playback position (#177)
+
+-------------------------------------------------------------------
+Fri Jun 09 08:50:47 UTC 2017 - [email protected]
+
+- Update to version 1.5.1+git~20170607:
+  * Debug command line option (#172)
+
+-------------------------------------------------------------------

Old:
----
  orion-1.5.1+git~20170602.tar.xz

New:
----
  orion-1.5.1+git~20170612.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ orion.spec ++++++
--- /var/tmp/diff_new_pack.eLe4ao/_old  2017-06-20 09:40:05.626619318 +0200
+++ /var/tmp/diff_new_pack.eLe4ao/_new  2017-06-20 09:40:05.630618754 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           orion
-Version:        1.5.1+git~20170602
+Version:        1.5.1+git~20170612
 Release:        0
 Summary:        Twitch stream client using Qt
 License:        GPL-3.0

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.eLe4ao/_old  2017-06-20 09:40:05.686610859 +0200
+++ /var/tmp/diff_new_pack.eLe4ao/_new  2017-06-20 09:40:05.690610296 +0200
@@ -1,4 +1,4 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/alamminsalo/orion.git</param>
-              <param 
name="changesrevision">fe4787b43bf32c4795031965fade34e1f797f7f2</param></service></servicedata>
\ No newline at end of file
+              <param 
name="changesrevision">d61db488c96621d8ffdf0ddf203a12e9966e707a</param></service></servicedata>
\ No newline at end of file

++++++ orion-1.5.1+git~20170602.tar.xz -> orion-1.5.1+git~20170612.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/orion-1.5.1+git~20170602/src/main.cpp 
new/orion-1.5.1+git~20170612/src/main.cpp
--- old/orion-1.5.1+git~20170602/src/main.cpp   2017-06-02 07:42:07.000000000 
+0200
+++ new/orion-1.5.1+git~20170612/src/main.cpp   2017-06-12 22:11:30.000000000 
+0200
@@ -47,6 +47,7 @@
 int main(int argc, char *argv[])
 {
     CustomApp app(argc, argv);
+    app.setApplicationVersion(APP_VERSION);
 
     //Single application solution
     RunGuard guard("wz0dPKqHv3vX0BBsUFZt");
@@ -55,6 +56,19 @@
         return -1;
     }
 
+    QCommandLineParser parser;
+    parser.setApplicationDescription("Desktop client for Twitch.tv");
+    parser.addHelpOption();
+    parser.addVersionOption();
+
+    QCommandLineOption debugOption(QStringList() << "d" << "debug", "show 
debug output");
+
+    parser.addOption(debugOption);
+
+    parser.process(app);
+
+    bool showDebugOutput = parser.isSet(debugOption);
+
     //Init engine
     QQmlApplicationEngine engine;
 
@@ -67,7 +81,9 @@
         app.setFont(QFont(":/fonts/NotoSans-Regular.ttf", 10, QFont::Normal, 
false));
 
 #ifndef  QT_DEBUG
-    qInstallMessageHandler(noisyFailureMsgHandler);
+    if (!showDebugOutput) {
+        qInstallMessageHandler(noisyFailureMsgHandler);
+    }
 #endif
     app.setWindowIcon(appIcon);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/orion-1.5.1+git~20170602/src/model/channelmanager.cpp 
new/orion-1.5.1+git~20170612/src/model/channelmanager.cpp
--- old/orion-1.5.1+git~20170602/src/model/channelmanager.cpp   2017-06-02 
07:42:07.000000000 +0200
+++ new/orion-1.5.1+git~20170612/src/model/channelmanager.cpp   2017-06-12 
22:11:30.000000000 +0200
@@ -419,6 +419,17 @@
     }
     settings.endArray();
 
+    int numLastPositions = settings.beginReadArray("lastPositions");
+    for (int i = 0; i < numLastPositions; i++) {
+        settings.setArrayIndex(i);
+        const QString channel = settings.value("channel").toString();
+        const QString vod = settings.value("vod").toString();
+        const quint64 lastPosition = settings.value("position").toULongLong();
+
+        vodLastPlaybackPositionLoaded(channel, vod, lastPosition, i);
+    }
+    settings.endArray();
+
     if (settings.contains("access_token")) {
         setAccessToken(settings.value("access_token").toString());
     } else {
@@ -471,6 +482,87 @@
         favouritesModel->getChannels().at(i)->writeToSettings(settings);
     }
     settings.endArray();
+
+    //Write last positions
+    int nextLastPositionEntry = settings.beginReadArray("lastPositions");
+    settings.endArray();
+
+    settings.beginWriteArray("lastPositions");
+    for (auto channelEntry = channelVodLastPositions.begin(); channelEntry != 
channelVodLastPositions.end(); channelEntry++) {
+        auto & vods = channelEntry.value();
+        for (auto vodEntry = vods.begin(); vodEntry != vods.end(); vodEntry++) 
{
+            auto & lastPosition = vodEntry.value();
+            if (lastPosition.modified) {
+                if (lastPosition.settingsIndex == -1) {
+                    lastPosition.settingsIndex = nextLastPositionEntry++;
+                }
+
+                settings.setArrayIndex(lastPosition.settingsIndex);
+                settings.setValue("channel", channelEntry.key());
+                settings.setValue("vod", vodEntry.key());
+                settings.setValue("position", vodEntry.value().lastPosition);
+            }
+        }
+    }
+    settings.endArray();
+}
+
+void ChannelManager::setVodLastPlaybackPosition(const QString & channel, const 
QString & vod, quint64 position) {
+    auto channelEntry = channelVodLastPositions.find(channel);
+    if (channelEntry == channelVodLastPositions.end()) {
+        channelEntry = channelVodLastPositions.insert(channel, QMap<QString, 
LastPosition>());
+    }
+
+    auto & vodMap = channelEntry.value();
+    auto vodEntry = vodMap.find(vod);
+    if (vodEntry != vodMap.end()) {
+        vodEntry.value().lastPosition = position;
+        vodEntry.value().modified = true;
+    }
+    else {
+        // -1 index to be replaced at settings save time
+        vodMap.insert(vod, {position, true, -1});
+    }
+
+    emit vodLastPositionUpdated(channel, vod, position);
+}
+
+void ChannelManager::vodLastPlaybackPositionLoaded(const QString & channel, 
const QString & vod, quint64 position, int settingsIndex) {
+    auto channelEntry = channelVodLastPositions.find(channel);
+    if (channelEntry == channelVodLastPositions.end()) {
+        channelEntry = channelVodLastPositions.insert(channel, QMap<QString, 
LastPosition>());
+    }
+
+    auto & vodMap = channelEntry.value();
+    vodMap.remove(vod);
+    vodMap.insert(vod, {position, false, settingsIndex});
+}
+
+QVariant ChannelManager::getVodLastPlaybackPosition(const QString & channel, 
const QString & vod) {
+    auto channelEntry = channelVodLastPositions.find(channel);
+    if (channelEntry == channelVodLastPositions.end()) {
+        return QVariant();
+    }
+    
+    auto & vodMap = channelEntry.value();
+    auto vodEntry = vodMap.find(vod);
+    if (vodEntry == vodMap.end()) {
+        return QVariant();
+    }
+
+    return vodEntry.value().lastPosition;
+}
+
+QVariantMap ChannelManager::getChannelVodsLastPlaybackPositions(const QString 
& channel) {
+    QVariantMap out;
+    auto channelEntry = channelVodLastPositions.find(channel);
+    if (channelEntry != channelVodLastPositions.end()) {
+        auto & vodMap = channelEntry.value();
+        for (auto vodEntry = vodMap.constBegin(); vodEntry != 
vodMap.constEnd(); vodEntry++) {
+            out.insert(vodEntry.key(), vodEntry.value().lastPosition);
+        }
+    }
+    return out;
 }
 
 void ChannelManager::addToFavourites(const quint32 &id){
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/orion-1.5.1+git~20170602/src/model/channelmanager.h 
new/orion-1.5.1+git~20170612/src/model/channelmanager.h
--- old/orion-1.5.1+git~20170602/src/model/channelmanager.h     2017-06-02 
07:42:07.000000000 +0200
+++ new/orion-1.5.1+git~20170612/src/model/channelmanager.h     2017-06-12 
22:11:30.000000000 +0200
@@ -31,6 +31,12 @@
 
 class ChannelManager;
 
+struct LastPosition {
+    quint64 lastPosition;
+    bool modified;
+    int settingsIndex;
+};
+
 class BadgeImageProvider : public ImageProvider {
     Q_OBJECT
 public:
@@ -126,6 +132,10 @@
     static const quint32 BLOCKED_USER_LIST_FETCH_LIMIT;
     void getBlockedUserList();
 
+    QMap<QString, QMap<QString, LastPosition>> channelVodLastPositions;
+
+    void vodLastPlaybackPositionLoaded(const QString & channel, const QString 
& vod, quint64 position, int settingsIndex);
+
 public:
     ChannelManager(NetworkManager *netman, bool hiDpi);
     ~ChannelManager();
@@ -187,6 +197,10 @@
     Q_INVOKABLE void getVodStartTime(quint64 vodId);
     Q_INVOKABLE void getVodChatPiece(quint64 vodId, quint64 offset);
 
+    Q_INVOKABLE void setVodLastPlaybackPosition(const QString & channel, const 
QString & vod, quint64 position);
+    Q_INVOKABLE QVariant getVodLastPlaybackPosition(const QString & channel, 
const QString & vod);
+    Q_INVOKABLE QVariantMap getChannelVodsLastPlaybackPositions(const QString 
& channel);
+
     void setSwapChat(bool value);
     bool getSwapChat();
     void setTextScaleFactor(double value);
@@ -306,6 +320,8 @@
     void userBlocked(const QString & blockedUsername);
     void userUnblocked(const QString & unblockedUsername);
 
+    void vodLastPositionUpdated(const QString & channel, const QString & vod, 
const quint64 position);
+
 public slots:
     void checkFavourites();
     void addToFavourites(const quint32&);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/orion-1.5.1+git~20170602/src/qml/PlayerView.qml 
new/orion-1.5.1+git~20170612/src/qml/PlayerView.qml
--- old/orion-1.5.1+git~20170602/src/qml/PlayerView.qml 2017-06-02 
07:42:07.000000000 +0200
+++ new/orion-1.5.1+git~20170612/src/qml/PlayerView.qml 2017-06-12 
22:11:30.000000000 +0200
@@ -29,6 +29,8 @@
     property var streamMap
     property bool isVod: false
     property bool streamOnline: true
+    property string curVodId
+    property int lastSetPosition
 
     property bool cursorHidden: false
     property string currentQualityName
@@ -156,18 +158,18 @@
         g_cman.setQuality(streamName);
     }
 
-    function getStreams(channel, vod){
-        getChannel(channel, vod, true);
+    function getStreams(channel, vod, startPos){
+        getChannel(channel, vod, true, startPos);
     }
 
     function getChat(channel) {
-        getChannel(channel, null, false);
+        getChannel(channel, null, false, 0);
         if (chatview.status == 0) {
             chatview.status++;
         }
     }
 
-    function getChannel(channel, vod, wantVideo){
+    function getChannel(channel, vod, wantVideo, startPos){
 
         if (!channel){
             return
@@ -185,12 +187,14 @@
             else {
                 g_vodmgr.getBroadcasts(vod._id)
                 isVod = true
+                root.curVodId = vod._id
+                root.lastSetPosition = startPos
 
                 duration = vod.duration
 
                 console.log("Setting up VOD, duration " + vod.duration)
 
-                seekBar.setPosition(0, duration)
+                seekBar.setPosition(startPos, duration)
             }
         } else {
             isVod = false;
@@ -222,7 +226,7 @@
             } else {
                 var vodIdNum = parseInt(vod._id.substring(1));
                 console.log("replaying chat for vod", vodIdNum, "starting at", 
startEpochTime);
-                chatview.replayChat(currentChannel.name, currentChannel._id, 
vodIdNum, startEpochTime);
+                chatview.replayChat(currentChannel.name, currentChannel._id, 
vodIdNum, startEpochTime, startPos);
             }
         } else {
             chatview.joinChannel(currentChannel.name, currentChannel._id);
@@ -306,8 +310,15 @@
         }
 
         onPositionChanged: {
-            chatview.playerPositionUpdate(renderer.position);
-            seekBar.setPosition(renderer.position, duration)
+            var newPos = renderer.position;
+            chatview.playerPositionUpdate(newPos);
+            if (root.isVod) {
+                if (Math.abs(newPos - root.lastSetPosition) > 10) {
+                    root.lastSetPosition = newPos;
+                    
g_cman.setVodLastPlaybackPosition(root.currentChannel.name, root.curVodId, 
newPos);
+                }
+            }
+            seekBar.setPosition(newPos, duration);
         }
 
         onPlayingResumed: {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/orion-1.5.1+git~20170602/src/qml/VodsView.qml 
new/orion-1.5.1+git~20170612/src/qml/VodsView.qml
--- old/orion-1.5.1+git~20170602/src/qml/VodsView.qml   2017-06-02 
07:42:07.000000000 +0200
+++ new/orion-1.5.1+git~20170612/src/qml/VodsView.qml   2017-06-12 
22:11:30.000000000 +0200
@@ -18,9 +18,12 @@
 import "util.js" as Util
 
 Item{
+    id: vodsView
+
     anchors.fill: parent
     property variant selectedChannel
     property int itemCount: 0
+    property var channelVodPositions
 
     function search(channel){
 
@@ -41,6 +44,8 @@
 
         header.text = "Videos for " + selectedChannel.title;
 
+        channelVodPositions = 
g_cman.getChannelVodsLastPlaybackPositions(channel.name);
+
         g_vodmgr.search(selectedChannel._id, 0, 35)
 
         itemCount = 35
@@ -61,6 +66,18 @@
         }
     }
 
+    Connections {
+        target: g_cman
+        onVodLastPositionUpdated: {
+            //console.log("onVodLastPositionUpdated", channel, vod, position);
+            if (selectedChannel.name == channel) {
+                channelVodPositions[vod] = position;
+                // need binding to update
+                channelVodPositions = channelVodPositions;
+            }
+        }
+    }
+
     CommonGrid {
         id: vods
         tooltipEnabled: true
@@ -80,17 +97,34 @@
             views: model.views
             preview: model.preview
             duration: model.duration
+            position: channelVodPositions[model.id] || 0
             game: model.game
             createdAt: model.createdAt
         }
 
         onItemClicked: {
-            playerView.getStreams(selectedChannel, clickedItem)
+            var lastPlaybackPosition = 
vods.getLastPlaybackPosition(selectedChannel, clickedItem);
+            playerView.getStreams(selectedChannel, clickedItem, 
lastPlaybackPosition == null? 0 : lastPlaybackPosition);
+        }
+
+        function getLastPlaybackPosition(channel, vod) {
+            console.log("getLastPlaybackPosition", channel.name, vod._id);
+            return g_cman.getVodLastPlaybackPosition(channel.name, vod._id);
         }
 
         onItemRightClicked: {
             _menu.item = clickedItem
-            _menu.popup()
+
+            var lastPlayed = getLastPlaybackPosition(selectedChannel, 
clickedItem);
+            var haveLastPlayTime = lastPlayed != null;
+            _furthestPlayedMenuItem.enabled = haveLastPlayTime;
+            if (haveLastPlayTime) {
+               _furthestPlayedMenuItem.text = "Watch video from " + 
Util.getTime(lastPlayed);
+            } else {
+               _furthestPlayedMenuItem.text = "Watch video from furthest 
played";
+            }
+
+            _menu.popup();
         }
 
         onItemTooltipHover: {
@@ -114,10 +148,17 @@
         ContextMenu {
             id: _menu
             MenuItem {
-                text: "Watch video"
+                text: "Watch video from start"
                 //text: "Watch;play"
                 onTriggered: {
-                    playerView.getStreams(selectedChannel, _menu.item)
+                    playerView.getStreams(selectedChannel, _menu.item, 0)
+                }
+            }
+
+            MenuItem {
+                id: _furthestPlayedMenuItem
+                onTriggered: {
+                    playerView.getStreams(selectedChannel, _menu.item, 
vods.getLastPlaybackPosition(selectedChannel, _menu.item))
                 }
             }
         }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/orion-1.5.1+git~20170602/src/qml/components/Video.qml 
new/orion-1.5.1+git~20170612/src/qml/components/Video.qml
--- old/orion-1.5.1+git~20170602/src/qml/components/Video.qml   2017-06-02 
07:42:07.000000000 +0200
+++ new/orion-1.5.1+git~20170612/src/qml/components/Video.qml   2017-06-12 
22:11:30.000000000 +0200
@@ -20,6 +20,7 @@
     property string title
     property string preview
     property int views
+    property int position
     property int duration
     property string game
     property string createdAt
@@ -90,6 +91,16 @@
                 bottom: container.bottom
             }
         }
+
+        Rectangle {
+            height: infoRect.height
+            width: container.width * root.position / root.duration
+            color: Styles.purple
+            anchors {
+                left: container.left
+                bottom: container.bottom
+            }
+        }
 
         Text {
             id: channelTitle
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/orion-1.5.1+git~20170602/src/qml/irc/Chat.qml 
new/orion-1.5.1+git~20170612/src/qml/irc/Chat.qml
--- old/orion-1.5.1+git~20170602/src/qml/irc/Chat.qml   2017-06-02 
07:42:07.000000000 +0200
+++ new/orion-1.5.1+git~20170612/src/qml/irc/Chat.qml   2017-06-12 
22:11:30.000000000 +0200
@@ -86,8 +86,8 @@
         messageReceived("notice", null, "", false, false, false, [], true, 
"Joined channel #" + channelName, false)
     }
 
-    function replayChat(channelName, channelId, vodId, startEpochTime) {
-        chat.replay(channelName, channelId, vodId, startEpochTime, 0)
+    function replayChat(channelName, channelId, vodId, startEpochTime, 
startPos) {
+        chat.replay(channelName, channelId, vodId, startEpochTime, startPos)
         enterChannelCommon(channelName, channelId);
         root.replayMode = true
         messageReceived("notice", null, "", false, false, false, [], true, 
"Starting chat replay #" + channelName + " v" + vodId, false)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/orion-1.5.1+git~20170602/src/qml/irc/ChatView.qml 
new/orion-1.5.1+git~20170612/src/qml/irc/ChatView.qml
--- old/orion-1.5.1+git~20170602/src/qml/irc/ChatView.qml       2017-06-02 
07:42:07.000000000 +0200
+++ new/orion-1.5.1+git~20170612/src/qml/irc/ChatView.qml       2017-06-12 
22:11:30.000000000 +0200
@@ -79,11 +79,11 @@
         chat.leaveChannel()
     }
 
-    function replayChat(channelName, channelId, vodId, startEpochTime) {
+    function replayChat(channelName, channelId, vodId, startEpochTime, 
startPos) {
         viewerListEnabled = false;
         cleanupPrevChannel()
         chat.leaveChannel()
-        chat.replayChat(channelName, channelId, vodId, startEpochTime);
+        chat.replayChat(channelName, channelId, vodId, startEpochTime, 
startPos);
     }
 
     function playerSeek(newOffset) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/orion-1.5.1+git~20170602/src/util/jsonparser.cpp 
new/orion-1.5.1+git~20170612/src/util/jsonparser.cpp
--- old/orion-1.5.1+git~20170602/src/util/jsonparser.cpp        2017-06-02 
07:42:07.000000000 +0200
+++ new/orion-1.5.1+git~20170612/src/util/jsonparser.cpp        2017-06-12 
22:11:30.000000000 +0200
@@ -358,7 +358,7 @@
 
         url = QString("http://usher.twitch.tv/api/channel/hls/%1";).arg(channel 
+ QString(".m3u8"))
                 + QString("?player=twitchweb")
-                + QString("&token=%1").arg(tokenData)
+                + QString("&token=") + QUrl::toPercentEncoding(tokenData)
                 + QString("&sig=%1").arg(sig)
                 + QString("&allow_source=true&$allow_audio_only=true");
     }


Reply via email to