在Python中循环并写入嵌套的JSON数组

huangapple go评论78阅读模式
英文:

Loop in Python and write to a Nested JSON array

问题

这是一个用于视频编辑应用程序的情况,其中有多个轨道,可以容纳一个或多个剪辑。

我们要提取的是一个 JSON 文件,其中包含与每个剪辑的起始帧/结束帧相关的所有信息。

这里是我们当前拥有的 JSON 结果:

{
    "framesPerSecond": 24,
    "StartFrame": 1,
    "lastFrame": 1293,
    "clip_element": [
        {
            "clip_name": "",
            "track_info": [
                {
                    "start": 1,
                    "first": 1, #剪辑开始播放的位置
                    "last": 1293, #剪辑结束的帧
                    "hold_last": "0" #目前未使用。
                }
            ],
            "transitions": "none" #目前未使用。
        }
    ]
}

添加另一个剪辑到不同的轨道上,我们期望有另一个带有 "clip_name" 和 "track_info" 的 JSON 对象,如下所示:

"clip_element": [
    {
        "clip_name": "",
        "track_info": [
            {
                "start": 1,
                "first": 1, #剪辑开始播放的位置
                "last": 891, #剪辑结束的帧
                "hold_last": "0" #目前未使用。
            }
        ],
        "transitions": "none" #目前未使用。
    },
    {
        "clip_name": "",
        "track_info": [
            {
                "start": 891,
                "first": 892, #剪辑开始播放的位置
                "last": 1293, #剪辑结束的帧
                "hold_last": "0" #目前未使用。
            }
        ],
        "transitions": "none" #目前未使用。
    }
]

然而,第二个剪辑覆盖了第一个剪辑,而不是创建一个新的 JSON 对象,这主要是由于我们的代码中硬编码的指针导致的。

实现参考如下:

all_tracks = get_app().project.get("layers")
track_count = 0
json_data = track_dict
for track in reversed(sorted(all_tracks, key=itemgetter('number'))):
    existing_track = Track.get(number=track.get("number"))
    if not existing_track:
        log.error('No track object found with number: %s' % track.get("number"))
        continue

    # 轨道名称
    track_name = track.get("label")
    clips_on_track = Clip.filter(layer=track.get("number"))
    if not clips_on_track:
        continue

    with open("%s-%s.json" % (file_path.replace(".json", ""), track_name), 'w', encoding="utf8") as f:
        # 循环遍历此轨道上的剪辑
        for index, clip in enumerate(clips_on_track, start=1):
            start_frame = codeToFrames(clip.data.get('start'), fps_num, fps_den)
            end_frame = codeToFrames(clip.data.get('end'), fps_num, fps_den)
            start_frame_position = codeToFrames(clip.data.get('position'), fps_num, fps_den)
            end_frame_position = codeToFrames(clip.data.get('position') + (clip.data.get('end') - clip.data.get('start')), fps_num, fps_den)
            clip_end_frame = timecodeToFrames(clip.data.get('position') + (clip.data.get('end')), fps_num, fps_den)

            has_video = clip.data.get("reader", {}).get("has_video", False)
            if has_video:
                track_count += 1
                index += 1
                json_data['FramesPerSecond'] = fps_num
                json_data['StartFrame'] = round(start_frame)
                json_data['LastFrames'] = round(end_frame_position)
                json_data['clip_element'][0]['clip_name'] = track_name
                json_data['clip_element'][0]['track_info'][0]['start'] = round(start_frame) + 1 
                json_data['clip_element'][0]['track_info'][0]['first'] = round(start_frame_position)
                json_data['clip_element'][0]['track_info'][0]['last'] = round(clip_end_frame)
                json_data['clip_element'][0]['track_info'][0]['hold_last'] = round(clip_end_frame)
                json.dump(json_data, f, indent=4)

我们尝试创建一个列表来保存数据,并使用嵌套的循环来遍历轨道上的每个剪辑,但似乎没有成功,因为将数据再次附加回去没有存储预期的结果(语法问题)。

因为这似乎需要为每个关键字(start_frame),(end_frame)等编写循环,所以确保语法正确非常关键,这就是我们在这里发布的原因。

更新:.append 的方法有效,当轨道上有多个剪辑时,它会创建一个新的 JSON 对象!此外,我稍微修改了它,以便也附加 "clip_name"。

{
    "framesPerSecond": 24,
    "StartFrame": 1,
    "lastFrame": 1327,
    "clip_element": [
        {
            "clip_name": "",
            "track_info": {
                "start": 1,
                "first": 0,
                "last": 701,
                "hold_last": 701
            },
            "transition": "none"
        },
        {
            "clip_name": "",
            "track_info": {
                "start": 1,
                "first": 626,
                "last": 1327,
                "hold_last": 1327
            },
            "transition": "none"
        }
    ]
}
英文:

This is for a video editing app, where we have several tracks that can house a clip or clips.
What we want to extract, is a JSON file, with all the information related to the starting frame / end frame of each clip.
While we have that when using one clip, the issue is while using multiple clips, the iteration overwrites the previous clip, instead of creating a new JSON object in the array.

Here's the JSON results we currently have:

{
"framesPerSecond": 24,
"StartFrame": 1,
"lastFrame": 1293,
"clip_element": [
{
"clip_name": "",
"track_info": [
{
"start": 1,
"first": 1, #where this clip starts playing
"last": 1293, #frame which the clip ends
"hold_last": "0" #not in use at the moment.
}
],
"transitions": "none" #not in use at the moment.
}
]
}

Adding another clip on a different track, we expect to have another JSON object with "clip_name", "track_info" like this:

