Design: add support for querying files

Introduction

Currently, files are still tightly coupled with scenes, images and galleries. As the next step for making files more independent of their logical objects, we should introduce the ability to query files.

This is mostly for myself. However since I won’t get to it until I’m finished with the sidebar stuff, if you feel confident enough to start on this, please let me know.

Scope

This design covers the server-side only. While the frontend client will be considered in the graphql API design, the graphical design of any user interfaces should be discussed as a separate topic.

There will need to be a similar design done for folder querying, which I expect to be a smaller job. I will not be including its design here.

Design

graphql interface

input FingerprintFilterInput {
  type: String!
  value: String!
  "Hamming distance - defaults to 0"
  distance: Int
}

input VideoFileFilterInput {
  resolution: ResolutionCriterionInput
  orientation: OrientationCriterionInput
  framerate: IntCriterionInput
  bitrate: IntCriterionInput
  video_codec: StringCriterionInput
  audio_codec: StringCriterionInput
  
  "in seconds"
  duration: IntCriterionInput

  captions: StringCriterionInput
  
  interactive: Boolean
  interactive_speed: IntCriterionInput
}

input ImageFileFilterType {
  resolution: ResolutionCriterionInput
  orientation: OrientationCriterionInput
}

input FileFilterType {
  AND: FileFilterType
  OR: FileFilterType
  NOT: FileFilterType

  path: StringCriterionInput
  basename: StringCriterionInput
  dir: StringCriterionInput

  parent_folder: HierarchicalMultiCriterionInput

  "Filter by modification time"
  mod_time: TimestampCriterionInput

  "Filter files that have an exact match available"
  duplicated: PHashDuplicationCriterionInput  

  "find files based on hash"
  hashes: [FingerprintFilterInput!]

  video_file_filter: VideoFileFilterInput
  image_file_filter: ImageFileFilterType
  
  scene_count: IntCriterionInput
  image_count: IntCriterionInput
  gallery_count: IntCriterionInput

  "Filter by related scenes that meet this criteria"
  scenes_filter: SceneFilterType
  "Filter by related images that meet this criteria"
  images_filter: ImageFilterType
  "Filter by related galleries that meet this criteria"
  galleries_filter: GalleryFilterType

  "Filter by creation time"
  created_at: TimestampCriterionInput
  "Filter by last update time"
  updated_at: TimestampCriterionInput
}

type FindFilesResultType {
  count: Int!
  
  "Total megapixels of any image files"
  megapixels: Float!
  "Total duration in seconds of any video files"
  duration: Float!

  "Total file size in bytes"
  filesize: Int!

  files: [BaseFile!]!
}

type Query {
  "Find a file by its id or path"
  findFile(id: ID, path: String): BaseFile!

  "Queries for Files"
  findFiles(
    file_filter: FileFilterType
    filter: FindFilterType
    ids: [ID!]
  ): FindFilesResultType!
}

We should consider adding dirname: String! field to BaseFile. This will return the path up to the basename. We will need to write a resolver for this. A folder: Folder! would also be useful, but this will require a dataloader batch operation.

sqlite package

FileStore has Find and FindByPath defined already, so these can be used for findFile.

Embarassingly, we actually have FileStore.Query in the current code, but it’s not called by anything and is completely untested. Unit tests will need to be written for it. See scene_test.go for a starting point.

FileQueryOptions will need to add options for getting the total duration, megapixels, file size. FileQueryResult will need results for these.

FileStore.makeQuery should be rewritten to follow the conventions in SceneStore.makeQuery. FileStore.Query will need to be adjusted accordingly. q handling will need to be changed to include fingerprints (see SceenStore.makeFilter).

fileFilterHandler will need to be declared in file_filter.go. The scene_filter.go code will do as a good starting point. image_filter.go should also be used to reuse the image-specific filtering code.

Next steps

After this is complete, the next priority would be the folder querying functionality, then a proper think about how this would fit in the UI.

Feedback

Let me know if I missed something or anything seems incorrect.

2 Likes