本文为 ShotGrid 的 Python API 学习笔记。

注册网站

如果已经有了自己可操作的 ShotGrid 网站页面,就直接开始吧。没有的话需要在 Autodesk 官网下找到ShotGrid 注册自己的 ShotGrid 网站页面,设置邮箱和电话号码后,获取登录账户和密码(可以获得30天的试用时间),就可以开始下面的操作了。

安装

最低要求
  • Python 2.7 或 Python 3.7
下载并写入Python搜索路径
  • 手动下载
    • 下载 PythonAPI 库到本地:从这下载最新版本到本地。
    • 将下载的 PythonAPI 加入到 PYTHONPATH 环境变量中,用于我们在代码中可搜索到对应的模块。
  • pip下载
    • 安装最新版本
      pip install git+https://github.com/shotgunsoftware/python-api.git
    • 安装特定版本
      pip install git+https://github.com/shotgunsoftware/python-api.git@v3.0.26

登录

直接使用用户名和密码,用户身份登录的脚本操作,会生成事件,其中存储了一些额外的元数据,EventLogEntry用于标识事件是由代表用户的脚本创建的。
事件生成控制 png
而使用脚本身份验证登录前,必须在Shotgun 中注册 (User>Scripts)并具有有效的 API 密钥 (密钥需要在创建的时候记录下来,创建完后不再显示).

  • 基于用户名登陆验证

    sg = shotgun_api3.Shotgun("https://piedpiper.shotgunstudio.com",
                            login="rhendriks",
                            password="c0mPre$Hi0n")
  • 基于脚本登录验证

    sg = shotgun_api3.Shotgun("https://piedpiper.shotgunstudio.com",
                            script_name="rhendriks",
                            api_key="c0mPre$Hi0n")

查询内容

查询结果默认返回查询对象的id,字段中的实体通过id连接,如果使用实体作为过滤项(过滤条件有大括号),每个filter中的实体都应该包含实体的id,这个实体用于筛选查询的范围,那么必须使用实体的id进行过滤,不能使用名称或其他条件,例如[ “shot”,”is”,{“type”:”Shot”,”id”:1173}];如果过滤项不是实体,那么可以使用名称或其他字段进行过滤,但必须使用点语法(链式调用),例如[ “shot.Shot.code”,”is”,”seq110”]。点语法用于查询点语法中使用的实体以外的实体,例如,project.Project.name为点语法的项目名,只能通过项目名查场次和镜头等,不能用它查询项目本身。查询本身不用点语法,直接使用shotgun.find(“Project”,[ “name”,”is”,”Test_Fly”],[]);点语法:”fieldname.entityname.fieldname.entityname.fieldname…” 只能单实体关系使用语法,由于性能问题,一个字段链接了多个实体时,不能通过点语法获得结果,需要遍历获取。不显示字段代码名称的字段,可以从filed > 右键菜单 > ConfigField 中获取field code名称

  • 查询所有项目

    sg_project = sg.find("Project", [], ["id", "name"])
  • 查询指定名称的项目(默认返回id)

    sg_project = sg.find("Project", [['name', 'is', "Test_Fly"]])
  • 查询指定项目所有的场次(通过项目id获取,可直接使用查询到的实体获取相关内容)

    sg_project = sg.find("Project", [['name', 'is', "Test_Fly"]])[0]["id"]
    sg_sequence = sg.find("Sequence", [['project', 'is', {'type': 'Project', 'id': sg_project}]])
  • 查询指定项目的场次(通过项目名称获取,使用点语法)

    sg_sequence = sg.find("Sequence", [['project.Project.name', 'is', "Test_Fly"]])
  • 获取指定项目的所有镜头(通过项目名称获取)

    sg_shot = sg.find("Shot", [['project.Project.name', 'is', "Test_Fly"]])
  • 获取指定场次的所有镜头(通过场次id获取)

    sg_shot1 = sg.find("Shot", [["sg_sequence", "is", {"type":"Sequence", "id":44}]], [ "code"])
  • 获取指定场次的状态为IP所有镜头(通过场次id获取)

    sg_shot2 = sg.find("Shot", [["sg_sequence","is", {"type":"Sequence","id":44}],["sg_status_list", "is", "ip"]],[ "code"])
  • 获取指定场次的状态为IP所有镜头(通过场次名称和项目共同筛选获取)

    sg_shot3 = sg.find("Shot", [["sg_sequence","is",{"type":"Sequence","Sequence Name":"seq001"}],["sg_status_list", "is", "ip"], ['project', 'is',{'type':'Project','id':122}]])
  • 获取指定场次的状态为IP所有镜头(通过场次名称和项目共同筛选获取)

    sg_shots = sg.find("Shot", [["sg_sequence","is",{"type":"Sequence","Sequence Name":"seq001"}],["sg_status_list", "is", "ip"], ['project', 'is',{'type':'Project','id':122}]])
  • 获取指定镜头的资产

    project_id = 122
    sequence_id = 182
    filter =  [
      ['project', 'is', {'type': 'Project', 'id': project_id}],
      ['sg_asset_type', 'is', 'Character'],
      ['sequences', 'is', {'type': 'Sequence', 'id': sequence_id}]] 
    fields = ['id', 'code', 'sg_asset_type']
    asset = sg.find("Asset", filter, fields)
  • 获取指定类型的资产

    fields = ['id', 'sg_asset_type', 'code']
    filters = [
      ['project', 'is', {'type': 'Project', 'id':122}],
      ['sequence', 'is', {'type': 'Sequence', 'id': 145}],
      ['sg_asset_type', 'is', 'Character']]
    Character = sg.find('Asset', filters, fields)
  • 计算指定Sequence里所有的任务数量,并找到其中最近截止日期

    entity_type='Task'
    filter = [['entity.Shot.sg_sequence', 'is', {'type':'Sequence', 'id':2}],['sg_status_list', 'is_not', 'na']]
    summary_field = [{'field':'id', 'type':'count'},{'field':'due_date','type':'latest'}]
    result = sg.summarize(entity_type,filter,summary_field)
    #最近的截至日期,和当前场次所有任务的总数
    #{'groups': [], 'summaries': {'due_date': '2013-07-05', 'id': 30}}  
  • 获取指定 Version id 的mov

    mov = sg.find("Version", ["id", "is", 12321], [ "sg_uploaded_movie"])
  • 查询所有的工作流环节

    pipeline = shotgun.find("Step",[ ],[ "code"])
  • 查询指定工作流环节

    shotgun.find("Step",[ "code","is","Animation"],[])
  • 查询指定id的镜头

    shotgun.find("Shot",[ "id","is","1207"],[ "code"])
  • 获取指定镜头的指定环节的task信息(task是单独的,筛选它的link字段为entity,因此下面是筛选link字段中id为1207的镜头。注意,过滤器的第三项是要过滤的实体的话,必须使用实体id)

    shotgun.find("Task",[[ "entity","is",{"type":"shot","id":1207}],[ "shot","is",{"type":"Shot","id":1174}],[ "content","is","anim"]],[])
  • 获取指定镜头、指定环节、指定名称的task信息

    shotgun.find("Task",[[ "entity","is",{"type":"shot","id":1207}],[ "shot","is",{"type":"Shot","id":1174}],[ "content","is","anim"]],[])

