Hi Charles. An OTIO could be generated from a Cut and/or a Shot, depending on what you want to do. For a Cut, the CutItemIn/Out can be used to construct the OTIO source_range. The available_range is more tricky. The in and out points on the Cut represent the media being consumed from the CutItem, but not necessarily all of its available frames. Generally speaking, anything related to the available_range for an OTIO Clip should come from the Version linked to the Shot. So you could use the Version.last_frame - Version.first_frame + 1 to determine the available_range. If this information is not available, I would say it’s fine to leave it out, as available_range is not required for a valid OTIO.
One thing to be careful of when getting the Version linked to the Shot, is that there can be multiple and the CutItem does not always specify which Version it is using. If it does not, you will have to decide which one to use. For example, you may want to filter around the Version status looking for an approved version. Another possibility is to filter around a particular pipeline_step of the Task linked to the Shot.
No. Shot duration and CutItem duration are not necessarily the same. If the Shot is used in multiple Cuts, its duration can be (and usually is) the union all the CutItems that refer to the Shot. You can use the CutItem duration field to get the duration for the OTIO Clip’s source_range. If it’s not set, you can subtract the CutItemIn from CutItemOut and add 1.
There is a Cut fps and a Shot fps. For the Shot, you need to look at the Version linked to the Shot to get its fps. If you are making an OTIO for a Cut, you probably want to prefer the Version fps for the available_range and the Cut fps for the source_range.