def open_project_json(projectFileName): """ open project json Args: projectFileName (str): path of project Returns: str: project path bool: True if project changed dict: BORIS project str: message """ logging.debug("open project: {0}".format(projectFileName)) projectChanged = False msg = "" if not os.path.isfile(projectFileName): return projectFileName, projectChanged, { "error": "File {} not found".format(projectFileName) }, msg s = open(projectFileName, "r").read() try: pj = json.loads(s) except: return projectFileName, projectChanged, { "error": "This project file seems corrupted" }, msg # transform time to decimal pj = utilities.convert_time_to_decimal(pj) # add coding_map key to old project files if not "coding_map" in pj: pj["coding_map"] = {} projectChanged = True # add subject description if "project_format_version" in pj: for idx in [x for x in pj[SUBJECTS]]: if not "description" in pj[SUBJECTS][idx]: pj[SUBJECTS][idx]["description"] = "" projectChanged = True # check if project file version is newer than current BORIS project file version if "project_format_version" in pj and Decimal( pj["project_format_version"]) > Decimal(project_format_version): return projectFileName, projectChanged, { "error": ("This project file was created with a more recent version of BORIS.\n" "You must update BORIS to open it") }, msg # check if old version v. 0 *.obs if "project_format_version" not in pj: # convert VIDEO, AUDIO -> MEDIA pj['project_format_version'] = project_format_version projectChanged = True for obs in [x for x in pj[OBSERVATIONS]]: # remove 'replace audio' key if "replace audio" in pj[OBSERVATIONS][obs]: del pj[OBSERVATIONS][obs]['replace audio'] if pj[OBSERVATIONS][obs][TYPE] in ['VIDEO', 'AUDIO']: pj[OBSERVATIONS][obs][TYPE] = MEDIA # convert old media list in new one if len(pj[OBSERVATIONS][obs][FILE]): d1 = {PLAYER1: [pj[OBSERVATIONS][obs][FILE][0]]} if len(pj[OBSERVATIONS][obs][FILE]) == 2: d1[PLAYER2] = [pj[OBSERVATIONS][obs][FILE][1]] pj[OBSERVATIONS][obs][FILE] = d1 # convert VIDEO, AUDIO -> MEDIA for idx in [x for x in pj[SUBJECTS]]: key, name = pj[SUBJECTS][idx] pj[SUBJECTS][idx] = {"key": key, "name": name, "description": ""} msg = ( "The project file was converted to the new format (v. {}) in use with your version of BORIS.<br>" "Choose a new file name for saving it." ).format(project_format_version) projectFileName = "" for obs in pj[OBSERVATIONS]: if not "time offset second player" in pj[OBSERVATIONS][obs]: pj[OBSERVATIONS][obs]["time offset second player"] = Decimal("0.0") projectChanged = True # update modifiers to JSON format project_lowerthan4 = False logging.debug("project_format_version: {}".format( utilities.versiontuple(pj["project_format_version"]))) if "project_format_version" in pj and utilities.versiontuple( pj["project_format_version"]) < utilities.versiontuple("4.0"): for idx in pj[ETHOGRAM]: if pj[ETHOGRAM][idx]["modifiers"]: if isinstance(pj[ETHOGRAM][idx]["modifiers"], str): project_lowerthan4 = True modif_set_list = pj[ETHOGRAM][idx]["modifiers"].split("|") modif_set_dict = {} for modif_set in modif_set_list: modif_set_dict[str(len(modif_set_dict))] = { "name": "", "type": SINGLE_SELECTION, "values": modif_set.split(",") } pj[ETHOGRAM][idx]["modifiers"] = dict(modif_set_dict) else: pj[ETHOGRAM][idx]["modifiers"] = {} if not project_lowerthan4: msg = "The project version was updated from {} to {}".format( pj["project_format_version"], project_format_version) pj["project_format_version"] = project_format_version projectChanged = True # add category key if not found for idx in pj[ETHOGRAM]: if "category" not in pj[ETHOGRAM][idx]: pj[ETHOGRAM][idx]["category"] = "" logging.debug("project_lowerthan4: {}".format(project_lowerthan4)) if project_lowerthan4: copyfile(projectFileName, projectFileName.replace(".boris", "_old_version.boris")) msg = ( "The project was updated to the current project version ({project_format_version}).\n\n" "The old file project was saved as {project_file_name}").format( project_format_version=project_format_version, project_file_name=projectFileName.replace( ".boris", "_old_version.boris")) # if one file is present in player #1 -> set "media_info" key with value of media_file_info project_updated = False for obs in pj[OBSERVATIONS]: if pj[OBSERVATIONS][obs][TYPE] in [ MEDIA ] and "media_info" not in pj[OBSERVATIONS][obs]: pj[OBSERVATIONS][obs]['media_info'] = { "length": {}, "fps": {}, "hasVideo": {}, "hasAudio": {} } for player in [PLAYER1, PLAYER2]: # fix bug Anne Maijer 2017-07-17 if pj[OBSERVATIONS][obs]["file"] == []: pj[OBSERVATIONS][obs]["file"] = {"1": [], "2": []} for media_file_path in pj[OBSERVATIONS][obs]["file"][player]: # FIX: ffmpeg path ret, msg = utilities.check_ffmpeg_path() if not ret: return projectFileName, projectChanged, { "error": "FFmpeg path not found" }, "" else: ffmpeg_bin = msg nframe, videoTime, videoDuration, fps, hasVideo, hasAudio = utilities.accurate_media_analysis( ffmpeg_bin, media_file_path) if videoDuration: pj[OBSERVATIONS][obs]['media_info']["length"][ media_file_path] = videoDuration pj[OBSERVATIONS][obs]['media_info']["fps"][ media_file_path] = fps pj[OBSERVATIONS][obs]['media_info']["hasVideo"][ media_file_path] = hasVideo pj[OBSERVATIONS][obs]['media_info']["hasAudio"][ media_file_path] = hasAudio project_updated, projectChanged = True, True else: # file path not found if ("media_file_info" in pj[OBSERVATIONS][obs] and len( pj[OBSERVATIONS][obs]["media_file_info"]) == 1 and len(pj[OBSERVATIONS][obs]["file"][PLAYER1]) == 1 and len(pj[OBSERVATIONS][obs]["file"][PLAYER2]) == 0): media_md5_key = list(pj[OBSERVATIONS][obs] ["media_file_info"].keys())[0] # duration pj[OBSERVATIONS][obs]["media_info"] = { "length": { media_file_path: pj[OBSERVATIONS][obs]["media_file_info"] [media_md5_key]["video_length"] / 1000 } } project_updated, projectChanged = True, True # FPS if "nframe" in pj[OBSERVATIONS][obs][ "media_file_info"][media_md5_key]: pj[OBSERVATIONS][obs]['media_info']['fps'] = { media_file_path: pj[OBSERVATIONS][obs]['media_file_info'] [media_md5_key]['nframe'] / (pj[OBSERVATIONS][obs]['media_file_info'] [media_md5_key]['video_length'] / 1000) } else: pj[OBSERVATIONS][obs]['media_info']['fps'] = { media_file_path: 0 } if project_updated: msg = "The media files information was updated to the new project format." return projectFileName, projectChanged, pj, msg
def open_project_json(projectFileName): """ open project json Args: projectFileName (str): path of project Returns: str: project path bool: True if project changed dict: BORIS project str: message """ logging.debug("open project: {0}".format(projectFileName)) projectChanged = False msg = "" if not os.path.isfile(projectFileName): return projectFileName, projectChanged, { "error": "File {} not found".format(projectFileName) }, msg try: s = open(projectFileName, "r").read() except PermissionError: return projectFileName, projectChanged, { "error": "File {}: Permission denied".format(projectFileName) }, msg except Exception: return projectFileName, projectChanged, { "error": "Error on file {}: {}".format(projectFileName, sys.exc_info()[1]) }, msg try: pj = json.loads(s) except json.decoder.JSONDecodeError: return projectFileName, projectChanged, { "error": "This project file seems corrupted" }, msg except Exception: return projectFileName, projectChanged, { "error": "This project file seems corruptedError on file {}: {}".format( projectFileName, sys.exc_info()[1]) }, msg # transform time to decimal pj = utilities.convert_time_to_decimal(pj) # add coding_map key to old project files if "coding_map" not in pj: pj["coding_map"] = {} projectChanged = True # add subject description if "project_format_version" in pj: for idx in [x for x in pj[SUBJECTS]]: if "description" not in pj[SUBJECTS][idx]: pj[SUBJECTS][idx]["description"] = "" projectChanged = True # check if project file version is newer than current BORIS project file version if "project_format_version" in pj and Decimal( pj["project_format_version"]) > Decimal(project_format_version): return ( projectFileName, projectChanged, { "error": ("This project file was created with a more recent version of BORIS.<br>" "You must update BORIS to <b>v. >= {}</b> to open this project" ).format(pj["project_format_version"]) }, msg, ) # check if old version v. 0 *.obs if "project_format_version" not in pj: # convert VIDEO, AUDIO -> MEDIA pj["project_format_version"] = project_format_version projectChanged = True for obs in [x for x in pj[OBSERVATIONS]]: # remove 'replace audio' key if "replace audio" in pj[OBSERVATIONS][obs]: del pj[OBSERVATIONS][obs]["replace audio"] if pj[OBSERVATIONS][obs][TYPE] in ["VIDEO", "AUDIO"]: pj[OBSERVATIONS][obs][TYPE] = MEDIA # convert old media list in new one if len(pj[OBSERVATIONS][obs][FILE]): d1 = {PLAYER1: [pj[OBSERVATIONS][obs][FILE][0]]} if len(pj[OBSERVATIONS][obs][FILE]) == 2: d1[PLAYER2] = [pj[OBSERVATIONS][obs][FILE][1]] pj[OBSERVATIONS][obs][FILE] = d1 # convert VIDEO, AUDIO -> MEDIA for idx in [x for x in pj[SUBJECTS]]: key, name = pj[SUBJECTS][idx] pj[SUBJECTS][idx] = {"key": key, "name": name, "description": ""} msg = ( "The project file was converted to the new format (v. {}) in use with your version of BORIS.<br>" "Choose a new file name for saving it." ).format(project_format_version) projectFileName = "" # update modifiers to JSON format # check if project format version < 4 (modifiers were str) project_lowerthan4 = False if "project_format_version" in pj and utilities.versiontuple( pj["project_format_version"]) < utilities.versiontuple("4.0"): for idx in pj[ETHOGRAM]: if pj[ETHOGRAM][idx]["modifiers"]: if isinstance(pj[ETHOGRAM][idx]["modifiers"], str): project_lowerthan4 = True modif_set_list = pj[ETHOGRAM][idx]["modifiers"].split("|") modif_set_dict = {} for modif_set in modif_set_list: modif_set_dict[str(len(modif_set_dict))] = { "name": "", "type": SINGLE_SELECTION, "values": modif_set.split(",") } pj[ETHOGRAM][idx]["modifiers"] = dict(modif_set_dict) else: pj[ETHOGRAM][idx]["modifiers"] = {} if not project_lowerthan4: msg = "The project version was updated from {} to {}".format( pj["project_format_version"], project_format_version) pj["project_format_version"] = project_format_version projectChanged = True # add category key if not found for idx in pj[ETHOGRAM]: if "category" not in pj[ETHOGRAM][idx]: pj[ETHOGRAM][idx]["category"] = "" # if one file is present in player #1 -> set "media_info" key with value of media_file_info for obs in pj[OBSERVATIONS]: if pj[OBSERVATIONS][obs][TYPE] in [ MEDIA ] and MEDIA_INFO not in pj[OBSERVATIONS][obs]: pj[OBSERVATIONS][obs][MEDIA_INFO] = { LENGTH: {}, "fps": {}, "hasVideo": {}, "hasAudio": {} } for player in [PLAYER1, PLAYER2]: # fix bug Anne Maijer 2017-07-17 if pj[OBSERVATIONS][obs][FILE] == []: pj[OBSERVATIONS][obs][FILE] = {"1": [], "2": []} for media_file_path in pj[OBSERVATIONS][obs]["file"][player]: # FIX: ffmpeg path ret, msg = utilities.check_ffmpeg_path() if not ret: return projectFileName, projectChanged, { "error": "FFmpeg path not found" }, "" else: ffmpeg_bin = msg r = utilities.accurate_media_analysis( ffmpeg_bin, media_file_path) if "duration" in r and r["duration"]: pj[OBSERVATIONS][obs][MEDIA_INFO][LENGTH][ media_file_path] = float(r["duration"]) pj[OBSERVATIONS][obs][MEDIA_INFO][FPS][ media_file_path] = float(r["fps"]) pj[OBSERVATIONS][obs][MEDIA_INFO]["hasVideo"][ media_file_path] = r["has_video"] pj[OBSERVATIONS][obs][MEDIA_INFO]["hasAudio"][ media_file_path] = r["has_audio"] project_updated, projectChanged = True, True else: # file path not found if ("media_file_info" in pj[OBSERVATIONS][obs] and len( pj[OBSERVATIONS][obs]["media_file_info"]) == 1 and len( pj[OBSERVATIONS][obs][FILE][PLAYER1]) == 1 and len(pj[OBSERVATIONS][obs][FILE][PLAYER2]) == 0): media_md5_key = list(pj[OBSERVATIONS][obs] ["media_file_info"].keys())[0] # duration pj[OBSERVATIONS][obs][MEDIA_INFO] = { LENGTH: { media_file_path: pj[OBSERVATIONS][obs]["media_file_info"] [media_md5_key]["video_length"] / 1000 } } projectChanged = True # FPS if "nframe" in pj[OBSERVATIONS][obs][ "media_file_info"][media_md5_key]: pj[OBSERVATIONS][obs][MEDIA_INFO][FPS] = { media_file_path: pj[OBSERVATIONS][obs]["media_file_info"] [media_md5_key]["nframe"] / (pj[OBSERVATIONS][obs]["media_file_info"] [media_md5_key]["video_length"] / 1000) } else: pj[OBSERVATIONS][obs][MEDIA_INFO][FPS] = { media_file_path: 0 } # update project to v.7 for time offset second player project_lowerthan7 = False for obs in pj[OBSERVATIONS]: if "time offset second player" in pj[OBSERVATIONS][obs]: if MEDIA_INFO not in pj[OBSERVATIONS][obs]: pj[OBSERVATIONS][obs][MEDIA_INFO] = {} if "offset" not in pj[OBSERVATIONS][obs][MEDIA_INFO]: pj[OBSERVATIONS][obs][MEDIA_INFO]["offset"] = {} for player in pj[OBSERVATIONS][obs][FILE]: pj[OBSERVATIONS][obs][MEDIA_INFO]["offset"][player] = 0.0 if pj[OBSERVATIONS][obs]["time offset second player"]: pj[OBSERVATIONS][obs][MEDIA_INFO]["offset"]["2"] = float( pj[OBSERVATIONS][obs]["time offset second player"]) del pj[OBSERVATIONS][obs]["time offset second player"] project_lowerthan7 = True msg = ( "The project file was converted to the new format (v. {project_version}) in use with your version of BORIS.<br>" "Please note that this new version will NOT be compatible with previous BORIS versions (< v. {project_version}).<br>" ).format(project_version=project_format_version) projectChanged = True if project_lowerthan7: msg = ( "The project was updated to the current project version ({project_format_version})." ).format(project_format_version=project_format_version) try: copyfile( projectFileName, projectFileName.replace( ".boris", ".v{}.boris".format(pj["project_format_version"]))) msg += "\n\nThe old file project was saved as {}".format( projectFileName.replace( ".boris", ".v{}.boris".format(pj["project_format_version"]))) except Exception: pass pj["project_format_version"] = project_format_version return projectFileName, projectChanged, pj, msg
def test_2(self): r = utilities.versiontuple("1.2") assert r == (1,2)
def test_3(self): r = utilities.versiontuple("1") assert r == (1,)
def test_4(self): r = utilities.versiontuple("") assert r == ()
def test_1(self): r = utilities.versiontuple("1.2.3") assert r == (1,2,3)
def test_3(self): r = utilities.versiontuple("1") assert r == (1,)
def test_2(self): r = utilities.versiontuple("1.2") assert r == (1,2)
def test_1(self): r = utilities.versiontuple("1.2.3") assert r == (1,2,3)
def open_project_json(projectFileName): """ open project json Args: projectFileName (str): path of project Returns: str: project path bool: True if project changed dict: BORIS project str: message """ logging.debug("Abrir projeto: {0}".format(projectFileName)) projectChanged = False msg = "" if not os.path.isfile(projectFileName): return projectFileName, projectChanged, { "error": "Arquivo {} não existe".format(projectFileName) }, msg s = open(projectFileName, "r").read() try: pj = json.loads(s) except: return projectFileName, projectChanged, { "error": "Este arquivo de projeto parece corrompido" }, msg # transform time to decimal pj = utilities.convert_time_to_decimal(pj) # add coding_map key to old project files if not "coding_map" in pj: pj["coding_map"] = {} projectChanged = True # add subject description if "project_format_version" in pj: for idx in [x for x in pj[SUBJECTS]]: if not "description" in pj[SUBJECTS][idx]: pj[SUBJECTS][idx]["description"] = "" projectChanged = True # check if project file version is newer than current BORIS project file version if "project_format_version" in pj and Decimal( pj["project_format_version"]) > Decimal(project_format_version): return projectFileName, projectChanged, { "error": ("Este arquivo de projeto foi criado com uma versão mais recente do BORIS.<br>" "Você pode utilizar o BORIS <b>v. >= {}</b> Para abri esse arquivo" ).format(pj["project_format_version"]) }, msg # check if old version v. 0 *.obs if "project_format_version" not in pj: # convert VIDEO, AUDIO -> MEDIA pj['project_format_version'] = project_format_version projectChanged = True for obs in [x for x in pj[OBSERVATIONS]]: # remove 'replace audio' key if "replace audio" in pj[OBSERVATIONS][obs]: del pj[OBSERVATIONS][obs]['replace audio'] if pj[OBSERVATIONS][obs][TYPE] in ['VIDEO', 'AUDIO']: pj[OBSERVATIONS][obs][TYPE] = MEDIA # convert old media list in new one if len(pj[OBSERVATIONS][obs][FILE]): d1 = {PLAYER1: [pj[OBSERVATIONS][obs][FILE][0]]} if len(pj[OBSERVATIONS][obs][FILE]) == 2: d1[PLAYER2] = [pj[OBSERVATIONS][obs][FILE][1]] pj[OBSERVATIONS][obs][FILE] = d1 # convert VIDEO, AUDIO -> MEDIA for idx in [x for x in pj[SUBJECTS]]: key, name = pj[SUBJECTS][idx] pj[SUBJECTS][idx] = {"key": key, "name": name, "description": ""} msg = ( "O arquivo de projeto foi convertido para o novo formato (v. {}) Em uso com sua versão do BORIS.<br>" "Escolha um novo nome de arquivo para salvá-lo." ).format(project_format_version) projectFileName = "" for obs in pj[OBSERVATIONS]: if not "time offset second player" in pj[OBSERVATIONS][obs]: pj[OBSERVATIONS][obs]["time offset second player"] = Decimal("0.0") projectChanged = True # update modifiers to JSON format project_lowerthan4 = False logging.debug("project_format_version: {}".format( utilities.versiontuple(pj["project_format_version"]))) if "project_format_version" in pj and utilities.versiontuple( pj["project_format_version"]) < utilities.versiontuple("4.0"): for idx in pj[ETHOGRAM]: if pj[ETHOGRAM][idx]["modifiers"]: if isinstance(pj[ETHOGRAM][idx]["modifiers"], str): project_lowerthan4 = True modif_set_list = pj[ETHOGRAM][idx]["modifiers"].split("|") modif_set_dict = {} for modif_set in modif_set_list: modif_set_dict[str(len(modif_set_dict))] = { "name": "", "type": SINGLE_SELECTION, "values": modif_set.split(",") } pj[ETHOGRAM][idx]["modifiers"] = dict(modif_set_dict) else: pj[ETHOGRAM][idx]["modifiers"] = {} if not project_lowerthan4: msg = "A versão do projeto foi atualizada de {} para {}".format( pj["project_format_version"], project_format_version) pj["project_format_version"] = project_format_version projectChanged = True # add category key if not found for idx in pj[ETHOGRAM]: if "category" not in pj[ETHOGRAM][idx]: pj[ETHOGRAM][idx]["category"] = "" logging.debug("project_lowerthan4: {}".format(project_lowerthan4)) if project_lowerthan4: copyfile(projectFileName, projectFileName.replace(".boris", "_old_version.boris")) msg = ( "O projeto foi atualizado para a versão atual do projeto ({project_format_version}).\n\n" "O projeto de arquivo antigo foi salvo como {project_file_name}" ).format(project_format_version=project_format_version, project_file_name=projectFileName.replace( ".boris", "_old_version.boris")) # if one file is present in player #1 -> set "media_info" key with value of media_file_info project_updated = False for obs in pj[OBSERVATIONS]: if pj[OBSERVATIONS][obs][TYPE] in [ MEDIA ] and "media_info" not in pj[OBSERVATIONS][obs]: pj[OBSERVATIONS][obs]['media_info'] = { "length": {}, "fps": {}, "hasVideo": {}, "hasAudio": {} } for player in [PLAYER1, PLAYER2]: # fix bug Anne Maijer 2017-07-17 if pj[OBSERVATIONS][obs]["file"] == []: pj[OBSERVATIONS][obs]["file"] = {"1": [], "2": []} for media_file_path in pj[OBSERVATIONS][obs]["file"][player]: # FIX: ffmpeg path ret, msg = utilities.check_ffmpeg_path() if not ret: return projectFileName, projectChanged, { "error": "FFmpeg path not found" }, "" else: ffmpeg_bin = msg #nframe, videoTime, videoDuration, fps, hasVideo, hasAudio = utilities.accurate_media_analysis(ffmpeg_bin, media_file_path) r = utilities.accurate_media_analysis2( ffmpeg_bin, media_file_path) if "error" in r: return projectFileName, projectChanged, { "error": r["error"] }, "" if r["duration"]: pj[OBSERVATIONS][obs]["media_info"]["length"][ media_file_path] = r["duration"] pj[OBSERVATIONS][obs]["media_info"]["fps"][ media_file_path] = r["fps"] pj[OBSERVATIONS][obs]["media_info"]["hasVideo"][ media_file_path] = r["has_video"] pj[OBSERVATIONS][obs]["media_info"]["hasAudio"][ media_file_path] = r["has_audio"] project_updated, projectChanged = True, True else: # file path not found if ("media_file_info" in pj[OBSERVATIONS][obs] and len( pj[OBSERVATIONS][obs]["media_file_info"]) == 1 and len(pj[OBSERVATIONS][obs]["file"][PLAYER1]) == 1 and len(pj[OBSERVATIONS][obs]["file"][PLAYER2]) == 0): media_md5_key = list(pj[OBSERVATIONS][obs] ["media_file_info"].keys())[0] # duration pj[OBSERVATIONS][obs]["media_info"] = { "length": { media_file_path: pj[OBSERVATIONS][obs]["media_file_info"] [media_md5_key]["video_length"] / 1000 } } project_updated, projectChanged = True, True # FPS if "nframe" in pj[OBSERVATIONS][obs][ "media_file_info"][media_md5_key]: pj[OBSERVATIONS][obs]['media_info']['fps'] = { media_file_path: pj[OBSERVATIONS][obs]['media_file_info'] [media_md5_key]['nframe'] / (pj[OBSERVATIONS][obs]['media_file_info'] [media_md5_key]['video_length'] / 1000) } else: pj[OBSERVATIONS][obs]['media_info']['fps'] = { media_file_path: 0 } if project_updated: msg = "As informações dos arquivos de mídia foram atualizadas para o novo formato do projeto." return projectFileName, projectChanged, pj, msg
def open_project_json(projectFileName): """ open project json Args: projectFileName (str): path of project Returns: str: project path bool: True if project changed dict: BORIS project str: message """ logging.debug("open project: {0}".format(projectFileName)) projectChanged = False msg = "" if not os.path.isfile(projectFileName): return projectFileName, projectChanged, {"error": "File {} not found".format(projectFileName)}, msg try: s = open(projectFileName, "r").read() except PermissionError: return projectFileName, projectChanged, {"error": "File {}: Permission denied".format(projectFileName)}, msg except Exception: return projectFileName, projectChanged, {"error": "Error on file {}: {}".format(projectFileName, sys.exc_info()[1])}, msg try: pj = json.loads(s) except json.decoder.JSONDecodeError: return projectFileName, projectChanged, {"error": "This project file seems corrupted"}, msg except Exception: return projectFileName, projectChanged, {"error": "This project file seems corruptedError on file {}: {}".format(projectFileName, sys.exc_info()[1])}, msg # transform time to decimal pj = utilities.convert_time_to_decimal(pj) # add coding_map key to old project files if "coding_map" not in pj: pj["coding_map"] = {} projectChanged = True # add subject description if "project_format_version" in pj: for idx in [x for x in pj[SUBJECTS]]: if "description" not in pj[SUBJECTS][idx]: pj[SUBJECTS][idx]["description"] = "" projectChanged = True # check if project file version is newer than current BORIS project file version if "project_format_version" in pj and Decimal(pj["project_format_version"]) > Decimal(project_format_version): return ( projectFileName, projectChanged, { "error": ( "This project file was created with a more recent version of BORIS.<br>" "You must update BORIS to <b>v. >= {}</b> to open this project" ).format(pj["project_format_version"]) }, msg, ) # check if old version v. 0 *.obs if "project_format_version" not in pj: # convert VIDEO, AUDIO -> MEDIA pj["project_format_version"] = project_format_version projectChanged = True for obs in [x for x in pj[OBSERVATIONS]]: # remove 'replace audio' key if "replace audio" in pj[OBSERVATIONS][obs]: del pj[OBSERVATIONS][obs]["replace audio"] if pj[OBSERVATIONS][obs][TYPE] in ["VIDEO", "AUDIO"]: pj[OBSERVATIONS][obs][TYPE] = MEDIA # convert old media list in new one if len(pj[OBSERVATIONS][obs][FILE]): d1 = {PLAYER1: [pj[OBSERVATIONS][obs][FILE][0]]} if len(pj[OBSERVATIONS][obs][FILE]) == 2: d1[PLAYER2] = [pj[OBSERVATIONS][obs][FILE][1]] pj[OBSERVATIONS][obs][FILE] = d1 # convert VIDEO, AUDIO -> MEDIA for idx in [x for x in pj[SUBJECTS]]: key, name = pj[SUBJECTS][idx] pj[SUBJECTS][idx] = {"key": key, "name": name, "description": ""} msg = ( "The project file was converted to the new format (v. {}) in use with your version of BORIS.<br>" "Choose a new file name for saving it." ).format(project_format_version) projectFileName = "" # update modifiers to JSON format # check if project format version < 4 (modifiers were str) project_lowerthan4 = False if "project_format_version" in pj and utilities.versiontuple(pj["project_format_version"]) < utilities.versiontuple("4.0"): for idx in pj[ETHOGRAM]: if pj[ETHOGRAM][idx]["modifiers"]: if isinstance(pj[ETHOGRAM][idx]["modifiers"], str): project_lowerthan4 = True modif_set_list = pj[ETHOGRAM][idx]["modifiers"].split("|") modif_set_dict = {} for modif_set in modif_set_list: modif_set_dict[str(len(modif_set_dict))] = {"name": "", "type": SINGLE_SELECTION, "values": modif_set.split(",")} pj[ETHOGRAM][idx]["modifiers"] = dict(modif_set_dict) else: pj[ETHOGRAM][idx]["modifiers"] = {} if not project_lowerthan4: msg = "The project version was updated from {} to {}".format(pj["project_format_version"], project_format_version) pj["project_format_version"] = project_format_version projectChanged = True # add category key if not found for idx in pj[ETHOGRAM]: if "category" not in pj[ETHOGRAM][idx]: pj[ETHOGRAM][idx]["category"] = "" # if one file is present in player #1 -> set "media_info" key with value of media_file_info for obs in pj[OBSERVATIONS]: if pj[OBSERVATIONS][obs][TYPE] in [MEDIA] and MEDIA_INFO not in pj[OBSERVATIONS][obs]: pj[OBSERVATIONS][obs][MEDIA_INFO] = {LENGTH: {}, "fps": {}, "hasVideo": {}, "hasAudio": {}} for player in [PLAYER1, PLAYER2]: # fix bug Anne Maijer 2017-07-17 if pj[OBSERVATIONS][obs][FILE] == []: pj[OBSERVATIONS][obs][FILE] = {"1": [], "2": []} for media_file_path in pj[OBSERVATIONS][obs]["file"][player]: # FIX: ffmpeg path ret, msg = utilities.check_ffmpeg_path() if not ret: return projectFileName, projectChanged, {"error": "FFmpeg path not found"}, "" else: ffmpeg_bin = msg r = utilities.accurate_media_analysis(ffmpeg_bin, media_file_path) if "duration" in r and r["duration"]: pj[OBSERVATIONS][obs][MEDIA_INFO][LENGTH][media_file_path] = float(r["duration"]) pj[OBSERVATIONS][obs][MEDIA_INFO][FPS][media_file_path] = float(r["fps"]) pj[OBSERVATIONS][obs][MEDIA_INFO]["hasVideo"][media_file_path] = r["has_video"] pj[OBSERVATIONS][obs][MEDIA_INFO]["hasAudio"][media_file_path] = r["has_audio"] project_updated, projectChanged = True, True else: # file path not found if ( "media_file_info" in pj[OBSERVATIONS][obs] and len(pj[OBSERVATIONS][obs]["media_file_info"]) == 1 and len(pj[OBSERVATIONS][obs][FILE][PLAYER1]) == 1 and len(pj[OBSERVATIONS][obs][FILE][PLAYER2]) == 0 ): media_md5_key = list(pj[OBSERVATIONS][obs]["media_file_info"].keys())[0] # duration pj[OBSERVATIONS][obs][MEDIA_INFO] = { LENGTH: {media_file_path: pj[OBSERVATIONS][obs]["media_file_info"][media_md5_key]["video_length"] / 1000} } projectChanged = True # FPS if "nframe" in pj[OBSERVATIONS][obs]["media_file_info"][media_md5_key]: pj[OBSERVATIONS][obs][MEDIA_INFO][FPS] = { media_file_path: pj[OBSERVATIONS][obs]["media_file_info"][media_md5_key]["nframe"] / (pj[OBSERVATIONS][obs]["media_file_info"][media_md5_key]["video_length"] / 1000) } else: pj[OBSERVATIONS][obs][MEDIA_INFO][FPS] = {media_file_path: 0} # update project to v.7 for time offset second player project_lowerthan7 = False for obs in pj[OBSERVATIONS]: if "time offset second player" in pj[OBSERVATIONS][obs]: if MEDIA_INFO not in pj[OBSERVATIONS][obs]: pj[OBSERVATIONS][obs][MEDIA_INFO] = {} if "offset" not in pj[OBSERVATIONS][obs][MEDIA_INFO]: pj[OBSERVATIONS][obs][MEDIA_INFO]["offset"] = {} for player in pj[OBSERVATIONS][obs][FILE]: pj[OBSERVATIONS][obs][MEDIA_INFO]["offset"][player] = 0.0 if pj[OBSERVATIONS][obs]["time offset second player"]: pj[OBSERVATIONS][obs][MEDIA_INFO]["offset"]["2"] = float(pj[OBSERVATIONS][obs]["time offset second player"]) del pj[OBSERVATIONS][obs]["time offset second player"] project_lowerthan7 = True msg = ( "The project file was converted to the new format (v. {project_version}) in use with your version of BORIS.<br>" "Please note that this new version will NOT be compatible with previous BORIS versions (< v. {project_version}).<br>" ).format(project_version=project_format_version) projectChanged = True if project_lowerthan7: msg = ( "The project was updated to the current project version ({project_format_version})." ).format(project_format_version=project_format_version) try: copyfile(projectFileName, projectFileName.replace(".boris", ".v{}.boris".format(pj["project_format_version"]))) msg += "\n\nThe old file project was saved as {}".format(projectFileName.replace(".boris", ".v{}.boris".format(pj["project_format_version"]))) except Exception: pass pj["project_format_version"] = project_format_version return projectFileName, projectChanged, pj, msg