下载mov

下载指定 Version id 的mov

mov = sg.find("Version", ["id", "is", 12321], ["sg_uploaded_movie"])
localpath = r"E:\temp" + mov["sg_uploaded_movie"]["name"]
sg.download_attachment(version["sg_uploaded_movie"], file_path=local_file_path)

创建内容

  • 创建镜头

    shotname = "test001"
    data = {
      'project': {'type': 'Project', 'id': 122},
      'sg_sequence': {'type': 'Sequence', 'id': 145},
      'code': shotname,
      'sg_status_list': 'ip'
    }
    shot = sg.create('Shot', data)
  • 在镜头的pipeline步环节下创建task(一个流程环节可以有多个任务)

    animationStepId = 106
    shotId = 1173 
    data = {
      'project': {'type': 'Project', 'id': 122},
      'content': 'anim', # 任务名
      'step': {'name': 'Animation', 'type': 'Step', 'id': animationStepId},
      'entity': {'type': 'Shot', 'id': shotId}
    }
    task = sg.create('Task', data)
  • Task下创建Version

    taskCode = 'testVersion_v001'
    shotId = 1173 
    taskId = 5964
    data = {
      'project': {'type': 'Project', 'id': 122},
      'code' : taskCode,
      'sg_status_list' : 'rev',
      'entity': {'type': 'Shot', 'id': shotId}, 
      'sg_task': {'type': 'Task', 'id': taskId}, 
      'user': {'type': 'HumanUser', 'id': 220} # 创建Version的人员
    }
    version = sg.create('Version', data)
  • 创建带有镜头和任务链接的版本

    shotID = 1173
    taskID = 5964
     data = { 'project': {'type': 'Project','id': 122},
            'code': '100_010_anim_v1',
            'description': 'first pass at opening shot with bunnies',
            'sg_path_to_frames': '/v1/gun/s100/010/frames/anim/100_010_animv1_jack.#.jpg',
            'sg_status_list': 'rev',
            'entity': {'type': 'Shot', 'id':  shotID},
            'sg_task': {'type': 'Task', 'id': taskID},
            'user': {'type': 'HumanUser', 'id': 165} }
     result = sg.create('Version', data)
     
  • 使用任务模板创建任务

    filters = [['code','is', '3D Shot Template' ]]
    taskTemplate = sg.find_one('TaskTemplate', filters)  # 查找任务模板
    taskId = 5964
    data = {'project': {'type': 'Project','id': 122},
          'code': 'seq001_sc001',
          'description': 'creating a task with taskTemplate',
          'task_template': template }
    result = sg.create('Shot', data)
  • 创建自定义实体 Entity(查找方式和查找别的实体一样)

    data = {
      'project': {'type': 'Project', 'id': 122},
      'code': 'test_plate_v001',
      'sg_shot': {'type': 'Shot', 'id': 1173},
      'updated_by': {'type': 'Group', 'id': 3}, # 更新用户为群组
      'sg_original_resolution': '1920x1080',
      'sg_plate_type': 'BG01',
      'sg_frames_scanned': 150,
      'sg_scan_start': 1,
      'sg_scan_end': 150
    }
    plate = sg.create('CustomEntity10', data)
  • 上传缩略图

    versionID = 214
    picPath = "/v1/gun/s100/010/beauties/anim/100_010_animv1.jpg"
    sg.upload_thumbnail("Version", versionID, picPath)