"clip_element": [
{
"clip_name": "",
"track_info": [
{
"start": 1,
"first": 1, #where this clip starts playing
"last": 891, #frame which the clip ends
"hold_last": "0" #not in use at the moment.
}
],
"transitions": "none" #not in use at the moment.
},
{
"clip_name": "",
"track_info": [
{
"start": 891,
"first": 892, #where this clip starts playing
"last": 1293, #frame which the clip ends
"hold_last": "0" #not in use at the moment.
}
],
"transitions": "none" #not in use at the moment.
},

Instead the 2nd clip, overwrites the first one, without creating an new JSON object, which mainly is due to hardcoded pointer towards the JSON in our code.

The implementation for reference:

all_tracks = get_app().project.get("layers")
track_count = 0
json_data = track_dict
for track in reversed(sorted(all_tracks, key=itemgetter('number'))):
existing_track = Track.get(number=track.get("number"))
if not existing_track:
log.error('No track object found with number: %s' % track.get("number"))
continue
# Track name
track_name = track.get("label")
clips_on_track = Clip.filter(layer=track.get("number"))
if not clips_on_track:
continue
with open("%s-%s.json" % (file_path.replace(".json", ""), track_name), 'w', encoding="utf8") as f:
# Loop through clips on this track
for index, clip in enumerate(clips_on_track, start=1):
start_frame = codeToFrames(clip.data.get('start'), fps_num, fps_den)
end_frame = codeToFrames(clip.data.get('end'), fps_num, fps_den)
start_frame_position = codeToFrames(clip.data.get('position'), fps_num, fps_den)
end_frame_position = codeToFrames(clip.data.get('position') + (clip.data.get('end') - clip.data.get('start')), fps_num, fps_den)
clip_end_frame = timecodeToFrames(clip.data.get('position') + (clip.data.get('end')), fps_num, fps_den)
has_video = clip.data.get("reader", {}).get("has_video", False)
if has_video:
track_count += 1
index += 1
json_data['FramesPerSecond'] = fps_num
json_data['StartFrame'] = round(start_frame)
json_data['LastFrames'] = round(end_frame_position)
json_data['clip_element'][0]['clip_name'] = track_name
json_data['clip_element'][0]['track_info'][0]['start'] = round(start_frame) + 1 
json_data['clip_element'][0]['track_info'][0]['first'] = round(start_frame_position)
json_data['clip_element'][0]['track_info'][0]['last'] = round(clip_end_frame)
json_data['clip_element'][0]['track_info'][0]['hold_last'] = round(clip_end_frame)
json.dump(json_data, f, indent=4)

We tried by creating a list to hold the data, and using a nested for loop to go through each clip on the track, but it seems that didn't work, as appending the data back again didn't stored the expected results. (syntax issues)

Because this seems to require a for loop for each key (start_frame), (end_frame) etc. is crucial to get the syntax right, which is why we're posting it here.

UPDATE:
The .append worked and created a new JSON object when there's more than 1 clips on the track!
Also, I modified it a little to also append the "clip_name" as well.

{
"framesPerSecond": 24,
"StartFrame": 1,
"lastFrame": 1327,
"clip_element": [
{
"clip_name": "",
"track_info": {
"start": 1,
"first": 0,
"last": 701,
"hold_last": 701
},
"transition": "none"
},
{
"clip_name": "",
"track_info": {
"start": 1,
"first": 626,
"last": 1327,
"hold_last": 1327
},
"transition": "none"
}
]
}

答案1

得分: 0

我猜问题出在这些行上:

json_data['clip_element'][0]['clip_name'] = track_name
json_data['clip_element'][0]['track_info'].append(
{
'start': round(start_frame) + 1,
'first': round(start_frame_position),
'last': round(clip_end_frame),
'hold_last': round(clip_end_frame),
}
)


`json_data['clip_element'][0]['track_info']` 是一个数组,`json_data['clip_element'][0]['track_info'][0]` 是数组中的第一个元素。所以你一直在覆盖第一个元素。
你应该是想要将新数据添加到数组中。可能应该像这样:

json_data['clip_element'][0]['clip_name'] = track_name
json_data['clip_element'][0]['track_info'].append(
{
'start': round(start_frame) + 1,
'first': round(start_frame_position),
'last': round(clip_end_frame),
'hold_last': round(clip_end_frame),
}
)


我不能在和你运行代码的同一环境中运行这段代码,所以无法测试这个示例。
英文:

I'm going to guess the problem is these lines:

json_data['clip_element'][0]['clip_name'] = track_name
json_data['clip_element'][0]['track_info'][0]['start'] = round(start_frame) + 1 
json_data['clip_element'][0]['track_info'][0]['first'] = round(start_frame_position)
json_data['clip_element'][0]['track_info'][0]['last'] = round(clip_end_frame)
json_data['clip_element'][0]['track_info'][0]['hold_last'] = round(clip_end_frame)

json_data['clip_element'][0]['track_info'] is an array and json_data['clip_element'][0]['track_info'][0] is the first element in that array. So you're always overwriting the first element.

Instead, you want to append to the array. Probably something like this:

json_data['clip_element'][0]['clip_name'] = track_name
json_data['clip_element'][0]['track_info'].append(
{
'start': round(start_frame) + 1,
'first': round(start_frame_position),
'last': round(clip_end_frame),
'hold_last': round(clip_end_frame),
}
)

I can't run this code in the same context as you're running yours so I can't test this sample.

huangapple
  • 本文由 发表于 2023年2月24日 05:58:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/75550746.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定