def get_dataset_by_name(self, dataset_name):
        """
        Retrieve information from Conservator about the first dataset matching
        the supplied name.

        The ID of a matching dataset returned by this method can then be used
        to retrieve its frames.

        :param dataset_name: The name of a dataset to retrieve information
                             about.
        :type dataset_name: str
        :returns: A dict containing fields retrieved from Conservator.
        :rtype: dict
        """
        var_data = {"name": dataset_name}
        res = try_graphql_query(
            self.client, """
        query datasetByName($name: String!) {
          datasets(searchText: $name) {
            id
            name
            frameCount
          }
        }
        """, json.dumps(var_data), self.logger)
        #print(json.dumps(res, indent=4))
        dataset_info = {}
        if 'datasets' in res['data']:
            for dset_info in res['data']['datasets']:
                if dset_info['name'] == dataset_name:
                    dataset_info = dset_info
                    break
        return dataset_info
    def add_frames_to_dataset(self, dataset_id, frame_id_list):
        """
        Associate the given frame IDs with the given dataset ID.

        :param dataset_id: The ID of a Conservator dataset
        :type dataset_id: str
        :param frame_id_list: A list of Conservator frame IDs to be added
        :type frame_id_list: list
        :returns: tuple of dataset's name and new frame count
        :rtype: 2-tuple
        """
        name = ""
        new_framecount = 0

        for sublist in next_sublist(frame_id_list, 20):
            add_frames_input = {"datasetId": dataset_id, "frameIds": sublist}
            var_data = {"framesinput": add_frames_input}
            # addFramesToDataset
            res = try_graphql_query(
                self.client, """
            mutation newDatasetFrames($framesinput: AddFramesToDatasetInput!) {
              addFramesToDataset(input: $framesinput) {
                name
                frameCount
              }
            }
            """, json.dumps(var_data), self.logger)
            # print(json.dumps(res, indent=4))

            if res and ('addFramesToDataset' in res['data']):
                name = res['data']['addFramesToDataset']['name']
                new_framecount += res['data']['addFramesToDataset'][
                    'frameCount']
        return name, new_framecount
    def get_dataset_frame_info_by_id(self, frame_id):
        """
        Request information about a given dataset frame ID from Conservator.

        :param frame_id: The ID of a Conservator video frame.
        :type frame_id: str
        :returns: A dict containing fields retrieved from Conservator.
        :rtype: dict
        """
        dest_search_info = None
        var_data = {"id": frame_id}
        res = try_graphql_query(
            self.client, """
        query frameDetailsFromId($id: ID!) {
          datasetFrame(id: $id) {
            id
            frameId
            frameIndex
            videoId
          }
        }
        """, json.dumps(var_data), self.logger)
        #print(json.dumps(res, indent=4))
        if res and ('datasetFrame' in res['data']):
            dest_search_info = res['data']['datasetFrame']
        return dest_search_info
 def get_video_info_list(self, collection_id, row_count=20, page_offset=0):
     """
     Query info about all videos in a collection.
     """
     var_data = {
         "collid": collection_id,
         "limit": row_count,
         "page": page_offset
     }
     res = try_graphql_query(
         self.client, """
     query getVideosInFolder($collid: ID!, $limit: Int!, $page: Int!) {
       videos(collectionId: $collid, limit: $limit, page: $page) {
         id
         tags
         filename
         description
         assetType
       }
     }
     """, json.dumps(var_data), self.logger)
     #print(json.dumps(res, indent=4))
     videos = None
     if res and ("videos" in res['data']):
         videos = res['data']['videos']
     return videos
 def generate_signed_upload_url(self, video_id):
     """
     Retrieve an upload URL for a newly-created video.
     """
     var_data = {"videoid": video_id, "contenttype": ""}
     res = try_graphql_query(
         self.client, """
     mutation generateSignedVideoUploadUrl($videoid: String!, $contenttype: String!) {
       generateSignedVideoUploadUrl(videoId: $videoid, contentType: $contenttype) {
         signedUrl
       }
     }
     """, json.dumps(var_data), self.logger)
     # print(json.dumps(res, indent=4))
     url = ""
     data = {}
     if res['data'] is not None and "generateSignedVideoUploadUrl" in res[
             'data']:
         # This can fail if a URL was already requested before but no file
         # was uploaded to it.
         full_url = res['data']['generateSignedVideoUploadUrl']['signedUrl']
         url, data_str = full_url.split('?')
         data_fields = data_str.split('&')
         data = OrderedDict([dat.split('=') for dat in data_fields])
     return url, data, full_url
    def create_dataset(self, dataset_name):
        """
        Create new dataset in Conservator with the given name.

        The ID of a matching dataset returned by this method can then be used
        to add (and subsequently, retrieve) its frames.

        :param dataset_name: The name of dataset to create
        :type dataset_name: str
        :returns: String containing unique id of new dataset
        :rtype: str
        """
        dataset_id = None

        existing_dataset = self.get_dataset_by_name(dataset_name)
        if existing_dataset:
            self.logger.warning("Refusing to re-create existing dataset '%s'.",
                                dataset_name)
            return existing_dataset["id"]
        create_dataset_input = {"name": dataset_name}
        var_data = {"input": create_dataset_input}
        res = try_graphql_query(
            self.client, """
        mutation newDataset($input: CreateDatasetInput!) {
          createDataset(input: $input) {
            id
          }
        }
        """, json.dumps(var_data), self.logger)
        #print(json.dumps(res, indent=4))

        if 'createDataset' in res['data']:
            dataset_id = res['data']['createDataset']['id']
        return dataset_id
    def get_frame_from_video_by_index(self, video_id, frame_index):
        """
        Given a video ID and a frame index into the video, return information
        about the specified frame.

        :param video_id: The ID of a Conservator video.
        :type video_id: str
        :param frame_index: The frame number to retrieve information about.
        :type frame_index: int
        :returns: A dict containg information about the frame.
        :rtype: dict
        """
        frame_info = {}
        var_data = {"id": video_id, "frameindex": frame_index}
        res = try_graphql_query(
            self.client, """
        query videoFrameInfoFromIndex($id: String!, $frameindex: Int!) {
          video(id: $id) {
            frames(frameIndex: $frameindex) {
              id
              height
              width
            }
          }
        }
        """, json.dumps(var_data), self.logger)
        # print(json.dumps(res, indent=4))
        if res and ('video' in res['data']) and res['data']['video']['frames']:
            frame_info = res['data']['video']['frames'][0]
        return frame_info
 def image_exists_in_folder(self, collection_id, filename):
     """
     Return information about the first image found in a collection with the
     supplied file name.
     """
     var_data = {"collectionid": collection_id, "filename": filename}
     res = try_graphql_query(
         self.client, """
     query imageExistsInCollection($collectionid: ID!, $filename: String!) {
       images(collectionId: $collectionid, searchText: $filename) {
         id
         filename
         createdAt
         state
       }
     }
     """, json.dumps(var_data), self.logger)
     # print(json.dumps(res, indent=4))
     image_info = None
     if "images" in res['data']:
         for im_info in res['data']['images']:
             if im_info['filename'] == filename:
                 image_info = im_info
                 break
     return image_info
    def get_brief_video_info_by_id(self, video_id):
        """
        Look up a video ID found in a dataset, and return information about it.

        :param video_id: The ID of a Conservator video.
        :type video_id: str
        :returns: A dict containing fields retrieved from Conservator.
        :rtype: dict
        """
        video_info = {}
        var_data = {"id": video_id}
        res = try_graphql_query(
            self.client, """
        query videoInfoFromID($id: String!) {
          video(id: $id) {
            name
            description
            framesCount
            assetType
          }
        }
        """, json.dumps(var_data), self.logger)
        # print(json.dumps(res, indent=4))
        if res and ('video' in res['data']):
            video_info = res['data']['video']
        return video_info
 def remove_video(self, video_id):
     """
     Remove an existing video from conservator.
     """
     var_data = {"videoid": video_id}
     res = try_graphql_query(
         self.client, """
       mutation removeBrokenVideo($videoid: String!) {
         removeVideo(id: $videoid)
       }
     """, json.dumps(var_data), self.logger)
     # print(json.dumps(res, indent=4))
     remove_ok = False
     if "removeVideo" in res['data']:
         remove_ok = res['data']['removeVideo']
     return remove_ok
    def get_image_count(self, project_name):
        """
        Get the number of images associated with `project_name`.
        """
        var_data = {"name": project_name}
        res = try_graphql_query(self.client, """
        query projectImageCount($name: String!) {
          projects(where: { name: $name }) {
            dataRowCount
          }
        }
        """, json.dumps(var_data), self.logger)

        count = 0
        if 'projects' in res['data'] and res['data']['projects']:
            count = res['data']['projects'][0]['dataRowCount']
        return count
    def get_project_id(self, project_name):
        """
        Get the Labelbox ID for `project_name`.
        """
        var_data = {"name": project_name}
        res = try_graphql_query(self.client, """
        query projectImageCount($name: String!) {
          projects(where: { name: $name }) {
            id
          }
        }
        """, json.dumps(var_data), self.logger)

        proj_id = None
        if 'projects' in res['data'] and res['data']['projects']:
            proj_id = res['data']['projects'][0]['id']
        return proj_id
    def get_dataset_info(self, dataset_id, frame_count):
        """
        Collect information about the requested number of frames from a
        dataset, in the order in which they were added to the dataset.

        :param dataset_id: The ID of a Conservator dataset
        :type dataset_id: str
        :param frame_count: The number of frames to retrieve.
        :type frame_count: int
        :returns: A dict containing fields retrieved from Conservator.
        :rtype: dict
        """
        dataset_frames = []
        query_pages = int(frame_count / self.FRAME_QUERY_LIMIT)
        remainder = frame_count % self.FRAME_QUERY_LIMIT
        if remainder:
            query_pages += 1
        var_data = {"id": dataset_id}
        for page_n in range(query_pages):
            var_data['page'] = page_n
            var_data['limit'] = self.FRAME_QUERY_LIMIT
            res = try_graphql_query(
                self.client, """
            query datasetFramesById($id: ID!, $page: Int!, $limit: Int!) {
              datasetFramesOnly(id: $id, page: $page, limit: $limit) {
                datasetFrames {
                  id
                  frameId
                  frameIndex
                  video {
                    id
                  }
                }
                totalCount
              }
            }
            """, json.dumps(var_data), self.logger)
            # print(json.dumps(res, indent=4))
            if 'datasetFramesOnly' in res['data']:
                for a_dset_frame in res['data']['datasetFramesOnly'][
                        'datasetFrames']:
                    frame_info = {"frameId": a_dset_frame['frameId']}
                    frame_info['frameIndex'] = a_dset_frame['frameIndex']
                    frame_info['videoId'] = a_dset_frame['video']['id']
                    dataset_frames.append(frame_info)
        return dataset_frames
 def process_video(self, video_id):
     """
     Process an uploaded video.
     """
     var_data = {"videoid": video_id, "shouldnotify": False}
     res = try_graphql_query(
         self.client, """
     mutation processAutoUploadedVideo($videoid: String!, $shouldnotify: Boolean) {
       processVideo(id: $videoid, shouldNotify: $shouldnotify) {
         id
       }
     }
     """, json.dumps(var_data), self.logger)
     # print(json.dumps(res, indent=4))
     vidid = None
     if "data" in res and res['data'] and "processVideo" in res['data']:
         vidid = res['data']['processVideo']['id']
     return vidid
 def get_subfolder_info_list(self, folder_id):
     """
     Find information about a collection's child folders.
     """
     var_data = {"parentid": folder_id}
     res = try_graphql_query(
         self.client, """
     query subFolders($parentid: ID!) {
       collections(parentId: $parentid) {
         id
         name
         path
       }
     }
     """, json.dumps(var_data), self.logger)
     collections = None
     if res and ("collections" in res['data']):
         collections = res['data']['collections']
     return collections
 def get_collection_id(self, project_name, parent_id=None):
     # projects are toplevel collections
     var_data = {"parentid": parent_id}
     res = try_graphql_query(
         self.client, """
     query allCollections($parentid: ID) {
       collections(parentId: $parentid) {
         name
         id
         parentId
       }
     }
     """, json.dumps(var_data), self.logger)
     proj_id = None
     for project_info in res['data']['collections']:
         if project_info['name'] == project_name:
             proj_id = project_info['id']
             break
     return proj_id
 def get_video_info(self, video_id):
     """
     Retrieve information about a known video ID.
     """
     var_data = {"videoid": video_id}
     res = try_graphql_query(
         self.client, """
       query getVideoInfo($videoid: String!) {
         video(id: $videoid) {
           id
           filename
           createdAt
           state
         }
       }
     """, json.dumps(var_data), self.logger)
     # print(json.dumps(res, indent=4))
     vid_info = {}
     if "video" in res['data']:
         vid_info = res['data']['video']
     return vid_info
 def get_image_info(self, image_id):
     """
     Retrieve information about a known image ID.
     """
     var_data = {"imageid": image_id}
     res = try_graphql_query(
         self.client, """
       query getImageInfo($imageid: String!) {
         image(id: $imageid) {
           id
           filename
           createdAt
           state
         }
       }
     """, json.dumps(var_data), self.logger)
     # print(json.dumps(res, indent=4))
     im_info = {}
     if "image" in res['data']:
         im_info = res['data']['image']
     return im_info
 def create_new_video(self, collection_id, filename):
     """
     Create a new video in Conservator as part of the given collection_id.
     """
     new_file_info = None
     var_data = {"collectionid": collection_id, "filename": filename}
     res = try_graphql_query(
         self.client, """
     mutation createVideoInCollection($filename: String!, $collectionid: ID!) {
       createVideo(filename: $filename, collectionId: $collectionid) {
         id
         filename
         createdAt
         state
       }
     }
     """, json.dumps(var_data), self.logger)
     # print(json.dumps(res, indent=4))
     if "createVideo" in res['data']:
         new_file_info = res['data']['createVideo']
     return new_file_info
    def add_videos_to_dataset(self,
                              dataset_id,
                              video_id_list,
                              frame_skip=None):
        """
        Add frames from the given video IDs to the given dataset ID.

        :param dataset_id: The ID of a Conservator dataset.
        :type dataset_id: str
        :param video_id_list: A list of video IDs to add to the dataset.
        :type video_id_list: list
        :param frame_skip: Skip this many frames between frames added to the
                           dataset.
        :type frame_skip: None | int
        :returns: A tuple of the dataset's name and new frame count.
        :rtype: 2-tuple
        """
        # addVideosToDataset
        add_videos_input = {
            "datasetId": dataset_id,
            "videoIds": video_id_list,
            "frameSkip": frame_skip
        }
        var_data = {"videosinput": add_videos_input}
        res = try_graphql_query(
            self.client, """
        mutation newDatasetVideos($videosinput: AddVideosToDatasetInput!) {
          addVideosToDataset(input: $videosinput) {
            name
            frameCount
          }
        }
        """, json.dumps(var_data), self.logger)
        # print(json.dumps(res, indent=4))
        name = ""
        new_framecount = 0
        if res and ('addVideosToDataset' in res['data']):
            name = res['data']['addVideosToDataset']['name']
            new_framecount = res['data']['addVideosToDataset']['frameCount']
        return name, new_framecount
 def get_project_id(self, project_name):
     """
     Given a project name, find its Conservator ID.
     """
     # Projects are toplevel collections.
     res = try_graphql_query(self.client,
                             """
     query allProjects {
       collections(parentId: null) {
         name
         id
       }
     }
     """,
                             logger=self.logger)
     proj_id = None
     if res and ("collections" in res['data']):
         for project_info in res['data']['collections']:
             if project_info['name'] == project_name:
                 proj_id = project_info['id']
                 break
     return proj_id
 def get_image_counts(self, collection_id):
     """
     Collect immediate counts of videos and images in a collection, as well
     as counts that include all subfolders.
     """
     var_data = {"id": collection_id}
     res = try_graphql_query(
         self.client, """
     query imageCountRecursive($id: ID!) {
       collection(id: $id) {
         recursiveVideoCount
         videoCount
         recursiveImageCount
         imageCount
       }
     }
     """, json.dumps(var_data), self.logger)
     #print(res)
     item_counts = None
     if res and ("collection" in res["data"]):
         item_counts = res['data']['collection']
     return item_counts
    def get_project_image_info(self, project_name, row_count=10, row_skip=0):
        """
        Get both Labelbox and Conservator IDs for every frame in
        `project_name`.
        """
        var_data = {"name": project_name, "first": row_count, "skip": row_skip}
        res = try_graphql_query(self.client, """
        query projectImageInfo($name: String!, $first: PageSize, $skip: Int) {
          projects(where: { name: $name }) {
            dataRows(first: $first, skip: $skip) {
              id
              deleted
              externalId
              rowData
            }
          }
        }
        """, json.dumps(var_data), self.logger)

        image_info = {}
        if 'projects' in res['data'] and res['data']['projects']:
            image_info = res['data']['projects'][0]['dataRows']
        return image_info
    def get_full_video_info_by_name(self, filename):
        """
        Search Conservator for a list of files matching the given filename.  If
        matching videos are found, return information about them in a list.

        :param filename: A substring to match Conservator video names against.
        :type filename: str
        :returns: A dict containing fields retrieved from Conservator.
        :rtype: dict
        """
        dest_search_info = None
        var_data = {"name": filename}
        res = try_graphql_query(
            self.client, """
        query videoFromName($name: String!) {
          videos(searchText: $name) {
            name
            filename
            id
            userId
            framesCount
            fileSize
            createdAt
            modifiedAt
            description
            width
            height
            state
            tags
            collections
          }
        }
        """, json.dumps(var_data), self.logger)
        #print(json.dumps(res, indent=4))
        if res and ('videos' in res['data']):
            dest_search_info = res['data']['videos']
        return dest_search_info
    def get_full_video_info_by_id(self, video_id):
        """
        Request information about a given video ID from Conservator, and return
        it in a single-value list.

        :param video_id: The ID of a Conservator video.
        :type video_id: str
        :returns: A dict containing fields retrieved from Conservator.
        :rtype: dict
        """
        dest_search_info = None
        var_data = {"id": video_id}
        res = try_graphql_query(
            self.client, """
        query videoDetailsFromId($id: String!) {
          video(id: $id) {
            name
            filename
            id
            userId
            framesCount
            fileSize
            createdAt
            modifiedAt
            description
            width
            height
            state
            tags
            collections
          }
        }
        """, json.dumps(var_data), self.logger)
        #print(json.dumps(res, indent=4))
        if res and ('video' in res['data']):
            dest_search_info = [res['data']['video']]
        return dest_search_info