1
# ##### BEGIN GPL LICENSE BLOCK #####
3
# This program is free software; you can redistribute it and/or
4
# modify it under the terms of the GNU General Public License
5
# as published by the Free Software Foundation; either version 2
6
# of the License, or (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software Foundation,
15
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
# ##### END GPL LICENSE BLOCK #####
23
"author": "Campbell Barton",
25
"blender": (2, 65, 0),
26
"location": "Sequencer -> Track View Properties",
27
"description": "Load a CMX formatted EDL into the sequencer",
29
"wiki_url": "http://wiki.blender.org/index.php/Extensions:"
30
"2.6/Py/Scripts/Import-Export/EDL_Import",
32
"category": "Import-Export"}
37
# ImportHelper is a helper class, defines filename and
38
# invoke() function which calls the file selector.
39
from bpy_extras.io_utils import ImportHelper
40
from bpy.props import (StringProperty,
45
from bpy.types import Operator
47
# ----------------------------------------------------------------------------
51
class ReloadEDL(Operator):
52
bl_idname = "sequencer.import_edl_refresh"
53
bl_label = "Refresh Reels"
55
def execute(self, context):
57
from . import parse_edl
60
edl_import_info = scene.edl_import_info
62
filepath = edl_import_info.filepath
65
if not os.path.exists(filepath):
66
self.report({'ERROR'}, "File Not Found %r" % filepath)
69
elist = parse_edl.EditList()
70
if not elist.parse(filepath, dummy_fps):
71
self.report({'ERROR'}, "Failed to parse EDL %r" % filepath)
75
edl_import_info = scene.edl_import_info
76
bl_reels = edl_import_info.reels
78
data_prev = {reel.name: (reel.filepath, reel.frame_offset)
79
for reel in edl_import_info.reels}
81
reels = elist.reels_as_dict()
82
reels = [k for k in reels.keys() if k not in parse_edl.BLACK_ID]
84
# re-create reels collection, keeping old values
86
for k in sorted(reels):
89
filepath, frame_offset = data_prev.get(k, (None, None))
90
if filepath is not None:
91
reel.filepath = filepath
92
reel.frame_offset = frame_offset
97
class FindReelsEDL(Operator):
98
"""Scan a path for missing reel files, """ \
99
""" Matching by reel name and existing filename when set"""
100
bl_idname = "sequencer.import_edl_findreel"
101
bl_label = "Find Missing Reel Files"
102
directory = StringProperty(
107
def missing_reels(context):
109
scene = context.scene
110
edl_import_info = scene.edl_import_info
111
return [reel for reel in edl_import_info.reels
112
if not os.path.exists(reel.filepath)]
114
def execute(self, context):
117
# walk over .avi, .mov, .wav etc.
118
def media_file_walker(path):
119
ext_check = bpy.path.extensions_movie | bpy.path.extensions_audio
120
for dirpath, dirnames, filenames in os.walk(path):
122
if dirpath.startswith("."):
124
for filename in filenames:
125
fileonly, ext = os.path.splitext(filename)
126
ext_lower = ext.lower()
127
if ext_lower in ext_check:
128
yield os.path.join(dirpath, filename), fileonly
130
scene = context.scene
131
edl_import_info = scene.edl_import_info
133
bl_reels = FindReelsEDL.missing_reels(context)
134
assert(len(bl_reels))
136
# Search is as follows
137
# Each reel has a triple:
138
# ([search_names, ...], [(priority, found_file), ...], bl_reel)
139
bl_reels_search = [(set(), [], reel) for reel in bl_reels]
141
# first get the search names...
142
for reel_names, reel_files_found, reel in bl_reels_search:
144
reel_names_list.append(reel.name.lower())
146
# add non-extension version of the reel name
147
if "." in reel_names_list[-1]:
148
reel_names_list.append(os.path.splitext(reel_names_list[-1])[0])
150
# use the filepath if set
151
reel_filepath = reel.filepath
153
reel_filepath = os.path.basename(reel_filepath)
154
reel_filepath = os.path.splitext(reel_filepath)[0]
155
reel_names_list.append(reel_filepath.lower())
157
# when '_' are found, replace with space
158
reel_names_list += [reel_filepath.replace("_", " ")
159
for reel_filepath in reel_names_list
160
if "_" in reel_filepath]
161
reel_names.update(reel_names_list)
164
print("Searching or %d reels" % len(bl_reels_search))
165
for reel_names, reel_files_found, reel in bl_reels_search:
166
print("Reel: %r --> (%s)" % (reel.name, " ".join(sorted(reel_names))))
169
for filename, fileonly in media_file_walker(self.directory):
170
for reel_names, reel_files_found, reel in bl_reels_search:
171
if fileonly.lower() in reel_names:
172
reel_files_found.append((0, filename))
174
# check on partial match
176
if fileonly.startswith(r):
177
reel_files_found.append((1, filename))
178
if fileonly.endswith(r):
179
reel_files_found.append((2, filename))
181
# apply back and report
184
for reel_names, reel_files_found, reel in bl_reels_search:
186
# make sure partial matches end last
187
reel_files_found.sort()
188
reel.filepath = reel_files_found[0][1]
193
self.report({'INFO'} if tot_fail == 0 else {'WARNING'},
194
"Found %d clips, missing %d" % (tot_done, tot_fail))
198
def invoke(self, context, event):
200
scene = context.scene
201
edl_import_info = scene.edl_import_info
203
if not FindReelsEDL.missing_reels(context):
204
self.report({'INFO'},
205
"Nothing to do, all reels point to valid files")
208
# default to the EDL path
209
if not self.directory and edl_import_info.filepath:
210
self.directory = os.path.dirname(edl_import_info.filepath)
212
wm = context.window_manager
213
wm.fileselect_add(self)
214
return {"RUNNING_MODAL"}
217
class ImportEDL(Operator):
218
"""Import an EDL into the sequencer"""
219
bl_idname = "sequencer.import_edl"
220
bl_label = "Import Video Sequence (.edl)"
222
def execute(self, context):
224
from . import import_edl
225
scene = context.scene
226
edl_import_info = scene.edl_import_info
228
filepath = edl_import_info.filepath
229
reel_filepaths = {reel.name: reel.filepath
230
for reel in edl_import_info.reels}
231
reel_offsets = {reel.name: reel.frame_offset
232
for reel in edl_import_info.reels}
234
if not os.path.exists(filepath):
235
self.report({'ERROR'}, "File Not Found %r" % filepath)
238
msg = import_edl.load_edl(
240
reel_filepaths, reel_offsets,
241
edl_import_info.frame_offset)
244
self.report({'WARNING'}, msg)
249
# ----------------------------------------------------------------------------
250
# Persistent Scene Data Types (store EDL import info)
252
class EDLReelInfo(bpy.types.PropertyGroup):
253
name = StringProperty(
256
filepath = StringProperty(
260
frame_offset = IntProperty(
265
class EDLImportInfo(bpy.types.PropertyGroup):
266
filepath = StringProperty(
269
reels = bpy.props.CollectionProperty(
272
frame_offset = IntProperty(
273
name="Global Frame Offset",
276
# ----------------------------------------------------------------------------
277
# Panel to show EDL Import UI
280
class SEQUENCER_PT_import_edl(bpy.types.Panel):
281
bl_label = "EDL Import"
282
bl_space_type = 'SEQUENCE_EDITOR'
283
bl_region_type = 'UI'
285
def draw(self, context):
288
scene = context.scene
289
edl_import_info = scene.edl_import_info
291
layout.operator(ImportEDL.bl_idname)
293
col = layout.column(align=True)
294
col.prop(edl_import_info, "frame_offset")
295
col.prop(edl_import_info, "filepath", text="")
296
col.operator(ReloadEDL.bl_idname, icon='FILE_REFRESH')
300
for reel in scene.edl_import_info.reels:
301
col = box.column(align=True)
302
col.label(text=reel.name)
303
col.prop(reel, "filepath", text="")
304
col.prop(reel, "frame_offset")
307
box.label("Empty (No EDL Data)")
309
box.operator(FindReelsEDL.bl_idname, icon='EXTERNAL_DATA')
313
bpy.utils.register_class(ReloadEDL)
314
bpy.utils.register_class(FindReelsEDL)
315
bpy.utils.register_class(ImportEDL)
316
bpy.utils.register_class(SEQUENCER_PT_import_edl)
319
bpy.utils.register_class(EDLReelInfo)
320
bpy.utils.register_class(EDLImportInfo)
321
bpy.types.Scene.edl_import_info = PointerProperty(type=EDLImportInfo)
325
bpy.utils.unregister_class(ReloadEDL)
326
bpy.utils.unregister_class(FindReelsEDL)
327
bpy.utils.unregister_class(ImportEDL)
328
bpy.utils.unregister_class(SEQUENCER_PT_import_edl)
331
bpy.utils.unregister_class(EDLImportInfo)
332
bpy.utils.unregister_class(EDLReelInfo)
333
del bpy.types.Scene.edl_import_info