Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QWebkit to QWebEngine Conversion #2512

Closed
wants to merge 15 commits into from
Closed

QWebkit to QWebEngine Conversion #2512

wants to merge 15 commits into from

Conversation

Dotrar
Copy link

@Dotrar Dotrar commented Jan 6, 2019

this closes
#2144
#2057
plus another bug that I've lost the reference to.

it was easier to fix this problem than to fix my computer telling me:
python3-pyqt5.qtwebkit is already the newest version (5.11.3+dfsg-1+b3)

Converts QWebkit to QWebEngine; as per what is recommended.

Only 1 known problem with this patch, I don't know where secondsToTime is called in the QT code, and there was a bug with ability to convert QJson -> QString, so I edited it in functions.js instead, it seems the only thing that had problems with that was ruler.js; - if someone wants to fix this up.

By all means, it works completely as expected. QtWebkitWidgets isn't coming back. The fact that it's still there in some distrubitions isn't to be abused because it won't be there forever.

Regards.


What works:

  • Adjusting slider
  • visual effects
  • importing video on different tracks in different positions
  • Slicing at the current cursor position

What doesn't work:

  • The ruler text looks silly, /timeline/js/directives/ruler.js:179

@Dotrar
Copy link
Author

Dotrar commented Jan 6, 2019

Checks fail because I dunno how to use Jarvis, code works fine with latest pyqt5.qtwebengine

@DylanC
Copy link
Collaborator

DylanC commented Jan 7, 2019

@Dotrar - This is really great. I found this message in the Travis build log:

Traceback (most recent call last):
File "src/tests/query_tests.py", line 54, in setUpClass
TestQueryClass.app = OpenShotApp(sys.argv, mode="unittest")
File "/home/travis/build/OpenShot/openshot-qt/src/classes/app.py", line 159, in init
from windows.main_window import MainWindow
File "/home/travis/build/OpenShot/openshot-qt/src/windows/main_window.py", line 45, in
from windows.views.timeline_webview import TimelineWebView
File "/home/travis/build/OpenShot/openshot-qt/src/windows/views/timeline_webview.py", line 41, in
from PyQt5.QtWebEngineWidgets import QWebEngineView as QWebView
ImportError: No module named 'PyQt5.QtWebEngineWidgets'

Perhaps the version of Qt we are using at the moment is too old. (version 5.2.1) QWebEngine didn't exist until later versions of Qt. @ferdnyc - Should we move to QWebEngine now that someone has done the work for it? 😆


# Find position from javascript
js_position = self.eval_js(JS_SCOPE_SELECTOR + ".GetJavaScriptPosition(" + str(position.x()) + ");")
self.eval_js(JS_SCOPE_SELECTOR + ".GetJavaScriptPosition(" + str(position.x()) + ");",self.store)
js_positoin = self.consume()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo here, should be js_position.

Copy link
Contributor

@ferdnyc ferdnyc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Dotrar , I took a quick look. I have more to add, but I have to run out now so I wanted to submit this first, even though it's incomplete.

storeChanged = pyqtSignal(str)

def store(self,val):
log.error('storing val {}'.format(val))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is clearly not an error. log.info() please.

loop.exec_()

ret = self._last_js_var
log.error('returning val {}'.format(ret))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, not an error.

@@ -154,27 +157,51 @@
MENU_SPLIT_AUDIO_MULTIPLE = 1




Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove these two blank lines, please — the two above are plenty.


from PyQt5.QtWebEngineWidgets import QWebEngineView as QWebView
from PyQt5.QtWebChannel import QWebChannel

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the blank lines between these imports.

self._last_js_var = None



Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove all three (extra) blank lines, they're in the middle of the __init__ method.

@ferdnyc
Copy link
Contributor

ferdnyc commented Jan 11, 2019

One general question: Do we really need to import qwebchannel.js into the OpenShot source? This QT help doc makes me think we don't.

@Dotrar
Copy link
Author

Dotrar commented Jan 11, 2019

Yeah, fair, I'll fix up the formatting when I get back from my holidays on the 14th. The pull request was an afterthought. And there still is the bug with regards to the timeline issue. Where would one look to fix that up?

@ferdnyc
Copy link
Contributor

ferdnyc commented Jan 11, 2019

Yeah, fair, I'll fix up the formatting when I get back from my holidays on the 14th. The pull request was an afterthought.

And to be fair, I haven't even tried to run it yet, that was just quick by-inspection stuff. I'll be able to give better impressions once I've tried it. If it works, then... great! Ultimately that's the test.

I'm a little worried about two things:

  1. Performance. Firing off a whole separate event loop for each JavaScript call feels heavy, though I suppose not necessarily any heavier than QWebKit's synchronous calls back-and-forth between Python and JS. But I think running some performance metrics vs. the old code would be a prudent thing.
  2. Thread safety. I'm still wrapping my head around store() / consume(), but the use of a single self._last_js_var to hold the data being passed out from JavaScript to Python makes me nervous — it certainly doesn't seem async-safe, is there a possibility multiple threads could trample each other's data?