更新内容

  • 更新镜头

    shotId = 1173
    data = {
      'description': 'Open on a beautiful field with fuzzy bunnies',
      'sg_status_list': 'ip'
      }
    result = sg.update('Shot', shotId, data)
  • 更新Mov到镜头

    shotId = 423
    mov_file = '/data/show/ne2/100_110/anim/01.mlk-02b.mov'
    sg.upload("Shot", shotId, mov_file, field_name="sg_latest_quicktime", display_name="Latest QT")

删除内容

  • 删除指定id的project实体

    sg_delete = sg.delete("Project",155)
  • 删除指定镜头

    shotId = 1173
    result = sg.delete("Shot",shotId)

恢复内容

  • 恢复删掉的镜头
    shotId = 1173
    sg.revive("Shot", shotId)

批量处理(创建,删除,更新)镜头

使用batch函数的任务,要么全部完成,要么全都不完成

batch_data = []
for i in range(1,100):
    data = {
        "code": "shot_%04d" % i,
        "project": project
    }
    batch_data.append({"request_type": "create", "entity_type": "Shot", "data": data})
sg.batch(batch_data)  
batch_data = [
  {"request_type": "create", "entity_type": "Shot", "data": {"code": "New Shot 1", "project": project}},
  {"request_type": "update", "entity_type": "Shot", "entity_id": 3624, "data": {"code": "Changed 1"}},
  {"request_type": "delete", "entity_type": "Shot", "entity_id": 3624}
]
sg.batch(batch_data) # 三种不同类型可同时存在

关闭链接

sg.close()

部分可查询实体类型

实体类型名称 实体含义
ActionMenuItem 动作菜单
ApiUser 脚本
Asset 资产
Attachment 附件
Booking 人员规划
Camera 摄像机
ClientUser 客户
Composition 合成
Cut 剪辑镜头
CutItem 剪辑镜头项
Delivery 分发
Department 部门
Episode
EventLogEntry 事件日志
FilesystemLocation 文件系统位置
Group
HumanUser 人员
Icon 图标
Level 关卡
LocalStorage 本地存储
MocapPass 动作捕捉过程
MocapSetup 动作捕捉设置
MocapTake 动作捕捉条目
MocapTakeRange 动作捕捉条目范围
Note 反馈,记录
Page 页面
PageHit 页面点击
PageSetting 页面设置
Performer 演员
PermissionRuleSet 权限组设置
Phase 项目时间表
PhysicalAsset 实拍道具
PipelineConfiguration 工作流工序配置
Playlist 播放表单
PlaylistShare 共享的播放表单
Project 项目
PublishedFile 已发布文件
PublishedFileDependency 已发布文件依存关系
PublishedFileType 已发布文件类型
Release 软件发布版本
Reply 回复
Revision 修正版本
Routine 运动捕捉例程
RvLicense RV许可证
Scene
Sequence
ShootDay 拍摄日期
Shot 镜头
Software DCC软件
Status 状态
Step 工作流工序
Tag 标签
Task 任务
TaskDependency 任务依存关系
TaskTemplate 任务模版
Ticket 软件开发工单
TimeLog 工时记录
Version 版本

参考文档

ShotGrid API文档:https://developer.shotgridsoftware.com/python-api/
用户帮助文档:https://shotgunsoftware.zendesk.com/hc/zh-cn
站点状态查询网站:https://status.shotgridsoftware.com/
shot教学视频:https://space.bilibili.com/399556599