analytics.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  1. # THIS FILE IS A PART OF VCStudio
  2. # PYTHON 3
  3. import os
  4. import datetime
  5. import json
  6. from studio import checklist
  7. from studio import story
  8. from studio import schedule
  9. from settings import settings
  10. from settings import talk
  11. def iftime(string):
  12. if len(string) != len("00:00:00"):
  13. return False
  14. if len(string.split(":")) != 3:
  15. return False
  16. try:
  17. for n, i in enumerate(string.split(":")):
  18. if len(i) != 2:
  19. return False
  20. i = int(i)
  21. if n == 0 and i > 23:
  22. return False
  23. if i > 59:
  24. return False
  25. except:
  26. pass
  27. return True
  28. def ifdate(string):
  29. if len(string) != len("1997/07/30"):
  30. return False
  31. new_date_format = "%Y/%m/%d"
  32. try:
  33. datetime.datetime.strptime(string, new_date_format)
  34. ret = True
  35. except:
  36. ret = False
  37. return ret
  38. def get_legacy(project_location):
  39. # This function will return analytics data about a project. This particular
  40. # function is desinged to read old, Blender-Organizer projects. It's a first
  41. # step of conversion. And used to display basic analitycs into the
  42. # project-manager.
  43. name_tmp = project_location[project_location.rfind("/")+1:]
  44. data = {
  45. "name" : name_tmp, # Name of the project (typed properly)
  46. "director" : "", # Name of the project's director.
  47. "status" : "", # Projects's comment / type
  48. "donework" : 0.0, # Percentage of Assets and Scenes done
  49. "fraction" : 0.0, # Project's completion percentage
  50. "checklist" : 0.0, # Project's main checklist percentage
  51. "startdate" : "0000/00/00", # Date of the start of the project
  52. "deadline" : "0000/00/00", # Date when project's deadline is
  53. "duration" : 0, # Amount in days between startdate and deadline
  54. "timepassed" : 0.0, # Percentage of how much time had passed
  55. "dayspassed" : 0, # Amount of days since the startdate
  56. "chr_factor" : 1, # Importance factor for Characters
  57. "veh_factor" : 1, # Importance factor for Vehicles
  58. "loc_factor" : 1, # Importance factor for Locations
  59. "obj_factor" : 1, # Importance factor for Objects (Other)
  60. "rnd_factor" : 4, # Importance factor for Scenes (Renders)
  61. "chr" : 0.0, # Percentage of Characters done
  62. "veh" : 0.0, # Percentage of Vehicles done
  63. "loc" : 0.0, # Percentage of Locations done
  64. "obj" : 0.0, # Percentage of Objects (Other) done
  65. "rnd" : 0.0, # Percentage of Scenes (Renders) done
  66. "dates" : {} # Per date, detailed data about the project
  67. }
  68. # For the future we will have to use some kind of network system. Where
  69. # different people contribute to one project. For example director, writer,
  70. # animator. For this I want to introduce a USERNAME thing. I will add them
  71. # later to tasks and schedulings.
  72. Username = settings.read("Username")
  73. if not Username:
  74. Username = "Blender-Organizer User"
  75. # Okay let's get the name, director and status from the old file. Funny that
  76. # it still survived from so far back. In the Organizer 1.0 you had to manually
  77. # type in the number of assets that had to be done in each category.
  78. # And so for this task was created a file called "project.data". Here is
  79. # an example :
  80. # Project :Moria's Race
  81. # Status :Short Action Driving Film
  82. # Director :J.Y.Amihud
  83. # Character:1
  84. # Locations:1
  85. # Objects :1
  86. # Vehicles :1
  87. # Scenes :4
  88. # So that's survived up to the last Blender-Organizer. But no longer the
  89. # last 5 lines were utilized. I was using it mainly for the first 3 things.
  90. # Tho from a version 4.85 of Blender-Organizer those last lines were used
  91. # to controll the influence factor. Basically the number stored will multiply
  92. # the number of times a given category is counted in the final percentage.
  93. # For example animating scenes should take more then half the time of the
  94. # project. More then 50% of the project then should be in the scenes. But
  95. # previous / primitive algorythm was giving each category an even 20%. So
  96. # of course I fixed it. LOL.
  97. # I think for VCStudio I gonna make a more unified file format. That will
  98. # unite all "project.data", "percentage_hystory.data", "history.data" and
  99. # "schedule.data".
  100. # I'm going to still have the main checklist separate tho. The checklist
  101. # format is quite good.
  102. projectdata = open(project_location+"/project.data")
  103. projectdata = projectdata.read()
  104. projectdata = projectdata.split("\n")
  105. for line in projectdata:
  106. if line.startswith("Project"):
  107. data["name"] = line[line.find(":")+1:]
  108. elif line.startswith("Status"):
  109. data["status"] = line[line.find(":")+1:]
  110. elif line.startswith("Director"):
  111. data["director"] = line[line.find(":")+1:]
  112. # Next up some integer conversions. So...
  113. elif line.startswith("Character"):
  114. try:
  115. data["chr_factor"] = int(line[line.find(":")+1:])
  116. except:
  117. data["chr_factor"] = 1
  118. elif line.startswith("Vehicles"):
  119. try:
  120. data["veh_factor"] = int(line[line.find(":")+1:])
  121. except:
  122. data["veh_factor"] = 1
  123. elif line.startswith("Locations"):
  124. try:
  125. data["loc_factor"] = int(line[line.find(":")+1:])
  126. except:
  127. data["loc_factor"] = 1
  128. elif line.startswith("Objects"):
  129. try:
  130. data["obj_factor"] = int(line[line.find(":")+1:])
  131. except:
  132. data["obj_factor"] = 1
  133. elif line.startswith("Scenes"):
  134. try:
  135. data["rnd_factor"] = int(line[line.find(":")+1:])
  136. except:
  137. data["rnd_factor"] = 1
  138. # Okay this first file was easy. Let's now parse the main checklist and
  139. # get 5 more values. Funny thing is that for the old checklists and new
  140. # checklists you can use the same function to read them. ( The main check-
  141. # list data ). But old checklists had something else in there that was
  142. # making them a bit different from VCStudio checklists. It's the STR and FIN
  143. # variables in the beginig.
  144. # See in the Organizer 1.0 there was no scheduling system as there was in
  145. # Blender-Orgaznier 4.9. The scheduling was done per asset and not per
  146. # action in the checklist. So STR and FIN were 2 dates between which you
  147. # should have had working on the asset.
  148. # But in the main checklists ("project.progress") those 2 survived to the
  149. # late Blender-Organizer as a project startdate and deadline.
  150. # One more rub that I have is that date format was 00/00/0000 and not the
  151. # way better one 0000/00/00 which makes sorting easy. So yeah...
  152. old_date_format = "%d/%m/%Y"
  153. new_date_format = "%Y/%m/%d"
  154. projectdata = open(project_location+"/project.progress")
  155. projectdata = projectdata.read()
  156. projectdata = projectdata.split("\n")
  157. startdate = datetime.datetime.today()
  158. deadline = datetime.datetime.today()
  159. try:
  160. for line in projectdata:
  161. if line.startswith("STR"):
  162. startdate = datetime.datetime.strptime(line[4:], old_date_format)
  163. data["startdate"] = datetime.datetime.strftime(startdate, new_date_format)
  164. elif line.startswith("FIN"):
  165. deadline = datetime.datetime.strptime(line[4:], old_date_format)
  166. data["deadline"] = datetime.datetime.strftime(deadline, new_date_format)
  167. except:
  168. data["startdate"] = datetime.datetime.strftime(datetime.datetime.today(), new_date_format)
  169. data["deadline"] = datetime.datetime.strftime(datetime.datetime.today()+datetime.timedelta(days=30), new_date_format)
  170. # So we've go the dates. Let's calculate time perventage I guess.
  171. delta = deadline - startdate
  172. data["duration"] = int(delta.days)
  173. delta = datetime.datetime.today() - startdate
  174. data["dayspassed"] = int(delta.days)
  175. data["timepassed"] = data["dayspassed"] / data["duration"]
  176. if data["timepassed"] > 1.0:
  177. data["timepassed"] = 1.0
  178. # Now let's lauch the main checklist and get the data from there. I mean
  179. # the percentage. Btw It's just a hard thing. That I needed a separate
  180. # function for it.
  181. try:
  182. projectdata = checklist.get_list(project_location+"/project.progress")
  183. data["checklist"] = projectdata["fraction"]
  184. except:
  185. pass
  186. # NEXT THING. As I love to type it into place where people read me while I'm
  187. # working. We've got data from 2 files. Now we need to get data from ALL the
  188. # project.
  189. # First we going to get data about the assets. Because it's relativelly easy
  190. # compared to the story. For which you need to parce a crazy complicated .bos
  191. # file. Which is a complex database in it's own right.
  192. # So let's go and quickly get data about the assets.
  193. asstfols = ["chr", "veh", "loc", "obj"]
  194. astlist = []
  195. for n , f in enumerate(asstfols):
  196. flist = []
  197. if len(os.listdir(project_location+"/dev/"+f)) > 0:
  198. for asset in os.listdir(project_location+"/dev/"+f):
  199. if asset+".blend" in os.listdir(project_location+"/ast/"+f):
  200. flist.append(1.0)
  201. else:
  202. try:
  203. fcheck = checklist.get_list(project_location+"/dev/"+f+"/"+asset+"/asset.progress")
  204. flist.append(fcheck["fraction"])
  205. except:
  206. flist.append(0.0)
  207. # The multiplication thing that I was talking about earlier.
  208. multiply = data[f+"_factor"]
  209. for m in range(multiply):
  210. astlist.append(sum(flist)/len(flist))
  211. data[f] = sum(flist)/len(flist)
  212. # For the next step I need to have the story parsed and read. But it's going
  213. # to be so hard. That I will need to write a separate function for it.
  214. data["rnd"] = story.get_legacy(project_location)["fraction"]
  215. # After all of it we need to get the final project percentage.
  216. multiply = data["rnd_factor"]
  217. for m in range(multiply):
  218. astlist.append(data["rnd"])
  219. try:
  220. data["donework"] = sum(astlist) / len(astlist)
  221. except:
  222. data["donework"] = 0.0
  223. data["fraction"] = (data["donework"] + data["checklist"]) / 2
  224. # Next section of this data gathering will be about history, scheduling and
  225. # similar things. I gonna create a dictionary of dates. And input data about
  226. # those dates into the dates.
  227. # One thing that I have to make sure about is that some dates could be out-
  228. # side of the range between startdate and deadline. So I have to read the
  229. # files and add them dynamically.
  230. # Let's start by reading scheduling.
  231. sdata = open(project_location+"/schedule.data")
  232. sdata = sdata.read()
  233. sdata = sdata.split("\n")
  234. # Good that schedules already have the right date format. Altho I think of
  235. # actually using a datetime object as a date. Or is it too much? Let me think
  236. # I do think loudly. And sinse I have nobody to talk to I will type it here.
  237. # If you couldn't tell already. Let's write it as a string for now. Because
  238. # it's easier to work wit strings. Maybe in future I will write it as a
  239. # datetime object. If i'll find benefit to this.
  240. for date in sdata:
  241. # Let's separate the string into 3 components. Basically scheduling is
  242. # list of tasks in various checklists through out the project. Example:
  243. # 2020/11/30 /dev/obj/Morias_Bike/asset.progress Rigging=:> Make Bones
  244. # 2021/05/01 project.progress Marketing=:> Release
  245. # The first entry is a date formatted yyyy/mm/dd. Then comes path of the
  246. # checklist location. Relative to the project_location. Then a url type
  247. # thing for with in the checklist. Separating entries with "=:>"
  248. # Also I have to note that in the old Blender-Organizer date 1997/07/30
  249. # which is my birthday, will make the task be everyday. It will have it's
  250. # own Green color. Usually when you make a new project there are a list
  251. # of task created for this date.
  252. if date:
  253. d = date[:date.find(" ")] # Date
  254. f = date[date.find(" ")+1:date.replace(" ", ".", 1).find(" ")] # File
  255. t = date[date.replace(" ", ".", 1).find(" ")+1:].split("=:>") # Task
  256. if d not in data["dates"]:
  257. data["dates"][d] = {}
  258. # Now in order to decide how to input this data into the data["dates"]
  259. # we need to look at history at first. Because first of all it has
  260. # similar syntax. But on the other hand it's a bit more complex.
  261. # 2020/07/05 03:06:34 /dev/chr/Civilian_Child_2/asset.progress Rigging=:> Face Rig=:> Mouth area [V]
  262. # 2020/07/05 03:06:35 /dev/chr/Civilian_Child_2/asset.progress Rigging=:> Ready to make AST [V]
  263. # 2020/07/05 03:06:37 /dev/chr/Civilian_Child_2/Civilian_Child_2.blend [Openned]
  264. # 2020/07/05 03:07:56 /dev/chr/Civilian_Child_2/autolink.data [Updated]
  265. # 2020/07/05 03:08:08 pln/main.bos [Edited]
  266. # 2020/07/05 03:08:13 /rnd/Scene_2a5jfq6126fe/1/Cc1_IK_Test.blend [Openned]
  267. # 2020/07/05 03:08:25 /rnd/Scene_2a5jfq6126fe/1/Cc1_IK_Test.blend [Linked]
  268. # 2020/07/05 03:08:25 /rnd/Scene_2a5jfq6126fe/1/Cc1_IK_Test.blend [Openned]
  269. # Also history has a feature missing in the schedules. But there is
  270. # a rub. Scheduling you can rearange by moving them arround. And you
  271. # can simply move a task to a different day if you so desire.
  272. # In the history apart from the date you also have time up to the second
  273. # which is a bit more precise in terms of when exactly you made a
  274. # given task. And I would like scheduling to have the same type of
  275. # precision. Maybe even introduce a notification system if a certain
  276. # task is due. But it makes the moving of tasks highly complicated
  277. # to visualize.
  278. # Maybe a timeline could be a cool idea. Like in the VSE of blender.
  279. # a place where you could put specific points on a timeline. And time
  280. # to the next point will be hte length of the part.
  281. # You could move the dots so to change timing of parts. And maybe
  282. # select them to type in precise values. Could work.
  283. # Let's separate the schedule to 3 types. Asset, Scene, Main.
  284. # If it's a scene we are talking about. IK it's a bit shitty. Because
  285. # I will need to parse this as well. But who cares.
  286. if f.startswith("/rnd"):
  287. ty = "scenes"
  288. url = f[:f.rfind("/")].replace("/rnd", "", 1)
  289. url = url[:url.rfind("/")]
  290. fn = f.replace("/rnd", "", 1).replace(url, "")
  291. elif f.startswith("/dev"):
  292. ty = "assets"
  293. url = f[:f.rfind("/")].replace("/dev", "", 1)
  294. fn = f.replace("/dev", "", 1).replace(url, "")
  295. else:
  296. ty = "files"
  297. url = ""
  298. fn = f
  299. if not ty in data["dates"][d]:
  300. data["dates"][d][ty] = {}
  301. if not url in data["dates"][d][ty]:
  302. data["dates"][d][ty][url] = []
  303. data["dates"][d][ty][url].append([
  304. "00:00:00",
  305. "schedule",
  306. fn,
  307. t,
  308. Username
  309. ])
  310. # Okay I don't really know what exactly did I just do. But it's seems like
  311. # a good starting point. Up to a working verion of VCStudio i can edit and
  312. # change these all I want. Okay I guess it's time to parse another, way
  313. # harder file. The history. LOL.
  314. # First let's deal with the persantage history file. It's kind of a funny
  315. # one as well. The funny part is that it has no consistancy at all. I will
  316. # need to convert it as well. It has a stupid %y-%m-%d format. Which is WTF.
  317. history_percentage_format = "%y-%m-%d"
  318. hdata = open(project_location+"/percentage_hystory.data") # IK spelling LOL
  319. hdata = hdata.read()
  320. hdata = hdata.split("\n")
  321. for date in hdata:
  322. if date.startswith("DATE"):
  323. # An example of the formatting is actually quite amazing. It's going
  324. # to be realively simple. Example:
  325. # DATE 20-06-26 42.64%
  326. # As you can see it's the word DATE then that date then the fraction
  327. # as a percantage. Separated by a spacebar.
  328. try:
  329. t, d, f = date.split(" ")
  330. # Converting the d into a normal date
  331. d = datetime.datetime.strptime(d, history_percentage_format)
  332. d = datetime.datetime.strftime(d, new_date_format)
  333. # Converting the f into a fraction
  334. f = float(f.replace("%", "")) / 100
  335. except:
  336. continue
  337. # I just don't want to deal with poeple who are editing the file
  338. # manually and then say I did something wrong that the program crashed
  339. if d not in data["dates"]:
  340. data["dates"][d] = {}
  341. data["dates"][d]["fractions"] = {
  342. "project":f, # The fraction we recieved from the file
  343. "checklist":0.0, # Place holder for checklist fraction
  344. "chr":0.0, # \
  345. "veh":0.0, # |
  346. "loc":0.0, # > - Plaseholders for categories
  347. "obj":0.0, # |
  348. "rnd":0.0 # /
  349. }
  350. # Okay this file was parsed. Which was relativelly simple. NOW. Let's
  351. # do something a bit harder. Or is it as simple as the other? IDK
  352. # History file. Example was a bit earlier.
  353. hdata = open(project_location+"/history.data")
  354. hdata = hdata.read()
  355. hdata = hdata.split("\n")
  356. for line in hdata:
  357. if not line:
  358. continue
  359. # So basically every line is quite simple from the left side. But becomes
  360. # quite complex on the right side. So let's get the left side things
  361. date = line[:line.find(" ")]
  362. time = line[line.find(" ")+1:line.replace(" ", ".", 1).find(" ")]
  363. path = line[line.replace(" ", ".", 1).find(" ")+1:line.replace(" ", ".", 2).find(" ")]
  364. done = line[line.replace(" ", ".", 2).find(" ")+1:]
  365. # I made a mistake allowing paths to have spaces in them. And I need to
  366. # make sure we have the whole path and not only up to a point.
  367. while done[0] != "[" and ".progress" not in path and "[" in done:
  368. transporting = done[:done.find(" ")]
  369. path = path+" "+transporting
  370. done = done.replace(transporting+" ", "")
  371. # "date" will be our standard date. yyyy/mm/dd. Then "time" is out time
  372. # from the current day. 24 hours system. hh:mm:ss. "path" is the file to
  373. # which the change was done. We will need to parse this one. Because it
  374. # contains the full path to let's say a blend file. While we want to
  375. # know which asset for example was accessed. Then "done" is the rest of
  376. # the string. Basically it tells what was actually done with a given file.
  377. # We will need to parse this one as well somehow. And it scares me a lot
  378. # One thing that we can use it for is restoring the old scheduling list.
  379. # Becuase in lazy attempt to make user know that a given task is finished
  380. # I would just delete the task from the schedule file entirely. But
  381. # in the history file you can find instances of [scheduled] with the full
  382. # path of a task and the date to which it was scheduled. So yeah.
  383. # Let's get to work.
  384. f = path # Copied from previous
  385. if f.startswith("/rnd"):
  386. ty = "scenes"
  387. url = f[:f.rfind("/")].replace("/rnd", "", 1)
  388. url = url[:url.rfind("/")]
  389. fn = f.replace("/rnd", "", 1).replace(url, "")
  390. elif f.startswith("/dev"):
  391. ty = "assets"
  392. url = f[:f.rfind("/")].replace("/dev", "", 1)
  393. fn = f.replace("/dev", "", 1).replace(url, "")
  394. elif f.startswith("/ast") and ".blend" in f:
  395. ty = "assets"
  396. url = f[:f.rfind(".")].replace("/ast", "", 1)
  397. fn = "[asset_blend]"
  398. else:
  399. ty = "files"
  400. url = ""
  401. fn = f
  402. # Now in order to parse the "done" variable. We need to define functions
  403. # that we are not looking for. Simple (Trivial) Operations.
  404. simple_operations = [
  405. "[Edited]",
  406. "[Openned]",
  407. "[Linked]",
  408. "[Edited]",
  409. "[Updated]",
  410. "[Added]",
  411. "[Added Asset]"
  412. ]
  413. # Basically if "done" in on that list. It's something to do with
  414. # checklists. And then we have either [V], [ ] or [Scheduled]
  415. if done not in simple_operations:
  416. if "[Scheduled]" in done:
  417. # These are the missing scheduling data I was talking about.
  418. # Let's parse this data from the back. The one on the back
  419. # should be the DATE. Then spacebar. Then the [Scheduled] then
  420. # another spacebar then the task.
  421. missingdate = done[done.rfind(" ")+1:]
  422. missingtask = done[:done.rfind(" [Scheduled]")].split("=:>")
  423. # Let's add them into the data. I don't what it will be. Let's
  424. # see.
  425. if not missingdate in data["dates"]:
  426. data["dates"][missingdate] = {}
  427. if not ty in data["dates"][missingdate]:
  428. data["dates"][missingdate][ty] = {}
  429. if not url in data["dates"][missingdate][ty]:
  430. data["dates"][missingdate][ty][url] = []
  431. data["dates"][missingdate][ty][url].append([
  432. "00:00:00",
  433. "schedule",
  434. fn,
  435. missingtask,
  436. Username
  437. ])
  438. # Or else it's a checklist whether been checked or unchecked
  439. else:
  440. if "[V]" in done:
  441. done = done.replace(" [V]", "").split("=:>")
  442. check = "[Checked]"
  443. else:
  444. done = done.replace(" [ ]", "").split("=:>")
  445. check = "[Un-Checked]"
  446. # Putting the thing into the data
  447. if not date in data["dates"]:
  448. data["dates"][date] = {}
  449. if not ty in data["dates"][date]:
  450. data["dates"][date][ty] = {}
  451. if not url in data["dates"][date][ty]:
  452. data["dates"][date][ty][url] = []
  453. data["dates"][date][ty][url].append([
  454. time,
  455. "history",
  456. fn,
  457. check,
  458. done,
  459. Username
  460. ])
  461. #print(data["dates"][date][ty][url])
  462. # Now let's add all the others.
  463. else:
  464. if not date in data["dates"]:
  465. data["dates"][date] = {}
  466. if not ty in data["dates"][date]:
  467. data["dates"][date][ty] = {}
  468. if not url in data["dates"][date][ty]:
  469. data["dates"][date][ty][url] = []
  470. data["dates"][date][ty][url].append([
  471. time,
  472. "history",
  473. fn,
  474. done,
  475. Username
  476. ])
  477. #print(ty, url, fn, done)
  478. #for i in sorted(data["dates"]):
  479. # print(i)
  480. # print()
  481. # print(data["dates"][i])
  482. # print()
  483. # print()
  484. #data_save(project_location, data)
  485. return data
  486. def save(project, data):
  487. # This file will save analitycs data.
  488. try:
  489. os.mkdir(project+'/set/')
  490. except:
  491. pass
  492. with open(project+'/set/analytics.json', 'w') as fp:
  493. json.dump(data, fp, sort_keys=True, indent=4)
  494. def load(project_location):
  495. # This is a simple load analytics funtion.
  496. name_tmp = project_location[project_location.rfind("/")+1:]
  497. data = {
  498. "name" : name_tmp, # Name of the project (typed properly)
  499. "director" : "", # Name of the project's director.
  500. "status" : "", # Projects's comment / type
  501. "donework" : 0.0, # Percentage of Assets and Scenes done
  502. "fraction" : 0.0, # Project's completion percentage
  503. "checklist" : 0.0, # Project's main checklist percentage
  504. "startdate" : "0000/00/00", # Date of the start of the project
  505. "deadline" : "0000/00/00", # Date when project's deadline is
  506. "duration" : 0, # Amount in days between startdate and deadline
  507. "timepassed" : 0.0, # Percentage of how much time had passed
  508. "dayspassed" : 0, # Amount of days since the startdate
  509. "chr_factor" : 1, # Importance factor for Characters
  510. "veh_factor" : 1, # Importance factor for Vehicles
  511. "loc_factor" : 1, # Importance factor for Locations
  512. "obj_factor" : 1, # Importance factor for Objects (Other)
  513. "rnd_factor" : 4, # Importance factor for Scenes (Renders)
  514. "chr" : 0.0, # Percentage of Characters done
  515. "veh" : 0.0, # Percentage of Vehicles done
  516. "loc" : 0.0, # Percentage of Locations done
  517. "obj" : 0.0, # Percentage of Objects (Other) done
  518. "rnd" : 0.0, # Percentage of Scenes (Renders) done
  519. "dates" : {} # Per date, detailed data about the project
  520. }
  521. try:
  522. with open(project_location+'/set/analytics.json') as json_file:
  523. data = json.load(json_file)
  524. except:
  525. pass
  526. try:
  527. projectdata = checklist.get_list(project_location+"/set/project.progress")
  528. data["checklist"] = projectdata["fraction"]
  529. except:
  530. make = open(project_location+"/set/project.progress", "w")
  531. make.write("[ ] Story\n")
  532. make.write("[ ] "+talk.text("chr")+"\n")
  533. make.write("[ ] "+talk.text("veh")+"\n")
  534. make.write("[ ] "+talk.text("loc")+"\n")
  535. make.write("[ ] "+talk.text("obj")+"\n")
  536. make.write("[ ] Animation\n")
  537. make.write("[ ] Rendering")
  538. make.close()
  539. # Let's see if dates are fine. Or if they are even dates.
  540. new_date_format = "%Y/%m/%d"
  541. if not ifdate(data["startdate"]) or not ifdate(data["deadline"]):
  542. data["startdate"] = datetime.datetime.strftime(datetime.datetime.today(), new_date_format)
  543. data["deadline"] = datetime.datetime.strftime(datetime.datetime.today()+datetime.timedelta(days=30), new_date_format)
  544. # So we've go the dates. Let's calculate time perventage I guess.
  545. startdate = datetime.datetime.strptime(data["startdate"], new_date_format)
  546. deadline = datetime.datetime.strptime(data["deadline"] , new_date_format)
  547. delta = deadline - startdate
  548. data["duration"] = int(delta.days)
  549. delta = datetime.datetime.today() - startdate
  550. data["dayspassed"] = int(delta.days)
  551. data["timepassed"] = data["dayspassed"] / data["duration"]
  552. if data["timepassed"] > 1.0:
  553. data["timepassed"] = 1.0
  554. # LET's FILTER THE SCHEDULES
  555. data["dates"] = schedule.filter(project_location, data["dates"])
  556. # NEXT THING. As I love to type it into place where people read me while I'm
  557. # working. We've got data from 2 files. Now we need to get data from ALL the
  558. # project.
  559. # First we going to get data about the assets. Because it's relativelly easy
  560. # compared to the story. For which you need to parce a crazy complicated .bos
  561. # file. Which is a complex database in it's own right.
  562. # So let's go and quickly get data about the assets.
  563. asstfols = ["chr", "veh", "loc", "obj"]
  564. astlist = []
  565. for n , f in enumerate(asstfols):
  566. flist = []
  567. if len(os.listdir(project_location+"/dev/"+f)) > 0:
  568. for asset in os.listdir(project_location+"/dev/"+f):
  569. if asset+".blend" in os.listdir(project_location+"/ast/"+f):
  570. flist.append(1.0)
  571. else:
  572. try:
  573. fcheck = checklist.get_list(project_location+"/dev/"+f+"/"+asset+"/asset.progress")
  574. flist.append(fcheck["fraction"])
  575. except:
  576. flist.append(0.0)
  577. # The multiplication thing that I was talking about earlier.
  578. multiply = data[f+"_factor"]
  579. for m in range(multiply):
  580. astlist.append(sum(flist)/len(flist))
  581. data[f] = sum(flist)/len(flist)
  582. # For the next step I need to have the story parsed and read. But it's going
  583. # to be so hard. That I will need to write a separate function for it.
  584. data["rnd"] = story.load(project_location)["fraction"]
  585. # After all of it we need to get the final project percentage.
  586. multiply = data["rnd_factor"]
  587. for m in range(multiply):
  588. astlist.append(data["rnd"])
  589. try:
  590. data["donework"] = sum(astlist) / len(astlist)
  591. except:
  592. data["donework"] = 0.0
  593. data["fraction"] = (data["donework"] + data["checklist"]) / 2
  594. # Let's record it for today.
  595. today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format)
  596. if today not in data["dates"]:
  597. data["dates"][today] = {}
  598. data["dates"][today]["fractions"] = {
  599. "project":data["fraction"],
  600. "checklist":data["checklist"],
  601. "chr":data["chr"],
  602. "veh":data["veh"],
  603. "loc":data["loc"],
  604. "obj":data["obj"],
  605. "rnd":data["rnd"]
  606. }
  607. return data