From e85be921deaf3937d1410892153fcad7453a8e61 Mon Sep 17 00:00:00 2001 From: "Jeison Yehuda Amihud (Blender Dumbass)" <blenderdumbass@gmail.com> Date: Mon, 30 Nov 2020 13:19:22 +0000 Subject: [PATCH] History / Scheduling Parsing Now it can read and even save files from the history / scheduling form the old Blender-Organizer. In the end you can see some commented file writing things. You can plug your own location there and test this feature out. It gives hell of a clean file. I know I'll have to be able to parse the new file as well. Yeah. --- studio/analytics.py | 460 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 460 insertions(+) diff --git a/studio/analytics.py b/studio/analytics.py index c246168..cdc46ca 100644 --- a/studio/analytics.py +++ b/studio/analytics.py @@ -238,6 +238,466 @@ def get_legacy(project_location): # similar things. I gonna create a dictionary of dates. And input data about # those dates into the dates. + # One thing that I have to make sure about is that some dates could be out- + # side of the range between startdate and deadline. So I have to read the + # files and add them dynamically. + # Let's start by reading scheduling. + + sdata = open(project_location+"/schedule.data") + sdata = sdata.read() + sdata = sdata.split("\n") + + # Good that schedules already have the right date format. Altho I think of + # actually using a datetime object as a date. Or is it too much? Let me think + # I do think loudly. And sinse I have nobody to talk to I will type it here. + # If you couldn't tell already. Let's write it as a string for now. Because + # it's easier to work wit strings. Maybe in future I will write it as a + # datetime object. If i'll find benefit to this. + + for date in sdata: + + # Let's separate the string into 3 components. Basically scheduling is + # list of tasks in various checklists through out the project. Example: + + # 2020/11/30 /dev/obj/Morias_Bike/asset.progress Rigging=:> Make Bones + # 2021/05/01 project.progress Marketing=:> Release + + # The first entry is a date formatted yyyy/mm/dd. Then comes path of the + # checklist location. Relative to the project_location. Then a url type + # thing for with in the checklist. Separating entries with "=:>" + + # Also I have to note that in the old Blender-Organizer date 1997/07/30 + # which is my birthday, will make the task be everyday. It will have it's + # own Green color. Usually when you make a new project there are a list + # of task created for this date. + + if date: + d = date[:date.find(" ")] # Date + f = date[date.find(" ")+1:date.replace(" ", ".", 1).find(" ")] # File + t = date[date.replace(" ", ".", 1).find(" ")+1:].split("=:>") # Task + + if d not in data["dates"]: + data["dates"][d] = {} + + # Now in order to decide how to input this data into the data["dates"] + # we need to look at history at first. Because first of all it has + # similar syntax. But on the other hand it's a bit more complex. + + # 2020/07/05 03:06:34 /dev/chr/Civilian_Child_2/asset.progress Rigging=:> Face Rig=:> Mouth area [V] + # 2020/07/05 03:06:35 /dev/chr/Civilian_Child_2/asset.progress Rigging=:> Ready to make AST [V] + # 2020/07/05 03:06:37 /dev/chr/Civilian_Child_2/Civilian_Child_2.blend [Openned] + # 2020/07/05 03:07:56 /dev/chr/Civilian_Child_2/autolink.data [Updated] + # 2020/07/05 03:08:08 pln/main.bos [Edited] + # 2020/07/05 03:08:13 /rnd/Scene_2a5jfq6126fe/1/Cc1_IK_Test.blend [Openned] + # 2020/07/05 03:08:25 /rnd/Scene_2a5jfq6126fe/1/Cc1_IK_Test.blend [Linked] + # 2020/07/05 03:08:25 /rnd/Scene_2a5jfq6126fe/1/Cc1_IK_Test.blend [Openned] + + # Also history has a feature missing in the schedules. But there is + # a rub. Scheduling you can rearange by moving them arround. And you + # can simply move a task to a different day if you so desire. + + # In the history apart from the date you also have time up to the second + # which is a bit more precise in terms of when exactly you made a + # given task. And I would like scheduling to have the same type of + # precision. Maybe even introduce a notification system if a certain + # task is due. But it makes the moving of tasks highly complicated + # to visualize. + + # Maybe a timeline could be a cool idea. Like in the VSE of blender. + # a place where you could put specific points on a timeline. And time + # to the next point will be hte length of the part. + + # You could move the dots so to change timing of parts. And maybe + # select them to type in precise values. Could work. + + + # Let's separate the schedule to 3 types. Asset, Scene, Main. + + # If it's a scene we are talking about. IK it's a bit shitty. Because + # I will need to parse this as well. But who cares. + + if f.startswith("/rnd"): + ty = "scenes" + url = f[:f.rfind("/")].replace("/rnd", "", 1) + url = url[:url.rfind("/")] + fn = f.replace("/rnd", "", 1).replace(url, "") + + + + + elif f.startswith("/dev"): + ty = "assets" + url = f[:f.rfind("/")].replace("/dev", "", 1) + fn = f.replace("/dev", "", 1).replace(url, "") + + + + else: + ty = "files" + url = "" + fn = f + + if not ty in data["dates"][d]: + data["dates"][d][ty] = {} + + if not url in data["dates"][d][ty]: + data["dates"][d][ty][url] = [] + + data["dates"][d][ty][url].append([ + "00:00:00", + "schedule", + fn, + t + ]) + + # Okay I don't really know what exactly did I just do. But it's seems like + # a good starting point. Up to a working verion of VCStudio i can edit and + # change these all I want. Okay I guess it's time to parse another, way + # harder file. The history. LOL. + + # First let's deal with the persantage history file. It's kind of a funny + # one as well. The funny part is that it has no consistancy at all. I will + # need to convert it as well. It has a stupid %y-%m-%d format. Which is WTF. + + history_percentage_format = "%y-%m-%d" + + hdata = open(project_location+"/percentage_hystory.data") # IK spelling LOL + hdata = hdata.read() + hdata = hdata.split("\n") + + for date in hdata: + if date.startswith("DATE"): + + # An example of the formatting is actually quite amazing. It's going + # to be realively simple. Example: + + # DATE 20-06-26 42.64% + + # As you can see it's the word DATE then that date then the fraction + # as a percantage. Separated by a spacebar. + + try: + t, d, f = date.split(" ") + + # Converting the d into a normal date + + d = datetime.datetime.strptime(d, history_percentage_format) + d = datetime.datetime.strftime(d, new_date_format) + + # Converting the f into a fraction + + f = float(f.replace("%", "")) / 100 + + except: + continue + + # I just don't want to deal with poeple who are editing the file + # manually and then say I did something wrong that the program crashed + + if d not in data["dates"]: + data["dates"][d] = {} + + data["dates"][d]["fractions"] = { + "project":f, # The fraction we recieved from the file + "checklist":0.0, # Place holder for checklist fraction + "chr":0.0, # \ + "veh":0.0, # | + "loc":0.0, # > - Plaseholders for categories + "obj":0.0, # | + "rnd":0.0 # / + } + + + # Okay this file was parsed. Which was relativelly simple. NOW. Let's + # do something a bit harder. Or is it as simple as the other? IDK + # History file. Example was a bit earlier. + + hdata = open(project_location+"/history.data") + hdata = hdata.read() + hdata = hdata.split("\n") + + for line in hdata: + + if not line: + continue + + # So basically every line is quite simple from the left side. But becomes + # quite complex on the right side. So let's get the left side things + + date = line[:line.find(" ")] + time = line[line.find(" ")+1:line.replace(" ", ".", 1).find(" ")] + path = line[line.replace(" ", ".", 1).find(" ")+1:line.replace(" ", ".", 2).find(" ")] + done = line[line.replace(" ", ".", 2).find(" ")+1:] + + # I made a mistake allowing paths to have spaces in them. And I need to + # make sure we have the whole path and not only up to a point. + + while done[0] != "[" and ".progress" not in path and "[" in done: + + transporting = done[:done.find(" ")] + + path = path+" "+transporting + done = done.replace(transporting+" ", "") + + + # "date" will be our standard date. yyyy/mm/dd. Then "time" is out time + # from the current day. 24 hours system. hh:mm:ss. "path" is the file to + # which the change was done. We will need to parse this one. Because it + # contains the full path to let's say a blend file. While we want to + # know which asset for example was accessed. Then "done" is the rest of + # the string. Basically it tells what was actually done with a given file. + # We will need to parse this one as well somehow. And it scares me a lot + + # One thing that we can use it for is restoring the old scheduling list. + # Becuase in lazy attempt to make user know that a given task is finished + # I would just delete the task from the schedule file entirely. But + # in the history file you can find instances of [scheduled] with the full + # path of a task and the date to which it was scheduled. So yeah. + + # Let's get to work. + + f = path # Copied from previous + + if f.startswith("/rnd"): + ty = "scenes" + url = f[:f.rfind("/")].replace("/rnd", "", 1) + url = url[:url.rfind("/")] + fn = f.replace("/rnd", "", 1).replace(url, "") + + + elif f.startswith("/dev"): + ty = "assets" + url = f[:f.rfind("/")].replace("/dev", "", 1) + fn = f.replace("/dev", "", 1).replace(url, "") + + elif f.startswith("/ast") and ".blend" in f: + ty = "assets" + url = f[:f.rfind(".")].replace("/ast", "", 1) + fn = "[asset_blend]" + + else: + ty = "files" + url = "" + fn = f + + # Now in order to parse the "done" variable. We need to define functions + # that we are not looking for. Simple (Trivial) Operations. + + simple_operations = [ + "[Edited]", + "[Openned]", + "[Linked]", + "[Edited]", + "[Updated]", + "[Added]", + "[Added Asset]" + ] + + # Basically if "done" in on that list. It's something to do with + # checklists. And then we have either [V], [ ] or [Scheduled] + + if done not in simple_operations: + if "[Scheduled]" in done: + + # These are the missing scheduling data I was talking about. + # Let's parse this data from the back. The one on the back + # should be the DATE. Then spacebar. Then the [Scheduled] then + # another spacebar then the task. + + missingdate = done[done.rfind(" ")+1:] + missingtask = done[:done.rfind(" [Scheduled]")].split("=:>") + + # Let's add them into the data. I don't what it will be. Let's + # see. + + + if not missingdate in data["dates"]: + data["dates"][missingdate] = {} + + if not ty in data["dates"][missingdate]: + data["dates"][missingdate][ty] = {} + + if not url in data["dates"][missingdate][ty]: + data["dates"][missingdate][ty][url] = [] + + data["dates"][missingdate][ty][url].append([ + "00:00:00", + "schedule", + fn, + missingtask + ]) + + # Or else it's a checklist whether been checked or unchecked + + else: + if "[V]" in done: + done = done.replace(" [V]", "").split("=:>") + check = True + else: + done = done.replace(" [ ]", "").split("=:>") + check = False + + # Putting the thing into the data + + if not date in data["dates"]: + data["dates"][date] = {} + + if not ty in data["dates"][date]: + data["dates"][date][ty] = {} + + if not url in data["dates"][date][ty]: + data["dates"][date][ty][url] = [] + + data["dates"][date][ty][url].append([ + time, + "history", + fn, + "[Checklist]", + [ + done, + check + ] + ]) + + # Now let's add all the others. + + else: + if not date in data["dates"]: + data["dates"][date] = {} + + if not ty in data["dates"][date]: + data["dates"][date][ty] = {} + + if not url in data["dates"][date][ty]: + data["dates"][date][ty][url] = [] + + data["dates"][date][ty][url].append([ + time, + "history", + fn, + done + ]) + + #print(ty, url, fn, done) + + + + + data_save(data) return data +def data_save(data): + + # This function will save the data to the /set folder. It will include a + # a whole lot of inforamtion. Basically all analytics data will be there. + + new_date_format = "%Y/%m/%d" + + lines = [] + + lines.append("##################### VCStudio Analytics File #####################") + lines.append("") + lines.append(" Last update: "+datetime.datetime.strftime(datetime.datetime.today(), new_date_format)) + lines.append("") + lines.append(" Project : "+data["name"]) + lines.append(" Director: "+data["director"]) + lines.append(" Comment : "+data["status"]) + lines.append("") + lines.append(" From: "+data["startdate"]+" To: "+data["deadline"]) + lines.append("") + lines.append("-------------------------------------------------------------------") + lines.append("") + lines.append(" CURREND PROGRESS : "+str(data["fraction"]*100)+"%") + lines.append("") + lines.append(" Current actuall : "+str(data["donework"]*100)+"%") + lines.append(" Current checklist : "+str(data["checklist"]*100)+"%") + lines.append("") + lines.append(" Current Characters: "+str(data["chr"]*100)+"%") + lines.append(" Current Vehicled : "+str(data["veh"]*100)+"%") + lines.append(" Current Locations : "+str(data["loc"]*100)+"%") + lines.append(" Current Other(obj): "+str(data["obj"]*100)+"%") + lines.append(" Current Scenes : "+str(data["rnd"]*100)+"%") + lines.append("") + lines.append("-------------------------------------------------------------------") + lines.append("") + lines.append(" Bias:") + lines.append(" Characters: X "+str(data["chr_factor"])) + lines.append(" Vehicled : X "+str(data["veh_factor"])) + lines.append(" Locations : X "+str(data["loc_factor"])) + lines.append(" Other(obj): X "+str(data["obj_factor"])) + lines.append(" Scenes : X "+str(data["rnd_factor"])) + lines.append("") + lines.append("##################### Schedule / History #####################") + lines.append("") + + for date in sorted(data["dates"]): + lines.append(" "+date) + + date = data["dates"][date] + + if "fractions" in date: + lines.append("") + lines.append(" Actuall : "+str(date["fractions"]["project"]*100)+"%") + lines.append("") + lines.append(" Characters: "+str(date["fractions"]["chr"]*100)+"%") + lines.append(" Vehicles : "+str(date["fractions"]["veh"]*100)+"%") + lines.append(" Locations : "+str(date["fractions"]["loc"]*100)+"%") + lines.append(" Other(obj): "+str(date["fractions"]["obj"]*100)+"%") + lines.append(" Scenes : "+str(date["fractions"]["rnd"]*100)+"%") + + for thing in ["assets", "scenes", "files"]: + if thing in date: + + lines.append("") + lines.append(" ---- "+thing+" :") + + for asset in sorted( date[thing] ): + lines.append(" ---- "+asset+" : ") + lines.append("") + for task in date[thing][asset]: + + + if task[1] == "schedule": + lines.append(" "+task[0]+" "+task[1]) + lines.append(" "+task[2]) + lines.append("") + spaces = " " + for directory in task[3]: + spaces = spaces + ":..." + lines.append(spaces+directory) + + elif task[3] == "[Checklist]": + lines.append(" "+task[0]+" "+task[1]+" "+task[3]) + lines.append(" "+task[2]) + lines.append("") + spaces = " " + okay = " [Un-Checked]" + if task[4][1]: + okay = " [Checked]" + for directory in task[4][0]: + spaces = spaces + ":..." + add_okay = "" + if directory == task[4][0][-1]: + add_okay = okay + lines.append(spaces+directory+add_okay) + + else: + lines.append(" "+task[0]+" "+task[1]+" "+task[3]) + lines.append(" "+task[2]) + + lines.append("") + + + lines.append("") + lines.append("-------------------------------------------------------------------") + lines.append("") + + #test = open("/home/vcs/Desktop/testfile.vcsa", "w") + + + for i in lines: + print(i) + #test.write(i+"\n") + + #test.close()