28
28
"""
29
29
30
30
import os
31
- import sys
32
31
import time
33
32
from copy import deepcopy
34
33
from functools import partial
35
34
from random import uniform
36
- from urllib .parse import urlparse
37
35
from operator import itemgetter
38
36
39
37
import openshot # Python module for libopenshot (required video editing module installed separately)
@@ -181,7 +179,7 @@ def eval_js(self, code, retries=0):
181
179
# Not ready, try again in a few milliseconds
182
180
if retries > 1 :
183
181
log .warning ("TimelineWebView::eval_js() called before document ready event. Script queued: %s" % code )
184
- QTimer .singleShot (100 , partial (self .eval_js , code , retries + 1 ))
182
+ QTimer .singleShot (100 , partial (self .eval_js , code , retries + 1 ))
185
183
return None
186
184
else :
187
185
# Execute JS code
@@ -228,7 +226,7 @@ def update_clip_data(self, clip_json, only_basic_props=True, ignore_reader=False
228
226
clip_data = json .loads (clip_json )
229
227
else :
230
228
clip_data = clip_json
231
- except :
229
+ except Exception :
232
230
# Failed to parse json, do nothing
233
231
return
234
232
@@ -250,7 +248,8 @@ def update_clip_data(self, clip_json, only_basic_props=True, ignore_reader=False
250
248
existing_clip .data ["start" ] = clip_data ["start" ]
251
249
existing_clip .data ["end" ] = clip_data ["end" ]
252
250
253
- # Always remove the Reader attribute (since nothing updates it, and we are wrapping clips in FrameMappers anyway)
251
+ # Always remove the Reader attribute (since nothing updates it,
252
+ # and we are wrapping clips in FrameMappers anyway)
254
253
if ignore_reader and "reader" in existing_clip .data :
255
254
existing_clip .data .pop ("reader" )
256
255
@@ -576,7 +575,6 @@ def ShowClipMenu(self, clip_id=None):
576
575
Fade_Menu .addMenu (Position_Menu )
577
576
menu .addMenu (Fade_Menu )
578
577
579
-
580
578
# Animate Menu
581
579
Animate_Menu = QMenu (_ ("Animate" ), self )
582
580
Animate_None = Animate_Menu .addAction (_ ("No Animation" ))
@@ -828,7 +826,7 @@ def ShowClipMenu(self, clip_id=None):
828
826
return menu .popup (QCursor .pos ())
829
827
830
828
def Transform_Triggered (self , action , clip_ids ):
831
- print ("Transform_Triggered" )
829
+ log . info ("Transform_Triggered" )
832
830
833
831
# Emit signal to transform this clip (for the 1st clip id)
834
832
if clip_ids :
@@ -930,9 +928,9 @@ def Split_Audio_Triggered(self, action, clip_ids):
930
928
all_tracks = get_app ().project .get ("layers" )
931
929
932
930
# Clear audio override
933
- p = openshot .Point (1 , - 1.0 , openshot .CONSTANT ) # Override has_audio keyframe to False
931
+ p = openshot .Point (1 , - 1.0 , openshot .CONSTANT ) # Override has_audio keyframe to False
934
932
p_object = json .loads (p .Json ())
935
- clip .data ["has_audio" ] = { "Points" : [p_object ]}
933
+ clip .data ["has_audio" ] = {"Points" : [p_object ]}
936
934
937
935
# Remove the ID property from the clip (so it becomes a new one)
938
936
clip .id = None
@@ -947,12 +945,12 @@ def Split_Audio_Triggered(self, action, clip_ids):
947
945
# Clear channel filter on new clip
948
946
p = openshot .Point (1 , - 1.0 , openshot .CONSTANT )
949
947
p_object = json .loads (p .Json ())
950
- clip .data ["channel_filter" ] = { "Points" : [p_object ]}
948
+ clip .data ["channel_filter" ] = {"Points" : [p_object ]}
951
949
952
950
# Filter out video on the new clip
953
- p = openshot .Point (1 , 0.0 , openshot .CONSTANT ) # Override has_video keyframe to False
951
+ p = openshot .Point (1 , 0.0 , openshot .CONSTANT ) # Override has_video keyframe to False
954
952
p_object = json .loads (p .Json ())
955
- clip .data ["has_video" ] = { "Points" : [p_object ]}
953
+ clip .data ["has_video" ] = {"Points" : [p_object ]}
956
954
# Also set scale to None
957
955
# Workaround for https://github.com/OpenShot/openshot-qt/issues/2882
958
956
clip .data ["scale" ] = openshot .SCALE_NONE
@@ -969,7 +967,7 @@ def Split_Audio_Triggered(self, action, clip_ids):
969
967
continue
970
968
971
969
# Adjust the layer, so this new audio clip doesn't overlap the parent
972
- clip .data ['layer' ] = next_track_number # Add to layer below clip
970
+ clip .data ['layer' ] = next_track_number # Add to layer below clip
973
971
974
972
# Adjust the clip title
975
973
channel_label = _ ("(all channels)" )
@@ -992,12 +990,12 @@ def Split_Audio_Triggered(self, action, clip_ids):
992
990
# Each clip is filtered to a different channel
993
991
p = openshot .Point (1 , channel , openshot .CONSTANT )
994
992
p_object = json .loads (p .Json ())
995
- clip .data ["channel_filter" ] = { "Points" : [p_object ]}
993
+ clip .data ["channel_filter" ] = {"Points" : [p_object ]}
996
994
997
995
# Filter out video on the new clip
998
- p = openshot .Point (1 , 0.0 , openshot .CONSTANT ) # Override has_video keyframe to False
996
+ p = openshot .Point (1 , 0.0 , openshot .CONSTANT ) # Override has_video keyframe to False
999
997
p_object = json .loads (p .Json ())
1000
- clip .data ["has_video" ] = { "Points" : [p_object ]}
998
+ clip .data ["has_video" ] = {"Points" : [p_object ]}
1001
999
# Also set scale to None
1002
1000
# Workaround for https://github.com/OpenShot/openshot-qt/issues/2882
1003
1001
clip .data ["scale" ] = openshot .SCALE_NONE
@@ -1014,7 +1012,7 @@ def Split_Audio_Triggered(self, action, clip_ids):
1014
1012
continue
1015
1013
1016
1014
# Adjust the layer, so this new audio clip doesn't overlap the parent
1017
- clip .data ['layer' ] = max (next_track_number , 0 ) # Add to layer below clip
1015
+ clip .data ['layer' ] = max (next_track_number , 0 ) # Add to layer below clip
1018
1016
1019
1017
# Adjust the clip title
1020
1018
channel_label = _ ("(channel %s)" ) % (channel + 1 )
@@ -1041,9 +1039,9 @@ def Split_Audio_Triggered(self, action, clip_ids):
1041
1039
continue
1042
1040
1043
1041
# Filter out audio on the original clip
1044
- p = openshot .Point (1 , 0.0 , openshot .CONSTANT ) # Override has_audio keyframe to False
1042
+ p = openshot .Point (1 , 0.0 , openshot .CONSTANT ) # Override has_audio keyframe to False
1045
1043
p_object = json .loads (p .Json ())
1046
- clip .data ["has_audio" ] = { "Points" : [p_object ]}
1044
+ clip .data ["has_audio" ] = {"Points" : [p_object ]}
1047
1045
1048
1046
# Save filter on original clip
1049
1047
self .update_clip_data (clip .data , only_basic_props = False , ignore_reader = True )
@@ -1082,36 +1080,35 @@ def Layout_Triggered(self, action, clip_ids):
1082
1080
# Clear scale keyframes
1083
1081
p = openshot .Point (1 , 1.0 , openshot .BEZIER )
1084
1082
p_object = json .loads (p .Json ())
1085
- clip .data ["scale_x" ] = { "Points" : [p_object ]}
1086
- clip .data ["scale_y" ] = { "Points" : [p_object ]}
1083
+ clip .data ["scale_x" ] = {"Points" : [p_object ]}
1084
+ clip .data ["scale_y" ] = {"Points" : [p_object ]}
1087
1085
1088
1086
# Clear location keyframes
1089
1087
p = openshot .Point (1 , 0.0 , openshot .BEZIER )
1090
1088
p_object = json .loads (p .Json ())
1091
- clip .data ["location_x" ] = { "Points" : [p_object ]}
1092
- clip .data ["location_y" ] = { "Points" : [p_object ]}
1089
+ clip .data ["location_x" ] = {"Points" : [p_object ]}
1090
+ clip .data ["location_y" ] = {"Points" : [p_object ]}
1093
1091
1094
1092
if action == MENU_LAYOUT_CENTER or \
1095
- action == MENU_LAYOUT_TOP_LEFT or \
1096
- action == MENU_LAYOUT_TOP_RIGHT or \
1097
- action == MENU_LAYOUT_BOTTOM_LEFT or \
1098
- action == MENU_LAYOUT_BOTTOM_RIGHT :
1093
+ action == MENU_LAYOUT_TOP_LEFT or \
1094
+ action == MENU_LAYOUT_TOP_RIGHT or \
1095
+ action == MENU_LAYOUT_BOTTOM_LEFT or \
1096
+ action == MENU_LAYOUT_BOTTOM_RIGHT :
1099
1097
# Reset scale mode
1100
1098
clip .data ["scale" ] = openshot .SCALE_FIT
1101
1099
clip .data ["gravity" ] = new_gravity
1102
1100
1103
1101
# Add scale keyframes
1104
1102
p = openshot .Point (1 , 0.5 , openshot .BEZIER )
1105
1103
p_object = json .loads (p .Json ())
1106
- clip .data ["scale_x" ] = { "Points" : [p_object ]}
1107
- clip .data ["scale_y" ] = { "Points" : [p_object ]}
1104
+ clip .data ["scale_x" ] = {"Points" : [p_object ]}
1105
+ clip .data ["scale_y" ] = {"Points" : [p_object ]}
1108
1106
1109
1107
# Add location keyframes
1110
1108
p = openshot .Point (1 , 0.0 , openshot .BEZIER )
1111
1109
p_object = json .loads (p .Json ())
1112
- clip .data ["location_x" ] = { "Points" : [p_object ]}
1113
- clip .data ["location_y" ] = { "Points" : [p_object ]}
1114
-
1110
+ clip .data ["location_x" ] = {"Points" : [p_object ]}
1111
+ clip .data ["location_y" ] = {"Points" : [p_object ]}
1115
1112
1116
1113
if action == MENU_LAYOUT_ALL_WITH_ASPECT :
1117
1114
# Update all intersecting clips
@@ -1452,7 +1449,7 @@ def Paste_Triggered(self, action, position, layer_id, clip_ids, tran_ids):
1452
1449
continue
1453
1450
1454
1451
# Apply clipboard to clip (there should only be a single key in this dict)
1455
- for k ,v in self .copy_clipboard [list (self .copy_clipboard )[0 ]].items ():
1452
+ for k , v in self .copy_clipboard [list (self .copy_clipboard )[0 ]].items ():
1456
1453
if k != 'id' :
1457
1454
# Overwrite clips properties (which are in the clipboard)
1458
1455
clip .data [k ] = v
@@ -1489,9 +1486,9 @@ def Nudge_Triggered(self, action, clip_ids, tran_ids):
1489
1486
fps = get_app ().project .get ("fps" )
1490
1487
fps_float = float (fps ["num" ]) / float (fps ["den" ])
1491
1488
nudgeDistance = float (action ) / float (fps_float )
1492
- nudgeDistance /= 2.0 # 1/2 frame
1489
+ nudgeDistance /= 2.0 # 1/2 frame
1493
1490
if abs (nudgeDistance ) < 0.01 :
1494
- nudgeDistance = 0.01 * action # nudge is less than the minimum of +/- 0.01s
1491
+ nudgeDistance = 0.01 * action # nudge is less than the minimum of +/- 0.01s
1495
1492
log .info ("Nudging by %s sec" % nudgeDistance )
1496
1493
1497
1494
# Loop through each selected clip (find furthest left and right edge)
@@ -1566,7 +1563,6 @@ def Nudge_Triggered(self, action, clip_ids, tran_ids):
1566
1563
# Save changes
1567
1564
self .update_transition_data (tran .data , only_basic_props = False )
1568
1565
1569
-
1570
1566
def Align_Triggered (self , action , clip_ids , tran_ids ):
1571
1567
"""Callback for alignment context menus"""
1572
1568
log .info (action )
@@ -1608,7 +1604,6 @@ def Align_Triggered(self, action, clip_ids, tran_ids):
1608
1604
if position + (end_of_tran - start_of_tran ) > right_edge or right_edge == - 1.0 :
1609
1605
right_edge = position + (end_of_tran - start_of_tran )
1610
1606
1611
-
1612
1607
# Loop through each selected clip (update position to align clips)
1613
1608
for clip_id in clip_ids :
1614
1609
# Get existing clip object
@@ -1985,10 +1980,6 @@ def Rotate_Triggered(self, action, clip_ids, position="Start of Clip"):
1985
1980
log .info (action )
1986
1981
prop_name = "rotation"
1987
1982
1988
- # Get FPS from project
1989
- fps = get_app ().project .get ("fps" )
1990
- fps_float = float (fps ["num" ]) / float (fps ["den" ])
1991
-
1992
1983
# Loop through each selected clip
1993
1984
for clip_id in clip_ids :
1994
1985
@@ -2036,9 +2027,9 @@ def Time_Triggered(self, action, clip_ids, speed="1X", playhead_position=0.0):
2036
2027
2037
2028
# Loop through each selected clip
2038
2029
for clip_id in clip_ids :
2039
-
2040
2030
# Get existing clip object
2041
2031
clip = Clip .get (id = clip_id )
2032
+
2042
2033
if not clip :
2043
2034
# Invalid clip, skip to next item
2044
2035
continue
@@ -2061,16 +2052,15 @@ def Time_Triggered(self, action, clip_ids, speed="1X", playhead_position=0.0):
2061
2052
if "original_data" in clip .data .keys ():
2062
2053
original_duration = clip .data ["original_data" ]["duration" ]
2063
2054
2064
- print ('ORIGINAL DURATION: %s' % original_duration )
2065
- print (clip .data )
2055
+ log . info ('ORIGINAL DURATION: %s' % original_duration )
2056
+ log . info (clip .data )
2066
2057
2067
2058
# Extend end & duration (due to freeze)
2068
2059
clip .data ["end" ] = float (clip .data ["end" ]) + freeze_seconds
2069
2060
clip .data ["duration" ] = float (clip .data ["duration" ]) + freeze_seconds
2070
2061
clip .data ["reader" ]["video_length" ] = float (clip .data ["reader" ]["video_length" ]) + freeze_seconds
2071
2062
2072
2063
# Determine start frame from position
2073
- freeze_length_frames = round (freeze_seconds * fps_float ) + 1
2074
2064
start_animation_seconds = float (clip .data ["start" ]) + (playhead_position - float (clip .data ["position" ]))
2075
2065
start_animation_frames = round (start_animation_seconds * fps_float ) + 1
2076
2066
start_animation_frames_value = start_animation_frames
@@ -2178,7 +2168,7 @@ def Time_Triggered(self, action, clip_ids, speed="1X", playhead_position=0.0):
2178
2168
# Clear all keyframes
2179
2169
p = openshot .Point (start_animation , 0.0 , openshot .LINEAR )
2180
2170
p_object = json .loads (p .Json ())
2181
- clip .data [prop_name ] = { "Points" : [p_object ]}
2171
+ clip .data ['time' ] = {"Points" : [p_object ]}
2182
2172
2183
2173
# Get the ending frame
2184
2174
end_of_clip = round (float (clip .data ["end" ]) * fps_float ) + 1
@@ -2264,44 +2254,45 @@ def show_all_clips(self, clip, stretch=False):
2264
2254
for row in range (0 , number_of_rows ):
2265
2255
2266
2256
# Loop through clips on this row
2267
- column_string = " - - - "
2268
2257
for col in range (0 , max_clips_on_row ):
2269
- if clip_index < number_of_clips :
2270
- # Calculate X & Y
2271
- X = float (col ) * width
2272
- Y = float (row ) * height
2273
-
2274
- # Modify clip layout settings
2275
- selected_clip = available_clips [clip_index ]
2276
- selected_clip .data ["gravity" ] = openshot .GRAVITY_TOP_LEFT
2277
-
2278
- if stretch :
2279
- selected_clip .data ["scale" ] = openshot .SCALE_STRETCH
2280
- else :
2281
- selected_clip .data ["scale" ] = openshot .SCALE_FIT
2282
-
2283
- # Set scale keyframes
2284
- w = openshot .Point (1 , width , openshot .BEZIER )
2285
- w_object = json .loads (w .Json ())
2286
- selected_clip .data ["scale_x" ] = { "Points" : [w_object ]}
2287
- h = openshot .Point (1 , height , openshot .BEZIER )
2288
- h_object = json .loads (h .Json ())
2289
- selected_clip .data ["scale_y" ] = { "Points" : [h_object ]}
2290
- x_point = openshot .Point (1 , X , openshot .BEZIER )
2291
- x_object = json .loads (x_point .Json ())
2292
- selected_clip .data ["location_x" ] = { "Points" : [x_object ]}
2293
- y_point = openshot .Point (1 , Y , openshot .BEZIER )
2294
- y_object = json .loads (y_point .Json ())
2295
- selected_clip .data ["location_y" ] = { "Points" : [y_object ]}
2296
-
2297
- log .info ('Updating clip id: %s' % selected_clip .data ["id" ])
2298
- log .info ('width: %s, height: %s' % (width , height ))
2299
-
2300
- # Increment Clip Index
2301
- clip_index += 1
2258
+ if clip_index >= number_of_clips :
2259
+ continue
2302
2260
2303
- # Save changes
2304
- self .update_clip_data (selected_clip .data , only_basic_props = False , ignore_reader = True )
2261
+ # Calculate X & Y
2262
+ X = float (col ) * width
2263
+ Y = float (row ) * height
2264
+
2265
+ # Modify clip layout settings
2266
+ selected_clip = available_clips [clip_index ]
2267
+ selected_clip .data ["gravity" ] = openshot .GRAVITY_TOP_LEFT
2268
+
2269
+ if stretch :
2270
+ selected_clip .data ["scale" ] = openshot .SCALE_STRETCH
2271
+ else :
2272
+ selected_clip .data ["scale" ] = openshot .SCALE_FIT
2273
+
2274
+ # Set scale keyframes
2275
+ w = openshot .Point (1 , width , openshot .BEZIER )
2276
+ w_object = json .loads (w .Json ())
2277
+ selected_clip .data ["scale_x" ] = {"Points" : [w_object ]}
2278
+ h = openshot .Point (1 , height , openshot .BEZIER )
2279
+ h_object = json .loads (h .Json ())
2280
+ selected_clip .data ["scale_y" ] = {"Points" : [h_object ]}
2281
+ x_point = openshot .Point (1 , X , openshot .BEZIER )
2282
+ x_object = json .loads (x_point .Json ())
2283
+ selected_clip .data ["location_x" ] = {"Points" : [x_object ]}
2284
+ y_point = openshot .Point (1 , Y , openshot .BEZIER )
2285
+ y_object = json .loads (y_point .Json ())
2286
+ selected_clip .data ["location_y" ] = {"Points" : [y_object ]}
2287
+
2288
+ log .info ('Updating clip id: %s' % selected_clip .data ["id" ])
2289
+ log .info ('width: %s, height: %s' % (width , height ))
2290
+
2291
+ # Increment Clip Index
2292
+ clip_index += 1
2293
+
2294
+ # Save changes
2295
+ self .update_clip_data (selected_clip .data , only_basic_props = False , ignore_reader = True )
2305
2296
2306
2297
def Reverse_Transition_Triggered (self , tran_ids ):
2307
2298
"""Callback for reversing a transition"""
@@ -2520,7 +2511,7 @@ def movePlayhead(self, position_frames):
2520
2511
def centerOnPlayhead (self ):
2521
2512
""" Center the timeline on the current playhead position """
2522
2513
# Execute JavaScript to center the timeline
2523
- cmd = JS_SCOPE_SELECTOR + '.centerOnPlayhead();' ;
2514
+ cmd = JS_SCOPE_SELECTOR + '.centerOnPlayhead();'
2524
2515
self .eval_js (cmd )
2525
2516
2526
2517
@pyqtSlot (int )
@@ -2660,9 +2651,6 @@ def dragEnterEvent(self, event):
2660
2651
# Add Clip
2661
2652
def addClip (self , data , position ):
2662
2653
2663
- # Get app object
2664
- app = get_app ()
2665
-
2666
2654
# Search for matching file in project data (if any)
2667
2655
file_id = data [0 ]
2668
2656
file = File .get (id = file_id )
@@ -2671,13 +2659,6 @@ def addClip(self, data, position):
2671
2659
# File not found, do nothing
2672
2660
return
2673
2661
2674
- if (file .data ["media_type" ] == "video" or file .data ["media_type" ] == "image" ):
2675
- # Determine thumb path
2676
- thumb_path = os .path .join (info .THUMBNAIL_PATH , "%s.png" % file .data ["id" ])
2677
- else :
2678
- # Audio file
2679
- thumb_path = os .path .join (info .PATH , "images" , "AudioThumbnail.png" )
2680
-
2681
2662
# Get file name
2682
2663
filename = os .path .basename (file .data ["path" ])
2683
2664
@@ -2698,8 +2679,6 @@ def addClip(self, data, position):
2698
2679
return # Do nothing
2699
2680
2700
2681
# Check for optional start and end attributes
2701
- start_frame = 1
2702
- end_frame = new_clip ["reader" ]["duration" ]
2703
2682
if 'start' in file .data .keys ():
2704
2683
new_clip ["start" ] = file .data ['start' ]
2705
2684
if 'end' in file .data .keys ():
0 commit comments