Jeison Yehuda Amihud (Blender Dumbass)
06afb118d7
It was jumping a little bit back every time I added a new shot. And it always offsetting my daily percentage since it is much more sensitive to smallest changes. I hope this fixes it.
1180 lines
61 KiB
Python
1180 lines
61 KiB
Python
# THIS FILE IS A PART OF VCStudio
|
|
# PYTHON 3
|
|
|
|
import os
|
|
import datetime
|
|
import json
|
|
|
|
# This is for the export. We need a window for it. Maybe I will make my own.
|
|
import gi
|
|
gi.require_version('Gtk', '3.0')
|
|
from gi.repository import Gtk
|
|
import zipfile
|
|
import re
|
|
|
|
|
|
from settings import talk
|
|
from studio import checklist
|
|
#import checklist
|
|
|
|
def get_legacy(project_location):
|
|
|
|
# This function will read the .bos (Blender-Organizer Story) files. Primarily
|
|
# to convert them to .vcss (VCStudio Story) files.
|
|
# The concept is similar. But in order to work with them outside of reading
|
|
# and writting the file directly. I want to make a dictionary format with in
|
|
# the python. (Similarly to how I did with checklists and analytics)
|
|
|
|
# In the .bos file there was what I thought was clever at the time but
|
|
# ultimatly a dumb idea to make EVENTS and not scenes. The idea was that in
|
|
# a single event could be multiple scenes. But in reality it very rearly used
|
|
# and creating scenes with in events created a potential user error situation.
|
|
|
|
# So I want to get rid of all the EVENTS and read Scenes directly. Unless
|
|
# the event is empty of scenes. In which case to create a scene with the
|
|
# text of that event.
|
|
|
|
data = {
|
|
"fraction": 0.0, # Percentage of the Scenes finished.
|
|
"camera" : [0,0], # The position of where the user left
|
|
"selected": [], # List of selected items in the story editor
|
|
"active": None, # Active item.
|
|
"scenes" : {}, # List of scenes.
|
|
"arrows" : [], # List of connections. (A LIST. NOT DICT.)
|
|
"links" : [], # List of links to files or assets.
|
|
"markers": {}, # List of markers.
|
|
"events" : {} # List of frame like containers. (It will have similar)
|
|
} # function as events. But will have no text data with in
|
|
# it. It will be more like Blender's node editor's Frame.
|
|
|
|
# Even tho I want to change radically the idea of events. We still need to
|
|
# think in the events terms. Because we are parsing and old file. Funny how
|
|
# I will need to write this thing twice. For both file-types.
|
|
|
|
# I can't read it the way I read most other files. Because it's not line-
|
|
# based. But more something like HTML file. So it's going to be a little
|
|
# issue.
|
|
|
|
bos = open(project_location+"/pln/main.bos")
|
|
bos = bos.read()
|
|
|
|
cx, cy = 1, 1
|
|
|
|
if "</camera>" in bos:
|
|
camera = bos[bos.find("<camera>")+8:]
|
|
camera = camera[:camera.find("</camera>")]
|
|
camera = camera.split(",")
|
|
|
|
for num, val in enumerate(camera):
|
|
try:
|
|
camera[num] = float(val)
|
|
except:
|
|
camera[num] = 0.0
|
|
|
|
try:
|
|
cx = float(camera[2])
|
|
cy = float(camera[3])
|
|
except:
|
|
pass
|
|
print (cy, cx)
|
|
|
|
# Some stupid me made decision early in a story editor's life to use
|
|
# per-pixel X coordinates and per line Y coordinates. Which is something
|
|
# like 100 times the difference. Okay 50 ish is a default value for Y.
|
|
|
|
# I'm not going to do anything about it right now. Maximum a bit later.
|
|
|
|
camera = [camera[0], camera[1]] # I don't want scale to exist here.
|
|
|
|
data["camera"] = camera
|
|
|
|
|
|
# Events. They are very important. Now in the Blender-Organizer I used an
|
|
# HTML like format to mark shots and assets with in the text. But it's not
|
|
# a very efficient way of doing it. Because it requiered constant parsing
|
|
# of the text in real time. Which caused quite a noticable lag. And also
|
|
# every time I needed to read a part of it. I had to do parsing of the text.
|
|
|
|
# So I guess the VCSS file format will be designed to deal with this kind of
|
|
# thing. I'm actually more toward putting the text into separate files. Simple
|
|
# text documents. And making the VCSS a linking system.
|
|
|
|
if "</event>" in bos:
|
|
for event in bos.split("</event>")[:-1]:
|
|
event = event[event.find("<event>")+8:]
|
|
|
|
# Now we have text of the event. Let's parse out of it folowing
|
|
# stuff. We will need it if there are multiple scenes. Or when
|
|
# there are no scenes at all.
|
|
|
|
eventname = event[event.find('"')+1:event.replace('"'," ",1).find('"')]
|
|
|
|
# Let's parse the coordinates.
|
|
|
|
c = event[event.find('[')+1:event.find(']')]
|
|
c = c.split(",")
|
|
|
|
eventpositon = [float(c[0])*cx,float(c[2])*cy]
|
|
eventsize = [float(c[1])*cx,60.0]
|
|
|
|
# Now since we know the name of the event and the sizes. We can
|
|
# start parsing the scenes from the text with in the event.
|
|
|
|
eventtext = event[event.find(']')+2:-1]
|
|
|
|
# Now basically have to do the same exact thing with <scene> and
|
|
# later with <shot>, <item> to make all work.
|
|
|
|
# But first let's record a scene if it has no scene in it.
|
|
|
|
|
|
|
|
if not "<scene>" in eventtext:
|
|
|
|
if eventname in data["scenes"]:
|
|
eventname = eventname + "_copy"
|
|
|
|
data["scenes"][eventname] = {
|
|
"fraction":0.0, # Percentage
|
|
"position":eventpositon,
|
|
"size":eventsize,
|
|
"parent":"", # For when it's in a Frame (Event)
|
|
"shots":[[
|
|
"text_block",[["text", eventtext]]
|
|
]]
|
|
}
|
|
|
|
else:
|
|
|
|
# If there are more then 1 scene per event. We want to create
|
|
# an event, frame thing for them.
|
|
|
|
aos = eventtext.count("<scene>")
|
|
|
|
parent = "" #This will be it's name
|
|
|
|
if aos > 1:
|
|
parent = eventname
|
|
|
|
data["events"][eventname] = {
|
|
"position":eventpositon,
|
|
"size":[0,0]
|
|
}
|
|
|
|
# Now let's continue parsing the scenes.
|
|
|
|
for num, scene in enumerate(eventtext.split("</scene>")[:-1]):
|
|
|
|
scenename = scene[scene.find('"')+1:scene.replace('"'," ",1).find('"')]
|
|
scenename = scenename.replace(" ", "_")
|
|
scenetext = scene[scene.replace('"', " ", 1).find('"')+1:-1]
|
|
|
|
|
|
scenesize = [eventsize[0] / aos , eventsize[1]]
|
|
sceneposition = [eventpositon[0] + scenesize[0]*num,
|
|
eventpositon[1]]
|
|
|
|
|
|
data["scenes"][scenename] = {
|
|
"fraction":0.0, # Percentage
|
|
"position":sceneposition,
|
|
"size":scenesize,
|
|
"parent":parent, # For when it's in a Frame (Event)
|
|
"shots":[[
|
|
"text_block",[["text", scenetext]]
|
|
]]
|
|
}
|
|
|
|
# Parsing the text inside the scenes... OMG. Finding the SHOTS.
|
|
|
|
for scenename in data["scenes"]:
|
|
|
|
scenetext = data["scenes"][scenename]["shots"][0][1][0][1]
|
|
|
|
# Okay so we have both scene name and scene text. So it's
|
|
# time so send this data into the main data thingy, right?
|
|
# Wrong. Now we need to parse pointers to the shots, assets
|
|
# and other stuff. This file format gonna take a while.
|
|
|
|
# If you look into the history of this file on NotABug there
|
|
# Will be a version with a novel-long article here in the
|
|
# comments. I was toying with ideas of how to make stuff
|
|
# work. I will not change the whole system a bit from what
|
|
# I though there. (Using text pointers) and make it more like
|
|
# list of shot_block or text_block. Which both are just text.
|
|
# But one has a bit more metadata then the other. And inside
|
|
# which you can specify links, frases, images and simple text...
|
|
|
|
# So first of all we need to break the text up into shots.
|
|
|
|
shots = []
|
|
|
|
sa = scenetext.count("<shot>") # Shots amount
|
|
ts = scenetext # Copy of the scene text to butcher
|
|
|
|
for s in range(sa):
|
|
|
|
# If the first part of the scene is not a shot.
|
|
|
|
if not ts.startswith("<shot>"):
|
|
shots.append([
|
|
"text_block", [["text",ts[:ts.find("<shot>")]]]
|
|
])
|
|
|
|
# Now we need to erase the part from the ts.
|
|
|
|
ts = ts[ts.find("<shot>")+6:]
|
|
|
|
# Now we can parse the shot itself. We need the name.
|
|
|
|
if ts.count('"') > 1:
|
|
shotname = ts[ts.find('"')+1:ts.replace('"', " ", 1).find('"')]
|
|
ts = ts[ts.replace('"', " ", 1).find('"')+1:]
|
|
else:
|
|
shotname = "Unnamed"
|
|
|
|
|
|
|
|
# Put it also into the list.
|
|
|
|
shots.append([
|
|
"shot_block", shotname, [["text",ts[:ts.find("</shot>")]]]
|
|
])
|
|
|
|
# And erase it.
|
|
|
|
ts = ts[ts.find("</shot>")+7:]
|
|
|
|
shots.append([
|
|
"text_block", [["text",ts]]
|
|
])
|
|
|
|
|
|
|
|
# Now I want to get a fraction from a scene.
|
|
|
|
shotsfractions = []
|
|
|
|
for shot in shots:
|
|
if shot[0] == "shot_block":
|
|
|
|
# Let's see if it has a checklist.
|
|
|
|
if os.path.exists(project_location\
|
|
+"/rnd/"+scenename+"/"+shot[1]+"/shot.progress"):
|
|
|
|
check = checklist.get_list(project_location\
|
|
+"/rnd/"+scenename+"/"+shot[1]+"/shot.progress")
|
|
shotsfractions.append(check["fraction"])
|
|
else:
|
|
|
|
folder = project_location\
|
|
+"/rnd/"+scenename+"/"+shot[1]
|
|
|
|
try:
|
|
|
|
if len(os.listdir(folder+"/rendered")) > 0:
|
|
shotsfractions.append(1.0)
|
|
|
|
elif len(os.listdir(folder+"/test_rnd")) > 0:
|
|
shotsfractions.append(0.8)
|
|
|
|
elif len(os.listdir(folder+"/opengl")) > 0:
|
|
shotsfractions.append(0.6)
|
|
|
|
elif len(os.listdir(folder+"/storyboard")) > 0:
|
|
shotsfractions.append(0.4)
|
|
|
|
elif len(os.listdir(folder+"/extra")) > 0:
|
|
shotsfractions.append(0.2)
|
|
except:
|
|
shotsfractions.append(0.0)
|
|
|
|
# Writting parsed verions of the scenes. With all the shots
|
|
|
|
data["scenes"][scenename]["shots"] = shots
|
|
|
|
# Now that we have SHOTS Fractions we need a scene fraction.
|
|
|
|
try:
|
|
data["scenes"][scenename]["fraction"] = \
|
|
sum(shotsfractions) / len(shotsfractions)
|
|
except:
|
|
data["scenes"][scenename]["fraction"] = 0.0
|
|
|
|
# Now since we have shots and we have their factors. I'd like to do
|
|
# parsing of the text parts inside shots and texts between shots to
|
|
# find all the images, links and phrases.
|
|
|
|
for scenename in data["scenes"]:
|
|
for shotnum, shot in enumerate(data["scenes"][scenename]["shots"]):
|
|
|
|
# Our shot data could be either text_block ot shot_block
|
|
# and they are formatted a little bit differently.
|
|
|
|
if shot[0] == "shot_block":
|
|
text = shot[2][0][1]
|
|
else:
|
|
text = shot[1][0][1]
|
|
|
|
# Now keep in mind that similar stuff has to be done again
|
|
# when we saving the parsed text back
|
|
|
|
textblock = []
|
|
|
|
# This requires some extreme cleverness. Since I already hate
|
|
# this file format. WHY IS IT SO COMPLICATED?!
|
|
|
|
part = ""
|
|
skip = 0
|
|
|
|
for num, letter in enumerate(text):
|
|
|
|
if num >= skip:
|
|
|
|
if part.endswith("<item>"):
|
|
|
|
# putting the normal text in
|
|
if part[skip:].replace("<item>", ""):
|
|
textblock.append([
|
|
"text", part[skip:].replace("<item>", "")
|
|
])
|
|
|
|
# parsing the item
|
|
itempart = text[num:text[num:].find("</item>")+num]
|
|
link = itempart[itempart.find('"')+1:
|
|
itempart.replace('"', " ", 1).find('"')]
|
|
|
|
if link.startswith("/dev"):
|
|
link = link[4:]
|
|
|
|
itemtext = itempart[itempart.replace('"', " ", 1).find('"')+1:]
|
|
|
|
# puttin the link into the list
|
|
textblock.append([
|
|
"link", link, itemtext
|
|
])
|
|
|
|
# skiping to after the item
|
|
skip = text[num:].find("</item>")+6
|
|
part = ""
|
|
|
|
# Images. With the <>
|
|
|
|
elif part.endswith("<image>"):
|
|
|
|
# putting the normal text in
|
|
if part[skip:].replace("<image>", ""):
|
|
textblock.append([
|
|
"text", part[skip:].replace("<image>", "")
|
|
])
|
|
|
|
# parsing the item
|
|
link = text[num:text[num:].find("</image>")+num]
|
|
|
|
textblock.append([
|
|
"image", link
|
|
])
|
|
|
|
# skiping to after the item
|
|
skip = text[num:].find("</image>")+7
|
|
part = ""
|
|
|
|
# Images. With the [] (a little older version but still
|
|
# should be supported by default)
|
|
|
|
elif part.endswith("[image]"):
|
|
|
|
# putting the normal text in
|
|
if part[skip:].replace("[image]", ""):
|
|
textblock.append([
|
|
"text", part[skip:].replace("[image]", "")
|
|
])
|
|
|
|
# parsing the item
|
|
link = text[num:text[num:].find("[/image]")+num]
|
|
|
|
textblock.append([
|
|
"image", link
|
|
])
|
|
|
|
# skiping to after the item
|
|
skip = text[num:].find("[/image]")+7
|
|
part = ""
|
|
|
|
# Now let's figure out the frases. Because it has a
|
|
# text based thing in the beginning. Or maybe it's going
|
|
# to be anything that was before it? Hmm...
|
|
elif part.endswith(" - ["):
|
|
|
|
# putting the normal text in
|
|
if part[skip:].replace(" - [", ""):
|
|
textblock.append([
|
|
"text", part[skip:].replace(" - [", "")
|
|
])
|
|
|
|
# I designed the - [ thing to type conversation
|
|
# easier. Example:
|
|
|
|
# John - [Hello, World.]
|
|
|
|
# This would be John saying the words "Hello, World."
|
|
# but with the inclusion of <item> it became quite a
|
|
# problem. Because I would like John to be a link.
|
|
|
|
# It ended up looking something like:
|
|
|
|
#<itme>"/dev/chr/John"John</item> - [Hello, World.]
|
|
|
|
# This is a bit of a problem. Because any link that
|
|
# marked as <item> is already in a textblock list.
|
|
|
|
character = []
|
|
|
|
# If it's a link
|
|
|
|
if textblock[-1][0] == "link":
|
|
character = textblock[-1]
|
|
del textblock[-1]
|
|
|
|
# If it's just a text
|
|
|
|
elif textblock[-1][0] == "text":
|
|
character = textblock[-1][1]
|
|
character = character[character.rfind("\n")+1:]
|
|
|
|
if character:
|
|
textblock[-1][1] = textblock[-1][1].replace(character, "")
|
|
character = ["text", character]
|
|
|
|
# Now let's get the frase
|
|
frase = text[num:text[num:].find("]")+num]
|
|
|
|
# If any character. Put it into a textblock
|
|
|
|
if character:
|
|
textblock.append([
|
|
"frase", character, frase
|
|
])
|
|
|
|
|
|
# skiping to after the item
|
|
skip = text[num:].find("]")
|
|
part = ""
|
|
|
|
else:
|
|
part = part + letter
|
|
|
|
# LAST PART (WHY DIDN'T I THINK ABOUT ERLIER OMG)
|
|
textblock.append([
|
|
"text", part[skip:]
|
|
])
|
|
|
|
if shot[0] == "shot_block":
|
|
data["scenes"][scenename]["shots"][shotnum][2] = textblock
|
|
else:
|
|
data["scenes"][scenename]["shots"][shotnum][1] = textblock
|
|
|
|
# Okay this was event. LOL. This is a large function to parse them all.
|
|
# Crazy complex bastards. Anyway. It's over. And we have to only do the
|
|
# easy rest of it. Untill we will get to calculating the project. Because
|
|
# we need to filter out all scenes that are not in the main chain.
|
|
|
|
# Let's start with hard thing first. So to feel good when having to do the
|
|
# easy stuff in the end. ARROWS. (connections between scenes)
|
|
|
|
|
|
|
|
# To make it work. We need to fisrt of all earase all the stuff before
|
|
# the first arrow. Because <arrow> could be mentioned in the script it
|
|
# self. Similarly <image> is too. So it's good to complitelly clear bos
|
|
# out of anything that came before.
|
|
|
|
bos = bos[bos.rfind("</event>"):]
|
|
|
|
# From here everything is PER LINE BASED... YEAH!!!!
|
|
|
|
bos = bos.split("\n")
|
|
|
|
for line in bos:
|
|
|
|
# This is arrows...
|
|
|
|
if line.startswith("<arrow>"):
|
|
|
|
arrow = line[line.find("<")+7:line.rfind("</")].split(" --> ")
|
|
newarrow = []
|
|
for i in arrow:
|
|
i = i.split(",")
|
|
if i[0] != "-1":
|
|
newarrow.append([
|
|
"scene", i[1][1:-1]
|
|
])
|
|
else:
|
|
newarrow.append(
|
|
i[1][1:-1]
|
|
)
|
|
data["arrows"].append(newarrow)
|
|
|
|
# And this is links. Formerly known as Images. Initially the idea was to
|
|
# just store images. But later. I started adding assets like this as well.
|
|
|
|
elif line.startswith("<image>"):
|
|
stuff = line.split(",")
|
|
link = stuff[3][1:-1]
|
|
coordinates = []
|
|
try:
|
|
coordinates.append(float(stuff[0].replace("<image>", ""))*cx)
|
|
except:
|
|
coordinates.append(0.0)
|
|
|
|
try:
|
|
coordinates.append(float(stuff[1])*cy)
|
|
except:
|
|
coordinates.append(0.0)
|
|
|
|
# Lately the primary reason to use <image> was linking assets directly
|
|
# into story editor's space. But it was a hack. Basically I was
|
|
# linking a preview image. Preview.png or Preview.jpg from the
|
|
# renders of the asset. And the drawer of the images in the story-
|
|
# editor already knew to redirect the clicks to a different function.
|
|
# But for VCStudio I want to link to asset or a file.
|
|
|
|
linktype = "file"
|
|
|
|
if "/renders/Preview." in link:
|
|
linktype = "asset"
|
|
link = link[:link.rfind("/renders/Preview.")].replace("/dev", "")
|
|
|
|
data["links"].append([
|
|
linktype, link, coordinates, ""
|
|
])
|
|
|
|
# Markers. I nearly forgot about the markers. In the Story-Editor of
|
|
# Blender-Orgaznier they were something like markers in VSE in Blender.
|
|
# Vertical lines visible on every altitude.
|
|
|
|
elif line.startswith("<marker>"):
|
|
marker = line.replace("<marker>", "").replace("</marker>", "").split(",")
|
|
|
|
try:
|
|
markloc = float(marker[0])
|
|
except:
|
|
markloc = 0.0
|
|
|
|
markstring = marker[1].replace('"', "")
|
|
|
|
# I do want to do something quite interesting with markers in the
|
|
# VCStudio tho. I want them to be like little nodes with text while
|
|
# in the frame. And be like directional guides. Sticking to the
|
|
# edges of the screen when outside the screen. Something like items
|
|
# that are outside of the map in the videogames. So you can see
|
|
# which direction are they. For this markers will need to have
|
|
# both X and Y coordinates.
|
|
|
|
data["markers"][markstring] = [markloc, 0.0, ""]
|
|
|
|
# For now the Y is 0. Because we are reading from the old version.
|
|
|
|
|
|
# Okay we've got the Arrows data. Pretty much all the data. Now we just
|
|
# need to calculate the scenes fraction. For that we need to recreate the
|
|
# train of scenes. From START till END.
|
|
|
|
fractions = []
|
|
lastarrow = 'start'
|
|
|
|
|
|
for i in data["arrows"]:
|
|
if lastarrow == "end":
|
|
break
|
|
for arrow in data["arrows"]:
|
|
if arrow[0] == lastarrow:
|
|
lastarrow = arrow[1]
|
|
if arrow[1] != "end":
|
|
fractions.append(
|
|
data["scenes"][arrow[1][1]]["fraction"]
|
|
)
|
|
else:
|
|
break
|
|
|
|
# FINAL STUFF...
|
|
|
|
try:
|
|
data["fraction"] = sum(fractions) / len(fractions)
|
|
except:
|
|
data["fraction"] = 0.0
|
|
|
|
#save(project_location, data)
|
|
#data = load(project_location)
|
|
|
|
return data
|
|
|
|
def get_asset_data(win, name, force=False):
|
|
|
|
# This function will return a data of about the asset.
|
|
|
|
if name not in win.assets or force:
|
|
|
|
data = {
|
|
"fraction":0.0
|
|
}
|
|
|
|
try:
|
|
# Now let's get a fraction of the asset
|
|
if os.path.exists(win.project+"/ast/"+name+".blend"):
|
|
data["fraction"] = 1.0
|
|
else:
|
|
check = checklist.get_list(win.project+"/dev/"+name+"/asset.progress")
|
|
data["fraction"] = check["fraction"]
|
|
except:
|
|
pass
|
|
|
|
win.assets[name] = data
|
|
|
|
return win.assets[name]
|
|
|
|
def save(project, story):
|
|
|
|
# This is a save of the new VCStudio. Which is using a standard file format.
|
|
# so people could parse the data themselves. ( Or because I'm lazy )
|
|
|
|
try:
|
|
os.mkdir(project+'/pln/')
|
|
except:
|
|
pass
|
|
|
|
with open(project+'/pln/story.vcss', 'w') as fp:
|
|
json.dump(story, fp, sort_keys=True, indent=4)
|
|
|
|
def load(project):
|
|
|
|
# This is a convertion back from JSON data to out beloved python dict
|
|
try:
|
|
with open(project+'/pln/story.vcss') as json_file:
|
|
data = json.load(json_file)
|
|
except:
|
|
|
|
# If there is no file.
|
|
data = {
|
|
"fraction": 0.0, # Percentage of the Scenes finished.
|
|
"camera" : [0,0], # The position of where the user left
|
|
"selected": [], # List of selected items in the story editor
|
|
"active": None, # Active item.
|
|
"scenes" : {}, # List of scenes.
|
|
"arrows" : [], # List of connections. (A LIST. NOT DICT.)
|
|
"links" : [], # List of links to files or assets.
|
|
"markers": {}, # List of markers.
|
|
"events" : {} # List of frame like containers. (It will have similar)
|
|
} # function as events. But will have no text data with in
|
|
# it. It will be more like Blender's node editor's Frame.
|
|
|
|
|
|
# I forgot to update the scenes analytics lol.
|
|
|
|
for scenename in data["scenes"]:
|
|
|
|
shotsfractions = []
|
|
shotslengths = []
|
|
textlength = 0
|
|
prevtextpos = 0
|
|
for shot in data["scenes"][scenename]["shots"]:
|
|
for t in shot[-1]:
|
|
textlength = textlength + len(t[-1])
|
|
if shot[0] == "shot_block":
|
|
|
|
# Let's see if it has a checklist.
|
|
|
|
if os.path.exists(project\
|
|
+"/rnd/"+scenename+"/"+shot[1]+"/shot.progress"):
|
|
|
|
check = checklist.get_list(project\
|
|
+"/rnd/"+scenename+"/"+shot[1]+"/shot.progress")
|
|
shotsfractions.append(check["fraction"])
|
|
else:
|
|
|
|
folder = project\
|
|
+"/rnd/"+scenename+"/"+shot[1]
|
|
|
|
try:
|
|
|
|
if len(os.listdir(folder+"/rendered")) > 0:
|
|
shotsfractions.append(1.0)
|
|
|
|
elif len(os.listdir(folder+"/test_rnd")) > 0:
|
|
shotsfractions.append(0.8)
|
|
|
|
elif len(os.listdir(folder+"/opengl")) > 0:
|
|
shotsfractions.append(0.6)
|
|
|
|
elif len(os.listdir(folder+"/storyboard")) > 0:
|
|
shotsfractions.append(0.4)
|
|
|
|
elif len(os.listdir(folder+"/extra")) > 0:
|
|
shotsfractions.append(0.2)
|
|
except:
|
|
shotsfractions.append(0.0)
|
|
|
|
shotslengths.append( textlength - prevtextpos )
|
|
prevtextpos = textlength
|
|
|
|
# Adjusting fractions based on the length of the text marked.
|
|
|
|
lastlen = 0
|
|
for t in data["scenes"][scenename]["shots"][-1][-1]:
|
|
lastlen = lastlen + len(t[-1])
|
|
|
|
|
|
try:
|
|
avgtxtlng = sum(shotslengths) / len(shotslengths)
|
|
except:
|
|
avgtxtlng = 1
|
|
|
|
avgtxtlng = min(1, avgtxtlng)
|
|
|
|
sf = []
|
|
for n, i in enumerate(shotsfractions):
|
|
try:
|
|
l = shotslengths[n]
|
|
except:
|
|
l = 0
|
|
|
|
|
|
nf = l / (textlength - lastlen) * i
|
|
|
|
sf.append(nf)
|
|
|
|
# If the last block isn't shot_block. It's safe to assume that
|
|
# not all of the shots are yet marked in the text. Therefor we
|
|
# want to estimate how much is marked.
|
|
|
|
multiply_by = 1
|
|
if not data["scenes"][scenename].get("no_more_shots") and data["scenes"][scenename]["shots"][-1][0] == "text_block":
|
|
|
|
try:
|
|
multiply_by = (textlength - lastlen) / textlength
|
|
except:
|
|
multiply_by = 1
|
|
|
|
|
|
try:
|
|
data["scenes"][scenename]["fraction"] = \
|
|
( sum(sf) ) * multiply_by
|
|
except:
|
|
data["scenes"][scenename]["fraction"] = 0.0
|
|
|
|
|
|
|
|
|
|
fractions = []
|
|
lastarrow = 'start'
|
|
|
|
|
|
for i in data["arrows"]:
|
|
if lastarrow == "end":
|
|
break
|
|
for arrow in data["arrows"]:
|
|
if arrow[0] == lastarrow:
|
|
lastarrow = arrow[1]
|
|
if arrow[1] != "end":
|
|
fractions.append(
|
|
data["scenes"][arrow[1][1]]["fraction"]
|
|
)
|
|
else:
|
|
break
|
|
|
|
# FINAL STUFF...
|
|
|
|
try:
|
|
data["fraction"] = sum(fractions) / len(fractions)
|
|
except:
|
|
data["fraction"] = 0.0
|
|
|
|
|
|
return data
|
|
|
|
def undo_record(win):
|
|
|
|
# This function will record undo of the story. The undo will be basically
|
|
# copies of the script JSON file as a whole. The /pln/story.vcss
|
|
|
|
# This function will not read the files. It's not nessesary. But it will
|
|
# make a copy of the whole thing. So I guess we need to implement some kind
|
|
# of limiter.
|
|
try:
|
|
limit = int(win.settings["Undo_Limit"])
|
|
|
|
# Now let's advance the undo history 1 forward.
|
|
win.undo_index = min(len(win.undo_history)+1, limit)
|
|
|
|
# Let's read our file. Which might not exist.
|
|
f = open(win.project+'/pln/story.vcss')
|
|
|
|
win.undo_history.append(f.read())
|
|
|
|
# And now let's limit our selves
|
|
|
|
win.undo_history = win.undo_history[0-limit:]
|
|
except:
|
|
pass
|
|
|
|
# Following 2 functions are a big buggy at the moment. I will aprecieate if
|
|
# someone going to look at them. Maybe it's to do with studio/studio_storyLayer.py
|
|
# where I was testing them. But they work. Just not every time.
|
|
|
|
def undo(win):
|
|
|
|
# This function will do the undo. Tho this function will not nessesarily
|
|
# sens the Ctrl - Z by it self. It should be activated from any place
|
|
# in the UI.
|
|
|
|
# Let's move our index back 1 way.
|
|
win.undo_index = max(0, win.undo_index-1)
|
|
|
|
|
|
# Now let's read our data
|
|
d = win.undo_history[win.undo_index]
|
|
|
|
# And let's save the data back to the file
|
|
f = open(win.project+'/pln/story.vcss', "w")
|
|
f.write(d)
|
|
f.close()
|
|
|
|
# And let's refresh story
|
|
win.story = load(win.project)
|
|
|
|
def redo(win):
|
|
|
|
# This function will do the redo. Tho this function will not nessesarily
|
|
# sens the Ctrl - Y by it self. It should be activated from any place
|
|
# in the UI.
|
|
|
|
# Let's move our index back 1 way.
|
|
win.undo_index = min(len(win.undo_history)-1, win.undo_index+1)
|
|
|
|
|
|
# Now let's read our data
|
|
d = win.undo_history[win.undo_index]
|
|
|
|
# And let's save the data back to the file
|
|
f = open(win.project+'/pln/story.vcss', "w")
|
|
f.write(d)
|
|
f.close()
|
|
|
|
# And let's refresh story
|
|
win.story = load(win.project)
|
|
|
|
def export_to_odt(win):
|
|
|
|
# This function will export the story to the ODT format. The ODT format is
|
|
# basically a zip file. With images and other stuff. And a context.xml file
|
|
# where you have all the styles and the text with task of style. This is
|
|
# very handy since we need to only make a simple text document with a folder
|
|
# of images.
|
|
|
|
# First let's call a file save dialog. I'm going to use the standard Gtk
|
|
# one. Maybe will make my own.
|
|
|
|
folderchooser = Gtk.FileChooserDialog(talk.text("export_tooltip"),
|
|
None,
|
|
Gtk.FileChooserAction.SAVE,
|
|
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
|
Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
|
|
folderchooser.set_default_response(Gtk.ResponseType.OK)
|
|
response = folderchooser.run()
|
|
if response == Gtk.ResponseType.OK:
|
|
savefilename = folderchooser.get_filename()
|
|
else:
|
|
folderchooser.destroy()
|
|
return
|
|
folderchooser.destroy()
|
|
|
|
|
|
# We are going to start the folder for this converion. For this in the
|
|
# new_file directory we have an example ODT file. It's basically a zip
|
|
# file that we want to use. Let's unzip it.
|
|
|
|
referencefile = "/new_file/reference.odt"
|
|
|
|
# Let's clear the folder from previouw parsing if such exists.
|
|
|
|
try:
|
|
os.system("rm -rf /tmp/odt_export")
|
|
except:
|
|
pass
|
|
|
|
# And make the folder again.
|
|
os.makedirs("/tmp/odt_export")
|
|
|
|
# Now let's unzip our contents into there.
|
|
|
|
ref = zipfile.ZipFile(os.getcwd()+referencefile, "r")
|
|
ref.extractall("/tmp/odt_export")
|
|
ref.close()
|
|
|
|
# Now there will be the Pictures directory that contains the test image
|
|
# of Moria standing in front of the window and looking at the racetrack.
|
|
# we don't need it. But we need the folder it self.
|
|
|
|
try:
|
|
os.remove("/tmp/odt_export/Pictures/1000020100000780000004380D1DEC99F7A147C7.png")
|
|
except:
|
|
pass
|
|
|
|
# By the way. If you want to look at this image. Just into the reference.odt
|
|
# you will see it there in the text.
|
|
|
|
|
|
# Now we going to start writing to the context.xml file. So let's open it.
|
|
|
|
save = open("/tmp/odt_export/content.xml", "w")
|
|
|
|
# First stuff that we are going to write are the headers. So LibreOffice
|
|
# will not start going nutz. And saying how corrupter the file is.
|
|
|
|
save.write('''<?xml version="1.0" encoding="UTF-8"?><office:document-content xmlns:officeooo="http://openoffice.org/2009/office" xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:ooo="http://openoffice.org/2004/office" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" office:version="1.2"><office:scripts/><office:font-face-decls><style:font-face style:name="Lohit Devanagari1" svg:font-family="'Lohit Devanagari'"/><style:font-face style:name="Mitra Mono" svg:font-family="'Mitra Mono'" style:font-pitch="fixed"/><style:font-face style:name="Nimbus Mono PS" svg:font-family="'Nimbus Mono PS'" style:font-pitch="fixed"/><style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/><style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'" style:font-family-generic="swiss" style:font-pitch="variable"/><style:font-face style:name="Lohit Devanagari" svg:font-family="'Lohit Devanagari'" style:font-family-generic="system" style:font-pitch="variable"/><style:font-face style:name="Noto Sans CJK SC" svg:font-family="'Noto Sans CJK SC'" style:font-family-generic="system" style:font-pitch="variable"/><style:font-face style:name="Noto Serif CJK SC" svg:font-family="'Noto Serif CJK SC'" style:font-family-generic="system" style:font-pitch="variable"/></office:font-face-decls><office:automatic-styles><style:style style:name="P1" style:family="paragraph" style:parent-style-name="Footer"><style:text-properties officeooo:paragraph-rsid="0028a095"/></style:style><style:style style:name="P2" style:family="paragraph" style:parent-style-name="Standard"><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0017b0ac" officeooo:paragraph-rsid="0017b0ac"/></style:style><style:style style:name="frase_name" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties fo:text-align="center" style:justify-single-word="false"/><style:text-properties style:font-name="Nimbus Mono PS" fo:font-weight="bold" officeooo:rsid="0017b0ac" officeooo:paragraph-rsid="0017b0ac" style:font-weight-asian="bold" style:font-weight-complex="bold"/></style:style><style:style style:name="P4" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties fo:text-align="center" style:justify-single-word="false"/><style:text-properties style:font-name="Nimbus Mono PS" fo:font-size="22pt" fo:font-weight="bold" officeooo:rsid="0017b0ac" officeooo:paragraph-rsid="0017b0ac" style:font-size-asian="19.25pt" style:font-weight-asian="bold" style:font-size-complex="22pt" style:font-weight-complex="bold"/></style:style><style:style style:name="P5" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties fo:text-align="center" style:justify-single-word="false"/><style:text-properties style:font-name="Nimbus Mono PS" fo:font-size="22pt" fo:font-weight="bold" officeooo:rsid="001af4f2" officeooo:paragraph-rsid="001af4f2" style:font-size-asian="19.25pt" style:font-weight-asian="bold" style:font-size-complex="22pt" style:font-weight-complex="bold"/></style:style><style:style style:name="P6" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties fo:text-align="center" style:justify-single-word="false"/><style:text-properties style:font-name="Nimbus Mono PS" fo:font-size="18pt" fo:font-weight="bold" officeooo:rsid="001af4f2" officeooo:paragraph-rsid="001af4f2" style:font-size-asian="15.75pt" style:font-weight-asian="bold" style:font-size-complex="18pt" style:font-weight-complex="bold"/></style:style><style:style style:name="P7" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties fo:text-align="center" style:justify-single-word="false"/><style:text-properties style:font-name="Nimbus Mono PS" fo:font-size="14pt" fo:font-weight="bold" officeooo:rsid="001af4f2" officeooo:paragraph-rsid="001af4f2" style:font-size-asian="12.25pt" style:font-weight-asian="bold" style:font-size-complex="14pt" style:font-weight-complex="bold"/></style:style><style:style style:name="P8" style:family="paragraph" style:parent-style-name="Standard"><style:text-properties officeooo:paragraph-rsid="0017b0ac"/></style:style><style:style style:name="P9" style:family="paragraph" style:parent-style-name="Standard"><style:text-properties fo:color="#666666" style:font-name="Nimbus Mono PS" fo:font-size="10.5pt" fo:font-style="italic" officeooo:rsid="0017b0ac" officeooo:paragraph-rsid="0017b0ac" style:font-size-asian="10.5pt" style:font-style-asian="italic" style:font-size-complex="10.5pt" style:font-style-complex="italic"/></style:style><style:style style:name="frase" style:family="paragraph" style:parent-style-name="Standard" style:master-page-name=""><loext:graphic-properties draw:fill="none"/><style:paragraph-properties fo:margin-left="1in" fo:margin-right="1in" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0in" style:auto-text-indent="false" style:page-number="auto" fo:background-color="transparent"/><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0017b0ac" officeooo:paragraph-rsid="0017b0ac"/></style:style><style:style style:name="P11" style:family="paragraph" style:parent-style-name="Standard"><loext:graphic-properties draw:fill="none"/><style:paragraph-properties fo:margin-left="1in" fo:margin-right="1in" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0in" style:auto-text-indent="false" fo:background-color="transparent"/><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0017b0ac" officeooo:paragraph-rsid="0017b0ac"/></style:style><style:style style:name="scene_name" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties fo:text-align="start" style:justify-single-word="false" fo:break-before="page"/><style:text-properties style:font-name="Nimbus Mono PS" fo:font-weight="bold" officeooo:rsid="0017b0ac" officeooo:paragraph-rsid="0017b0ac" style:font-weight-asian="bold" style:font-weight-complex="bold"/></style:style><style:style style:name="P13" style:family="paragraph" style:parent-style-name="Standard"><loext:graphic-properties draw:fill="none"/><style:paragraph-properties fo:margin-left="0in" fo:margin-right="1in" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0in" style:auto-text-indent="false" fo:background-color="transparent"/><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0017b0ac" officeooo:paragraph-rsid="0024426e"/></style:style><style:style style:name="image_style" style:family="paragraph" style:parent-style-name="Standard" style:master-page-name=""><loext:graphic-properties draw:fill="none"/><style:paragraph-properties fo:margin-left="0in" fo:margin-right="0in" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0in" style:auto-text-indent="false" style:page-number="auto" fo:background-color="transparent"/><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0017b0ac" officeooo:paragraph-rsid="0028a095"/></style:style><style:style style:name="P15" style:family="paragraph" style:parent-style-name="Standard"><loext:graphic-properties draw:fill="none"/><style:paragraph-properties fo:margin-left="0in" fo:margin-right="0in" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0in" style:auto-text-indent="false" fo:background-color="transparent"/><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0017b0ac" officeooo:paragraph-rsid="0028a095"/></style:style><style:style style:name="P16" style:family="paragraph" style:parent-style-name="Standard"><loext:graphic-properties draw:fill="none"/><style:paragraph-properties fo:margin-left="0in" fo:margin-right="0in" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0in" style:auto-text-indent="false" fo:background-color="transparent"/><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0028a095" officeooo:paragraph-rsid="0028a095"/></style:style><style:style style:name="P17" style:family="paragraph" style:parent-style-name="Standard"><loext:graphic-properties draw:fill="none"/><style:paragraph-properties fo:margin-left="0in" fo:margin-right="0in" fo:text-align="center" style:justify-single-word="false" fo:text-indent="0in" style:auto-text-indent="false" fo:background-color="transparent"/><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0028a095" officeooo:paragraph-rsid="0028a095" fo:background-color="#808080"/></style:style><style:style style:name="T1" style:family="text"><style:text-properties fo:font-weight="bold" fo:background-color="transparent" loext:char-shading-value="0" style:font-weight-asian="bold" style:font-weight-complex="bold"/></style:style><style:style style:name="T2" style:family="text"><style:text-properties fo:font-weight="bold" fo:background-color="#ffffff" loext:char-shading-value="0" style:font-weight-asian="bold" style:font-weight-complex="bold"/></style:style><style:style style:name="T3" style:family="text"><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0017b0ac"/></style:style><style:style style:name="T4" style:family="text"><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0017cba4"/></style:style><style:style style:name="shot_1" style:family="text"><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0017b0ac" fo:background-color="#ffb66c" loext:char-shading-value="0"/></style:style><style:style style:name="shot_2" style:family="text"><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0017b0ac" fo:background-color="#ffe994" loext:char-shading-value="0"/></style:style><style:style style:name="shot_3" style:family="text"><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0017b0ac" fo:background-color="#e0c2cd" loext:char-shading-value="0"/></style:style><style:style style:name="shot_4" style:family="text"><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0017b0ac" fo:background-color="#b4c7dc" loext:char-shading-value="0"/></style:style><style:style style:name="shot_5" style:family="text"><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0017b0ac" fo:background-color="#afd095" loext:char-shading-value="0"/></style:style><style:style style:name="T10" style:family="text"><style:text-properties style:font-name="Nimbus Mono PS" officeooo:rsid="0028a095"/></style:style><style:style style:name="T11" style:family="text"><style:text-properties style:font-name="Nimbus Mono PS" fo:font-weight="bold" officeooo:rsid="0028a095" fo:background-color="#ffffff" loext:char-shading-value="0" style:font-weight-asian="bold" style:font-weight-complex="bold"/></style:style><style:style style:name="T12" style:family="text"><style:text-properties style:font-name="Nimbus Mono PS" fo:font-weight="normal" officeooo:rsid="0028a095" fo:background-color="#ffffff" loext:char-shading-value="0" style:font-weight-asian="normal" style:font-weight-complex="normal"/></style:style><style:style style:name="T13" style:family="text"><style:text-properties officeooo:rsid="0028a095"/></style:style><style:style style:name="T14" style:family="text"><style:text-properties fo:background-color="transparent" loext:char-shading-value="0"/></style:style><style:style style:name="T15" style:family="text"><style:text-properties fo:background-color="transparent" loext:char-shading-value="0"/></style:style><style:style style:name="fr1" style:family="graphic" style:parent-style-name="Graphics"><style:graphic-properties style:mirror="none" fo:clip="rect(0in, 0in, 0in, 0in)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/></style:style></office:automatic-styles><office:body><office:text text:use-soft-page-breaks="true"><office:forms form:automatic-focus="false" form:apply-design-mode="false"/><text:sequence-decls><text:sequence-decl text:display-outline-level="0" text:name="Illustration"/><text:sequence-decl text:display-outline-level="0" text:name="Table"/><text:sequence-decl text:display-outline-level="0" text:name="Text"/><text:sequence-decl text:display-outline-level="0" text:name="Drawing"/><text:sequence-decl text:display-outline-level="0" text:name="Figure"/></text:sequence-decls><text:p text:style-name="P4"/><text:p text:style-name="P4"/><text:p text:style-name="P4"/><text:p text:style-name="P4"/><text:p text:style-name="P4"/><text:p text:style-name="P4"/><text:p text:style-name="P4"/><text:p text:style-name="P4"/><text:p text:style-name="P4"/><text:p text:style-name="P4"/><text:p text:style-name="P4"/>''')
|
|
|
|
# Now let's write the name of the project
|
|
|
|
save.write('<text:p text:style-name="P5">'+win.analytics["name"]+'</text:p>')
|
|
|
|
# Now let's write the director's name
|
|
|
|
save.write('<text:p text:style-name="P6">'+win.analytics["director"]+'</text:p>')
|
|
|
|
# Now let's write the comment
|
|
|
|
save.write('<text:p text:style-name="P7">'+win.analytics["status"]+'</text:p>')
|
|
|
|
# Now let's write scenes them selves. We don't want all scene but only
|
|
# ones in the main chain. So we are ignoring the scenes that are meant for
|
|
# tests and such.
|
|
|
|
|
|
lastarrow = 'start'
|
|
for i in win.story["arrows"]:
|
|
if lastarrow == "end":
|
|
break
|
|
for arrow in win.story["arrows"]:
|
|
if arrow[0] == lastarrow:
|
|
lastarrow = arrow[1]
|
|
if arrow[1] != "end":
|
|
|
|
# Here is our scene name.
|
|
save.write('<text:p text:style-name="scene_name">'+arrow[1][1]+'</text:p>')
|
|
save.write('<text:p text:style-name="P2"/>')
|
|
|
|
# We need to get all the assets of the scene and write them
|
|
# net under the scene name.
|
|
|
|
assets = get_assets(win, arrow[1][1])
|
|
|
|
for cur in ["chr", "veh", "loc", "obj"]:
|
|
t = talk.text(cur)+": "
|
|
for a in assets:
|
|
|
|
if cur in a:
|
|
t = t +a[a.rfind("/")+1:]+", "
|
|
t = t[:-2]
|
|
|
|
if t != talk.text(cur):
|
|
save.write('<text:p text:style-name="P9">'+t+'</text:p>')
|
|
|
|
# Now let's actually write the text of the scene in there.
|
|
scene = win.story["scenes"][arrow[1][1]]["shots"]
|
|
|
|
save.write('<text:p text:style-name="P2"/>')
|
|
save.write('<text:p text:style-name="P8">')
|
|
|
|
for block in scene:
|
|
|
|
|
|
# For just text parts.
|
|
if block[0] == "text_block":
|
|
style = "T3"
|
|
else:
|
|
|
|
# If It's a shot. I want the shot color marking
|
|
|
|
shotis = block[1]
|
|
|
|
rcolors = [
|
|
"shot_1",
|
|
"shot_2",
|
|
"shot_3",
|
|
"shot_4",
|
|
"shot_5"
|
|
]
|
|
|
|
# Getting the color. It's not always works.
|
|
|
|
if "shot_colors" not in win.story:
|
|
win.story["shot_colors"] = {}
|
|
|
|
surl = "/"+arrow[1][1]+"/"+shotis
|
|
|
|
if surl not in win.story["shot_colors"]:
|
|
|
|
win.story["shot_colors"][surl] = rcolors[len(win.story["shot_colors"]) % len(rcolors)]
|
|
|
|
style = win.story["shot_colors"][surl]
|
|
|
|
# Now let's itterate over the text in the block.
|
|
|
|
for text in block[-1]:
|
|
|
|
# For just regular parts we have our regular text
|
|
|
|
if text[0] == "text" or text[0] == "link":
|
|
|
|
for line in re.split("(\n)",text[-1]):
|
|
|
|
if line == "\n":
|
|
save.write('</text:p>')
|
|
save.write('<text:p text:style-name="P8">')
|
|
|
|
else:
|
|
save.write('<text:span text:style-name="'+style+'">'+line+'</text:span>')
|
|
|
|
# For frases it's a bit different
|
|
|
|
elif text[0] == "frase":
|
|
|
|
# We gonna close the simle text part.
|
|
save.write('</text:p>')
|
|
|
|
# We gonna make a new line
|
|
save.write('<text:p text:style-name="P2"/>')
|
|
|
|
# We gonna write the name of the speaker
|
|
save.write('<text:p text:style-name="frase_name">'+text[1][-1]+'</text:p>')
|
|
|
|
# Then we open the text type
|
|
save.write('<text:p text:style-name="frase">')
|
|
|
|
# Then we write the frase
|
|
|
|
for line in re.split("(\n)",text[-1]):
|
|
if line == "\n":
|
|
save.write('</text:p>')
|
|
save.write('<text:p text:style-name="frase">')
|
|
|
|
else:
|
|
save.write('<text:span text:style-name="'+style+'">'+line+'</text:span>')
|
|
|
|
# Then we close the frase
|
|
save.write('</text:p>')
|
|
|
|
# And open back the other one
|
|
save.write('<text:p text:style-name="P8">')
|
|
|
|
|
|
# Now let's make images work. Okay. So there is our
|
|
# images folder. We need to copy our image to there
|
|
# first.
|
|
|
|
elif text[0] == "image":
|
|
|
|
# The image could be relative or absolute.
|
|
|
|
tmpurl = text[-1].replace("/", "_")
|
|
|
|
if os.path.exists(win.project+text[-1]):
|
|
f = open(win.project+text[-1], "rb")
|
|
else:
|
|
f = open(text[-1], "rb")
|
|
|
|
s = open("/tmp/odt_export/Pictures/"+tmpurl, "wb")
|
|
s.write(f.read())
|
|
f.close()
|
|
s.close()
|
|
|
|
# Now we have a copy of the image in the
|
|
# file. We need to draw it.
|
|
|
|
save.write('</text:p>')
|
|
save.write('<text:p text:style-name="P13"/><text:p text:style-name="image_style"><draw:frame draw:style-name="fr1" draw:name="Image1" text:anchor-type="char" svg:width="6.6929in" svg:height="3.7646in" draw:z-index="0">')
|
|
save.write('<draw:image xlink:href="Pictures/'+tmpurl+'" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" loext:mime-type="image/png"/>')
|
|
save.write('</draw:frame></text:p>')
|
|
save.write('<text:p text:style-name="P8">')
|
|
|
|
# There is a problem tho. We need to write
|
|
# the existance of this file into another
|
|
# place. if we don't do that. LibreOffice will
|
|
# think that the ODT is broken. So it will fix
|
|
# it and all gonna be great. Still not the best
|
|
# experience for the users. Please somebody
|
|
# figure it out.
|
|
|
|
|
|
|
|
save.write('</text:p>')
|
|
|
|
# After every scene is want a little line in the bottom
|
|
save.write('<text:p text:style-name="P2"/>')
|
|
save.write('<text:p text:style-name="P2"/>')
|
|
save.write('<text:p text:style-name="P17"><text:s text:c="66"/></text:p>')
|
|
|
|
|
|
else:
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Now let's close the file
|
|
|
|
save.write('</office:text></office:body></office:document-content>')
|
|
save.close()
|
|
|
|
|
|
|
|
# And now let's make the odt file in the given savefilename place
|
|
|
|
def zip_odt(src, dst):
|
|
zf = zipfile.ZipFile("%s.odt" % (dst), "w", zipfile.ZIP_DEFLATED) #changed file extension
|
|
abs_src = os.path.abspath(src)
|
|
for dirname, subdirs, files in os.walk(src):
|
|
for filename in files:
|
|
absname = os.path.abspath(os.path.join(dirname, filename))
|
|
arcname = absname[len(abs_src) + 1:]
|
|
zf.write(absname, arcname)
|
|
zf.close()
|
|
|
|
zip_odt("/tmp/odt_export", savefilename)
|
|
|
|
|
|
def get_assets(win, scene):
|
|
|
|
# This funtion will get the assets from any given scene.
|
|
|
|
assets = []
|
|
|
|
|
|
|
|
# Now let's read through the scene.
|
|
|
|
for shot in win.story["scenes"][scene]["shots"]:
|
|
|
|
|
|
# Let's read the shot
|
|
for asset in shot[-1]:
|
|
# Ignore text
|
|
if asset[0] == "text":
|
|
continue
|
|
|
|
# It's it's a staight up link. Just add it.
|
|
if asset[0] == "link" and asset[1] not in assets:
|
|
assets.append(asset[1])
|
|
|
|
# It's a link in a frase.
|
|
if asset[0] == "frase" and asset[1][0] == "link" and asset[1][1] not in assets:
|
|
assets.append(asset[1][1])
|
|
|
|
|
|
return assets
|