|
|
import json
|
|
|
|
|
|
def update_scratch_project_data(project_data):
|
|
|
"""
|
|
|
Updates variable and broadcast definitions in a Scratch project JSON,
|
|
|
populating the 'variables' and 'broadcasts' sections of the Stage target
|
|
|
and extracting initial values for variables.
|
|
|
|
|
|
Args:
|
|
|
project_data (dict): The loaded JSON data of the Scratch project.
|
|
|
|
|
|
Returns:
|
|
|
dict: The updated project JSON data.
|
|
|
"""
|
|
|
|
|
|
stage_target = None
|
|
|
for target in project_data['targets']:
|
|
|
if target.get('isStage'):
|
|
|
stage_target = target
|
|
|
break
|
|
|
|
|
|
if stage_target is None:
|
|
|
print("Error: Stage target not found in the project data.")
|
|
|
return project_data
|
|
|
|
|
|
|
|
|
if "variables" not in stage_target:
|
|
|
stage_target["variables"] = {}
|
|
|
if "broadcasts" not in stage_target:
|
|
|
stage_target["broadcasts"] = {}
|
|
|
|
|
|
|
|
|
def process_dict(obj):
|
|
|
if isinstance(obj, dict):
|
|
|
|
|
|
if obj.get("opcode") == "data_setvariableto":
|
|
|
variable_field = obj.get("fields", {}).get("VARIABLE")
|
|
|
value_input = obj.get("inputs", {}).get("VALUE")
|
|
|
|
|
|
if variable_field and isinstance(variable_field, list) and len(variable_field) == 2:
|
|
|
var_name = variable_field[0]
|
|
|
var_id = variable_field[1]
|
|
|
|
|
|
initial_value = ""
|
|
|
if value_input and isinstance(value_input, list) and len(value_input) > 1 and \
|
|
|
isinstance(value_input[1], list) and len(value_input[1]) > 1:
|
|
|
|
|
|
if value_input[1][0] == 10:
|
|
|
initial_value = str(value_input[1][1])
|
|
|
elif value_input[1][0] == 12 and len(value_input) > 2 and isinstance(value_input[2], list) and value_input[2][0] == 10:
|
|
|
initial_value = str(value_input[2][1])
|
|
|
elif isinstance(value_input[1], (str, int, float)):
|
|
|
initial_value = str(value_input[1])
|
|
|
|
|
|
|
|
|
|
|
|
stage_target["variables"][var_id] = [var_name, initial_value]
|
|
|
|
|
|
|
|
|
for key, value in obj.items():
|
|
|
|
|
|
if key == "VARIABLE" and isinstance(value, list) and len(value) == 2:
|
|
|
var_name = value[0]
|
|
|
var_id = value[1]
|
|
|
|
|
|
if var_id not in stage_target["variables"]:
|
|
|
stage_target["variables"][var_id] = [var_name, ""]
|
|
|
elif stage_target["variables"][var_id][0] != var_name:
|
|
|
stage_target["variables"][var_id][0] = var_name
|
|
|
|
|
|
|
|
|
|
|
|
elif key == "BROADCAST_INPUT" and isinstance(value, list) and len(value) == 2 and \
|
|
|
isinstance(value[1], list) and len(value[1]) == 3 and value[1][0] == 11:
|
|
|
broadcast_name = value[1][1]
|
|
|
broadcast_id = value[1][2]
|
|
|
|
|
|
stage_target["broadcasts"][broadcast_id] = broadcast_name
|
|
|
|
|
|
|
|
|
elif key == "BROADCAST_OPTION" and isinstance(value, list) and len(value) == 2:
|
|
|
broadcast_name = value[0]
|
|
|
broadcast_id = value[1]
|
|
|
|
|
|
stage_target["broadcasts"][broadcast_id] = broadcast_name
|
|
|
|
|
|
|
|
|
process_dict(value)
|
|
|
elif isinstance(obj, list):
|
|
|
for i, item in enumerate(obj):
|
|
|
|
|
|
if isinstance(item, list) and len(item) == 3 and item[0] == 12:
|
|
|
var_name = item[1]
|
|
|
var_id = item[2]
|
|
|
|
|
|
if var_id not in stage_target["variables"]:
|
|
|
stage_target["variables"][var_id] = [var_name, ""]
|
|
|
elif stage_target["variables"][var_id][0] != var_name:
|
|
|
stage_target["variables"][var_id][0] = var_name
|
|
|
|
|
|
process_dict(item)
|
|
|
|
|
|
|
|
|
for target in project_data['targets']:
|
|
|
if "blocks" in target:
|
|
|
for block_id, block_data in target["blocks"].items():
|
|
|
process_dict(block_data)
|
|
|
|
|
|
return project_data
|
|
|
|
|
|
def deduplicate_variables(project_data):
|
|
|
"""
|
|
|
Removes duplicate variable entries in the 'variables' dictionary of the Stage target,
|
|
|
prioritizing entries with non-empty values.
|
|
|
|
|
|
Args:
|
|
|
project_data (dict): The loaded JSON data of the Scratch project.
|
|
|
|
|
|
Returns:
|
|
|
dict: The updated project JSON data with deduplicated variables.
|
|
|
"""
|
|
|
|
|
|
stage_target = None
|
|
|
for target in project_data['targets']:
|
|
|
if target.get('isStage'):
|
|
|
stage_target = target
|
|
|
break
|
|
|
|
|
|
if stage_target is None:
|
|
|
print("Error: Stage target not found in the project data.")
|
|
|
return project_data
|
|
|
|
|
|
if "variables" not in stage_target:
|
|
|
return project_data
|
|
|
|
|
|
|
|
|
|
|
|
resolved_variables = {}
|
|
|
|
|
|
for var_id, var_info in stage_target["variables"].items():
|
|
|
var_name = var_info[0]
|
|
|
var_value = var_info[1]
|
|
|
|
|
|
if var_name not in resolved_variables:
|
|
|
|
|
|
resolved_variables[var_name] = [var_id, var_name, var_value]
|
|
|
else:
|
|
|
|
|
|
existing_id, existing_name, existing_value = resolved_variables[var_name]
|
|
|
|
|
|
|
|
|
if var_value != "" and existing_value == "":
|
|
|
resolved_variables[var_name] = [var_id, var_name, var_value]
|
|
|
|
|
|
|
|
|
|
|
|
elif var_value != "" and existing_value != "":
|
|
|
|
|
|
|
|
|
|
|
|
resolved_variables[var_name] = [var_id, var_name, var_value]
|
|
|
elif var_value == "" and existing_value == "":
|
|
|
|
|
|
resolved_variables[var_name] = [var_id, var_name, var_value]
|
|
|
|
|
|
|
|
|
|
|
|
new_variables_dict = {}
|
|
|
for var_name, var_data in resolved_variables.items():
|
|
|
var_id_to_keep = var_data[0]
|
|
|
var_name_to_keep = var_data[1]
|
|
|
var_value_to_keep = var_data[2]
|
|
|
new_variables_dict[var_id_to_keep] = [var_name_to_keep, var_value_to_keep]
|
|
|
|
|
|
stage_target["variables"] = new_variables_dict
|
|
|
|
|
|
return project_data
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
json_data = {
|
|
|
"targets": [
|
|
|
{"isStage": True, "name": "Stage", "variables": {},"lists": {}, "broadcasts": {}, "blocks": {
|
|
|
"event_whenflagclicked_1": {
|
|
|
"opcode": "event_whenflagclicked",
|
|
|
"inputs": {},
|
|
|
"fields": {},
|
|
|
"shadow": False,
|
|
|
"topLevel": True,
|
|
|
"parent": None,
|
|
|
"next": "data_setvariableto_1"
|
|
|
},
|
|
|
"data_setvariableto_1": {
|
|
|
"opcode": "data_setvariableto",
|
|
|
"inputs": {
|
|
|
"VALUE": [
|
|
|
1,
|
|
|
[
|
|
|
4,
|
|
|
"0"
|
|
|
]
|
|
|
]
|
|
|
},
|
|
|
"fields": {
|
|
|
"VARIABLE": [
|
|
|
"score",
|
|
|
"$ELgBAKpb[&l+DX$EMK4"
|
|
|
]
|
|
|
},
|
|
|
"shadow": False,
|
|
|
"topLevel": False,
|
|
|
"parent": "event_whenflagclicked_1",
|
|
|
"next": "data_setvariableto_2"
|
|
|
},
|
|
|
"data_setvariableto_2": {
|
|
|
"opcode": "data_setvariableto",
|
|
|
"inputs": {
|
|
|
"VALUE": [
|
|
|
1,
|
|
|
[
|
|
|
4,
|
|
|
"3"
|
|
|
]
|
|
|
]
|
|
|
},
|
|
|
"fields": {
|
|
|
"VARIABLE": [
|
|
|
"lives",
|
|
|
"Gb]1jA+H{h_6z1^Fn!-a"
|
|
|
]
|
|
|
},
|
|
|
"shadow": False,
|
|
|
"topLevel": False,
|
|
|
"parent": "data_setvariableto_1",
|
|
|
"next": "data_showvariable_1"
|
|
|
},
|
|
|
"data_showvariable_1": {
|
|
|
"opcode": "data_showvariable",
|
|
|
"inputs": {},
|
|
|
"fields": {
|
|
|
"VARIABLE": [
|
|
|
"score",
|
|
|
"$ELgBAKpb[&l+DX$EMK4"
|
|
|
]
|
|
|
},
|
|
|
"shadow": False,
|
|
|
"topLevel": False,
|
|
|
"parent": "data_setvariableto_2",
|
|
|
"next": "data_showvariable_2"
|
|
|
},
|
|
|
"data_showvariable_2": {
|
|
|
"opcode": "data_showvariable",
|
|
|
"inputs": {},
|
|
|
"fields": {
|
|
|
"VARIABLE": [
|
|
|
"lives",
|
|
|
"Gb]1jA+H{h_6z1^Fn!-a"
|
|
|
]
|
|
|
},
|
|
|
"shadow": False,
|
|
|
"topLevel": False,
|
|
|
"parent": "data_showvariable_1",
|
|
|
"next": "event_broadcast_1"
|
|
|
},
|
|
|
"event_broadcast_1": {
|
|
|
"opcode": "event_broadcast",
|
|
|
"inputs": {
|
|
|
"BROADCAST_INPUT": [
|
|
|
1,
|
|
|
[
|
|
|
11,
|
|
|
"Game Start",
|
|
|
"hN1d@^S}e)H~8(qp)rGN"
|
|
|
]
|
|
|
]
|
|
|
},
|
|
|
"fields": {},
|
|
|
"shadow": False,
|
|
|
"topLevel": False,
|
|
|
"parent": "data_showvariable_2",
|
|
|
"next": None
|
|
|
}
|
|
|
}, "comments": {}, "currentCostume": 1, "costumes": [{"name": "backdrop1", "dataFormat": "svg", "assetId": "cd21514d0531fdffb22204e0ec5ed84a", "md5ext": "cd21514d0531fdffb22204e0ec5ed84a.svg", "rotationCenterX": 240, "rotationCenterY": 180}, {"name": "Blue Sky", "bitmapResolution": 1, "dataFormat": "svg", "assetId": "e7c147730f19d284bcd7b3f00af19bb6", "rotationCenterX": 240, "rotationCenterY": 180}], "sounds": [{"name": "pop", "assetId": "83a9787d4cb6f3b7632b4ddfebf74367", "dataFormat": "wav", "format": "", "rate": 48000, "sampleCount": 1123, "md5ext": "83a9787d4cb6f3b7632b4ddfebf74367.wav"}], "volume": 100, "layerOrder": 0, "tempo": 60, "videoTransparency": 50, "videoState": "on", "textToSpeechLanguage": None},
|
|
|
{"isStage": False, "name": "Sprite1", "variables": {}, "lists": {}, "broadcasts": {}, "blocks": {}, "comments": {}, "currentCostume": 0, "costumes": [{"name": "costume1", "bitmapResolution": 1, "dataFormat": "svg", "assetId": "bcf454acf82e4504149f7ffe07081dbc", "md5ext": "bcf454acf82e4504149f7ffe07081dbc.svg", "rotationCenterX": 48, "rotationCenterY": 50}, {"name": "costume2", "bitmapResolution": 1, "dataFormat": "svg", "assetId": "0fb9be3e8397c983338cb71dc84d0b25", "md5ext": "0fb9be3e8397c983338cb71dc84d0b25.svg", "rotationCenterX": 46, "rotationCenterY": 53}], "sounds": [{"name": "Meow", "assetId": "83c36d806dc92327b9e7049a565c6bff", "dataFormat": "wav", "format": "", "rate": 48000, "sampleCount": 40681, "md5ext": "83c36d806dc92327b9e7049a565c6bff.wav"}], "volume": 100, "layerOrder": 1, "visible": True, "x": 0, "y": -120, "size": 100, "direction": 90, "draggable": False, "rotationStyle": "all around"},
|
|
|
{"isStage": False, "name": "Soccer Ball", "variables": {}, "lists": {}, "broadcasts": {}, "blocks": {}, "comments": {}, "currentCostume": 0, "costumes": [{"name": "soccer ball", "bitmapResolution": 1, "dataFormat": "svg", "assetId": "5d973d7a3a8be3f3bd6e1cd0f73c32b5", "md5ext": "5d973d7a3a8be3f3bd6e1cd0f73c32b5.svg", "rotationCenterX": 23, "rotationCenterY": 22}], "sounds": [{"name": "basketball bounce", "assetId": "1727f65b5f22d151685b8e5917456a60", "dataFormat": "wav", "format": "adpcm", "rate": 22050, "sampleCount": 8129, "md5ext": "1727f65b5f22d151685b8e5917456a60.wav"}], "volume": 100, "layerOrder": 2, "visible": True, "x": -130, "y": -60, "size": 100, "direction": 90, "draggable": False, "rotationStyle": "all around"}], "monitors": [{"id": "76*2udMupx@8!=)9Uqvj", "mode": "default", "opcode": "data_variable", "params": {"VARIABLE": "score"}, "spriteName": None, "value": "0", "width": 0, "height": 0, "x": 5, "y": 5, "visible": True, "sliderMin": 0, "sliderMax": 100, "isDiscrete": True}, {"id": "YiV;2%+lgjnJ$|*Jy.{H", "mode": "default", "opcode": "data_variable", "params": {"VARIABLE": "cloud Var"}, "spriteName": None, "value": 0, "width": 0, "height": 0, "x": 5, "y": 32, "visible": True, "sliderMin": 0, "sliderMax": 100, "isDiscrete": True}, {"id": "@D/}fdt{0XaJ`kRE0t~F", "mode": "default", "opcode": "data_variable", "params": {"VARIABLE": "lives"}, "spriteName": None, "value": "3", "width": 0, "height": 0, "x": 5, "y": 59, "visible": True, "sliderMin": 0, "sliderMax": 100, "isDiscrete": True}, {"id": "^R,uz7yRjtK`=uP~6SN4", "mode": "default", "opcode": "data_variable", "params": {"VARIABLE": "speed"}, "spriteName": None, "value": "5", "width": 0, "height": 0, "x": 5, "y": 86, "visible": True, "sliderMin": 0, "sliderMax": 100, "isDiscrete": True}], "extensions": [], "meta": {"semver": "3.0.0", "vm": "11.3.0", "agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"}}
|
|
|
|
|
|
|
|
|
updated_json_data = update_scratch_project_data(json_data)
|
|
|
updated_json_data = deduplicate_variables(json_data)
|
|
|
print(json.dumps(updated_json_data, indent=1)) |