And there still is the bug with regards to the timeline issue. Where would one look to fix that up?

Yeah, that... well....

Only 1 known problem with this patch, I don't know where secondsToTime is called in the QT code, and there was a bug with ability to convert QJson -> QString, so I edited it in functions.js instead, it seems the only thing that had problems with that was ruler.js; - if someone wants to fix this up.

The JavaScript secondsToTime isn't ever called by the PyQt code, in fact the Python has its own implementation of secondsToTime() in not one but two different places (src/windows/cutting.py:353 and src/windows/add_to_timeline:420), because code duplication sometimes feels like a defining feature of the codebase.

The spots to worry about, if I'm understanding correctly, would be the ones where JavaScript passes the results of secondsToTime OUT to a PyQt function. The only one I've found so far is here:

// Update GUI with position (to the preview can be updated)
if ($scope.Qt) {
timeline.PlayheadMoved(position_seconds, frame, secondsToTime(position_seconds, $scope.project.fps.num, $scope.project.fps.den));
}

That third argument becomes time_code in PlayheadMoved():

@pyqtSlot(float, int, str)
def PlayheadMoved(self, position_seconds, position_frames, time_code):
# Load the timeline into the Player (ignored if this has already happened)
self.window.LoadFileSignal.emit('')
if self.last_position_frames != position_frames:
# Update time code (to prevent duplicate previews)
self.last_position_frames = position_frames
# Notify main window of current frame
self.window.previewFrame(position_seconds, position_frames, time_code)

But here's the thing: As far as I can tell, time_code is NEVER used anywhere in the code. It's not used in PlayheadMoved(), and it's not used after it's passed to previewFrame(). So, it may be possible to just remove that argument entirely, and if that's the only reason that the result of JS secondsToTime had to be converted .toString() then that may not be necessary.

@ferdnyc
Copy link
Contributor

ferdnyc commented Jan 11, 2019

But here's the thing: As far as I can tell, time_code is NEVER used anywhere in the code. It's not used in PlayheadMoved(), and it's not used after it's passed to previewFrame().

(In fact, position_seconds is never used either, in the current code. The only argument there that's ever consumed is position_frames.)

@ferdnyc
Copy link
Contributor

ferdnyc commented Jan 11, 2019

I've gotta say, this is a little scary, when running the code. Even assuming they're all non-issues, I think we've gotta find some way to make them go away.

Properties without notify signal logspam
Property 'modal'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'windowModality'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'enabled'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'geometry'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'frameGeometry'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'normalGeometry'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'x'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'y'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'pos'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'frameSize'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'size'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'width'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'height'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'rect'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'childrenRect'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'childrenRegion'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'sizePolicy'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'minimumSize'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'maximumSize'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'minimumWidth'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'minimumHeight'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'maximumWidth'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'maximumHeight'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'sizeIncrement'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'baseSize'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'palette'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'font'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'cursor'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'mouseTracking'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'tabletTracking'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'isActiveWindow'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'focusPolicy'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'focus'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'contextMenuPolicy'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'updatesEnabled'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'visible'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'minimized'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'maximized'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'fullScreen'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'sizeHint'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'minimumSizeHint'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'acceptDrops'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'windowOpacity'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'windowModified'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'toolTip'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'toolTipDuration'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'statusTip'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'whatsThis'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'accessibleName'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'accessibleDescription'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'layoutDirection'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'autoFillBackground'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'styleSheet'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'locale'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'windowFilePath'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'inputMethodHints'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'iconSize'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'toolButtonStyle'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'animated'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'documentMode'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'tabShape'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'dockNestingEnabled'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'dockOptions'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'unifiedTitleAndToolBarOnMac'' of object 'MainWindow' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'modal'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'windowModality'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'enabled'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'geometry'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'frameGeometry'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'normalGeometry'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'x'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'y'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'pos'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'frameSize'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'size'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'width'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'height'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'rect'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'childrenRect'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'childrenRegion'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'sizePolicy'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'minimumSize'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'maximumSize'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'minimumWidth'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'minimumHeight'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'maximumWidth'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'maximumHeight'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'sizeIncrement'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'baseSize'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'palette'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'font'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'cursor'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'mouseTracking'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'tabletTracking'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'isActiveWindow'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'focusPolicy'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'focus'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'contextMenuPolicy'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'updatesEnabled'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'visible'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'minimized'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'maximized'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'fullScreen'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'sizeHint'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'minimumSizeHint'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'acceptDrops'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'windowOpacity'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'windowModified'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'toolTip'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'toolTipDuration'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'statusTip'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'whatsThis'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'accessibleName'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'accessibleDescription'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'layoutDirection'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'autoFillBackground'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'styleSheet'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'locale'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'windowFilePath'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'inputMethodHints'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'title'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'url'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'selectedText'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'hasSelection'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!
Property 'zoomFactor'' of object 'TimelineWebView' has no notify signal and is not constant, value updates in HTML will be broken!

@ferdnyc
Copy link
Contributor

ferdnyc commented Jan 11, 2019

So, it may be possible to just remove that argument entirely, and if that's the only reason that the result of JS secondsToTime had to be converted .toString() then that may not be necessary.

Yeah, this patch on top of your branch fixes click-to-seek for the playhead, and eliminates any complaints about type conversion:

From 89d872cef0c1fdcbceb1eb70996db28add1432f4 Mon Sep 17 00:00:00 2001
From: "FeRD (Frank Dana)" <ferdnyc@gmail.com>
Date: Fri, 11 Jan 2019 01:16:39 -0500
Subject: [PATCH] Don't pass JS time_code to PyQt

---
 src/timeline/js/controllers.js        | 2 +-
 src/timeline/js/functions.js          | 2 +-
 src/windows/main_window.py            | 2 +-
 src/windows/views/timeline_webview.py | 8 ++++----
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/timeline/js/controllers.js b/src/timeline/js/controllers.js
index 3f75d53a..220bb1f0 100644
--- a/src/timeline/js/controllers.js
+++ b/src/timeline/js/controllers.js
@@ -284,7 +284,7 @@ App.controller('TimelineCtrl',function($scope) {
 	  
 	  // Update GUI with position (to the preview can be updated)
 	  if ($scope.Qt) {
-		  timeline.PlayheadMoved(position_seconds, frame, secondsToTime(position_seconds, $scope.project.fps.num, $scope.project.fps.den));
+		  timeline.PlayheadMoved(position_seconds, frame);
 	  }
   };
 
diff --git a/src/timeline/js/functions.js b/src/timeline/js/functions.js
index e8feb7e7..dd10321f 100644
--- a/src/timeline/js/functions.js
+++ b/src/timeline/js/functions.js
@@ -154,7 +154,7 @@ function secondsToTime(secs, fps_num, fps_den)
 	var day = day % 7;
 
 	var frame = Math.round((milli / 1000.0) * (fps_num / fps_den)) + 1;
-    return { "week":padNumber(week,2), "day":padNumber(day,2), "hour":padNumber(hour,2), "min":padNumber(min,2), "sec":padNumber(sec,2), "milli":padNumber(milli,2), "frame":padNumber(frame,2) }.toString();
+    return { "week":padNumber(week,2), "day":padNumber(day,2), "hour":padNumber(hour,2), "min":padNumber(min,2), "sec":padNumber(sec,2), "milli":padNumber(milli,2), "frame":padNumber(frame,2) };
 }
 
 // Find the closest track number (based on a Y coordinate)
diff --git a/src/windows/main_window.py b/src/windows/main_window.py
index 2e3a1727..6bda7d33 100644
--- a/src/windows/main_window.py
+++ b/src/windows/main_window.py
@@ -838,7 +838,7 @@ class MainWindow(QMainWindow, updates.UpdateWatcher):
         win = Cutting(f, preview=True)
         win.show()
 
-    def previewFrame(self, position_seconds, position_frames, time_code):
+    def previewFrame(self, position_seconds, position_frames):
         """Preview a specific frame"""
         # Notify preview thread
         self.previewFrameSignal.emit(position_frames)
diff --git a/src/windows/views/timeline_webview.py b/src/windows/views/timeline_webview.py
index 10c29d8d..b3d53967 100644
--- a/src/windows/views/timeline_webview.py
+++ b/src/windows/views/timeline_webview.py
@@ -2520,8 +2520,8 @@ class TimelineWebView(QWebView, updates.UpdateInterface):
         # Seek to frame
         self.window.SeekSignal.emit(frame_number)
 
-    @pyqtSlot(float, int, str)
-    def PlayheadMoved(self, position_seconds, position_frames, time_code):
+    @pyqtSlot(float, int)
+    def PlayheadMoved(self, position_seconds, position_frames):
 
         # Load the timeline into the Player (ignored if this has already happened)
         self.window.LoadFileSignal.emit('')
@@ -2531,7 +2531,7 @@ class TimelineWebView(QWebView, updates.UpdateInterface):
             self.last_position_frames = position_frames
 
             # Notify main window of current frame
-            self.window.previewFrame(position_seconds, position_frames, time_code)
+            self.window.previewFrame(position_seconds, position_frames)
 
     @pyqtSlot(int)
     def movePlayhead(self, position_frames):
@@ -2818,7 +2818,7 @@ class TimelineWebView(QWebView, updates.UpdateInterface):
 
         # Find position from javascript
         self.eval_js(JS_SCOPE_SELECTOR + ".GetJavaScriptPosition(" + str(position.x()) + ");",self.store)
-        js_positoin = self.consume()
+        js_position = self.consume()
 
         # Loop through clips on the closest layer
         possible_clips = Clip.filter(layer=closest_layer)
-- 
2.20.1

(Also attached):
0001-Don-t-pass-JS-time_code-to-PyQt.patch.txt

ETA: Corrected, I was missing a chunk the first time.
ETA2: And again. I decided to include the js_positoin typo correction, because I suspect that's also part of it.

@ferdnyc
Copy link
Contributor

ferdnyc commented Jan 11, 2019

@DylanC

Perhaps the version of Qt we are using at the moment is too old. (version 5.2.1) QWebEngine didn't exist until later versions of Qt.

I'm not sure that's it... (a) I'm not sure that travis is actually using Qt 5.2.1 (the AppImage builds are, but those are still done at gitlab, maybe?); and (b) I'm pretty sure QtWebEngine existed in 5.2.1, at least in "technology preview" mode.

I'm pretty sure the issue is that QtWebEngine simply isn't installed in the travis environment. Both the QtWebKit and QtWebEngine Python modules are typically packaged separate from the rest of PyQt, and the travis environment will only have what's installed during setup. Which would be:

openshot-qt/.travis.yml

Lines 4 to 11 in 9fb791f

before_install:
- sudo add-apt-repository ppa:openshot.developers/libopenshot-daily -y
- sudo apt-get update -qq
- sudo apt-get install gcc-4.8 xvfb tar cmake libopenshot-dev libopenshot-audio-dev libunittest++-dev swig doxygen doxypy libssl-dev python3 python3-dev python3-pip python3-pyqt5 python3-setuptools python3-openshot python3-pyqt5 python3-pyqt5.qtmultimedia python3-pyqt5.qtopengl python3-pyqt5.qtsvg python3-pyqt5.qtwebkit python3-requests python3-xdg python3-zmq qttranslations5-l10n -y
- sudo apt autoremove -y
- wget https://files.pythonhosted.org/packages/d0/6d/9492644452727094543575de9846af5a2b9c764f760e2d414af7c876618c/cx_Freeze-5.0.1.tar.gz
- tar xf cx_Freeze-5.0.1.tar.gz
- cd cx_Freeze-5.0.1; python3 setup.py build; sudo python3 setup.py install; cd ..;

So I think something like python3-pyqt5.qtwebengine probably needs to be added to the apt-get install command there.

@ferdnyc
Copy link
Contributor

ferdnyc commented Jan 11, 2019

@Dotrar : If you're comfortable giving me commit access to your fork, I can commit my patch above to fix up that string-conversion issue, and try to unbreak travis for the PR. Up to you.

@ferdnyc
Copy link
Contributor

ferdnyc commented Jan 11, 2019

Well, that didn't work.

E: Unable to locate package python3-pyqt5.qtwebengine
E: Couldn't find any package by glob 'python3-pyqt5.qtwebengine'
E: Couldn't find any package by regex 'python3-pyqt5.qtwebengine'
The command "sudo apt-get install gcc-4.8 xvfb tar cmake libopenshot-dev libopenshot-audio-dev
 libunittest++-dev swig doxygen doxypy libssl-dev python3 python3-dev python3-pip python3-pyqt5
 python3-setuptools python3-openshot python3-pyqt5 python3-pyqt5.qtmultimedia
 python3-pyqt5.qtopengl python3-pyqt5.qtsvg python3-pyqt5.qtwebkit python3-pyqt5.qtwebengine
 python3-requests python3-xdg python3-zmq qttranslations5-l10n -y" failed and exited with 100
 during .
Your build has been stopped.

Hmm, there must be documentation on this environment somewhere...

@ferdnyc
Copy link
Contributor

ferdnyc commented Jan 11, 2019

Wow, you've gotta be kidding me. Not only is QtWebEngine apparently not in Ubuntu Trusty (the current build environment, which as @DylanC correctly noted is still running Qt 5.2.1), but it's apparently not in Ubuntu Xenial (Travis's newer option) either! It doesn't show up until Ubuntu Bionic (18.04)!

Presumably there's a way to add it to at least Xenial, and possibly even Trusty, via third-party PPA, but what a crapfest. #FrickinUbuntu

@ferdnyc
Copy link
Contributor

ferdnyc commented Jan 11, 2019

OK, this PPA contains Qt 5.8 for Trusty, complete with QtWebEngine — but no PyQt. Still, one step closer...

@ferdnyc
Copy link
Contributor

ferdnyc commented Jan 12, 2019

So, qutebrowser is "A keyboard-driven, vim-like browser based on PyQt5." which supports QtWebEngine and uses Travis CI.

AFAICT what they're doing is building inside a Docker image (actually, multiple docker images), including one that's based on arch (instead of any Ubuntu), and includes PyQt5.QtWebEgine. The rest don't use WebEngine, presumably because its availability on Debian/Ubuntu is so spotty and recent. "Fun!"

I had actually found, in my travels before I even learned of this, a Docker image which purports to supply "An Ubuntu Xenial based Qt 5.7 + QtWebEngine + Python 2.7 + PyQt5 container" (which is great except for the Python 2.7 part)... but it doesn't appear that there are any available builds of that container.

Anyway, I'm still exploring Docker, since I've never used it before today but now at least it's installed on my local machine.

@DylanC
Copy link
Collaborator

DylanC commented Jan 12, 2019

@ferdnyc -

Wow, you've gotta be kidding me. Not only is QtWebEngine apparently not in Ubuntu Trusty (the current build environment, which as @DylanC correctly noted is still running Qt 5.2.1), but it's apparently not in Ubuntu Xenial (Travis's newer option) either! It doesn't show up until Ubuntu Bionic (18.04)!

I found Qt 5.2.1 mentioned in the logs and I'm aware its the default for Trusty because I recently had to make my build run on Trusty for wide AppImage compatibility on my own project.

I remember during development (with my own project) I went from Qt 5.2.x to 5.12. During Qt 5.4 I was using a webkit based tool to show available updates. I remember the tool needed converting to QtWebEngine but QtWebEngine was not widely available. The dependency on this Qt web module became so annoying I just dropped it altogether.

@jonoomph
Copy link
Member

@Dotrar I've added an official branch called webengine-convert. Would you mind changing this PR to point at that branch instead of develop. This will allow me to run a bunch of tests with all our build servers, and see what breaks. 😄

@jonoomph jonoomph changed the title Webengine convert QWebkit to QWebEngine Conversion Jan 14, 2019
@jonoomph
Copy link
Member

Also, looks like we have a conflict now, since timeline_webview.py has been updated on the develop branch.

@Dotrar
Copy link
Author

Dotrar commented Jan 15, 2019

Alright, I've returned from holidays and I'll have a look at this tonight.

@Dotrar Dotrar changed the base branch from develop to webengine-convert January 15, 2019 23:32
@Dotrar
Copy link
Author

Dotrar commented Jan 16, 2019

I can't dev for the time being because of the switch over to "Settings" in #2520
can't install the latest libopenshot as it's not in the debian repos yet.
the instructions on the libopenshot build instructions are incorrect ( have to get it from git, not launchpad/bzr, among other things)
and my latest tries in compiling and installing the libopenshot results in segmentation faults for python.

@peanutbutterandcrackers
Copy link
Contributor

peanutbutterandcrackers commented Jan 16, 2019

@Dotrar - I wonder if the Daily PPA might be of some help

@Dotrar
Copy link
Author

Dotrar commented Jan 16, 2019

Ok got the PPA to work, I'll resume work on this now.

@Dotrar
Copy link
Author

Dotrar commented Jan 17, 2019

@jonoomph Thanks for the branch! :D


The latest changes to secondsToTime and etc fixed the timeline issue, so it is all working pretty great now. I renamed to the proper QWebEngineView so no one gets confused by looking at QWebView docs, fixed some of my formatting problems to try and play a little nicer in a team,


One general question: Do we really need to import qwebchannel.js into the OpenShot source? This QT help doc makes me think we don't.

the very first line of that mentions the need for the webchannel.js. but I mean, I'm not in love with the file, so if you find a way to get rid of it, by all means. It opens the WebChannel creation

logspam

The "Property XYZ" logspam is actually from the QT object. The only way to remove it, that I could think of, would be to have the TimelineWebView NOT be derived from QWebEngineView. I'm looking into this, might have to change the structure of that TimelineWebView, but ultimately it doesn't do anything, we're not trying to update the Qt properties in JS so we don't need to worry about it breaking. I'm not a wizz at "MVC" architecture but we'd be looking at making "TimelineController" instead of/alongside TimelineWebView

Async

I'm not sure if it's an issue and I'm not sure how the old way worked. Could there be issues? theoretically yes. Should we be worried? Not for the time being.

Most of the calls are very simple "get value" from the JS engine; if the JS engine takes a long time to do those, then I think there are bigger issues at play.
Currently, as far as I know, the only use of these js values are from the sequential calling within the timeline functions; Previously they waited for the result, and now we have emulated the same waiting.
The "Correct" way would probably be to make a status object that holds everything; ie: the timeline model/controller; and we just get the values willy nilly; but that is a little further down the line I believe, and quite a bit of a play around and refactoring to get that working.

Version conflicts

Part of the problem in keeping old software around is no one wants to be the first on the new version, which means things are built on older versions, and the cycle continues :P
I'm not sure what ubuntu does because I have a hard enough time with debian, and I need latest QT for some of my other work-related developments.

@ferdnyc
Copy link
Contributor

ferdnyc commented Jan 22, 2019

@Dotrar

One general question: Do we really need to import qwebchannel.js into the OpenShot source? This QT help doc makes me think we don't.

the very first line of that mentions the need for the webchannel.js. but I mean, I'm not in love with the file, so if you find a way to get rid of it, by all means. It opens the WebChannel creation

True, but I was more focused on the very next sentence, which is: "For clients run inside Qt WebEngine, you can load the file via qrc:///qtwebchannel/qwebchannel.js." 😁 (IOW, it's available in a resource file bundled with QtWebEngine.)

I'm just not totally clear on how to actually apply that in practice, since right now it's being loaded in timeline/index.html via a <script> tag, which requires a filesystem path. The qrc:/// reference can't be used in an HTML file, I guess it would... have to be applied using some Qt call that could be passed a QFile argument, maybe?

Aha! Or, from their own example code:

    QFileInfo jsFileInfo(QDir::currentPath() + "/qwebchannel.js");

    if (!jsFileInfo.exists())
        QFile::copy(":/qtwebchannel/qwebchannel.js",jsFileInfo.absoluteFilePath());

That's... pretty freakin' goofy, actually. But it would allow us to avoid including the file, and it'd mean that any updates or bugfixes in newer versions of QTWebEngine would automatically be picked up. I suppose we could copy qwebchannel.js somewhere under $HOME/.openshot_qt at startup? Or just add something to the build/packaging process that extracts qrc:///qtwebchannel/qwebchannel.js into the packaged openshot-qt tree (IFF QtWebEngine is enabled, should that become conditional), instead of keeping our own copy in the repo.

...Also, that's their "standalone" example, which runs the client in a web browser — so, the file definitely has to be available externally. We don't even want to do that. Since we DO want to run everything inside QtWebEngine, seems like there may still be a way to use the resource path directly. But the standalone example is also the only example, annoyingly... so if that is possible, it seems they're not going to make it too easy to figure out how. Anyway, I'll keep poking around. Not a big deal either way.

logspam
we're not trying to update the Qt properties in JS so we don't need to worry about it breaking.

Async
Most of the calls are very simple "get value" from the JS engine;
Currently, as far as I know, the only use of these js values are from the sequential calling within the timeline functions; Previously they waited for the result, and now we have emulated the same waiting.
The "Correct" way would probably be to make a status object that holds everything

(...Condensed to address a single set of related points)

Understood. And those are the sort of things I was getting at...

  1. That logspam feels like a hint that things aren't ideal — there may not be anything wrong with the code, but clearly there are baked-in assumptions in the WebEngine code that aren't being met. I find that when I encounter things like that, I can often use them as signposts to help guide me towards a more effective use of the code/APIs involved.
  2. As you say, "we're not trying to update the Qt properties in JS" — but, maybe we should be?
  3. "Most of the calls are very simple "get value" from the JS engine" — agreed, in fact the code devotes an inordinate amount of time to passing data back and forth between the Python and the JS, often synchronously despite how very expensive that context switch can be (especially when things start to bog down). But if the JS were connected up to properties on the Qt side, so that it could update them as needed, wouldn't it eliminate the need to do all of that data-passing? (Or, more precisely, wouldn't it just handle all of that automatically?)

It seems like, with the right properties connected up between the Python and JS sides, the data the Python side needs chould be available to it without having to query it synchronously from the JS side. And passing data to the JS side should ideally just be a matter of updating the Qt properties in Python, then firing off an async "refresh" to render the changes. No need for callbacks, no need for sync queries.

...But those are all bigger issues that don't need to be addressed in this PR, and they're all issues that very much exist in the existing QtWebKit code as well. (In fact, to some extent they probably exist because of QtWebKit.) The conversion to QtWebEngine gets us on the road to being able to address them, which is the important thing. Hopefully we can sort out availability of the module universally enough, it'd definitely be great to have. Thanks again for putting all the effort into this.

@SuslikV
Copy link
Contributor

SuslikV commented May 16, 2019

Maybe not a right place to ask, but is anybody has thoughts to make your own timeline widget in Qt? And get rid of all web viewing functions by single move? Like https://github.com/csuft/VideoTimeline (just an example!) or so?

@DylanC
Copy link
Collaborator

DylanC commented Jun 25, 2019

@SuslikV - Myself and @ferdnyc discussed this at length previously. We thought its a good idea but a large project to undertake.

@SuslikV
Copy link
Contributor

SuslikV commented Jul 1, 2019

@DylanC , do you afraid that it fails in some step? Or really it requires too much effort to spend it on the solution that will be almost not visible to end user? I understand that Timeline is like 50% of video editor success. And @jonoomph and others spent a lot of time to improve it (it still has number of bugs, but at least it works).
I hardly believe that all who made changes to the current Timeline lack skill, time or interest.

@DylanC
Copy link
Collaborator

DylanC commented Jul 16, 2019

do you afraid that it fails in some step? Or really it requires too much effort to spend it on the solution that will be almost not visible to end user? I understand that Timeline is like 50% of video editor success. And @jonoomph and others spent a lot of time to improve it (it still has number of bugs, but at least it works).

@SuslikV - Well the current solution does work. A new timeline would be far better but its hard to justify its development since it would be such a huge project of its own really. To most users all this time spent will just give them the same functionality. To more advanced users or developers its a great change for the project.

I hardly believe that all who made changes to the current Timeline lack skill, time or interest.

@SuslikV - I would say I do have the interest but I do not come from a python background, so maybe not the right skills. I have implemented changes for the project previously (for v2.4.3) but on much smaller changes.

Time is something I do lack right now though. I have a busy life at the moment and I run my own project too. As I said I am interested in this but interest without time or possibly skills wouldn't really be good enough to get it done.

@DylanC
Copy link
Collaborator

DylanC commented Jul 22, 2019

@ferdnyc - What is the status of this? Are we to reject the PR or merge in the future?

@ferdnyc
Copy link
Contributor

ferdnyc commented Jul 22, 2019

@DylanC

I'd still like to find a path other than "reject', because it's potentially very useful. We're light years away from even considering a merge, but I'd like to see it made available for more testing, and if possible by more people. I suppose there are two ways of going about that:

  1. We could merge it into a branch in the project repo, so that it can be checked out by anyone who wants to experiment with the WebEngine code. (Not that they can't do that now, directly from this PR, but... people generally don't and won't.) Actually a branch-merge is probably what we'd have to do regardless, even if we just wanted to implement my second option...
  2. We could move the QWebEngine changes from timeline_webview.py to their own timeline_webengineview.py or whatever copy of the timeline code, as that's the only file that requires major modification in this PR. All the rest of the changes here are minor and would be easy enough to incorporate into the current code without breaking WebKit support via a few well-placed if info.USE_WEBENGINE: type conditionals. Then it'd be possible for people to choose between the two right within the develop branch.

My only reluctance with the first option would be closing off @Dotrar 's ability to commit further changes to the branch. But it's been long enough since the last activity that I doubt that'll be a problem, and further changes can always be submitted by PR against the new branch anyway. (Which certainly would not suffer the same limbo-state delays we've subjected this PR to for several months, now, and my apologies to @Dotrar for that. Any future PRs against a topic branch could pretty much be rubber-stamp merged, since there's no effect on the main OpenShot build stability.) Scratch that, I see Dotrar's fork has been deleted so that's no longer a concern.

The first option would also potentially enable @jonoomph to set up an additional Daily Build stream for the code on that branch, if it ever progressed that far — you know, assuming we ever managed to successfully convince the CI farm to build it in the first place. (Baby steps.)

The second option would require that we keep the two timeline_fooview.py files in sync when changes are made to either of them, which is not the most attractive proposition and means it's probably a bad idea. The first option requires us to keep the entire branch in sync with every change made to develop, which isn't fun either even with git helping out doing merges... but it's still probably the less terrible option.

I still just think there's good stuff here that I'd hate to reject outright, but at the same time committing to a switch from QtWebKit to QtWebEngine isn't even on the horizon, when we're still not even able to build OpenShot with it on all of our build platforms, currently.

Oh, and then there are other things, like this from a while back in the conversation:

The spots to worry about, if I'm understanding correctly, would be the ones where JavaScript passes the results of secondsToTime OUT to a PyQt function. The only one I've found so far is here:

// Update GUI with position (to the preview can be updated)
if ($scope.Qt) {
timeline.PlayheadMoved(position_seconds, frame, secondsToTime(position_seconds, $scope.project.fps.num, $scope.project.fps.den));
}

That third argument becomes time_code in PlayheadMoved():

@pyqtSlot(float, int, str)
def PlayheadMoved(self, position_seconds, position_frames, time_code):
# Load the timeline into the Player (ignored if this has already happened)
self.window.LoadFileSignal.emit('')
if self.last_position_frames != position_frames:
# Update time code (to prevent duplicate previews)
self.last_position_frames = position_frames
# Notify main window of current frame
self.window.previewFrame(position_seconds, position_frames, time_code)

But here's the thing: As far as I can tell, time_code is NEVER used anywhere in the code. It's not used in PlayheadMoved(), and it's not used after it's passed to previewFrame(). So, it may be possible to just remove that argument entirely, and if that's the only reason that the result of JS secondsToTime had to be converted .toString() then that may not be necessary.

(In fact, position_seconds is never used either, in the current code. The only argument there that's ever consumed is position_frames.)

I just checked, and that's all still true, and I have no idea why I never bothered to submit a patch to the main repo removing those arguments. They're totally unnecessary, so why would we keep passing them back and forth for no reason? So, I'll put that PR together now, as it makes sense independent of anything to do with this PR.

...As far as this PR goes, given that the requesting branch no longer exists in GitHub I guess we should really consider it withdrawn.

@ferdnyc
Copy link
Contributor

ferdnyc commented Jul 22, 2019

Maybe not a right place to ask, but is anybody has thoughts to make your own timeline widget in Qt? And get rid of all web viewing functions by single move? Like https://github.com/csuft/VideoTimeline (just an example!) or so?

It's funny you should mention that, as the widget in question is implemented (in its v2 form) as C++ Qt code with a QML chaser. In other words, in a mix of C++ and JavaScript.

There's really no getting away from web-based rendering even in desktop applications, anymore. (Similarly, Gnome Shell leans heavily on a JavaScript engine for its interface.) It's just a question of different approaches towards integrating the web-based components with the rest of the toolkit. Qt's first two versions of that integration were QWebKit and QWebEngine, and that evolved into their third-generation web based platform QML. (Actually, QML initially evolved alongside them. So we're probably in at least the fourth generation, by now.)

The impression I get is that QML is a very natural fit with Qt's native language(s), QtQuick and C++ (which that timeline widget is written in), so it's a no brainer using it there.

I'm less sure how well it integrates with Python and PyQt. Riverbank assure us that it works "in exactly the same way", but sound suspiciously like a used car salesman when doing so. (I mean, it only takes them 6 bullet points before they've backpedaled so far that they insert this scary-admonition box):

Note: The PyQt support for QML requires knowledge of the internals of the C++ code that implements QML. This can (and does) change between Qt versions and may mean that some features only work with specific Qt versions and may not work at all with some future version of Qt.

And the caveats get progressively more scary as you make your way down the rest of that page.

As @DylanC said, it's something we've discussed at length in the past. (#1864) However, it never progressed beyond discussions, because as he said the current code is working and replacing it would be a massive task. (I also suspect that the undertaking is assumed to have guaranteed benefits in terms of speed or stability, that in reality would neither be as significant nor as easily achievable as people imagine.)

Speaking only for myself, it's a moot point because I'm not currently open to undertaking a project of that magnitude. But, feel free.

@SuslikV
Copy link
Contributor

SuslikV commented Jul 22, 2019

@ferdnyc Only you may think to use someones code in this project... I said JUST AN EXAMPLE!!! If you can't write your own widgets in Qt - you shouldn't modify this part of OpenShot completely. The idea behind this was exactly to get rid of the QT5MULTIMEDIA.DLL QT5NETWORK.DLL QT5POSITIONING.DLL QT5QML.DLL QT5QUICK.DLL QT5SENSORS.DLL QT5WEBCHANNEL.DLL - that is only required for QT5WEBKIT.DLL and QT5MULTIMEDIAWIDGETS.DLL QT5OPENGL.DLL QT5PRINTSUPPORT.DLL - that is only required for QT5WEBKITWIDGETS.DLL as part of webkit. The only needed libs of Qt is QT5WIDGETS.DLL QT5GUI.DLL QT5CORE.DLL and QT5SVG.DLL (optional). The info is based on Qt 5.12.3 build for MSYS2, Windows.

@ferdnyc
Copy link
Contributor

ferdnyc commented Jul 24, 2019

@SuslikV I realize the code was "JUST AN EXAMPLE!!!" — and as I pointed out, it was an example of a JavaScript-based, QML-and-C++ widget, a very common structure in recent Qt development.

The idea behind this was exactly to get rid of the QT5MULTIMEDIA.DLL QT5NETWORK.DLL QT5POSITIONING.DLL QT5QML.DLL QT5QUICK.DLL QT5SENSORS.DLL QT5WEBCHANNEL.DLL - that is only required for QT5WEBKIT.DLL

and QT5MULTIMEDIAWIDGETS.DLL QT5OPENGL.DLL QT5PRINTSUPPORT.DLL - that is only required for QT5WEBKITWIDGETS.DLL as part of webkit.

That is all incorrect. Most of those libraries are required for any Qt GUI development, they are not specific to Qt5WebKit or Qt5WebKitWidgets at all.

The only needed libs of Qt is QT5WIDGETS.DLL QT5GUI.DLL QT5CORE.DLL and QT5SVG.DLL (optional).

Again, simply not correct.

@ferdnyc
Copy link
Contributor

ferdnyc commented Jul 24, 2019

@SuslikV I do not think that you and I should have any further discussions regarding application development. They are not productive for either side.

@ferdnyc
Copy link
Contributor

ferdnyc commented Jul 24, 2019

Closing this as withdrawn, with the original source repo deleted and nobody to work on it, it's unlikely to progress.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants