Browse Source

Merge remote-tracking branch 'leszek/giza-content-migration' into giza-staging-update-with-content-migration

Mokhtar Naamani 3 years ago
parent
commit
1247079746
27 changed files with 4624 additions and 17 deletions
  1. 1 0
      package.json
  2. 1 0
      utils/migration-scripts/.eslintignore
  3. 9 0
      utils/migration-scripts/.gitignore
  4. 2 0
      utils/migration-scripts/.prettierignore
  5. 116 0
      utils/migration-scripts/README.md
  6. 3 0
      utils/migration-scripts/bin/run
  7. 3 0
      utils/migration-scripts/bin/run.cmd
  8. 93 0
      utils/migration-scripts/package.json
  9. 142 0
      utils/migration-scripts/src/RuntimeApi.ts
  10. 73 0
      utils/migration-scripts/src/commands/sumer-giza/migrateContent.ts
  11. 51 0
      utils/migration-scripts/src/commands/sumer-giza/retryFailedUploads.ts
  12. 1 0
      utils/migration-scripts/src/index.ts
  13. 308 0
      utils/migration-scripts/src/sumer-giza/AssetsManager.ts
  14. 40 0
      utils/migration-scripts/src/sumer-giza/AssetsMigration.ts
  15. 121 0
      utils/migration-scripts/src/sumer-giza/BaseMigration.ts
  16. 162 0
      utils/migration-scripts/src/sumer-giza/ChannelsMigration.ts
  17. 22 0
      utils/migration-scripts/src/sumer-giza/ContentHash.ts
  18. 69 0
      utils/migration-scripts/src/sumer-giza/ContentMigration.ts
  19. 30 0
      utils/migration-scripts/src/sumer-giza/ImageResizer.ts
  20. 192 0
      utils/migration-scripts/src/sumer-giza/VideosMigration.ts
  21. 120 0
      utils/migration-scripts/src/sumer-giza/sumer-query-node/api.ts
  22. 33 0
      utils/migration-scripts/src/sumer-giza/sumer-query-node/codegen.yml
  23. 229 0
      utils/migration-scripts/src/sumer-giza/sumer-query-node/generated/queries.ts
  24. 2565 0
      utils/migration-scripts/src/sumer-giza/sumer-query-node/generated/schema.ts
  25. 122 0
      utils/migration-scripts/src/sumer-giza/sumer-query-node/queries/queries.graphql
  26. 21 0
      utils/migration-scripts/tsconfig.json
  27. 95 17
      yarn.lock

+ 1 - 0
package.json

@@ -24,6 +24,7 @@
     "pioneer",
     "pioneer/packages/*",
     "utils/api-scripts",
+    "utils/migration-scripts",
     "query-node",
     "query-node/mappings",
     "query-node/generated/graphql-server",

+ 1 - 0
utils/migration-scripts/.eslintignore

@@ -0,0 +1 @@
+src/sumer-giza/sumer-query-node/generated

+ 9 - 0
utils/migration-scripts/.gitignore

@@ -0,0 +1,9 @@
+*-debug.log
+*-error.log
+/.nyc_output
+/dist
+/lib
+/package-lock.json
+/tmp
+node_modules
+results

+ 2 - 0
utils/migration-scripts/.prettierignore

@@ -0,0 +1,2 @@
+results
+src/sumer-giza/sumer-query-node/generated

+ 116 - 0
utils/migration-scripts/README.md

@@ -0,0 +1,116 @@
+migrations
+==========
+
+Joystream migrations scripts
+
+[![oclif](https://img.shields.io/badge/cli-oclif-brightgreen.svg)](https://oclif.io)
+[![Version](https://img.shields.io/npm/v/migrations.svg)](https://npmjs.org/package/migrations)
+[![Downloads/week](https://img.shields.io/npm/dw/migrations.svg)](https://npmjs.org/package/migrations)
+[![License](https://img.shields.io/npm/l/migrations.svg)](https://github.com/Joystream/joystream/blob/master/package.json)
+
+<!-- toc -->
+* [Usage](#usage)
+* [Commands](#commands)
+<!-- tocstop -->
+# Usage
+<!-- usage -->
+```sh-session
+$ npm install -g migration-scripts
+$ migration-scripts COMMAND
+running command...
+$ migration-scripts (-v|--version|version)
+migration-scripts/0.1.0 linux-x64 node-v14.16.1
+$ migration-scripts --help [COMMAND]
+USAGE
+  $ migration-scripts COMMAND
+...
+```
+<!-- usagestop -->
+# Commands
+<!-- commands -->
+* [`migration-scripts help [COMMAND]`](#migration-scripts-help-command)
+* [`migration-scripts sumer-giza:migrateContent`](#migration-scripts-sumer-gizamigratecontent)
+* [`migration-scripts sumer-giza:retryFailedUploads`](#migration-scripts-sumer-gizaretryfaileduploads)
+
+## `migration-scripts help [COMMAND]`
+
+display help for migration-scripts
+
+```
+USAGE
+  $ migration-scripts help [COMMAND]
+
+ARGUMENTS
+  COMMAND  command to show help for
+
+OPTIONS
+  --all  see all commands in CLI
+```
+
+_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v3.2.3/src/commands/help.ts)_
+
+## `migration-scripts sumer-giza:migrateContent`
+
+```
+USAGE
+  $ migration-scripts sumer-giza:migrateContent
+
+OPTIONS
+  -c, --channelIds=channelIds                                  (required) Channel ids to migrate
+  --channelBatchSize=channelBatchSize                          [default: 20] Channel batch size
+
+  --dataDir=dataDir                                            [default: /tmp/joystream/sumer-giza-migration] Directory
+                                                               for storing data objects to upload
+
+  --forceChannelOwnerMemberId=forceChannelOwnerMemberId        Can be used to force a specific channel owner for all
+                                                               channels, allowing to test the script in dev environment
+
+  --migrationStatePath=migrationStatePath                      [default:
+                                                               /home/leszek/projects/joystream/joystream-ws-2/utils/migr
+                                                               ation-scripts/results/sumer-giza] Path to migration
+                                                               results directory
+
+  --preferredDownloadSpEndpoints=preferredDownloadSpEndpoints  [default: https://storage-1.joystream.org/storage]
+                                                               Preferred storage node endpoints when downloading data
+                                                               objects
+
+  --queryNodeUri=queryNodeUri                                  [default: https://hydra.joystream.org/graphql] Query node
+                                                               uri
+
+  --sudoUri=sudoUri                                            [default: //Alice] Sudo key Substrate uri
+
+  --uploadSpBucketId=uploadSpBucketId                          [default: 0] Giza storage bucket id
+
+  --uploadSpEndpoint=uploadSpEndpoint                          [default: http://localhost:3333] Giza storage node
+                                                               endpoint to use for uploading
+
+  --videoBatchSize=videoBatchSize                              [default: 20] Video batch size
+
+  --wsProviderEndpointUri=wsProviderEndpointUri                [default: ws://localhost:9944] WS provider endpoint uri
+                                                               (Giza)
+```
+
+_See code: [src/commands/sumer-giza/migrateContent.ts](https://github.com/Joystream/joystream/blob/v0.1.0/src/commands/sumer-giza/migrateContent.ts)_
+
+## `migration-scripts sumer-giza:retryFailedUploads`
+
+```
+USAGE
+  $ migration-scripts sumer-giza:retryFailedUploads
+
+OPTIONS
+  -f, --failedUploadsPath=failedUploadsPath      (required) Path to failed uploads file
+
+  --dataDir=dataDir                              [default: /tmp/joystream/sumer-giza-migration] Directory where data
+                                                 objects to upload are stored
+
+  --uploadSpBucketId=uploadSpBucketId            [default: 0] Giza storage bucket id
+
+  --uploadSpEndpoint=uploadSpEndpoint            [default: http://localhost:3333] Giza storage node endpoint to use for
+                                                 uploading
+
+  --wsProviderEndpointUri=wsProviderEndpointUri  [default: ws://localhost:9944] WS provider endpoint uri (Giza)
+```
+
+_See code: [src/commands/sumer-giza/retryFailedUploads.ts](https://github.com/Joystream/joystream/blob/v0.1.0/src/commands/sumer-giza/retryFailedUploads.ts)_
+<!-- commandsstop -->

+ 3 - 0
utils/migration-scripts/bin/run

@@ -0,0 +1,3 @@
+#!/usr/bin/env node
+
+require('@oclif/command').run().then(require('@oclif/command/flush')).catch(require('@oclif/errors/handle'))

+ 3 - 0
utils/migration-scripts/bin/run.cmd

@@ -0,0 +1,3 @@
+@echo off
+
+node "%~dp0\run" %*

+ 93 - 0
utils/migration-scripts/package.json

@@ -0,0 +1,93 @@
+{
+  "name": "migration-scripts",
+  "description": "Joystream migration scripts",
+  "version": "0.1.0",
+  "author": "Joystream contributors",
+  "bin": {
+    "migration-scripts": "./bin/run"
+  },
+  "bugs": "https://github.com/Joystream/joystream/issues",
+  "dependencies": {
+    "@oclif/command": "^1",
+    "@oclif/config": "^1",
+    "@oclif/plugin-help": "^3.2.3",
+    "tslib": "^1",
+    "@joystream/types": "^0.17.0",
+    "@polkadot/api": "5.9.1",
+    "@polkadot/types": "5.9.1",
+    "@polkadot/keyring": "7.3.1",
+    "@polkadot/util": "7.3.1",
+    "@polkadot/util-crypto": "7.3.1",
+    "@apollo/client": "^3.2.5",
+    "cross-fetch": "^3.1.4",
+    "lodash": "^4.17.21",
+    "url-join": "^4.0.1",
+    "@types/url-join": "^4.0.1",
+    "axios": "^0.24.0",
+    "blake3": "^2.1.4",
+    "multihashes": "^4.0.3",
+    "moment": "^2.29.1",
+    "sharp": "^0.29.2",
+    "@types/sharp": "^0.29.2",
+    "form-data": "^4.0.0",
+    "node-cleanup": "^2.1.2",
+    "@types/node-cleanup": "^2.1.2"
+  },
+  "devDependencies": {
+    "@graphql-codegen/cli": "^1.21.4",
+    "@graphql-codegen/import-types-preset": "^1.18.1",
+    "@graphql-codegen/typescript": "^1.22.0",
+    "@graphql-codegen/typescript-document-nodes": "^1.17.11",
+    "@graphql-codegen/typescript-operations": "^1.17.16",
+    "@oclif/dev-cli": "^1",
+    "@types/node": "^14",
+    "globby": "^10",
+    "ts-node": "^8",
+    "typescript": "^3.3"
+  },
+  "engines": {
+    "node": ">=14.0.0",
+    "yarn": "^1.22.0"
+  },
+  "volta": {
+    "node": "14.16.1",
+    "yarn": "1.22.4"
+  },
+  "files": [
+    "/bin",
+    "/lib",
+    "/npm-shrinkwrap.json",
+    "/oclif.manifest.json"
+  ],
+  "homepage": "https://github.com/Joystream/joystream",
+  "keywords": [
+    "oclif"
+  ],
+  "license": "GPL-3.0-only",
+  "main": "lib/index.js",
+  "oclif": {
+    "commands": "./lib/commands",
+    "bin": "migration-scripts",
+    "plugins": [
+      "@oclif/plugin-help"
+    ],
+    "topics": {
+      "sumer-giza": {
+        "description": "Sumer-to-Giza migration scripts"
+      }
+    }
+  },
+  "repository": "Joystream/joystream",
+  "scripts": {
+    "postpack": "rm -f oclif.manifest.json",
+    "prepack": "rm -rf lib && tsc -b && oclif-dev manifest && oclif-dev readme",
+    "test": "echo NO TESTS",
+    "version": "oclif-dev readme && git add README.md",
+    "build": "tsc --build tsconfig.json",
+    "lint": "eslint ./src --ext .ts",
+    "checks": "tsc --noEmit --pretty && prettier ./ --check && yarn lint",
+    "format": "prettier ./ --write",
+    "generate:types:graphql": "yarn graphql-codegen -c ./src/sumer-giza/sumer-query-node/codegen.yml"
+  },
+  "types": "lib/index.d.ts"
+}

+ 142 - 0
utils/migration-scripts/src/RuntimeApi.ts

@@ -0,0 +1,142 @@
+import { types } from '@joystream/types'
+import { ApiPromise, SubmittableResult } from '@polkadot/api'
+import { SubmittableExtrinsic, AugmentedEvent, ApiOptions, AugmentedQuery } from '@polkadot/api/types'
+import { KeyringPair } from '@polkadot/keyring/types'
+import { Call } from '@polkadot/types/interfaces'
+import { Codec, IEvent } from '@polkadot/types/types'
+import { DispatchError } from '@polkadot/types/interfaces/system'
+import { UInt } from '@polkadot/types'
+import { Observable } from 'rxjs'
+import BN from 'bn.js'
+
+export class ExtrinsicFailedError extends Error {}
+
+// Joystream runtime api utility class. Based on distributor node CLI / Joystream CLI implementation
+
+type EventSection = keyof ApiPromise['events'] & string
+type EventMethod<Section extends EventSection> = keyof ApiPromise['events'][Section] & string
+type EventType<
+  Section extends EventSection,
+  Method extends EventMethod<Section>
+> = ApiPromise['events'][Section][Method] extends AugmentedEvent<'promise', infer T> ? IEvent<T> : never
+
+export class RuntimeApi extends ApiPromise {
+  constructor(options: Omit<ApiOptions, 'types'>) {
+    super({ ...options, types })
+  }
+
+  public findEvent<S extends EventSection, M extends EventMethod<S>>(
+    result: SubmittableResult,
+    section: S,
+    method: M
+  ): EventType<S, M> | undefined {
+    return result.findRecord(section, method)?.event as EventType<S, M> | undefined
+  }
+
+  public getEvent<S extends EventSection, M extends EventMethod<S>>(
+    result: SubmittableResult,
+    section: S,
+    method: M
+  ): EventType<S, M> {
+    const event = this.findEvent(result, section, method)
+    if (!event) {
+      throw new Error(`Cannot find expected ${section}.${method} event in result: ${JSON.stringify(result.toHuman())}`)
+    }
+    return event
+  }
+
+  public findEvents<S extends EventSection, M extends EventMethod<S>>(
+    result: SubmittableResult,
+    section: S,
+    method: M,
+    expectedCount?: number
+  ): EventType<S, M>[] {
+    const events = result.filterRecords(section, method).map((r) => r.event)
+    if (expectedCount && events.length !== expectedCount) {
+      throw new Error(
+        `Unexpected count of ${section}.${method} events in result: ${JSON.stringify(result.toHuman())}. ` +
+          `Expected: ${expectedCount}, Got: ${events.length}`
+      )
+    }
+    return (events.sort((a, b) => new BN(a.index).cmp(new BN(b.index))) as unknown) as EventType<S, M>[]
+  }
+
+  private formatDispatchError(err: DispatchError): string {
+    try {
+      const { name, docs } = this.registry.findMetaError(err.asModule)
+      return `${name} (${docs.join(', ')})`
+    } catch (e) {
+      return err.toString()
+    }
+  }
+
+  async entriesByIds<IDType extends UInt, ValueType extends Codec>(
+    apiMethod: AugmentedQuery<'promise', (key: IDType) => Observable<ValueType>, [IDType]>
+  ): Promise<[IDType, ValueType][]> {
+    const entries: [IDType, ValueType][] = (await apiMethod.entries()).map(([storageKey, value]) => [
+      storageKey.args[0] as IDType,
+      value,
+    ])
+
+    return entries.sort((a, b) => a[0].toNumber() - b[0].toNumber())
+  }
+
+  sendExtrinsic(keyPair: KeyringPair, tx: SubmittableExtrinsic<'promise'>): Promise<SubmittableResult> {
+    let txName = `${tx.method.section}.${tx.method.method}`
+    if (txName === 'sudo.sudo') {
+      const innerCall = tx.args[0] as Call
+      txName = `sudo.sudo(${innerCall.section}.${innerCall.method})`
+    }
+    console.log(`Sending ${txName} extrinsic from ${keyPair.address}`)
+    return new Promise((resolve, reject) => {
+      let unsubscribe: () => void
+      tx.signAndSend(keyPair, {}, (result) => {
+        if (!result || !result.status) {
+          return
+        }
+
+        if (result.status.isInBlock) {
+          unsubscribe()
+          result.events
+            .filter(({ event }) => event.section === 'system')
+            .forEach(({ event }) => {
+              if (event.method === 'ExtrinsicFailed') {
+                const dispatchError = event.data[0] as DispatchError
+                reject(
+                  new ExtrinsicFailedError(`Extrinsic execution error: ${this.formatDispatchError(dispatchError)}`)
+                )
+              } else if (event.method === 'ExtrinsicSuccess') {
+                if (txName === 'sudo.sudo') {
+                  const sudidEvent = this.getEvent(result, 'sudo', 'Sudid')
+                  const [dispatchResult] = sudidEvent.data
+                  if (dispatchResult.isErr) {
+                    return reject(
+                      new ExtrinsicFailedError(
+                        `Sudo extrinsic execution error! ${this.formatDispatchError(dispatchResult.asErr)}`
+                      )
+                    )
+                  }
+                }
+
+                if (txName === 'sudo.sudoAs') {
+                  const sudoAsDoneEvent = this.getEvent(result, 'sudo', 'SudoAsDone')
+                  const [sudoAsDone] = sudoAsDoneEvent.data
+                  if (sudoAsDone.isFalse) {
+                    return reject(new ExtrinsicFailedError(`SudoAs failed!`))
+                  }
+                }
+
+                resolve(result)
+              }
+            })
+        } else if (result.isError) {
+          reject(new ExtrinsicFailedError('Extrinsic execution error!'))
+        }
+      })
+        .then((unsubFunc) => (unsubscribe = unsubFunc))
+        .catch((e) =>
+          reject(new ExtrinsicFailedError(`Cannot send the extrinsic: ${e.message ? e.message : JSON.stringify(e)}`))
+        )
+    })
+  }
+}

+ 73 - 0
utils/migration-scripts/src/commands/sumer-giza/migrateContent.ts

@@ -0,0 +1,73 @@
+import { Command, flags } from '@oclif/command'
+import path from 'path'
+import os from 'os'
+import { ContentMigration } from '../../sumer-giza/ContentMigration'
+
+export class MigrateContentCommand extends Command {
+  static flags = {
+    queryNodeUri: flags.string({
+      description: 'Query node uri',
+      default: 'https://hydra.joystream.org/graphql',
+    }),
+    wsProviderEndpointUri: flags.string({
+      description: 'WS provider endpoint uri (Giza)',
+      default: 'ws://localhost:9944',
+    }),
+    sudoUri: flags.string({
+      description: 'Sudo key Substrate uri',
+      default: '//Alice',
+    }),
+    channelIds: flags.integer({
+      char: 'c',
+      multiple: true,
+      description: 'Channel ids to migrate',
+      required: true,
+    }),
+    dataDir: flags.string({
+      description: 'Directory for storing data objects to upload',
+      default: path.join(os.tmpdir(), 'joystream/sumer-giza-migration'),
+    }),
+    channelBatchSize: flags.integer({
+      description: 'Channel batch size',
+      default: 20,
+    }),
+    videoBatchSize: flags.integer({
+      description: 'Video batch size',
+      default: 20,
+    }),
+    forceChannelOwnerMemberId: flags.integer({
+      description:
+        'Can be used to force a specific channel owner for all channels, allowing to easily test the script in dev environment',
+      required: false,
+    }),
+    preferredDownloadSpEndpoints: flags.string({
+      multiple: true,
+      description: 'Preferred storage node endpoints when downloading data objects',
+      default: ['https://storage-1.joystream.org/storage'],
+    }),
+    uploadSpEndpoint: flags.string({
+      description: 'Giza storage node endpoint to use for uploading',
+      default: 'http://localhost:3333',
+    }),
+    uploadSpBucketId: flags.integer({
+      description: 'Giza storage bucket id',
+      default: 0,
+    }),
+    migrationStatePath: flags.string({
+      description: 'Path to migration results directory',
+      default: path.join(__dirname, '../../../results/sumer-giza'),
+    }),
+  }
+
+  async run(): Promise<void> {
+    const opts = this.parse(MigrateContentCommand).flags
+    try {
+      const migration = new ContentMigration(opts)
+      await migration.run()
+    } catch (e) {
+      console.error(e)
+      this.exit(-1)
+    }
+    this.exit(0)
+  }
+}

+ 51 - 0
utils/migration-scripts/src/commands/sumer-giza/retryFailedUploads.ts

@@ -0,0 +1,51 @@
+import { Command, flags } from '@oclif/command'
+import path from 'path'
+import os from 'os'
+import { WsProvider } from '@polkadot/rpc-provider'
+import { RuntimeApi } from '../../RuntimeApi'
+import { AssetsManager } from '../../sumer-giza/AssetsManager'
+
+export class RetryFailedUploadsCommand extends Command {
+  static flags = {
+    wsProviderEndpointUri: flags.string({
+      description: 'WS provider endpoint uri (Giza)',
+      default: 'ws://localhost:9944',
+    }),
+    dataDir: flags.string({
+      description: 'Directory where data objects to upload are stored',
+      default: path.join(os.tmpdir(), 'joystream/sumer-giza-migration'),
+    }),
+    uploadSpEndpoint: flags.string({
+      description: 'Giza storage node endpoint to use for uploading',
+      default: 'http://localhost:3333',
+    }),
+    uploadSpBucketId: flags.integer({
+      description: 'Giza storage bucket id',
+      default: 0,
+    }),
+    failedUploadsPath: flags.string({
+      char: 'f',
+      description: 'Path to failed uploads file',
+      required: true,
+    }),
+  }
+
+  async run(): Promise<void> {
+    const opts = this.parse(RetryFailedUploadsCommand).flags
+    try {
+      const provider = new WsProvider(opts.wsProviderEndpointUri)
+      const api = new RuntimeApi({ provider })
+      await api.isReadyOrError
+      const assetsManager = await AssetsManager.create({
+        api,
+        config: opts,
+      })
+      assetsManager.loadQueue(opts.failedUploadsPath)
+      await assetsManager.processQueuedUploads()
+    } catch (e) {
+      console.error(e)
+      this.exit(-1)
+    }
+    this.exit(0)
+  }
+}

+ 1 - 0
utils/migration-scripts/src/index.ts

@@ -0,0 +1 @@
+export { run } from '@oclif/command'

+ 308 - 0
utils/migration-scripts/src/sumer-giza/AssetsManager.ts

@@ -0,0 +1,308 @@
+import { DataObjectFieldsFragment } from './sumer-query-node/generated/queries'
+import BN from 'bn.js'
+import urljoin from 'url-join'
+import axios from 'axios'
+import fs from 'fs'
+import path from 'path'
+import { BagId, DataObjectCreationParameters, DataObjectId, UploadParameters } from '@joystream/types/storage'
+import { IEvent } from '@polkadot/types/types'
+import { Vec } from '@polkadot/types'
+import { Balance } from '@polkadot/types/interfaces'
+import FormData from 'form-data'
+import { ImageResizer } from './ImageResizer'
+import { QueryNodeApi } from './sumer-query-node/api'
+import { RuntimeApi } from '../RuntimeApi'
+import { ContentHash } from './ContentHash'
+import { promisify } from 'util'
+import { createType } from '@joystream/types'
+import { Readable, pipeline } from 'stream'
+import _ from 'lodash'
+
+export type AssetsManagerConfig = {
+  preferredDownloadSpEndpoints?: string[]
+  uploadSpBucketId: number
+  uploadSpEndpoint: string
+  dataDir: string
+}
+
+export type AssetsManagerParams = {
+  api: RuntimeApi
+  queryNodeApi?: QueryNodeApi
+  config: AssetsManagerConfig
+}
+
+export type AssetsManagerLoadableParams = {
+  dataObjectFeePerMB: BN
+  sumerStorageProviderEndpoints: string[]
+}
+
+export type AssetsToPrepare = {
+  [name: string]: {
+    data?: DataObjectFieldsFragment
+    targetSize?: [number, number]
+  }
+}
+
+export type PreparedAsset = {
+  params: DataObjectCreationParameters
+  index: number
+}
+
+export class AssetsManager {
+  private api: RuntimeApi
+  private config: AssetsManagerConfig
+  public readonly dataObjectFeePerMB: BN
+  private sumerStorageProviderEndpoints: string[]
+  private resizer: ImageResizer
+  private queuedUploads: Set<string>
+  private isQueueProcessing = false
+
+  public get queueSize(): number {
+    return this.queuedUploads.size
+  }
+
+  public static async create(params: AssetsManagerParams): Promise<AssetsManager> {
+    const { api } = params
+    const dataObjectFeePerMB = await api.query.storage.dataObjectPerMegabyteFee()
+    const sumerStorageProviderEndpoints = params.queryNodeApi
+      ? await AssetsManager.getSumerStorageProviderEndpoints(params.queryNodeApi)
+      : []
+    return new AssetsManager(params, { dataObjectFeePerMB, sumerStorageProviderEndpoints })
+  }
+
+  private constructor(params: AssetsManagerParams, loadableParams: AssetsManagerLoadableParams) {
+    const { api, config } = params
+    const { dataObjectFeePerMB, sumerStorageProviderEndpoints } = loadableParams
+    this.dataObjectFeePerMB = dataObjectFeePerMB
+    this.sumerStorageProviderEndpoints = sumerStorageProviderEndpoints
+    this.api = api
+    this.config = config
+    this.resizer = new ImageResizer()
+    this.queuedUploads = new Set()
+    fs.mkdirSync(this.tmpAssetPath(''), { recursive: true })
+    fs.mkdirSync(this.assetPath(''), { recursive: true })
+  }
+
+  private static async getSumerStorageProviderEndpoints(queryNodeApi: QueryNodeApi): Promise<string[]> {
+    const endpoints: string[] = []
+    const workers = await queryNodeApi.getStorageWorkers()
+    workers.forEach((w) => w.metadata && endpoints.push(w.metadata))
+    return endpoints
+  }
+
+  private tmpAssetPath(contentId: string): string {
+    return path.join(this.config.dataDir, 'tmp', contentId)
+  }
+
+  private assetPath(contentHash: string): string {
+    return path.join(this.config.dataDir, contentHash)
+  }
+
+  public calcDataObjectsFee(params: DataObjectCreationParameters[]): BN {
+    const { dataObjectFeePerMB, api } = this
+    const deletionPrize = api.consts.storage.dataObjectDeletionPrize
+    const totalSize = params
+      .reduce((a, b) => {
+        return a.add(b.getField('size'))
+      }, new BN(0))
+      .toNumber()
+    const totalStorageFee = dataObjectFeePerMB.muln(Math.ceil(totalSize / 1024 / 1024))
+    const totalDeletionPrize = deletionPrize.muln(params.length)
+    return totalStorageFee.add(totalDeletionPrize)
+  }
+
+  private async prepareAsset(
+    data: DataObjectFieldsFragment,
+    targetSize?: [number, number]
+  ): Promise<DataObjectCreationParameters | undefined> {
+    if (data.liaisonJudgement !== 'ACCEPTED') {
+      console.error(
+        `Data object ${data.joystreamContentId} has invalid liason judgement: ${data.liaisonJudgement}. Skipping...`
+      )
+      return
+    }
+    let objectSize = new BN(data.size).toNumber()
+    let path: string
+    try {
+      path = await this.fetchAssetWithRetry(data.joystreamContentId, objectSize)
+    } catch (e) {
+      console.error(`Data object ${data.joystreamContentId} was not fetched: ${(e as Error).message}`)
+      return
+    }
+    if (targetSize) {
+      try {
+        await this.resizer.resize(path, targetSize)
+        // Re-estabilish object size
+        objectSize = fs.statSync(path).size
+      } catch (e) {
+        console.error(
+          `Could not resize image ${path} to target size ${targetSize[0]}/${targetSize[1]}: ${(e as Error).message}`
+        )
+      }
+    }
+    const hash = await this.calcContentHash(path)
+    // Move asset to final path
+    fs.renameSync(path, this.assetPath(hash))
+    return createType<DataObjectCreationParameters, 'DataObjectCreationParameters'>('DataObjectCreationParameters', {
+      ipfsContentId: hash,
+      size: objectSize,
+    })
+  }
+
+  public async prepareAssets<T extends AssetsToPrepare>(
+    assetsToPrepare: T
+  ): Promise<{ [K in keyof T]?: PreparedAsset }> {
+    const preparedAssets: { [K in keyof T]?: PreparedAsset } = {}
+    let assetIndex = 0
+    await Promise.all(
+      Object.entries(assetsToPrepare).map(async ([assetName, { data, targetSize }]) => {
+        if (!data) {
+          return
+        }
+        const params = await this.prepareAsset(data, targetSize)
+        if (!params) {
+          return
+        }
+        preparedAssets[assetName as keyof T] = { params, index: assetIndex++ }
+      })
+    )
+    return preparedAssets
+  }
+
+  private calcContentHash(assetPath: string): Promise<string> {
+    return new Promise<string>((resolve, reject) => {
+      const fReadStream = fs.createReadStream(assetPath)
+      const hash = new ContentHash()
+      fReadStream.on('data', (chunk) => hash.update(chunk))
+      fReadStream.on('end', () => resolve(hash.digest()))
+      fReadStream.on('error', (err) => reject(err))
+    })
+  }
+
+  private async fetchAsset(endpoint: string, contentId: string, expectedSize: number): Promise<string> {
+    const assetEndpoint = urljoin(endpoint, `asset/v0/${contentId}`)
+    const response = await axios.get<Readable>(assetEndpoint, { responseType: 'stream', timeout: 5000 })
+    const pipe = promisify(pipeline)
+    const destPath = this.tmpAssetPath(contentId)
+    const fWriteStream = fs.createWriteStream(destPath)
+    await pipe(response.data, fWriteStream)
+    const { size } = fs.statSync(destPath)
+    if (size !== expectedSize) {
+      throw new Error('Invalid file size')
+    }
+    return destPath
+  }
+
+  private async fetchAssetWithRetry(contentId: string, expectedSize: number): Promise<string> {
+    const preferredDownloadSpEndpoints = this.config.preferredDownloadSpEndpoints || []
+    const alternativeEndpoints = _.difference(this.sumerStorageProviderEndpoints, preferredDownloadSpEndpoints)
+    const endpoints = _.shuffle(preferredDownloadSpEndpoints).concat(_.shuffle(alternativeEndpoints))
+    let lastError: Error | undefined
+    for (const endpoint of endpoints) {
+      try {
+        const tmpAssetPath = await this.fetchAsset(endpoint, contentId, expectedSize)
+        return tmpAssetPath
+      } catch (e) {
+        lastError = e as Error
+        continue
+      }
+    }
+    throw new Error(
+      `Could not fetch asset ${contentId} from any provider. Last error: ${
+        lastError && this.reqErrorMessage(lastError)
+      }`
+    )
+  }
+
+  private reqErrorMessage(e: unknown): string {
+    if (axios.isAxiosError(e)) {
+      return e.response ? JSON.stringify(e.response.data) : e.message
+    }
+    return e instanceof Error ? e.message : JSON.stringify(e)
+  }
+
+  private async uploadDataObject(bagId: string, dataObjectId: number): Promise<void> {
+    const {
+      config: { uploadSpBucketId, uploadSpEndpoint },
+    } = this
+    const dataObject = await this.api.query.storage.dataObjectsById(
+      { Dynamic: { Channel: bagId.split(':')[2] } },
+      dataObjectId
+    )
+    const dataPath = this.assetPath(Buffer.from(dataObject.ipfsContentId.toHex().replace('0x', ''), 'hex').toString())
+    if (!fs.existsSync(dataPath)) {
+      throw new Error(`Cannot upload object: ${dataObjectId}: ${dataPath} not found`)
+    }
+
+    const fileStream = fs.createReadStream(dataPath)
+    const formData = new FormData()
+    formData.append('dataObjectId', dataObjectId)
+    formData.append('storageBucketId', uploadSpBucketId)
+    formData.append('bagId', bagId)
+    formData.append('file', fileStream, { filename: path.basename(dataPath) })
+    let uploadSuccesful: boolean
+    try {
+      await axios({
+        method: 'POST',
+        url: urljoin(uploadSpEndpoint, 'api/v1/files'),
+        data: formData,
+        maxBodyLength: Infinity,
+        headers: {
+          'content-type': 'multipart/form-data',
+          ...formData.getHeaders(),
+        },
+      })
+      uploadSuccesful = true
+    } catch (e) {
+      uploadSuccesful = false
+      const msg = this.reqErrorMessage(e)
+      console.error(`Upload of object ${dataObjectId} to ${uploadSpEndpoint} failed: ${msg}`)
+    }
+
+    if (uploadSuccesful) {
+      // Remove asset from queuedUploads and temporary storage
+      this.queuedUploads.delete(`${bagId}|${dataObjectId}`)
+      try {
+        fs.rmSync(dataPath)
+      } catch (e) {
+        console.error(`Could not remove file "${dataPath}" after succesful upload...`)
+      }
+    }
+  }
+
+  public async processQueuedUploads(): Promise<void> {
+    if (this.isQueueProcessing) {
+      throw new Error('Uploads queue is already beeing processed!')
+    }
+    this.isQueueProcessing = true
+    console.log(`Uploading ${this.queueSize} data objects...`)
+    await Promise.all(
+      Array.from(this.queuedUploads).map((queuedUpload) => {
+        const [bagId, objectId] = queuedUpload.split('|')
+        return this.uploadDataObject(bagId, parseInt(objectId))
+      })
+    )
+    this.isQueueProcessing = false
+  }
+
+  public loadQueue(queueFilePath: string): void {
+    const queue: string[] = JSON.parse(fs.readFileSync(queueFilePath).toString())
+    this.queuedUploads = new Set(queue)
+  }
+
+  public saveQueue(queueFilePath: string): void {
+    fs.writeFileSync(queueFilePath, JSON.stringify(Array.from(this.queuedUploads)))
+  }
+
+  private queueUpload(bagId: BagId, objectId: DataObjectId): void {
+    const bagIdStr = `dynamic:channel:${bagId.asType('Dynamic').asType('Channel').toString()}`
+    this.queuedUploads.add(`${bagIdStr}|${objectId.toString()}`)
+  }
+
+  public async uploadFromEvents(events: IEvent<[Vec<DataObjectId>, UploadParameters, Balance]>[]): Promise<void> {
+    events.map(({ data: [objectIds, uploadParams] }) => {
+      objectIds.forEach((objectId) => this.queueUpload(uploadParams.bagId, objectId))
+    })
+    await this.processQueuedUploads()
+  }
+}

+ 40 - 0
utils/migration-scripts/src/sumer-giza/AssetsMigration.ts

@@ -0,0 +1,40 @@
+import { BaseMigration, BaseMigrationConfig, BaseMigrationParams, MigrationResult } from './BaseMigration'
+import { AssetsManager, AssetsManagerConfig } from './AssetsManager'
+
+export type AssetsMigrationConfig = BaseMigrationConfig & AssetsManagerConfig
+
+export type AssetsMigrationParams = BaseMigrationParams & {
+  config: AssetsMigrationConfig
+}
+
+export abstract class AssetsMigration extends BaseMigration {
+  protected config: AssetsMigrationConfig
+  protected assetsManager!: AssetsManager
+
+  public constructor({ api, queryNodeApi, config }: AssetsMigrationParams) {
+    super({ api, queryNodeApi, config })
+    this.config = config
+  }
+
+  public async init(): Promise<void> {
+    await super.init()
+    this.assetsManager = await AssetsManager.create({
+      api: this.api,
+      queryNodeApi: this.queryNodeApi,
+      config: this.config,
+    })
+  }
+
+  public abstract run(): Promise<MigrationResult>
+
+  protected saveMigrationState(): void {
+    super.saveMigrationState()
+    if (this.assetsManager.queueSize) {
+      const failedUploadsFilePath = this.getMigrationStateFilePath().replace(
+        '.json',
+        `FailedUploads_${Date.now()}.json`
+      )
+      this.assetsManager.saveQueue(failedUploadsFilePath)
+    }
+  }
+}

+ 121 - 0
utils/migration-scripts/src/sumer-giza/BaseMigration.ts

@@ -0,0 +1,121 @@
+import { SubmittableResult } from '@polkadot/api'
+import { KeyringPair } from '@polkadot/keyring/types'
+import { QueryNodeApi } from './sumer-query-node/api'
+import { RuntimeApi } from '../RuntimeApi'
+import { Keyring } from '@polkadot/keyring'
+import path from 'path'
+import nodeCleanup from 'node-cleanup'
+import _ from 'lodash'
+import fs from 'fs'
+
+export type MigrationResult = {
+  idsMap: Map<number, number>
+  failedMigrations: number[]
+}
+
+export type MigrationStateJson = {
+  idsMapEntries: [number, number][]
+  failedMigrations: number[]
+}
+
+export type BaseMigrationConfig = {
+  migrationStatePath: string
+  sudoUri: string
+}
+
+export type BaseMigrationParams = {
+  api: RuntimeApi
+  queryNodeApi: QueryNodeApi
+  config: BaseMigrationConfig
+}
+
+export abstract class BaseMigration {
+  abstract readonly name: string
+  protected api: RuntimeApi
+  protected queryNodeApi: QueryNodeApi
+  protected sudo!: KeyringPair
+  protected config: BaseMigrationConfig
+  protected failedMigrations: Set<number>
+  protected idsMap: Map<number, number>
+
+  public constructor({ api, queryNodeApi, config }: BaseMigrationParams) {
+    this.api = api
+    this.queryNodeApi = queryNodeApi
+    this.config = config
+    this.failedMigrations = new Set()
+    this.idsMap = new Map()
+    fs.mkdirSync(config.migrationStatePath, { recursive: true })
+  }
+
+  protected getMigrationStateFilePath(): string {
+    const { migrationStatePath } = this.config
+    return path.join(migrationStatePath, `${_.camelCase(this.name)}.json`)
+  }
+
+  public async init(): Promise<void> {
+    this.loadMigrationState()
+    nodeCleanup(() => this.saveMigrationState())
+    await this.loadSudoKey()
+  }
+
+  public abstract run(): Promise<MigrationResult>
+
+  protected getMigrationStateJson(): MigrationStateJson {
+    return {
+      idsMapEntries: Array.from(this.idsMap.entries()),
+      failedMigrations: Array.from(this.failedMigrations),
+    }
+  }
+
+  protected loadMigrationState(): void {
+    const stateFilePath = this.getMigrationStateFilePath()
+    if (fs.existsSync(stateFilePath)) {
+      const migrationStateJson = fs.readFileSync(stateFilePath).toString()
+      const migrationState: MigrationStateJson = JSON.parse(migrationStateJson)
+      this.idsMap = new Map(migrationState.idsMapEntries)
+    }
+  }
+
+  protected saveMigrationState(): void {
+    const stateFilePath = this.getMigrationStateFilePath()
+    const migrationState = this.getMigrationStateJson()
+    fs.writeFileSync(stateFilePath, JSON.stringify(migrationState, undefined, 2))
+  }
+
+  private async loadSudoKey() {
+    const { sudoUri } = this.config
+    const keyring = new Keyring({ type: 'sr25519' })
+    this.sudo = keyring.createFromUri(sudoUri)
+    const sudoKey = await this.api.query.sudo.key()
+    if (sudoKey.toString() !== this.sudo.address) {
+      throw new Error(`Invalid sudo key! Expected: ${sudoKey.toString()}, Got: ${this.sudo.address}`)
+    }
+  }
+
+  protected extractFailedSudoAsMigrations<T extends { id: string }>(result: SubmittableResult, batch: T[]): void {
+    const { api } = this
+    const sudoAsDoneEvents = api.findEvents(result, 'sudo', 'SudoAsDone')
+    if (sudoAsDoneEvents.length !== batch.length) {
+      throw new Error(`Could not extract failed migrations from: ${JSON.stringify(result.toHuman())}`)
+    }
+    const failedIds: number[] = []
+    sudoAsDoneEvents.forEach(({ data: [sudoAsDone] }, i) => {
+      if (sudoAsDone.isFalse) {
+        const id = parseInt(batch[i].id)
+        failedIds.push(id)
+        this.failedMigrations.add(id)
+      }
+    })
+    if (failedIds.length) {
+      console.error(`Failed to migrate:`, failedIds)
+    }
+  }
+
+  public getResult(): MigrationResult {
+    const { idsMap, failedMigrations } = this
+    return {
+      idsMap: new Map(idsMap.entries()),
+      failedMigrations: Array.from(failedMigrations),
+    }
+  }
+}

+ 162 - 0
utils/migration-scripts/src/sumer-giza/ChannelsMigration.ts

@@ -0,0 +1,162 @@
+import { AssetsMigration, AssetsMigrationConfig, AssetsMigrationParams } from './AssetsMigration'
+import { ChannelMetadata } from '@joystream/metadata-protobuf'
+import { ChannelFieldsFragment } from './sumer-query-node/generated/queries'
+import { createType } from '@joystream/types'
+import Long from 'long'
+import { ChannelCreationParameters } from '@joystream/types/content'
+import { CHANNEL_AVATAR_TARGET_SIZE, CHANNEL_COVER_TARGET_SIZE } from './ImageResizer'
+import { ChannelId } from '@joystream/types/common'
+import _ from 'lodash'
+import { MigrationResult } from './BaseMigration'
+
+export type ChannelsMigrationConfig = AssetsMigrationConfig & {
+  channelIds: number[]
+  channelBatchSize: number
+  forceChannelOwnerMemberId: number | undefined
+}
+
+export type ChannelsMigrationParams = AssetsMigrationParams & {
+  config: ChannelsMigrationConfig
+  forcedChannelOwner: { id: string; controllerAccount: string } | undefined
+}
+
+export type ChannelsMigrationResult = MigrationResult & {
+  videoIds: number[]
+}
+
+export class ChannelMigration extends AssetsMigration {
+  name = 'Channels migration'
+  protected config: ChannelsMigrationConfig
+  protected videoIds: number[] = []
+  protected forcedChannelOwner: { id: string; controllerAccount: string } | undefined
+
+  public constructor(params: ChannelsMigrationParams) {
+    super(params)
+    this.config = params.config
+    this.forcedChannelOwner = params.forcedChannelOwner
+  }
+
+  private getChannelOwnerMember({ id, ownerMember }: ChannelFieldsFragment) {
+    if (!ownerMember) {
+      throw new Error(`Chanel ownerMember missing: ${id}. Only member-owned channels are supported!`)
+    }
+
+    if (this.forcedChannelOwner) {
+      return this.forcedChannelOwner
+    }
+
+    return ownerMember
+  }
+
+  public async run(): Promise<ChannelsMigrationResult> {
+    await this.init()
+    const {
+      api,
+      config: { channelIds, channelBatchSize },
+    } = this
+    const ids = channelIds.sort((a, b) => a - b)
+    while (ids.length) {
+      const idsBatch = ids.splice(0, channelBatchSize)
+      console.log(`Fetching a batch of ${idsBatch.length} channels...`)
+      const channelsBatch = (await this.queryNodeApi.getChannelsByIds(idsBatch)).sort(
+        (a, b) => parseInt(a.id) - parseInt(b.id)
+      )
+      if (channelsBatch.length < idsBatch.length) {
+        console.error(
+          `Some channels were not be found: ${_.difference(
+            idsBatch,
+            channelsBatch.map((c) => parseInt(c.id))
+          )}`
+        )
+      }
+      const channelsToMigrate = channelsBatch.filter((c) => !this.idsMap.has(parseInt(c.id)))
+      if (channelsToMigrate.length < channelsBatch.length) {
+        console.log(
+          `${channelsToMigrate.length ? 'Some' : 'All'} channels in this batch were already migrated ` +
+            `(${channelsBatch.length - channelsToMigrate.length}/${channelsBatch.length})`
+        )
+      }
+      if (channelsToMigrate.length) {
+        const txs = _.flatten(await Promise.all(channelsToMigrate.map((c) => this.prepareChannel(c))))
+        const result = await api.sendExtrinsic(this.sudo, api.tx.utility.batch(txs))
+        const channelCreatedEvents = api.findEvents(result, 'content', 'ChannelCreated')
+        const newChannelIds: ChannelId[] = channelCreatedEvents.map((e) => e.data[1])
+        if (channelCreatedEvents.length !== channelsToMigrate.length) {
+          this.extractFailedSudoAsMigrations(result, channelsToMigrate)
+        }
+        const dataObjectsUploadedEvents = api.findEvents(result, 'storage', 'DataObjectsUploaded')
+        const newChannelMapEntries: [number, number][] = []
+        let newChannelIdIndex = 0
+        channelsToMigrate.forEach(({ id }) => {
+          if (this.failedMigrations.has(parseInt(id))) {
+            return
+          }
+          const newChannelId = newChannelIds[newChannelIdIndex++].toNumber()
+          this.idsMap.set(parseInt(id), newChannelId)
+          newChannelMapEntries.push([parseInt(id), newChannelId])
+        })
+        if (newChannelMapEntries.length) {
+          console.log('Channel map entries added!', newChannelMapEntries)
+          await this.assetsManager.uploadFromEvents(dataObjectsUploadedEvents)
+        }
+      }
+      const videoIdsToMigrate: number[] = channelsBatch.reduce<number[]>(
+        (res, { id, videos }) => (this.idsMap.has(parseInt(id)) ? res.concat(videos.map((v) => parseInt(v.id))) : res),
+        []
+      )
+      this.videoIds = this.videoIds.concat(videoIdsToMigrate)
+      if (videoIdsToMigrate.length) {
+        console.log(`Added ${videoIdsToMigrate.length} video ids to the list of videos to migrate`)
+      }
+    }
+    return {
+      ...this.getResult(),
+      videoIds: [...this.videoIds],
+    }
+  }
+
+  private async prepareChannel(channel: ChannelFieldsFragment) {
+    const { api } = this
+    const { avatarPhotoDataObject, coverPhotoDataObject, title, description, categoryId, isPublic, language } = channel
+
+    const ownerMember = this.getChannelOwnerMember(channel)
+
+    const assetsToPrepare = {
+      avatar: { data: avatarPhotoDataObject || undefined, targetSize: CHANNEL_AVATAR_TARGET_SIZE },
+      coverPhoto: { data: coverPhotoDataObject || undefined, targetSize: CHANNEL_COVER_TARGET_SIZE },
+    }
+    const preparedAssets = await this.assetsManager.prepareAssets(assetsToPrepare)
+    const meta = new ChannelMetadata({
+      title,
+      description,
+      category: categoryId ? Long.fromString(categoryId) : undefined,
+      avatarPhoto: preparedAssets.avatar?.index,
+      coverPhoto: preparedAssets.coverPhoto?.index,
+      isPublic,
+      language: language?.iso,
+    })
+    const assetsParams = Object.values(preparedAssets)
+      .sort((a, b) => a.index - b.index)
+      .map((a) => a.params)
+    const channelCreationParams = createType<ChannelCreationParameters, 'ChannelCreationParameters'>(
+      'ChannelCreationParameters',
+      {
+        assets: assetsParams.length
+          ? {
+              object_creation_list: assetsParams,
+              expected_data_size_fee: this.assetsManager.dataObjectFeePerMB,
+            }
+          : null,
+        meta: `0x${Buffer.from(ChannelMetadata.encode(meta).finish()).toString('hex')}`,
+      }
+    )
+    const feesToCover = this.assetsManager.calcDataObjectsFee(assetsParams)
+    return [
+      api.tx.balances.transferKeepAlive(ownerMember.controllerAccount, feesToCover),
+      api.tx.sudo.sudoAs(
+        ownerMember.controllerAccount,
+        api.tx.content.createChannel({ Member: ownerMember.id }, channelCreationParams)
+      ),
+    ]
+  }
+}

+ 22 - 0
utils/migration-scripts/src/sumer-giza/ContentHash.ts

@@ -0,0 +1,22 @@
+import { createHash, HashInput, NodeHash } from 'blake3'
+import { HashReader } from 'blake3/dist/wasm/nodejs'
+import { toB58String, encode } from 'multihashes'
+
+// Based on distributor node's implementation
+export class ContentHash {
+  private hash: NodeHash<HashReader>
+  public static readonly algorithm = 'blake3'
+
+  constructor() {
+    this.hash = createHash()
+  }
+
+  update(data: HashInput): this {
+    this.hash.update(data)
+    return this
+  }
+
+  digest(): string {
+    return toB58String(encode(this.hash.digest(), ContentHash.algorithm))
+  }
+}

+ 69 - 0
utils/migration-scripts/src/sumer-giza/ContentMigration.ts

@@ -0,0 +1,69 @@
+import { WsProvider } from '@polkadot/api'
+import { QueryNodeApi } from './sumer-query-node/api'
+import { RuntimeApi } from '../RuntimeApi'
+import { VideosMigration } from './VideosMigration'
+import { ChannelMigration } from './ChannelsMigration'
+
+export type ContentMigrationConfig = {
+  queryNodeUri: string
+  wsProviderEndpointUri: string
+  sudoUri: string
+  channelIds: number[]
+  dataDir: string
+  channelBatchSize: number
+  videoBatchSize: number
+  forceChannelOwnerMemberId: number | undefined
+  preferredDownloadSpEndpoints?: string[]
+  uploadSpBucketId: number
+  uploadSpEndpoint: string
+  migrationStatePath: string
+}
+
+export class ContentMigration {
+  private api: RuntimeApi
+  private queryNodeApi: QueryNodeApi
+  private config: ContentMigrationConfig
+
+  constructor(config: ContentMigrationConfig) {
+    const { queryNodeUri, wsProviderEndpointUri } = config
+    const provider = new WsProvider(wsProviderEndpointUri)
+    this.api = new RuntimeApi({ provider })
+    this.queryNodeApi = new QueryNodeApi(queryNodeUri)
+    this.config = config
+  }
+
+  private async getForcedChannelOwner(): Promise<{ id: string; controllerAccount: string } | undefined> {
+    const { forceChannelOwnerMemberId } = this.config
+    if (forceChannelOwnerMemberId) {
+      const ownerMember = await this.api.query.members.membershipById(forceChannelOwnerMemberId)
+      if (ownerMember.isEmpty) {
+        throw new Error(`Membership by id ${forceChannelOwnerMemberId} not found!`)
+      }
+      return {
+        id: forceChannelOwnerMemberId.toString(),
+        controllerAccount: ownerMember.controller_account.toString(),
+      }
+    }
+    return undefined
+  }
+
+  public async run(): Promise<void> {
+    const { api, queryNodeApi, config } = this
+    await this.api.isReadyOrError
+    const forcedChannelOwner = await this.getForcedChannelOwner()
+    const { idsMap: channelsMap, videoIds } = await new ChannelMigration({
+      api,
+      queryNodeApi,
+      config,
+      forcedChannelOwner,
+    }).run()
+    await new VideosMigration({
+      api,
+      queryNodeApi,
+      config,
+      channelsMap,
+      videoIds,
+      forcedChannelOwner,
+    }).run()
+  }
+}

+ 30 - 0
utils/migration-scripts/src/sumer-giza/ImageResizer.ts

@@ -0,0 +1,30 @@
+import sharp from 'sharp'
+import fs from 'fs'
+
+export const CHANNEL_AVATAR_TARGET_SIZE: [number, number] = [256, 256]
+export const VIDEO_THUMB_TARGET_SIZE: [number, number] = [640, 360]
+export const CHANNEL_COVER_TARGET_SIZE: [number, number] = [1920, 480]
+
+export class ImageResizer {
+  resize(imagePath: string, target: [number, number]): Promise<void> {
+    return new Promise((resolve, reject) => {
+      const [width, height] = target
+      const targetPath = `${imagePath}-resized`
+      sharp(imagePath)
+        .resize({
+          width,
+          height,
+          fit: 'outside',
+        })
+        .extract({ left: 0, top: 0, width, height })
+        .webp()
+        .toFile(targetPath, (err) => {
+          if (err) {
+            return reject(err)
+          }
+          fs.renameSync(targetPath, imagePath)
+          resolve()
+        })
+    })
+  }
+}

+ 192 - 0
utils/migration-scripts/src/sumer-giza/VideosMigration.ts

@@ -0,0 +1,192 @@
+import { VideoMetadata } from '@joystream/metadata-protobuf'
+import { VideoFieldsFragment } from './sumer-query-node/generated/queries'
+import _ from 'lodash'
+import { createType } from '@joystream/types'
+import Long from 'long'
+import { VideoCreationParameters, VideoId } from '@joystream/types/content'
+import moment from 'moment'
+import { VIDEO_THUMB_TARGET_SIZE } from './ImageResizer'
+import { AssetsMigration, AssetsMigrationConfig, AssetsMigrationParams } from './AssetsMigration'
+import { MigrationResult } from './BaseMigration'
+
+export type VideosMigrationConfig = AssetsMigrationConfig & {
+  videoBatchSize: number
+}
+
+export type VideosMigrationParams = AssetsMigrationParams & {
+  config: VideosMigrationConfig
+  videoIds: number[]
+  channelsMap: Map<number, number>
+  forcedChannelOwner: { id: string; controllerAccount: string } | undefined
+}
+
+export class VideosMigration extends AssetsMigration {
+  name = 'Videos migration'
+  protected config: VideosMigrationConfig
+  protected channelsMap: Map<number, number>
+  protected videoIds: number[]
+  protected forcedChannelOwner: { id: string; controllerAccount: string } | undefined
+
+  public constructor({ api, queryNodeApi, config, videoIds, channelsMap, forcedChannelOwner }: VideosMigrationParams) {
+    super({ api, queryNodeApi, config })
+    this.config = config
+    this.channelsMap = channelsMap
+    this.videoIds = videoIds
+    this.forcedChannelOwner = forcedChannelOwner
+  }
+
+  private getNewChannelId(oldChannelId: number): number {
+    const newChannelId = this.channelsMap.get(oldChannelId)
+    if (!newChannelId) {
+      throw new Error(`Missing new channel id for channel ${oldChannelId} in the channelMap!`)
+    }
+    return newChannelId
+  }
+
+  public async run(): Promise<MigrationResult> {
+    await this.init()
+    const {
+      api,
+      videoIds,
+      config: { videoBatchSize },
+    } = this
+    const idsToMigrate = videoIds.filter((id) => !this.idsMap.has(id)).sort((a, b) => a - b)
+    if (idsToMigrate.length < videoIds.length) {
+      const alreadyMigratedVideosNum = videoIds.length - idsToMigrate.length
+      console.log(
+        (idsToMigrate.length ? `${alreadyMigratedVideosNum}/${videoIds.length}` : 'All') +
+          ' videos already migrated, skippping...'
+      )
+    }
+    while (idsToMigrate.length) {
+      const idsBatch = idsToMigrate.splice(0, videoBatchSize)
+      console.log(`Fetching a batch of ${idsBatch.length} videos...`)
+      const videosBatch = (await this.queryNodeApi.getVideosByIds(idsBatch)).sort(
+        (a, b) => parseInt(a.id) - parseInt(b.id)
+      )
+      if (videosBatch.length < idsBatch.length) {
+        console.error(
+          `Some videos were not be found: ${_.difference(
+            idsBatch,
+            videosBatch.map((v) => parseInt(v.id))
+          )}`
+        )
+      }
+      const txs = _.flatten(await Promise.all(videosBatch.map((v) => this.prepareVideo(v))))
+      const result = await api.sendExtrinsic(this.sudo, api.tx.utility.batch(txs))
+      const videoCreatedEvents = api.findEvents(result, 'content', 'VideoCreated')
+      const newVideoIds: VideoId[] = videoCreatedEvents.map((e) => e.data[2])
+      if (videoCreatedEvents.length !== videosBatch.length) {
+        this.extractFailedSudoAsMigrations(result, videosBatch)
+      }
+
+      const dataObjectsUploadedEvents = api.findEvents(result, 'storage', 'DataObjectsUploaded')
+      const newVideoMapEntries: [number, number][] = []
+      let newVideoIdIndex = 0
+      videosBatch.forEach(({ id }) => {
+        if (this.failedMigrations.has(parseInt(id))) {
+          return
+        }
+        const newVideoId = newVideoIds[newVideoIdIndex++].toNumber()
+        this.idsMap.set(parseInt(id), newVideoId)
+        newVideoMapEntries.push([parseInt(id), newVideoId])
+      })
+      if (newVideoMapEntries.length) {
+        console.log('Video map entries added!', newVideoMapEntries)
+        await this.assetsManager.uploadFromEvents(dataObjectsUploadedEvents)
+      }
+    }
+    return this.getResult()
+  }
+
+  private getVideoData(video: VideoFieldsFragment) {
+    const { id, channel } = video
+
+    if (!channel) {
+      throw new Error(`Channel data missing for video: ${id}`)
+    }
+
+    if (!channel.ownerMember) {
+      throw new Error(`Channel ownerMember missing for video ${id}`)
+    }
+
+    let { ownerMember } = channel
+    if (this.forcedChannelOwner) {
+      ownerMember = this.forcedChannelOwner
+    }
+
+    return { ...video, channel: { ...channel, ownerMember } }
+  }
+
+  private async prepareVideo(video: VideoFieldsFragment) {
+    const { api } = this
+
+    const {
+      categoryId,
+      description,
+      duration,
+      hasMarketing,
+      isExplicit,
+      isPublic,
+      language,
+      license,
+      mediaDataObject,
+      mediaMetadata,
+      publishedBeforeJoystream,
+      thumbnailPhotoDataObject,
+      title,
+      channel: { ownerMember, id: oldChannelId },
+    } = this.getVideoData(video)
+
+    const channelId = this.getNewChannelId(parseInt(oldChannelId))
+
+    const assetsToPrepare = {
+      thumbnail: { data: thumbnailPhotoDataObject || undefined, targetSize: VIDEO_THUMB_TARGET_SIZE },
+      video: { data: mediaDataObject || undefined },
+    }
+    const preparedAssets = await this.assetsManager.prepareAssets(assetsToPrepare)
+    const meta = new VideoMetadata({
+      title,
+      description,
+      category: categoryId ? Long.fromString(categoryId) : undefined,
+      duration,
+      hasMarketing,
+      isExplicit,
+      isPublic,
+      language: language?.iso,
+      license: license,
+      mediaPixelHeight: mediaMetadata?.pixelHeight,
+      mediaPixelWidth: mediaMetadata?.pixelWidth,
+      mediaType: mediaMetadata?.encoding,
+      publishedBeforeJoystream: {
+        isPublished: !!publishedBeforeJoystream,
+        date: moment(publishedBeforeJoystream).format('YYYY-MM-DD'),
+      },
+      thumbnailPhoto: preparedAssets.thumbnail?.index,
+      video: preparedAssets.video?.index,
+    })
+    const assetsParams = Object.values(preparedAssets)
+      .sort((a, b) => a.index - b.index)
+      .map((a) => a.params)
+    const videoCreationParams = createType<VideoCreationParameters, 'VideoCreationParameters'>(
+      'VideoCreationParameters',
+      {
+        assets: assetsParams.length
+          ? {
+              object_creation_list: assetsParams,
+              expected_data_size_fee: this.assetsManager.dataObjectFeePerMB,
+            }
+          : null,
+        meta: `0x${Buffer.from(VideoMetadata.encode(meta).finish()).toString('hex')}`,
+      }
+    )
+    const feesToCover = this.assetsManager.calcDataObjectsFee(assetsParams)
+    return [
+      api.tx.balances.transferKeepAlive(ownerMember.controllerAccount, feesToCover),
+      api.tx.sudo.sudoAs(
+        ownerMember.controllerAccount,
+        api.tx.content.createVideo({ Member: ownerMember.id }, channelId, videoCreationParams)
+      ),
+    ]
+  }
+}

+ 120 - 0
utils/migration-scripts/src/sumer-giza/sumer-query-node/api.ts

@@ -0,0 +1,120 @@
+import {
+  ApolloClient,
+  NormalizedCacheObject,
+  HttpLink,
+  InMemoryCache,
+  DocumentNode,
+  isApolloError,
+  ApolloQueryResult,
+} from '@apollo/client/core'
+import fetch from 'cross-fetch'
+import {
+  ChannelCategoryFieldsFragment,
+  ChannelFieldsFragment,
+  GetChannelsByIds,
+  GetChannelsByIdsQuery,
+  GetChannelsByIdsQueryVariables,
+  GetChannelsCategories,
+  GetChannelsCategoriesQuery,
+  GetChannelsCategoriesQueryVariables,
+  GetStorageWorkers,
+  GetStorageWorkersQuery,
+  GetStorageWorkersQueryVariables,
+  GetVideoCategories,
+  GetVideoCategoriesQuery,
+  GetVideoCategoriesQueryVariables,
+  GetVideosByIds,
+  GetVideosByIdsQuery,
+  GetVideosByIdsQueryVariables,
+  VideoCategoryFieldsFragment,
+  VideoFieldsFragment,
+  WorkerFieldsFragment,
+} from './generated/queries'
+
+export class QueryNodeApi {
+  private endpoint: string
+  private apolloClient: ApolloClient<NormalizedCacheObject>
+  private retryAttempts: number
+  private retryIntervalMs: number
+
+  public constructor(endpoint: string, retryAttempts = 5, retryIntervalMs = 5000) {
+    this.endpoint = endpoint
+    this.retryAttempts = retryAttempts
+    this.retryIntervalMs = retryIntervalMs
+    this.apolloClient = new ApolloClient({
+      link: new HttpLink({ uri: endpoint, fetch }),
+      cache: new InMemoryCache(),
+      defaultOptions: { query: { fetchPolicy: 'no-cache', errorPolicy: 'all' } },
+    })
+  }
+
+  private async query<T>(queryFunc: () => Promise<ApolloQueryResult<T>>): Promise<ApolloQueryResult<T>> {
+    let attempts = 0
+    while (true) {
+      try {
+        const result = await queryFunc()
+        return result
+      } catch (e) {
+        if (e instanceof Error && isApolloError(e) && e.networkError) {
+          console.error(`Query node (${this.endpoint}) network error: ${e.networkError.message}`)
+          if (attempts++ > this.retryAttempts) {
+            throw new Error(`Maximum number of query retry attempts reached for ${this.endpoint}`)
+          }
+          console.log(`Retrying in ${this.retryIntervalMs}ms...`)
+          await new Promise((resolve) => setTimeout(resolve, this.retryIntervalMs))
+        } else {
+          throw e
+        }
+      }
+    }
+  }
+
+  // Query-node: get multiple entities
+  protected async multipleEntitiesQuery<
+    QueryT extends { [k: string]: unknown[] },
+    VariablesT extends Record<string, unknown>
+  >(query: DocumentNode, variables: VariablesT, resultKey: keyof QueryT): Promise<QueryT[keyof QueryT]> {
+    const q = this.query<QueryT>(() => this.apolloClient.query<QueryT, VariablesT>({ query, variables }))
+    return (await q).data[resultKey]
+  }
+
+  public getChannelCategories(): Promise<ChannelCategoryFieldsFragment[]> {
+    return this.multipleEntitiesQuery<GetChannelsCategoriesQuery, GetChannelsCategoriesQueryVariables>(
+      GetChannelsCategories,
+      {},
+      'channelCategories'
+    )
+  }
+
+  public getVideoCategories(): Promise<VideoCategoryFieldsFragment[]> {
+    return this.multipleEntitiesQuery<GetVideoCategoriesQuery, GetVideoCategoriesQueryVariables>(
+      GetVideoCategories,
+      {},
+      'videoCategories'
+    )
+  }
+
+  public getChannelsByIds(channelIds: string[] | number[]): Promise<ChannelFieldsFragment[]> {
+    return this.multipleEntitiesQuery<GetChannelsByIdsQuery, GetChannelsByIdsQueryVariables>(
+      GetChannelsByIds,
+      { ids: channelIds.map((id) => id.toString()) },
+      'channels'
+    )
+  }
+
+  public getVideosByIds(videoIds: string[] | number[]): Promise<VideoFieldsFragment[]> {
+    return this.multipleEntitiesQuery<GetVideosByIdsQuery, GetVideosByIdsQueryVariables>(
+      GetVideosByIds,
+      { ids: videoIds.map((id) => id.toString()) },
+      'videos'
+    )
+  }
+
+  public getStorageWorkers(): Promise<WorkerFieldsFragment[]> {
+    return this.multipleEntitiesQuery<GetStorageWorkersQuery, GetStorageWorkersQueryVariables>(
+      GetStorageWorkers,
+      {},
+      'workers'
+    )
+  }
+}

+ 33 - 0
utils/migration-scripts/src/sumer-giza/sumer-query-node/codegen.yml

@@ -0,0 +1,33 @@
+# Paths are relative to root distribution-node directory
+overwrite: true
+
+schema: https://hydra.joystream.org/graphql
+
+documents:
+  - 'src/sumer-giza/sumer-query-node/queries/*.graphql'
+
+config:
+  scalars:
+    Date: Date
+  preResolveTypes: true # avoid using Pick
+  skipTypename: true # skip __typename field in typings unless it's part of the query
+
+generates:
+  src/sumer-giza/sumer-query-node/generated/schema.ts:
+    hooks:
+      afterOneFileWrite:
+        - prettier --write
+        - eslint --fix
+    plugins:
+      - typescript
+  src/sumer-giza/sumer-query-node/generated/queries.ts:
+    preset: import-types
+    presetConfig:
+      typesPath: ./schema
+    hooks:
+      afterOneFileWrite:
+        - prettier --write
+        - eslint --fix
+    plugins:
+      - typescript-operations
+      - typescript-document-nodes

+ 229 - 0
utils/migration-scripts/src/sumer-giza/sumer-query-node/generated/queries.ts

@@ -0,0 +1,229 @@
+import * as Types from './schema'
+
+import gql from 'graphql-tag'
+export type VideoCategoryFieldsFragment = { id: string; name?: Types.Maybe<string> }
+
+export type ChannelCategoryFieldsFragment = { id: string; name?: Types.Maybe<string> }
+
+export type DataObjectFieldsFragment = {
+  id: string
+  joystreamContentId: string
+  size: number
+  liaisonJudgement: Types.LiaisonJudgement
+}
+
+export type VideoFieldsFragment = {
+  id: string
+  categoryId?: Types.Maybe<string>
+  title?: Types.Maybe<string>
+  description?: Types.Maybe<string>
+  duration?: Types.Maybe<number>
+  hasMarketing?: Types.Maybe<boolean>
+  publishedBeforeJoystream?: Types.Maybe<any>
+  isPublic?: Types.Maybe<boolean>
+  isCensored: boolean
+  isExplicit?: Types.Maybe<boolean>
+  isFeatured: boolean
+  thumbnailPhotoDataObject?: Types.Maybe<DataObjectFieldsFragment>
+  language?: Types.Maybe<{ iso: string }>
+  license?: Types.Maybe<{
+    code?: Types.Maybe<number>
+    attribution?: Types.Maybe<string>
+    customText?: Types.Maybe<string>
+  }>
+  mediaDataObject?: Types.Maybe<DataObjectFieldsFragment>
+  mediaMetadata?: Types.Maybe<{
+    pixelWidth?: Types.Maybe<number>
+    pixelHeight?: Types.Maybe<number>
+    size?: Types.Maybe<number>
+    encoding?: Types.Maybe<{
+      codecName?: Types.Maybe<string>
+      container?: Types.Maybe<string>
+      mimeMediaType?: Types.Maybe<string>
+    }>
+  }>
+  channel?: Types.Maybe<{ id: string; ownerMember?: Types.Maybe<{ id: string; controllerAccount: string }> }>
+}
+
+export type ChannelFieldsFragment = {
+  id: string
+  categoryId?: Types.Maybe<string>
+  rewardAccount?: Types.Maybe<string>
+  title?: Types.Maybe<string>
+  description?: Types.Maybe<string>
+  isPublic?: Types.Maybe<boolean>
+  isCensored: boolean
+  ownerMember?: Types.Maybe<{ id: string; controllerAccount: string }>
+  coverPhotoDataObject?: Types.Maybe<DataObjectFieldsFragment>
+  avatarPhotoDataObject?: Types.Maybe<DataObjectFieldsFragment>
+  language?: Types.Maybe<{ iso: string }>
+  videos: Array<{ id: string }>
+}
+
+export type WorkerFieldsFragment = { id: string; metadata?: Types.Maybe<string> }
+
+export type GetChannelsByIdsQueryVariables = Types.Exact<{
+  ids?: Types.Maybe<Array<Types.Scalars['ID']> | Types.Scalars['ID']>
+}>
+
+export type GetChannelsByIdsQuery = { channels: Array<ChannelFieldsFragment> }
+
+export type GetVideosByIdsQueryVariables = Types.Exact<{
+  ids?: Types.Maybe<Array<Types.Scalars['ID']> | Types.Scalars['ID']>
+}>
+
+export type GetVideosByIdsQuery = { videos: Array<VideoFieldsFragment> }
+
+export type GetVideoCategoriesQueryVariables = Types.Exact<{ [key: string]: never }>
+
+export type GetVideoCategoriesQuery = { videoCategories: Array<VideoCategoryFieldsFragment> }
+
+export type GetChannelsCategoriesQueryVariables = Types.Exact<{ [key: string]: never }>
+
+export type GetChannelsCategoriesQuery = { channelCategories: Array<ChannelCategoryFieldsFragment> }
+
+export type GetStorageWorkersQueryVariables = Types.Exact<{ [key: string]: never }>
+
+export type GetStorageWorkersQuery = { workers: Array<WorkerFieldsFragment> }
+
+export const VideoCategoryFields = gql`
+  fragment VideoCategoryFields on VideoCategory {
+    id
+    name
+  }
+`
+export const ChannelCategoryFields = gql`
+  fragment ChannelCategoryFields on ChannelCategory {
+    id
+    name
+  }
+`
+export const DataObjectFields = gql`
+  fragment DataObjectFields on DataObject {
+    id
+    joystreamContentId
+    size
+    liaisonJudgement
+  }
+`
+export const VideoFields = gql`
+  fragment VideoFields on Video {
+    id
+    categoryId
+    title
+    description
+    duration
+    thumbnailPhotoDataObject {
+      ...DataObjectFields
+    }
+    language {
+      iso
+    }
+    hasMarketing
+    publishedBeforeJoystream
+    isPublic
+    isCensored
+    isExplicit
+    license {
+      code
+      attribution
+      customText
+    }
+    mediaDataObject {
+      ...DataObjectFields
+    }
+    mediaMetadata {
+      encoding {
+        codecName
+        container
+        mimeMediaType
+      }
+      pixelWidth
+      pixelHeight
+      size
+    }
+    isFeatured
+    channel {
+      id
+      ownerMember {
+        id
+        controllerAccount
+      }
+    }
+  }
+  ${DataObjectFields}
+`
+export const ChannelFields = gql`
+  fragment ChannelFields on Channel {
+    id
+    ownerMember {
+      id
+      controllerAccount
+    }
+    categoryId
+    rewardAccount
+    title
+    description
+    coverPhotoDataObject {
+      ...DataObjectFields
+    }
+    avatarPhotoDataObject {
+      ...DataObjectFields
+    }
+    isPublic
+    isCensored
+    language {
+      iso
+    }
+    videos {
+      id
+    }
+  }
+  ${DataObjectFields}
+`
+export const WorkerFields = gql`
+  fragment WorkerFields on Worker {
+    id
+    metadata
+  }
+`
+export const GetChannelsByIds = gql`
+  query getChannelsByIds($ids: [ID!]) {
+    channels(where: { id_in: $ids }, limit: 1000) {
+      ...ChannelFields
+    }
+  }
+  ${ChannelFields}
+`
+export const GetVideosByIds = gql`
+  query getVideosByIds($ids: [ID!]) {
+    videos(where: { id_in: $ids }, limit: 1000) {
+      ...VideoFields
+    }
+  }
+  ${VideoFields}
+`
+export const GetVideoCategories = gql`
+  query getVideoCategories {
+    videoCategories {
+      ...VideoCategoryFields
+    }
+  }
+  ${VideoCategoryFields}
+`
+export const GetChannelsCategories = gql`
+  query getChannelsCategories {
+    channelCategories {
+      ...ChannelCategoryFields
+    }
+  }
+  ${ChannelCategoryFields}
+`
+export const GetStorageWorkers = gql`
+  query getStorageWorkers {
+    workers(where: { type_eq: STORAGE }) {
+      ...WorkerFields
+    }
+  }
+  ${WorkerFields}
+`

+ 2565 - 0
utils/migration-scripts/src/sumer-giza/sumer-query-node/generated/schema.ts

@@ -0,0 +1,2565 @@
+export type Maybe<T> = T | null
+export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] }
+export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> }
+export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> }
+/** All built-in and custom scalars, mapped to their actual values */
+export type Scalars = {
+  ID: string
+  String: string
+  Boolean: boolean
+  Int: number
+  Float: number
+  /** The javascript `Date` as string. Type represents date and time as the ISO Date string. */
+  DateTime: any
+  /** The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */
+  JSONObject: any
+}
+
+export enum AssetAvailability {
+  Accepted = 'ACCEPTED',
+  Pending = 'PENDING',
+  Invalid = 'INVALID',
+}
+
+export type BaseGraphQlObject = {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+}
+
+export type BaseModel = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+}
+
+export type BaseModelUuid = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+}
+
+export type BaseWhereInput = {
+  id_eq?: Maybe<Scalars['String']>
+  id_in?: Maybe<Array<Scalars['String']>>
+  createdAt_eq?: Maybe<Scalars['String']>
+  createdAt_lt?: Maybe<Scalars['String']>
+  createdAt_lte?: Maybe<Scalars['String']>
+  createdAt_gt?: Maybe<Scalars['String']>
+  createdAt_gte?: Maybe<Scalars['String']>
+  createdById_eq?: Maybe<Scalars['String']>
+  updatedAt_eq?: Maybe<Scalars['String']>
+  updatedAt_lt?: Maybe<Scalars['String']>
+  updatedAt_lte?: Maybe<Scalars['String']>
+  updatedAt_gt?: Maybe<Scalars['String']>
+  updatedAt_gte?: Maybe<Scalars['String']>
+  updatedById_eq?: Maybe<Scalars['String']>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['String']>
+  deletedAt_lt?: Maybe<Scalars['String']>
+  deletedAt_lte?: Maybe<Scalars['String']>
+  deletedAt_gt?: Maybe<Scalars['String']>
+  deletedAt_gte?: Maybe<Scalars['String']>
+  deletedById_eq?: Maybe<Scalars['String']>
+}
+
+export type Channel = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+  ownerMember?: Maybe<Membership>
+  ownerMemberId?: Maybe<Scalars['String']>
+  ownerCuratorGroup?: Maybe<CuratorGroup>
+  ownerCuratorGroupId?: Maybe<Scalars['String']>
+  category?: Maybe<ChannelCategory>
+  categoryId?: Maybe<Scalars['String']>
+  /** Reward account where revenue is sent if set. */
+  rewardAccount?: Maybe<Scalars['String']>
+  /** The title of the Channel */
+  title?: Maybe<Scalars['String']>
+  /** The description of a Channel */
+  description?: Maybe<Scalars['String']>
+  coverPhotoDataObject?: Maybe<DataObject>
+  coverPhotoDataObjectId?: Maybe<Scalars['String']>
+  /** URLs where the asset content can be accessed (if any) */
+  coverPhotoUrls: Array<Scalars['String']>
+  /** Availability meta information */
+  coverPhotoAvailability: AssetAvailability
+  avatarPhotoDataObject?: Maybe<DataObject>
+  avatarPhotoDataObjectId?: Maybe<Scalars['String']>
+  /** URLs where the asset content can be accessed (if any) */
+  avatarPhotoUrls: Array<Scalars['String']>
+  /** Availability meta information */
+  avatarPhotoAvailability: AssetAvailability
+  /** Flag signaling whether a channel is public. */
+  isPublic?: Maybe<Scalars['Boolean']>
+  /** Flag signaling whether a channel is censored. */
+  isCensored: Scalars['Boolean']
+  language?: Maybe<Language>
+  languageId?: Maybe<Scalars['String']>
+  videos: Array<Video>
+  createdInBlock: Scalars['Int']
+}
+
+export type ChannelCategoriesByNameFtsOutput = {
+  item: ChannelCategoriesByNameSearchResult
+  rank: Scalars['Float']
+  isTypeOf: Scalars['String']
+  highlight: Scalars['String']
+}
+
+export type ChannelCategoriesByNameSearchResult = ChannelCategory
+
+/** Category of media channel */
+export type ChannelCategory = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+  /** The name of the category */
+  name?: Maybe<Scalars['String']>
+  channels: Array<Channel>
+  createdInBlock: Scalars['Int']
+}
+
+export type ChannelCategoryConnection = {
+  totalCount: Scalars['Int']
+  edges: Array<ChannelCategoryEdge>
+  pageInfo: PageInfo
+}
+
+export type ChannelCategoryCreateInput = {
+  name?: Maybe<Scalars['String']>
+  createdInBlock: Scalars['Float']
+}
+
+export type ChannelCategoryEdge = {
+  node: ChannelCategory
+  cursor: Scalars['String']
+}
+
+export enum ChannelCategoryOrderByInput {
+  CreatedAtAsc = 'createdAt_ASC',
+  CreatedAtDesc = 'createdAt_DESC',
+  UpdatedAtAsc = 'updatedAt_ASC',
+  UpdatedAtDesc = 'updatedAt_DESC',
+  DeletedAtAsc = 'deletedAt_ASC',
+  DeletedAtDesc = 'deletedAt_DESC',
+  NameAsc = 'name_ASC',
+  NameDesc = 'name_DESC',
+  CreatedInBlockAsc = 'createdInBlock_ASC',
+  CreatedInBlockDesc = 'createdInBlock_DESC',
+}
+
+export type ChannelCategoryUpdateInput = {
+  name?: Maybe<Scalars['String']>
+  createdInBlock?: Maybe<Scalars['Float']>
+}
+
+export type ChannelCategoryWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  name_eq?: Maybe<Scalars['String']>
+  name_contains?: Maybe<Scalars['String']>
+  name_startsWith?: Maybe<Scalars['String']>
+  name_endsWith?: Maybe<Scalars['String']>
+  name_in?: Maybe<Array<Scalars['String']>>
+  createdInBlock_eq?: Maybe<Scalars['Int']>
+  createdInBlock_gt?: Maybe<Scalars['Int']>
+  createdInBlock_gte?: Maybe<Scalars['Int']>
+  createdInBlock_lt?: Maybe<Scalars['Int']>
+  createdInBlock_lte?: Maybe<Scalars['Int']>
+  createdInBlock_in?: Maybe<Array<Scalars['Int']>>
+  channels_none?: Maybe<ChannelWhereInput>
+  channels_some?: Maybe<ChannelWhereInput>
+  channels_every?: Maybe<ChannelWhereInput>
+  AND?: Maybe<Array<ChannelCategoryWhereInput>>
+  OR?: Maybe<Array<ChannelCategoryWhereInput>>
+}
+
+export type ChannelCategoryWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export type ChannelConnection = {
+  totalCount: Scalars['Int']
+  edges: Array<ChannelEdge>
+  pageInfo: PageInfo
+}
+
+export type ChannelCreateInput = {
+  ownerMember?: Maybe<Scalars['ID']>
+  ownerMemberId?: Maybe<Scalars['ID']>
+  ownerCuratorGroup?: Maybe<Scalars['ID']>
+  ownerCuratorGroupId?: Maybe<Scalars['ID']>
+  category?: Maybe<Scalars['ID']>
+  categoryId?: Maybe<Scalars['ID']>
+  rewardAccount?: Maybe<Scalars['String']>
+  title?: Maybe<Scalars['String']>
+  description?: Maybe<Scalars['String']>
+  coverPhotoDataObject?: Maybe<Scalars['ID']>
+  coverPhotoDataObjectId?: Maybe<Scalars['ID']>
+  coverPhotoUrls: Array<Scalars['String']>
+  coverPhotoAvailability: AssetAvailability
+  avatarPhotoDataObject?: Maybe<Scalars['ID']>
+  avatarPhotoDataObjectId?: Maybe<Scalars['ID']>
+  avatarPhotoUrls: Array<Scalars['String']>
+  avatarPhotoAvailability: AssetAvailability
+  isPublic?: Maybe<Scalars['Boolean']>
+  isCensored: Scalars['Boolean']
+  language?: Maybe<Scalars['ID']>
+  languageId?: Maybe<Scalars['ID']>
+  createdInBlock: Scalars['Float']
+}
+
+export type ChannelEdge = {
+  node: Channel
+  cursor: Scalars['String']
+}
+
+export enum ChannelOrderByInput {
+  CreatedAtAsc = 'createdAt_ASC',
+  CreatedAtDesc = 'createdAt_DESC',
+  UpdatedAtAsc = 'updatedAt_ASC',
+  UpdatedAtDesc = 'updatedAt_DESC',
+  DeletedAtAsc = 'deletedAt_ASC',
+  DeletedAtDesc = 'deletedAt_DESC',
+  OwnerMemberAsc = 'ownerMember_ASC',
+  OwnerMemberDesc = 'ownerMember_DESC',
+  OwnerMemberIdAsc = 'ownerMemberId_ASC',
+  OwnerMemberIdDesc = 'ownerMemberId_DESC',
+  OwnerCuratorGroupAsc = 'ownerCuratorGroup_ASC',
+  OwnerCuratorGroupDesc = 'ownerCuratorGroup_DESC',
+  OwnerCuratorGroupIdAsc = 'ownerCuratorGroupId_ASC',
+  OwnerCuratorGroupIdDesc = 'ownerCuratorGroupId_DESC',
+  CategoryAsc = 'category_ASC',
+  CategoryDesc = 'category_DESC',
+  CategoryIdAsc = 'categoryId_ASC',
+  CategoryIdDesc = 'categoryId_DESC',
+  RewardAccountAsc = 'rewardAccount_ASC',
+  RewardAccountDesc = 'rewardAccount_DESC',
+  TitleAsc = 'title_ASC',
+  TitleDesc = 'title_DESC',
+  DescriptionAsc = 'description_ASC',
+  DescriptionDesc = 'description_DESC',
+  CoverPhotoDataObjectAsc = 'coverPhotoDataObject_ASC',
+  CoverPhotoDataObjectDesc = 'coverPhotoDataObject_DESC',
+  CoverPhotoDataObjectIdAsc = 'coverPhotoDataObjectId_ASC',
+  CoverPhotoDataObjectIdDesc = 'coverPhotoDataObjectId_DESC',
+  CoverPhotoAvailabilityAsc = 'coverPhotoAvailability_ASC',
+  CoverPhotoAvailabilityDesc = 'coverPhotoAvailability_DESC',
+  AvatarPhotoDataObjectAsc = 'avatarPhotoDataObject_ASC',
+  AvatarPhotoDataObjectDesc = 'avatarPhotoDataObject_DESC',
+  AvatarPhotoDataObjectIdAsc = 'avatarPhotoDataObjectId_ASC',
+  AvatarPhotoDataObjectIdDesc = 'avatarPhotoDataObjectId_DESC',
+  AvatarPhotoAvailabilityAsc = 'avatarPhotoAvailability_ASC',
+  AvatarPhotoAvailabilityDesc = 'avatarPhotoAvailability_DESC',
+  IsPublicAsc = 'isPublic_ASC',
+  IsPublicDesc = 'isPublic_DESC',
+  IsCensoredAsc = 'isCensored_ASC',
+  IsCensoredDesc = 'isCensored_DESC',
+  LanguageAsc = 'language_ASC',
+  LanguageDesc = 'language_DESC',
+  LanguageIdAsc = 'languageId_ASC',
+  LanguageIdDesc = 'languageId_DESC',
+  CreatedInBlockAsc = 'createdInBlock_ASC',
+  CreatedInBlockDesc = 'createdInBlock_DESC',
+}
+
+export type ChannelUpdateInput = {
+  ownerMember?: Maybe<Scalars['ID']>
+  ownerMemberId?: Maybe<Scalars['ID']>
+  ownerCuratorGroup?: Maybe<Scalars['ID']>
+  ownerCuratorGroupId?: Maybe<Scalars['ID']>
+  category?: Maybe<Scalars['ID']>
+  categoryId?: Maybe<Scalars['ID']>
+  rewardAccount?: Maybe<Scalars['String']>
+  title?: Maybe<Scalars['String']>
+  description?: Maybe<Scalars['String']>
+  coverPhotoDataObject?: Maybe<Scalars['ID']>
+  coverPhotoDataObjectId?: Maybe<Scalars['ID']>
+  coverPhotoUrls?: Maybe<Array<Scalars['String']>>
+  coverPhotoAvailability?: Maybe<AssetAvailability>
+  avatarPhotoDataObject?: Maybe<Scalars['ID']>
+  avatarPhotoDataObjectId?: Maybe<Scalars['ID']>
+  avatarPhotoUrls?: Maybe<Array<Scalars['String']>>
+  avatarPhotoAvailability?: Maybe<AssetAvailability>
+  isPublic?: Maybe<Scalars['Boolean']>
+  isCensored?: Maybe<Scalars['Boolean']>
+  language?: Maybe<Scalars['ID']>
+  languageId?: Maybe<Scalars['ID']>
+  createdInBlock?: Maybe<Scalars['Float']>
+}
+
+export type ChannelWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  ownerMemberId_eq?: Maybe<Scalars['ID']>
+  ownerMemberId_in?: Maybe<Array<Scalars['ID']>>
+  ownerCuratorGroupId_eq?: Maybe<Scalars['ID']>
+  ownerCuratorGroupId_in?: Maybe<Array<Scalars['ID']>>
+  categoryId_eq?: Maybe<Scalars['ID']>
+  categoryId_in?: Maybe<Array<Scalars['ID']>>
+  rewardAccount_eq?: Maybe<Scalars['String']>
+  rewardAccount_contains?: Maybe<Scalars['String']>
+  rewardAccount_startsWith?: Maybe<Scalars['String']>
+  rewardAccount_endsWith?: Maybe<Scalars['String']>
+  rewardAccount_in?: Maybe<Array<Scalars['String']>>
+  title_eq?: Maybe<Scalars['String']>
+  title_contains?: Maybe<Scalars['String']>
+  title_startsWith?: Maybe<Scalars['String']>
+  title_endsWith?: Maybe<Scalars['String']>
+  title_in?: Maybe<Array<Scalars['String']>>
+  description_eq?: Maybe<Scalars['String']>
+  description_contains?: Maybe<Scalars['String']>
+  description_startsWith?: Maybe<Scalars['String']>
+  description_endsWith?: Maybe<Scalars['String']>
+  description_in?: Maybe<Array<Scalars['String']>>
+  coverPhotoDataObjectId_eq?: Maybe<Scalars['ID']>
+  coverPhotoDataObjectId_in?: Maybe<Array<Scalars['ID']>>
+  coverPhotoUrls_containsAll?: Maybe<Array<Scalars['String']>>
+  coverPhotoUrls_containsNone?: Maybe<Array<Scalars['String']>>
+  coverPhotoUrls_containsAny?: Maybe<Array<Scalars['String']>>
+  coverPhotoAvailability_eq?: Maybe<AssetAvailability>
+  coverPhotoAvailability_in?: Maybe<Array<AssetAvailability>>
+  avatarPhotoDataObjectId_eq?: Maybe<Scalars['ID']>
+  avatarPhotoDataObjectId_in?: Maybe<Array<Scalars['ID']>>
+  avatarPhotoUrls_containsAll?: Maybe<Array<Scalars['String']>>
+  avatarPhotoUrls_containsNone?: Maybe<Array<Scalars['String']>>
+  avatarPhotoUrls_containsAny?: Maybe<Array<Scalars['String']>>
+  avatarPhotoAvailability_eq?: Maybe<AssetAvailability>
+  avatarPhotoAvailability_in?: Maybe<Array<AssetAvailability>>
+  isPublic_eq?: Maybe<Scalars['Boolean']>
+  isPublic_in?: Maybe<Array<Scalars['Boolean']>>
+  isCensored_eq?: Maybe<Scalars['Boolean']>
+  isCensored_in?: Maybe<Array<Scalars['Boolean']>>
+  languageId_eq?: Maybe<Scalars['ID']>
+  languageId_in?: Maybe<Array<Scalars['ID']>>
+  createdInBlock_eq?: Maybe<Scalars['Int']>
+  createdInBlock_gt?: Maybe<Scalars['Int']>
+  createdInBlock_gte?: Maybe<Scalars['Int']>
+  createdInBlock_lt?: Maybe<Scalars['Int']>
+  createdInBlock_lte?: Maybe<Scalars['Int']>
+  createdInBlock_in?: Maybe<Array<Scalars['Int']>>
+  ownerMember?: Maybe<MembershipWhereInput>
+  ownerCuratorGroup?: Maybe<CuratorGroupWhereInput>
+  category?: Maybe<ChannelCategoryWhereInput>
+  coverPhotoDataObject?: Maybe<DataObjectWhereInput>
+  avatarPhotoDataObject?: Maybe<DataObjectWhereInput>
+  language?: Maybe<LanguageWhereInput>
+  videos_none?: Maybe<VideoWhereInput>
+  videos_some?: Maybe<VideoWhereInput>
+  videos_every?: Maybe<VideoWhereInput>
+  AND?: Maybe<Array<ChannelWhereInput>>
+  OR?: Maybe<Array<ChannelWhereInput>>
+}
+
+export type ChannelWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export type CuratorGroup = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+  /** Curators belonging to this group */
+  curatorIds: Array<Scalars['Int']>
+  /** Is group active or not */
+  isActive: Scalars['Boolean']
+  channels: Array<Channel>
+}
+
+export type CuratorGroupConnection = {
+  totalCount: Scalars['Int']
+  edges: Array<CuratorGroupEdge>
+  pageInfo: PageInfo
+}
+
+export type CuratorGroupCreateInput = {
+  curatorIds: Array<Scalars['Int']>
+  isActive: Scalars['Boolean']
+}
+
+export type CuratorGroupEdge = {
+  node: CuratorGroup
+  cursor: Scalars['String']
+}
+
+export enum CuratorGroupOrderByInput {
+  CreatedAtAsc = 'createdAt_ASC',
+  CreatedAtDesc = 'createdAt_DESC',
+  UpdatedAtAsc = 'updatedAt_ASC',
+  UpdatedAtDesc = 'updatedAt_DESC',
+  DeletedAtAsc = 'deletedAt_ASC',
+  DeletedAtDesc = 'deletedAt_DESC',
+  IsActiveAsc = 'isActive_ASC',
+  IsActiveDesc = 'isActive_DESC',
+}
+
+export type CuratorGroupUpdateInput = {
+  curatorIds?: Maybe<Array<Scalars['Int']>>
+  isActive?: Maybe<Scalars['Boolean']>
+}
+
+export type CuratorGroupWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  curatorIds_containsAll?: Maybe<Array<Scalars['Int']>>
+  curatorIds_containsNone?: Maybe<Array<Scalars['Int']>>
+  curatorIds_containsAny?: Maybe<Array<Scalars['Int']>>
+  isActive_eq?: Maybe<Scalars['Boolean']>
+  isActive_in?: Maybe<Array<Scalars['Boolean']>>
+  channels_none?: Maybe<ChannelWhereInput>
+  channels_some?: Maybe<ChannelWhereInput>
+  channels_every?: Maybe<ChannelWhereInput>
+  AND?: Maybe<Array<CuratorGroupWhereInput>>
+  OR?: Maybe<Array<CuratorGroupWhereInput>>
+}
+
+export type CuratorGroupWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+/** Manages content ids, type and storage provider decision about it */
+export type DataObject = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+  /** Content owner */
+  owner: DataObjectOwner
+  /** Content added at */
+  createdInBlock: Scalars['Int']
+  /** Content type id */
+  typeId: Scalars['Int']
+  /** Content size in bytes */
+  size: Scalars['Float']
+  liaison?: Maybe<Worker>
+  liaisonId?: Maybe<Scalars['String']>
+  /** Storage provider as liaison judgment */
+  liaisonJudgement: LiaisonJudgement
+  /** IPFS content id */
+  ipfsContentId: Scalars['String']
+  /** Joystream runtime content */
+  joystreamContentId: Scalars['String']
+  channelcoverPhotoDataObject?: Maybe<Array<Channel>>
+  channelavatarPhotoDataObject?: Maybe<Array<Channel>>
+  videothumbnailPhotoDataObject?: Maybe<Array<Video>>
+  videomediaDataObject?: Maybe<Array<Video>>
+}
+
+export type DataObjectConnection = {
+  totalCount: Scalars['Int']
+  edges: Array<DataObjectEdge>
+  pageInfo: PageInfo
+}
+
+export type DataObjectCreateInput = {
+  owner: Scalars['JSONObject']
+  createdInBlock: Scalars['Float']
+  typeId: Scalars['Float']
+  size: Scalars['Float']
+  liaison?: Maybe<Scalars['ID']>
+  liaisonId?: Maybe<Scalars['ID']>
+  liaisonJudgement: LiaisonJudgement
+  ipfsContentId: Scalars['String']
+  joystreamContentId: Scalars['String']
+}
+
+export type DataObjectEdge = {
+  node: DataObject
+  cursor: Scalars['String']
+}
+
+export enum DataObjectOrderByInput {
+  CreatedAtAsc = 'createdAt_ASC',
+  CreatedAtDesc = 'createdAt_DESC',
+  UpdatedAtAsc = 'updatedAt_ASC',
+  UpdatedAtDesc = 'updatedAt_DESC',
+  DeletedAtAsc = 'deletedAt_ASC',
+  DeletedAtDesc = 'deletedAt_DESC',
+  CreatedInBlockAsc = 'createdInBlock_ASC',
+  CreatedInBlockDesc = 'createdInBlock_DESC',
+  TypeIdAsc = 'typeId_ASC',
+  TypeIdDesc = 'typeId_DESC',
+  SizeAsc = 'size_ASC',
+  SizeDesc = 'size_DESC',
+  LiaisonAsc = 'liaison_ASC',
+  LiaisonDesc = 'liaison_DESC',
+  LiaisonIdAsc = 'liaisonId_ASC',
+  LiaisonIdDesc = 'liaisonId_DESC',
+  LiaisonJudgementAsc = 'liaisonJudgement_ASC',
+  LiaisonJudgementDesc = 'liaisonJudgement_DESC',
+  IpfsContentIdAsc = 'ipfsContentId_ASC',
+  IpfsContentIdDesc = 'ipfsContentId_DESC',
+  JoystreamContentIdAsc = 'joystreamContentId_ASC',
+  JoystreamContentIdDesc = 'joystreamContentId_DESC',
+}
+
+export type DataObjectOwner =
+  | DataObjectOwnerMember
+  | DataObjectOwnerChannel
+  | DataObjectOwnerDao
+  | DataObjectOwnerCouncil
+  | DataObjectOwnerWorkingGroup
+
+export type DataObjectOwnerChannel = {
+  /** Channel identifier */
+  channel: Scalars['Int']
+  /** Variant needs to have at least one property. This value is not used. */
+  dummy?: Maybe<Scalars['Int']>
+}
+
+export type DataObjectOwnerChannelCreateInput = {
+  channel: Scalars['Float']
+  dummy?: Maybe<Scalars['Float']>
+}
+
+export type DataObjectOwnerChannelUpdateInput = {
+  channel?: Maybe<Scalars['Float']>
+  dummy?: Maybe<Scalars['Float']>
+}
+
+export type DataObjectOwnerChannelWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  channel_eq?: Maybe<Scalars['Int']>
+  channel_gt?: Maybe<Scalars['Int']>
+  channel_gte?: Maybe<Scalars['Int']>
+  channel_lt?: Maybe<Scalars['Int']>
+  channel_lte?: Maybe<Scalars['Int']>
+  channel_in?: Maybe<Array<Scalars['Int']>>
+  dummy_eq?: Maybe<Scalars['Int']>
+  dummy_gt?: Maybe<Scalars['Int']>
+  dummy_gte?: Maybe<Scalars['Int']>
+  dummy_lt?: Maybe<Scalars['Int']>
+  dummy_lte?: Maybe<Scalars['Int']>
+  dummy_in?: Maybe<Array<Scalars['Int']>>
+  AND?: Maybe<Array<DataObjectOwnerChannelWhereInput>>
+  OR?: Maybe<Array<DataObjectOwnerChannelWhereInput>>
+}
+
+export type DataObjectOwnerChannelWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export type DataObjectOwnerCouncil = {
+  /** Variant needs to have at least one property. This value is not used. */
+  dummy?: Maybe<Scalars['Int']>
+}
+
+export type DataObjectOwnerCouncilCreateInput = {
+  dummy?: Maybe<Scalars['Float']>
+}
+
+export type DataObjectOwnerCouncilUpdateInput = {
+  dummy?: Maybe<Scalars['Float']>
+}
+
+export type DataObjectOwnerCouncilWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  dummy_eq?: Maybe<Scalars['Int']>
+  dummy_gt?: Maybe<Scalars['Int']>
+  dummy_gte?: Maybe<Scalars['Int']>
+  dummy_lt?: Maybe<Scalars['Int']>
+  dummy_lte?: Maybe<Scalars['Int']>
+  dummy_in?: Maybe<Array<Scalars['Int']>>
+  AND?: Maybe<Array<DataObjectOwnerCouncilWhereInput>>
+  OR?: Maybe<Array<DataObjectOwnerCouncilWhereInput>>
+}
+
+export type DataObjectOwnerCouncilWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export type DataObjectOwnerDao = {
+  /** DAO identifier */
+  dao: Scalars['Int']
+}
+
+export type DataObjectOwnerDaoCreateInput = {
+  dao: Scalars['Float']
+}
+
+export type DataObjectOwnerDaoUpdateInput = {
+  dao?: Maybe<Scalars['Float']>
+}
+
+export type DataObjectOwnerDaoWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  dao_eq?: Maybe<Scalars['Int']>
+  dao_gt?: Maybe<Scalars['Int']>
+  dao_gte?: Maybe<Scalars['Int']>
+  dao_lt?: Maybe<Scalars['Int']>
+  dao_lte?: Maybe<Scalars['Int']>
+  dao_in?: Maybe<Array<Scalars['Int']>>
+  AND?: Maybe<Array<DataObjectOwnerDaoWhereInput>>
+  OR?: Maybe<Array<DataObjectOwnerDaoWhereInput>>
+}
+
+export type DataObjectOwnerDaoWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export type DataObjectOwnerMember = {
+  /** Member identifier */
+  member: Scalars['Int']
+  /** Variant needs to have at least one property. This value is not used. */
+  dummy?: Maybe<Scalars['Int']>
+}
+
+export type DataObjectOwnerMemberCreateInput = {
+  member: Scalars['Float']
+  dummy?: Maybe<Scalars['Float']>
+}
+
+export type DataObjectOwnerMemberUpdateInput = {
+  member?: Maybe<Scalars['Float']>
+  dummy?: Maybe<Scalars['Float']>
+}
+
+export type DataObjectOwnerMemberWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  member_eq?: Maybe<Scalars['Int']>
+  member_gt?: Maybe<Scalars['Int']>
+  member_gte?: Maybe<Scalars['Int']>
+  member_lt?: Maybe<Scalars['Int']>
+  member_lte?: Maybe<Scalars['Int']>
+  member_in?: Maybe<Array<Scalars['Int']>>
+  dummy_eq?: Maybe<Scalars['Int']>
+  dummy_gt?: Maybe<Scalars['Int']>
+  dummy_gte?: Maybe<Scalars['Int']>
+  dummy_lt?: Maybe<Scalars['Int']>
+  dummy_lte?: Maybe<Scalars['Int']>
+  dummy_in?: Maybe<Array<Scalars['Int']>>
+  AND?: Maybe<Array<DataObjectOwnerMemberWhereInput>>
+  OR?: Maybe<Array<DataObjectOwnerMemberWhereInput>>
+}
+
+export type DataObjectOwnerMemberWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export type DataObjectOwnerWorkingGroup = {
+  /** Working group identifier */
+  workingGroup: Scalars['Int']
+}
+
+export type DataObjectOwnerWorkingGroupCreateInput = {
+  workingGroup: Scalars['Float']
+}
+
+export type DataObjectOwnerWorkingGroupUpdateInput = {
+  workingGroup?: Maybe<Scalars['Float']>
+}
+
+export type DataObjectOwnerWorkingGroupWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  workingGroup_eq?: Maybe<Scalars['Int']>
+  workingGroup_gt?: Maybe<Scalars['Int']>
+  workingGroup_gte?: Maybe<Scalars['Int']>
+  workingGroup_lt?: Maybe<Scalars['Int']>
+  workingGroup_lte?: Maybe<Scalars['Int']>
+  workingGroup_in?: Maybe<Array<Scalars['Int']>>
+  AND?: Maybe<Array<DataObjectOwnerWorkingGroupWhereInput>>
+  OR?: Maybe<Array<DataObjectOwnerWorkingGroupWhereInput>>
+}
+
+export type DataObjectOwnerWorkingGroupWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export type DataObjectUpdateInput = {
+  owner?: Maybe<Scalars['JSONObject']>
+  createdInBlock?: Maybe<Scalars['Float']>
+  typeId?: Maybe<Scalars['Float']>
+  size?: Maybe<Scalars['Float']>
+  liaison?: Maybe<Scalars['ID']>
+  liaisonId?: Maybe<Scalars['ID']>
+  liaisonJudgement?: Maybe<LiaisonJudgement>
+  ipfsContentId?: Maybe<Scalars['String']>
+  joystreamContentId?: Maybe<Scalars['String']>
+}
+
+export type DataObjectWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  owner_json?: Maybe<Scalars['JSONObject']>
+  createdInBlock_eq?: Maybe<Scalars['Int']>
+  createdInBlock_gt?: Maybe<Scalars['Int']>
+  createdInBlock_gte?: Maybe<Scalars['Int']>
+  createdInBlock_lt?: Maybe<Scalars['Int']>
+  createdInBlock_lte?: Maybe<Scalars['Int']>
+  createdInBlock_in?: Maybe<Array<Scalars['Int']>>
+  typeId_eq?: Maybe<Scalars['Int']>
+  typeId_gt?: Maybe<Scalars['Int']>
+  typeId_gte?: Maybe<Scalars['Int']>
+  typeId_lt?: Maybe<Scalars['Int']>
+  typeId_lte?: Maybe<Scalars['Int']>
+  typeId_in?: Maybe<Array<Scalars['Int']>>
+  size_eq?: Maybe<Scalars['Float']>
+  size_gt?: Maybe<Scalars['Float']>
+  size_gte?: Maybe<Scalars['Float']>
+  size_lt?: Maybe<Scalars['Float']>
+  size_lte?: Maybe<Scalars['Float']>
+  size_in?: Maybe<Array<Scalars['Float']>>
+  liaisonId_eq?: Maybe<Scalars['ID']>
+  liaisonId_in?: Maybe<Array<Scalars['ID']>>
+  liaisonJudgement_eq?: Maybe<LiaisonJudgement>
+  liaisonJudgement_in?: Maybe<Array<LiaisonJudgement>>
+  ipfsContentId_eq?: Maybe<Scalars['String']>
+  ipfsContentId_contains?: Maybe<Scalars['String']>
+  ipfsContentId_startsWith?: Maybe<Scalars['String']>
+  ipfsContentId_endsWith?: Maybe<Scalars['String']>
+  ipfsContentId_in?: Maybe<Array<Scalars['String']>>
+  joystreamContentId_eq?: Maybe<Scalars['String']>
+  joystreamContentId_contains?: Maybe<Scalars['String']>
+  joystreamContentId_startsWith?: Maybe<Scalars['String']>
+  joystreamContentId_endsWith?: Maybe<Scalars['String']>
+  joystreamContentId_in?: Maybe<Array<Scalars['String']>>
+  liaison?: Maybe<WorkerWhereInput>
+  channelcoverPhotoDataObject_none?: Maybe<ChannelWhereInput>
+  channelcoverPhotoDataObject_some?: Maybe<ChannelWhereInput>
+  channelcoverPhotoDataObject_every?: Maybe<ChannelWhereInput>
+  channelavatarPhotoDataObject_none?: Maybe<ChannelWhereInput>
+  channelavatarPhotoDataObject_some?: Maybe<ChannelWhereInput>
+  channelavatarPhotoDataObject_every?: Maybe<ChannelWhereInput>
+  videothumbnailPhotoDataObject_none?: Maybe<VideoMediaMetadataWhereInput>
+  videothumbnailPhotoDataObject_some?: Maybe<VideoMediaMetadataWhereInput>
+  videothumbnailPhotoDataObject_every?: Maybe<VideoMediaMetadataWhereInput>
+  videomediaDataObject_none?: Maybe<VideoMediaMetadataWhereInput>
+  videomediaDataObject_some?: Maybe<VideoMediaMetadataWhereInput>
+  videomediaDataObject_every?: Maybe<VideoMediaMetadataWhereInput>
+  AND?: Maybe<Array<DataObjectWhereInput>>
+  OR?: Maybe<Array<DataObjectWhereInput>>
+}
+
+export type DataObjectWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export type DeleteResponse = {
+  id: Scalars['ID']
+}
+
+export type Language = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+  /** Language identifier ISO 639-1 */
+  iso: Scalars['String']
+  createdInBlock: Scalars['Int']
+  channellanguage?: Maybe<Array<Channel>>
+  videolanguage?: Maybe<Array<Video>>
+}
+
+export type LanguageConnection = {
+  totalCount: Scalars['Int']
+  edges: Array<LanguageEdge>
+  pageInfo: PageInfo
+}
+
+export type LanguageCreateInput = {
+  iso: Scalars['String']
+  createdInBlock: Scalars['Float']
+}
+
+export type LanguageEdge = {
+  node: Language
+  cursor: Scalars['String']
+}
+
+export enum LanguageOrderByInput {
+  CreatedAtAsc = 'createdAt_ASC',
+  CreatedAtDesc = 'createdAt_DESC',
+  UpdatedAtAsc = 'updatedAt_ASC',
+  UpdatedAtDesc = 'updatedAt_DESC',
+  DeletedAtAsc = 'deletedAt_ASC',
+  DeletedAtDesc = 'deletedAt_DESC',
+  IsoAsc = 'iso_ASC',
+  IsoDesc = 'iso_DESC',
+  CreatedInBlockAsc = 'createdInBlock_ASC',
+  CreatedInBlockDesc = 'createdInBlock_DESC',
+}
+
+export type LanguageUpdateInput = {
+  iso?: Maybe<Scalars['String']>
+  createdInBlock?: Maybe<Scalars['Float']>
+}
+
+export type LanguageWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  iso_eq?: Maybe<Scalars['String']>
+  iso_contains?: Maybe<Scalars['String']>
+  iso_startsWith?: Maybe<Scalars['String']>
+  iso_endsWith?: Maybe<Scalars['String']>
+  iso_in?: Maybe<Array<Scalars['String']>>
+  createdInBlock_eq?: Maybe<Scalars['Int']>
+  createdInBlock_gt?: Maybe<Scalars['Int']>
+  createdInBlock_gte?: Maybe<Scalars['Int']>
+  createdInBlock_lt?: Maybe<Scalars['Int']>
+  createdInBlock_lte?: Maybe<Scalars['Int']>
+  createdInBlock_in?: Maybe<Array<Scalars['Int']>>
+  channellanguage_none?: Maybe<ChannelWhereInput>
+  channellanguage_some?: Maybe<ChannelWhereInput>
+  channellanguage_every?: Maybe<ChannelWhereInput>
+  videolanguage_none?: Maybe<VideoWhereInput>
+  videolanguage_some?: Maybe<VideoWhereInput>
+  videolanguage_every?: Maybe<VideoWhereInput>
+  AND?: Maybe<Array<LanguageWhereInput>>
+  OR?: Maybe<Array<LanguageWhereInput>>
+}
+
+export type LanguageWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export enum LiaisonJudgement {
+  Pending = 'PENDING',
+  Accepted = 'ACCEPTED',
+}
+
+export type License = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+  /** License code defined by Joystream */
+  code?: Maybe<Scalars['Int']>
+  /** Attribution (if required by the license) */
+  attribution?: Maybe<Scalars['String']>
+  /** Custom license content */
+  customText?: Maybe<Scalars['String']>
+  videolicense?: Maybe<Array<Video>>
+}
+
+export type LicenseConnection = {
+  totalCount: Scalars['Int']
+  edges: Array<LicenseEdge>
+  pageInfo: PageInfo
+}
+
+export type LicenseCreateInput = {
+  code?: Maybe<Scalars['Float']>
+  attribution?: Maybe<Scalars['String']>
+  customText?: Maybe<Scalars['String']>
+}
+
+export type LicenseEdge = {
+  node: License
+  cursor: Scalars['String']
+}
+
+export enum LicenseOrderByInput {
+  CreatedAtAsc = 'createdAt_ASC',
+  CreatedAtDesc = 'createdAt_DESC',
+  UpdatedAtAsc = 'updatedAt_ASC',
+  UpdatedAtDesc = 'updatedAt_DESC',
+  DeletedAtAsc = 'deletedAt_ASC',
+  DeletedAtDesc = 'deletedAt_DESC',
+  CodeAsc = 'code_ASC',
+  CodeDesc = 'code_DESC',
+  AttributionAsc = 'attribution_ASC',
+  AttributionDesc = 'attribution_DESC',
+  CustomTextAsc = 'customText_ASC',
+  CustomTextDesc = 'customText_DESC',
+}
+
+export type LicenseUpdateInput = {
+  code?: Maybe<Scalars['Float']>
+  attribution?: Maybe<Scalars['String']>
+  customText?: Maybe<Scalars['String']>
+}
+
+export type LicenseWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  code_eq?: Maybe<Scalars['Int']>
+  code_gt?: Maybe<Scalars['Int']>
+  code_gte?: Maybe<Scalars['Int']>
+  code_lt?: Maybe<Scalars['Int']>
+  code_lte?: Maybe<Scalars['Int']>
+  code_in?: Maybe<Array<Scalars['Int']>>
+  attribution_eq?: Maybe<Scalars['String']>
+  attribution_contains?: Maybe<Scalars['String']>
+  attribution_startsWith?: Maybe<Scalars['String']>
+  attribution_endsWith?: Maybe<Scalars['String']>
+  attribution_in?: Maybe<Array<Scalars['String']>>
+  customText_eq?: Maybe<Scalars['String']>
+  customText_contains?: Maybe<Scalars['String']>
+  customText_startsWith?: Maybe<Scalars['String']>
+  customText_endsWith?: Maybe<Scalars['String']>
+  customText_in?: Maybe<Array<Scalars['String']>>
+  videolanguage_none?: Maybe<VideoWhereInput>
+  videolanguage_some?: Maybe<VideoWhereInput>
+  videolanguage_every?: Maybe<VideoWhereInput>
+  AND?: Maybe<Array<LicenseWhereInput>>
+  OR?: Maybe<Array<LicenseWhereInput>>
+}
+
+export type LicenseWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export type MembersByHandleFtsOutput = {
+  item: MembersByHandleSearchResult
+  rank: Scalars['Float']
+  isTypeOf: Scalars['String']
+  highlight: Scalars['String']
+}
+
+export type MembersByHandleSearchResult = Membership
+
+/** Stored information about a registered user */
+export type Membership = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+  /** The unique handle chosen by member */
+  handle: Scalars['String']
+  /** A Url to member's Avatar image */
+  avatarUri?: Maybe<Scalars['String']>
+  /** Short text chosen by member to share information about themselves */
+  about?: Maybe<Scalars['String']>
+  /** Member's controller account id */
+  controllerAccount: Scalars['String']
+  /** Member's root account id */
+  rootAccount: Scalars['String']
+  /** Blocknumber when member was registered */
+  createdInBlock: Scalars['Int']
+  /** How the member was registered */
+  entry: MembershipEntryMethod
+  /** The type of subscription the member has purchased if any. */
+  subscription?: Maybe<Scalars['Int']>
+  channels: Array<Channel>
+}
+
+export type MembershipConnection = {
+  totalCount: Scalars['Int']
+  edges: Array<MembershipEdge>
+  pageInfo: PageInfo
+}
+
+export type MembershipCreateInput = {
+  handle: Scalars['String']
+  avatarUri?: Maybe<Scalars['String']>
+  about?: Maybe<Scalars['String']>
+  controllerAccount: Scalars['String']
+  rootAccount: Scalars['String']
+  createdInBlock: Scalars['Float']
+  entry: MembershipEntryMethod
+  subscription?: Maybe<Scalars['Float']>
+}
+
+export type MembershipEdge = {
+  node: Membership
+  cursor: Scalars['String']
+}
+
+export enum MembershipEntryMethod {
+  Paid = 'PAID',
+  Screening = 'SCREENING',
+  Genesis = 'GENESIS',
+}
+
+export enum MembershipOrderByInput {
+  CreatedAtAsc = 'createdAt_ASC',
+  CreatedAtDesc = 'createdAt_DESC',
+  UpdatedAtAsc = 'updatedAt_ASC',
+  UpdatedAtDesc = 'updatedAt_DESC',
+  DeletedAtAsc = 'deletedAt_ASC',
+  DeletedAtDesc = 'deletedAt_DESC',
+  HandleAsc = 'handle_ASC',
+  HandleDesc = 'handle_DESC',
+  AvatarUriAsc = 'avatarUri_ASC',
+  AvatarUriDesc = 'avatarUri_DESC',
+  AboutAsc = 'about_ASC',
+  AboutDesc = 'about_DESC',
+  ControllerAccountAsc = 'controllerAccount_ASC',
+  ControllerAccountDesc = 'controllerAccount_DESC',
+  RootAccountAsc = 'rootAccount_ASC',
+  RootAccountDesc = 'rootAccount_DESC',
+  CreatedInBlockAsc = 'createdInBlock_ASC',
+  CreatedInBlockDesc = 'createdInBlock_DESC',
+  EntryAsc = 'entry_ASC',
+  EntryDesc = 'entry_DESC',
+  SubscriptionAsc = 'subscription_ASC',
+  SubscriptionDesc = 'subscription_DESC',
+}
+
+export type MembershipUpdateInput = {
+  handle?: Maybe<Scalars['String']>
+  avatarUri?: Maybe<Scalars['String']>
+  about?: Maybe<Scalars['String']>
+  controllerAccount?: Maybe<Scalars['String']>
+  rootAccount?: Maybe<Scalars['String']>
+  createdInBlock?: Maybe<Scalars['Float']>
+  entry?: Maybe<MembershipEntryMethod>
+  subscription?: Maybe<Scalars['Float']>
+}
+
+export type MembershipWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  handle_eq?: Maybe<Scalars['String']>
+  handle_contains?: Maybe<Scalars['String']>
+  handle_startsWith?: Maybe<Scalars['String']>
+  handle_endsWith?: Maybe<Scalars['String']>
+  handle_in?: Maybe<Array<Scalars['String']>>
+  avatarUri_eq?: Maybe<Scalars['String']>
+  avatarUri_contains?: Maybe<Scalars['String']>
+  avatarUri_startsWith?: Maybe<Scalars['String']>
+  avatarUri_endsWith?: Maybe<Scalars['String']>
+  avatarUri_in?: Maybe<Array<Scalars['String']>>
+  about_eq?: Maybe<Scalars['String']>
+  about_contains?: Maybe<Scalars['String']>
+  about_startsWith?: Maybe<Scalars['String']>
+  about_endsWith?: Maybe<Scalars['String']>
+  about_in?: Maybe<Array<Scalars['String']>>
+  controllerAccount_eq?: Maybe<Scalars['String']>
+  controllerAccount_contains?: Maybe<Scalars['String']>
+  controllerAccount_startsWith?: Maybe<Scalars['String']>
+  controllerAccount_endsWith?: Maybe<Scalars['String']>
+  controllerAccount_in?: Maybe<Array<Scalars['String']>>
+  rootAccount_eq?: Maybe<Scalars['String']>
+  rootAccount_contains?: Maybe<Scalars['String']>
+  rootAccount_startsWith?: Maybe<Scalars['String']>
+  rootAccount_endsWith?: Maybe<Scalars['String']>
+  rootAccount_in?: Maybe<Array<Scalars['String']>>
+  createdInBlock_eq?: Maybe<Scalars['Int']>
+  createdInBlock_gt?: Maybe<Scalars['Int']>
+  createdInBlock_gte?: Maybe<Scalars['Int']>
+  createdInBlock_lt?: Maybe<Scalars['Int']>
+  createdInBlock_lte?: Maybe<Scalars['Int']>
+  createdInBlock_in?: Maybe<Array<Scalars['Int']>>
+  entry_eq?: Maybe<MembershipEntryMethod>
+  entry_in?: Maybe<Array<MembershipEntryMethod>>
+  subscription_eq?: Maybe<Scalars['Int']>
+  subscription_gt?: Maybe<Scalars['Int']>
+  subscription_gte?: Maybe<Scalars['Int']>
+  subscription_lt?: Maybe<Scalars['Int']>
+  subscription_lte?: Maybe<Scalars['Int']>
+  subscription_in?: Maybe<Array<Scalars['Int']>>
+  channels_none?: Maybe<ChannelWhereInput>
+  channels_some?: Maybe<ChannelWhereInput>
+  channels_every?: Maybe<ChannelWhereInput>
+  AND?: Maybe<Array<MembershipWhereInput>>
+  OR?: Maybe<Array<MembershipWhereInput>>
+}
+
+export type MembershipWhereUniqueInput = {
+  id?: Maybe<Scalars['ID']>
+  handle?: Maybe<Scalars['String']>
+}
+
+export type NextEntityId = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+  /** Next deterministic id for entities without custom id */
+  nextId: Scalars['Float']
+}
+
+export type NextEntityIdConnection = {
+  totalCount: Scalars['Int']
+  edges: Array<NextEntityIdEdge>
+  pageInfo: PageInfo
+}
+
+export type NextEntityIdCreateInput = {
+  nextId: Scalars['Float']
+}
+
+export type NextEntityIdEdge = {
+  node: NextEntityId
+  cursor: Scalars['String']
+}
+
+export enum NextEntityIdOrderByInput {
+  CreatedAtAsc = 'createdAt_ASC',
+  CreatedAtDesc = 'createdAt_DESC',
+  UpdatedAtAsc = 'updatedAt_ASC',
+  UpdatedAtDesc = 'updatedAt_DESC',
+  DeletedAtAsc = 'deletedAt_ASC',
+  DeletedAtDesc = 'deletedAt_DESC',
+  NextIdAsc = 'nextId_ASC',
+  NextIdDesc = 'nextId_DESC',
+}
+
+export type NextEntityIdUpdateInput = {
+  nextId?: Maybe<Scalars['Float']>
+}
+
+export type NextEntityIdWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  nextId_eq?: Maybe<Scalars['Float']>
+  nextId_gt?: Maybe<Scalars['Float']>
+  nextId_gte?: Maybe<Scalars['Float']>
+  nextId_lt?: Maybe<Scalars['Float']>
+  nextId_lte?: Maybe<Scalars['Float']>
+  nextId_in?: Maybe<Array<Scalars['Float']>>
+  AND?: Maybe<Array<NextEntityIdWhereInput>>
+  OR?: Maybe<Array<NextEntityIdWhereInput>>
+}
+
+export type NextEntityIdWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export type PageInfo = {
+  hasNextPage: Scalars['Boolean']
+  hasPreviousPage: Scalars['Boolean']
+  startCursor?: Maybe<Scalars['String']>
+  endCursor?: Maybe<Scalars['String']>
+}
+
+export type ProcessorState = {
+  lastCompleteBlock: Scalars['Float']
+  lastProcessedEvent: Scalars['String']
+  indexerHead: Scalars['Float']
+  chainHead: Scalars['Float']
+}
+
+export type Query = {
+  channelCategories: Array<ChannelCategory>
+  channelCategoryByUniqueInput?: Maybe<ChannelCategory>
+  channelCategoriesConnection: ChannelCategoryConnection
+  channels: Array<Channel>
+  channelByUniqueInput?: Maybe<Channel>
+  channelsConnection: ChannelConnection
+  curatorGroups: Array<CuratorGroup>
+  curatorGroupByUniqueInput?: Maybe<CuratorGroup>
+  curatorGroupsConnection: CuratorGroupConnection
+  dataObjects: Array<DataObject>
+  dataObjectByUniqueInput?: Maybe<DataObject>
+  dataObjectsConnection: DataObjectConnection
+  languages: Array<Language>
+  languageByUniqueInput?: Maybe<Language>
+  languagesConnection: LanguageConnection
+  licenses: Array<License>
+  licenseByUniqueInput?: Maybe<License>
+  licensesConnection: LicenseConnection
+  memberships: Array<Membership>
+  membershipByUniqueInput?: Maybe<Membership>
+  membershipsConnection: MembershipConnection
+  nextEntityIds: Array<NextEntityId>
+  nextEntityIdByUniqueInput?: Maybe<NextEntityId>
+  nextEntityIdsConnection: NextEntityIdConnection
+  channelCategoriesByName: Array<ChannelCategoriesByNameFtsOutput>
+  membersByHandle: Array<MembersByHandleFtsOutput>
+  search: Array<SearchFtsOutput>
+  videoCategoriesByName: Array<VideoCategoriesByNameFtsOutput>
+  videoCategories: Array<VideoCategory>
+  videoCategoryByUniqueInput?: Maybe<VideoCategory>
+  videoCategoriesConnection: VideoCategoryConnection
+  videoMediaEncodings: Array<VideoMediaEncoding>
+  videoMediaEncodingByUniqueInput?: Maybe<VideoMediaEncoding>
+  videoMediaEncodingsConnection: VideoMediaEncodingConnection
+  videoMediaMetadata: Array<VideoMediaMetadata>
+  videoMediaMetadataByUniqueInput?: Maybe<VideoMediaMetadata>
+  videoMediaMetadataConnection: VideoMediaMetadataConnection
+  videos: Array<Video>
+  videoByUniqueInput?: Maybe<Video>
+  videosConnection: VideoConnection
+  workers: Array<Worker>
+  workerByUniqueInput?: Maybe<Worker>
+  workersConnection: WorkerConnection
+}
+
+export type QueryChannelCategoriesArgs = {
+  offset?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  where?: Maybe<ChannelCategoryWhereInput>
+  orderBy?: Maybe<Array<ChannelCategoryOrderByInput>>
+}
+
+export type QueryChannelCategoryByUniqueInputArgs = {
+  where: ChannelCategoryWhereUniqueInput
+}
+
+export type QueryChannelCategoriesConnectionArgs = {
+  first?: Maybe<Scalars['Int']>
+  after?: Maybe<Scalars['String']>
+  last?: Maybe<Scalars['Int']>
+  before?: Maybe<Scalars['String']>
+  where?: Maybe<ChannelCategoryWhereInput>
+  orderBy?: Maybe<Array<ChannelCategoryOrderByInput>>
+}
+
+export type QueryChannelsArgs = {
+  offset?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  where?: Maybe<ChannelWhereInput>
+  orderBy?: Maybe<Array<ChannelOrderByInput>>
+}
+
+export type QueryChannelByUniqueInputArgs = {
+  where: ChannelWhereUniqueInput
+}
+
+export type QueryChannelsConnectionArgs = {
+  first?: Maybe<Scalars['Int']>
+  after?: Maybe<Scalars['String']>
+  last?: Maybe<Scalars['Int']>
+  before?: Maybe<Scalars['String']>
+  where?: Maybe<ChannelWhereInput>
+  orderBy?: Maybe<Array<ChannelOrderByInput>>
+}
+
+export type QueryCuratorGroupsArgs = {
+  offset?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  where?: Maybe<CuratorGroupWhereInput>
+  orderBy?: Maybe<Array<CuratorGroupOrderByInput>>
+}
+
+export type QueryCuratorGroupByUniqueInputArgs = {
+  where: CuratorGroupWhereUniqueInput
+}
+
+export type QueryCuratorGroupsConnectionArgs = {
+  first?: Maybe<Scalars['Int']>
+  after?: Maybe<Scalars['String']>
+  last?: Maybe<Scalars['Int']>
+  before?: Maybe<Scalars['String']>
+  where?: Maybe<CuratorGroupWhereInput>
+  orderBy?: Maybe<Array<CuratorGroupOrderByInput>>
+}
+
+export type QueryDataObjectsArgs = {
+  offset?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  where?: Maybe<DataObjectWhereInput>
+  orderBy?: Maybe<Array<DataObjectOrderByInput>>
+}
+
+export type QueryDataObjectByUniqueInputArgs = {
+  where: DataObjectWhereUniqueInput
+}
+
+export type QueryDataObjectsConnectionArgs = {
+  first?: Maybe<Scalars['Int']>
+  after?: Maybe<Scalars['String']>
+  last?: Maybe<Scalars['Int']>
+  before?: Maybe<Scalars['String']>
+  where?: Maybe<DataObjectWhereInput>
+  orderBy?: Maybe<Array<DataObjectOrderByInput>>
+}
+
+export type QueryLanguagesArgs = {
+  offset?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  where?: Maybe<LanguageWhereInput>
+  orderBy?: Maybe<Array<LanguageOrderByInput>>
+}
+
+export type QueryLanguageByUniqueInputArgs = {
+  where: LanguageWhereUniqueInput
+}
+
+export type QueryLanguagesConnectionArgs = {
+  first?: Maybe<Scalars['Int']>
+  after?: Maybe<Scalars['String']>
+  last?: Maybe<Scalars['Int']>
+  before?: Maybe<Scalars['String']>
+  where?: Maybe<LanguageWhereInput>
+  orderBy?: Maybe<Array<LanguageOrderByInput>>
+}
+
+export type QueryLicensesArgs = {
+  offset?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  where?: Maybe<LicenseWhereInput>
+  orderBy?: Maybe<Array<LicenseOrderByInput>>
+}
+
+export type QueryLicenseByUniqueInputArgs = {
+  where: LicenseWhereUniqueInput
+}
+
+export type QueryLicensesConnectionArgs = {
+  first?: Maybe<Scalars['Int']>
+  after?: Maybe<Scalars['String']>
+  last?: Maybe<Scalars['Int']>
+  before?: Maybe<Scalars['String']>
+  where?: Maybe<LicenseWhereInput>
+  orderBy?: Maybe<Array<LicenseOrderByInput>>
+}
+
+export type QueryMembershipsArgs = {
+  offset?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  where?: Maybe<MembershipWhereInput>
+  orderBy?: Maybe<Array<MembershipOrderByInput>>
+}
+
+export type QueryMembershipByUniqueInputArgs = {
+  where: MembershipWhereUniqueInput
+}
+
+export type QueryMembershipsConnectionArgs = {
+  first?: Maybe<Scalars['Int']>
+  after?: Maybe<Scalars['String']>
+  last?: Maybe<Scalars['Int']>
+  before?: Maybe<Scalars['String']>
+  where?: Maybe<MembershipWhereInput>
+  orderBy?: Maybe<Array<MembershipOrderByInput>>
+}
+
+export type QueryNextEntityIdsArgs = {
+  offset?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  where?: Maybe<NextEntityIdWhereInput>
+  orderBy?: Maybe<Array<NextEntityIdOrderByInput>>
+}
+
+export type QueryNextEntityIdByUniqueInputArgs = {
+  where: NextEntityIdWhereUniqueInput
+}
+
+export type QueryNextEntityIdsConnectionArgs = {
+  first?: Maybe<Scalars['Int']>
+  after?: Maybe<Scalars['String']>
+  last?: Maybe<Scalars['Int']>
+  before?: Maybe<Scalars['String']>
+  where?: Maybe<NextEntityIdWhereInput>
+  orderBy?: Maybe<Array<NextEntityIdOrderByInput>>
+}
+
+export type QueryChannelCategoriesByNameArgs = {
+  whereChannelCategory?: Maybe<ChannelCategoryWhereInput>
+  skip?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  text: Scalars['String']
+}
+
+export type QueryMembersByHandleArgs = {
+  whereMembership?: Maybe<MembershipWhereInput>
+  skip?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  text: Scalars['String']
+}
+
+export type QuerySearchArgs = {
+  whereVideo?: Maybe<VideoWhereInput>
+  whereChannel?: Maybe<ChannelWhereInput>
+  skip?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  text: Scalars['String']
+}
+
+export type QueryVideoCategoriesByNameArgs = {
+  whereVideoCategory?: Maybe<VideoCategoryWhereInput>
+  skip?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  text: Scalars['String']
+}
+
+export type QueryVideoCategoriesArgs = {
+  offset?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  where?: Maybe<VideoCategoryWhereInput>
+  orderBy?: Maybe<Array<VideoCategoryOrderByInput>>
+}
+
+export type QueryVideoCategoryByUniqueInputArgs = {
+  where: VideoCategoryWhereUniqueInput
+}
+
+export type QueryVideoCategoriesConnectionArgs = {
+  first?: Maybe<Scalars['Int']>
+  after?: Maybe<Scalars['String']>
+  last?: Maybe<Scalars['Int']>
+  before?: Maybe<Scalars['String']>
+  where?: Maybe<VideoCategoryWhereInput>
+  orderBy?: Maybe<Array<VideoCategoryOrderByInput>>
+}
+
+export type QueryVideoMediaEncodingsArgs = {
+  offset?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  where?: Maybe<VideoMediaEncodingWhereInput>
+  orderBy?: Maybe<Array<VideoMediaEncodingOrderByInput>>
+}
+
+export type QueryVideoMediaEncodingByUniqueInputArgs = {
+  where: VideoMediaEncodingWhereUniqueInput
+}
+
+export type QueryVideoMediaEncodingsConnectionArgs = {
+  first?: Maybe<Scalars['Int']>
+  after?: Maybe<Scalars['String']>
+  last?: Maybe<Scalars['Int']>
+  before?: Maybe<Scalars['String']>
+  where?: Maybe<VideoMediaEncodingWhereInput>
+  orderBy?: Maybe<Array<VideoMediaEncodingOrderByInput>>
+}
+
+export type QueryVideoMediaMetadataArgs = {
+  offset?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  where?: Maybe<VideoMediaMetadataWhereInput>
+  orderBy?: Maybe<Array<VideoMediaMetadataOrderByInput>>
+}
+
+export type QueryVideoMediaMetadataByUniqueInputArgs = {
+  where: VideoMediaMetadataWhereUniqueInput
+}
+
+export type QueryVideoMediaMetadataConnectionArgs = {
+  first?: Maybe<Scalars['Int']>
+  after?: Maybe<Scalars['String']>
+  last?: Maybe<Scalars['Int']>
+  before?: Maybe<Scalars['String']>
+  where?: Maybe<VideoMediaMetadataWhereInput>
+  orderBy?: Maybe<Array<VideoMediaMetadataOrderByInput>>
+}
+
+export type QueryVideosArgs = {
+  offset?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  where?: Maybe<VideoWhereInput>
+  orderBy?: Maybe<Array<VideoOrderByInput>>
+}
+
+export type QueryVideoByUniqueInputArgs = {
+  where: VideoWhereUniqueInput
+}
+
+export type QueryVideosConnectionArgs = {
+  first?: Maybe<Scalars['Int']>
+  after?: Maybe<Scalars['String']>
+  last?: Maybe<Scalars['Int']>
+  before?: Maybe<Scalars['String']>
+  where?: Maybe<VideoWhereInput>
+  orderBy?: Maybe<Array<VideoOrderByInput>>
+}
+
+export type QueryWorkersArgs = {
+  offset?: Maybe<Scalars['Int']>
+  limit?: Maybe<Scalars['Int']>
+  where?: Maybe<WorkerWhereInput>
+  orderBy?: Maybe<Array<WorkerOrderByInput>>
+}
+
+export type QueryWorkerByUniqueInputArgs = {
+  where: WorkerWhereUniqueInput
+}
+
+export type QueryWorkersConnectionArgs = {
+  first?: Maybe<Scalars['Int']>
+  after?: Maybe<Scalars['String']>
+  last?: Maybe<Scalars['Int']>
+  before?: Maybe<Scalars['String']>
+  where?: Maybe<WorkerWhereInput>
+  orderBy?: Maybe<Array<WorkerOrderByInput>>
+}
+
+export type SearchFtsOutput = {
+  item: SearchSearchResult
+  rank: Scalars['Float']
+  isTypeOf: Scalars['String']
+  highlight: Scalars['String']
+}
+
+export type SearchSearchResult = Channel | Video
+
+export type StandardDeleteResponse = {
+  id: Scalars['ID']
+}
+
+export type Subscription = {
+  stateSubscription: ProcessorState
+}
+
+export type Video = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+  channel?: Maybe<Channel>
+  channelId?: Maybe<Scalars['String']>
+  category?: Maybe<VideoCategory>
+  categoryId?: Maybe<Scalars['String']>
+  /** The title of the video */
+  title?: Maybe<Scalars['String']>
+  /** The description of the Video */
+  description?: Maybe<Scalars['String']>
+  /** Video duration in seconds */
+  duration?: Maybe<Scalars['Int']>
+  thumbnailPhotoDataObject?: Maybe<DataObject>
+  thumbnailPhotoDataObjectId?: Maybe<Scalars['String']>
+  /** URLs where the asset content can be accessed (if any) */
+  thumbnailPhotoUrls: Array<Scalars['String']>
+  /** Availability meta information */
+  thumbnailPhotoAvailability: AssetAvailability
+  language?: Maybe<Language>
+  languageId?: Maybe<Scalars['String']>
+  /** Whether or not Video contains marketing */
+  hasMarketing?: Maybe<Scalars['Boolean']>
+  /** If the Video was published on other platform before beeing published on Joystream - the original publication date */
+  publishedBeforeJoystream?: Maybe<Scalars['DateTime']>
+  /** Whether the Video is supposed to be publically displayed */
+  isPublic?: Maybe<Scalars['Boolean']>
+  /** Flag signaling whether a video is censored. */
+  isCensored: Scalars['Boolean']
+  /** Whether the Video contains explicit material. */
+  isExplicit?: Maybe<Scalars['Boolean']>
+  license?: Maybe<License>
+  licenseId?: Maybe<Scalars['String']>
+  mediaDataObject?: Maybe<DataObject>
+  mediaDataObjectId?: Maybe<Scalars['String']>
+  /** URLs where the asset content can be accessed (if any) */
+  mediaUrls: Array<Scalars['String']>
+  /** Availability meta information */
+  mediaAvailability: AssetAvailability
+  mediaMetadata?: Maybe<VideoMediaMetadata>
+  mediaMetadataId?: Maybe<Scalars['String']>
+  createdInBlock: Scalars['Int']
+  /** Is video featured or not */
+  isFeatured: Scalars['Boolean']
+}
+
+export type VideoCategoriesByNameFtsOutput = {
+  item: VideoCategoriesByNameSearchResult
+  rank: Scalars['Float']
+  isTypeOf: Scalars['String']
+  highlight: Scalars['String']
+}
+
+export type VideoCategoriesByNameSearchResult = VideoCategory
+
+export type VideoCategory = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+  /** The name of the category */
+  name?: Maybe<Scalars['String']>
+  videos: Array<Video>
+  createdInBlock: Scalars['Int']
+}
+
+export type VideoCategoryConnection = {
+  totalCount: Scalars['Int']
+  edges: Array<VideoCategoryEdge>
+  pageInfo: PageInfo
+}
+
+export type VideoCategoryCreateInput = {
+  name?: Maybe<Scalars['String']>
+  createdInBlock: Scalars['Float']
+}
+
+export type VideoCategoryEdge = {
+  node: VideoCategory
+  cursor: Scalars['String']
+}
+
+export enum VideoCategoryOrderByInput {
+  CreatedAtAsc = 'createdAt_ASC',
+  CreatedAtDesc = 'createdAt_DESC',
+  UpdatedAtAsc = 'updatedAt_ASC',
+  UpdatedAtDesc = 'updatedAt_DESC',
+  DeletedAtAsc = 'deletedAt_ASC',
+  DeletedAtDesc = 'deletedAt_DESC',
+  NameAsc = 'name_ASC',
+  NameDesc = 'name_DESC',
+  CreatedInBlockAsc = 'createdInBlock_ASC',
+  CreatedInBlockDesc = 'createdInBlock_DESC',
+}
+
+export type VideoCategoryUpdateInput = {
+  name?: Maybe<Scalars['String']>
+  createdInBlock?: Maybe<Scalars['Float']>
+}
+
+export type VideoCategoryWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  name_eq?: Maybe<Scalars['String']>
+  name_contains?: Maybe<Scalars['String']>
+  name_startsWith?: Maybe<Scalars['String']>
+  name_endsWith?: Maybe<Scalars['String']>
+  name_in?: Maybe<Array<Scalars['String']>>
+  createdInBlock_eq?: Maybe<Scalars['Int']>
+  createdInBlock_gt?: Maybe<Scalars['Int']>
+  createdInBlock_gte?: Maybe<Scalars['Int']>
+  createdInBlock_lt?: Maybe<Scalars['Int']>
+  createdInBlock_lte?: Maybe<Scalars['Int']>
+  createdInBlock_in?: Maybe<Array<Scalars['Int']>>
+  videos_none?: Maybe<VideoWhereInput>
+  videos_some?: Maybe<VideoWhereInput>
+  videos_every?: Maybe<VideoWhereInput>
+  AND?: Maybe<Array<VideoCategoryWhereInput>>
+  OR?: Maybe<Array<VideoCategoryWhereInput>>
+}
+
+export type VideoCategoryWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export type VideoConnection = {
+  totalCount: Scalars['Int']
+  edges: Array<VideoEdge>
+  pageInfo: PageInfo
+}
+
+export type VideoCreateInput = {
+  channel?: Maybe<Scalars['ID']>
+  channelId?: Maybe<Scalars['ID']>
+  category?: Maybe<Scalars['ID']>
+  categoryId?: Maybe<Scalars['ID']>
+  title?: Maybe<Scalars['String']>
+  description?: Maybe<Scalars['String']>
+  duration?: Maybe<Scalars['Float']>
+  thumbnailPhotoDataObject?: Maybe<Scalars['ID']>
+  thumbnailPhotoDataObjectId?: Maybe<Scalars['ID']>
+  thumbnailPhotoUrls: Array<Scalars['String']>
+  thumbnailPhotoAvailability: AssetAvailability
+  language?: Maybe<Scalars['ID']>
+  languageId?: Maybe<Scalars['ID']>
+  hasMarketing?: Maybe<Scalars['Boolean']>
+  publishedBeforeJoystream?: Maybe<Scalars['DateTime']>
+  isPublic?: Maybe<Scalars['Boolean']>
+  isCensored: Scalars['Boolean']
+  isExplicit?: Maybe<Scalars['Boolean']>
+  license?: Maybe<Scalars['ID']>
+  licenseId?: Maybe<Scalars['ID']>
+  mediaDataObject?: Maybe<Scalars['ID']>
+  mediaDataObjectId?: Maybe<Scalars['ID']>
+  mediaUrls: Array<Scalars['String']>
+  mediaAvailability: AssetAvailability
+  mediaMetadata?: Maybe<Scalars['ID']>
+  mediaMetadataId?: Maybe<Scalars['ID']>
+  createdInBlock: Scalars['Float']
+  isFeatured: Scalars['Boolean']
+}
+
+export type VideoEdge = {
+  node: Video
+  cursor: Scalars['String']
+}
+
+export type VideoMediaEncoding = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+  /** Encoding of the video media object */
+  codecName?: Maybe<Scalars['String']>
+  /** Media container format */
+  container?: Maybe<Scalars['String']>
+  /** Content MIME type */
+  mimeMediaType?: Maybe<Scalars['String']>
+  videomediametadataencoding?: Maybe<Array<VideoMediaMetadata>>
+}
+
+export type VideoMediaEncodingConnection = {
+  totalCount: Scalars['Int']
+  edges: Array<VideoMediaEncodingEdge>
+  pageInfo: PageInfo
+}
+
+export type VideoMediaEncodingCreateInput = {
+  codecName?: Maybe<Scalars['String']>
+  container?: Maybe<Scalars['String']>
+  mimeMediaType?: Maybe<Scalars['String']>
+}
+
+export type VideoMediaEncodingEdge = {
+  node: VideoMediaEncoding
+  cursor: Scalars['String']
+}
+
+export enum VideoMediaEncodingOrderByInput {
+  CreatedAtAsc = 'createdAt_ASC',
+  CreatedAtDesc = 'createdAt_DESC',
+  UpdatedAtAsc = 'updatedAt_ASC',
+  UpdatedAtDesc = 'updatedAt_DESC',
+  DeletedAtAsc = 'deletedAt_ASC',
+  DeletedAtDesc = 'deletedAt_DESC',
+  CodecNameAsc = 'codecName_ASC',
+  CodecNameDesc = 'codecName_DESC',
+  ContainerAsc = 'container_ASC',
+  ContainerDesc = 'container_DESC',
+  MimeMediaTypeAsc = 'mimeMediaType_ASC',
+  MimeMediaTypeDesc = 'mimeMediaType_DESC',
+}
+
+export type VideoMediaEncodingUpdateInput = {
+  codecName?: Maybe<Scalars['String']>
+  container?: Maybe<Scalars['String']>
+  mimeMediaType?: Maybe<Scalars['String']>
+}
+
+export type VideoMediaEncodingWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  codecName_eq?: Maybe<Scalars['String']>
+  codecName_contains?: Maybe<Scalars['String']>
+  codecName_startsWith?: Maybe<Scalars['String']>
+  codecName_endsWith?: Maybe<Scalars['String']>
+  codecName_in?: Maybe<Array<Scalars['String']>>
+  container_eq?: Maybe<Scalars['String']>
+  container_contains?: Maybe<Scalars['String']>
+  container_startsWith?: Maybe<Scalars['String']>
+  container_endsWith?: Maybe<Scalars['String']>
+  container_in?: Maybe<Array<Scalars['String']>>
+  mimeMediaType_eq?: Maybe<Scalars['String']>
+  mimeMediaType_contains?: Maybe<Scalars['String']>
+  mimeMediaType_startsWith?: Maybe<Scalars['String']>
+  mimeMediaType_endsWith?: Maybe<Scalars['String']>
+  mimeMediaType_in?: Maybe<Array<Scalars['String']>>
+  videomediametadataencoding_none?: Maybe<VideoMediaMetadataWhereInput>
+  videomediametadataencoding_some?: Maybe<VideoMediaMetadataWhereInput>
+  videomediametadataencoding_every?: Maybe<VideoMediaMetadataWhereInput>
+  AND?: Maybe<Array<VideoMediaEncodingWhereInput>>
+  OR?: Maybe<Array<VideoMediaEncodingWhereInput>>
+}
+
+export type VideoMediaEncodingWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export type VideoMediaMetadata = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+  encoding?: Maybe<VideoMediaEncoding>
+  encodingId?: Maybe<Scalars['String']>
+  /** Video media width in pixels */
+  pixelWidth?: Maybe<Scalars['Int']>
+  /** Video media height in pixels */
+  pixelHeight?: Maybe<Scalars['Int']>
+  /** Video media size in bytes */
+  size?: Maybe<Scalars['Float']>
+  video?: Maybe<Video>
+  createdInBlock: Scalars['Int']
+}
+
+export type VideoMediaMetadataConnection = {
+  totalCount: Scalars['Int']
+  edges: Array<VideoMediaMetadataEdge>
+  pageInfo: PageInfo
+}
+
+export type VideoMediaMetadataCreateInput = {
+  encoding?: Maybe<Scalars['ID']>
+  encodingId?: Maybe<Scalars['ID']>
+  pixelWidth?: Maybe<Scalars['Float']>
+  pixelHeight?: Maybe<Scalars['Float']>
+  size?: Maybe<Scalars['Float']>
+  createdInBlock: Scalars['Float']
+}
+
+export type VideoMediaMetadataEdge = {
+  node: VideoMediaMetadata
+  cursor: Scalars['String']
+}
+
+export enum VideoMediaMetadataOrderByInput {
+  CreatedAtAsc = 'createdAt_ASC',
+  CreatedAtDesc = 'createdAt_DESC',
+  UpdatedAtAsc = 'updatedAt_ASC',
+  UpdatedAtDesc = 'updatedAt_DESC',
+  DeletedAtAsc = 'deletedAt_ASC',
+  DeletedAtDesc = 'deletedAt_DESC',
+  EncodingAsc = 'encoding_ASC',
+  EncodingDesc = 'encoding_DESC',
+  EncodingIdAsc = 'encodingId_ASC',
+  EncodingIdDesc = 'encodingId_DESC',
+  PixelWidthAsc = 'pixelWidth_ASC',
+  PixelWidthDesc = 'pixelWidth_DESC',
+  PixelHeightAsc = 'pixelHeight_ASC',
+  PixelHeightDesc = 'pixelHeight_DESC',
+  SizeAsc = 'size_ASC',
+  SizeDesc = 'size_DESC',
+  CreatedInBlockAsc = 'createdInBlock_ASC',
+  CreatedInBlockDesc = 'createdInBlock_DESC',
+}
+
+export type VideoMediaMetadataUpdateInput = {
+  encoding?: Maybe<Scalars['ID']>
+  encodingId?: Maybe<Scalars['ID']>
+  pixelWidth?: Maybe<Scalars['Float']>
+  pixelHeight?: Maybe<Scalars['Float']>
+  size?: Maybe<Scalars['Float']>
+  createdInBlock?: Maybe<Scalars['Float']>
+}
+
+export type VideoMediaMetadataWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  encodingId_eq?: Maybe<Scalars['ID']>
+  encodingId_in?: Maybe<Array<Scalars['ID']>>
+  pixelWidth_eq?: Maybe<Scalars['Int']>
+  pixelWidth_gt?: Maybe<Scalars['Int']>
+  pixelWidth_gte?: Maybe<Scalars['Int']>
+  pixelWidth_lt?: Maybe<Scalars['Int']>
+  pixelWidth_lte?: Maybe<Scalars['Int']>
+  pixelWidth_in?: Maybe<Array<Scalars['Int']>>
+  pixelHeight_eq?: Maybe<Scalars['Int']>
+  pixelHeight_gt?: Maybe<Scalars['Int']>
+  pixelHeight_gte?: Maybe<Scalars['Int']>
+  pixelHeight_lt?: Maybe<Scalars['Int']>
+  pixelHeight_lte?: Maybe<Scalars['Int']>
+  pixelHeight_in?: Maybe<Array<Scalars['Int']>>
+  size_eq?: Maybe<Scalars['Float']>
+  size_gt?: Maybe<Scalars['Float']>
+  size_gte?: Maybe<Scalars['Float']>
+  size_lt?: Maybe<Scalars['Float']>
+  size_lte?: Maybe<Scalars['Float']>
+  size_in?: Maybe<Array<Scalars['Float']>>
+  createdInBlock_eq?: Maybe<Scalars['Int']>
+  createdInBlock_gt?: Maybe<Scalars['Int']>
+  createdInBlock_gte?: Maybe<Scalars['Int']>
+  createdInBlock_lt?: Maybe<Scalars['Int']>
+  createdInBlock_lte?: Maybe<Scalars['Int']>
+  createdInBlock_in?: Maybe<Array<Scalars['Int']>>
+  encoding?: Maybe<VideoMediaEncodingWhereInput>
+  video?: Maybe<VideoWhereInput>
+  AND?: Maybe<Array<VideoMediaMetadataWhereInput>>
+  OR?: Maybe<Array<VideoMediaMetadataWhereInput>>
+}
+
+export type VideoMediaMetadataWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export enum VideoOrderByInput {
+  CreatedAtAsc = 'createdAt_ASC',
+  CreatedAtDesc = 'createdAt_DESC',
+  UpdatedAtAsc = 'updatedAt_ASC',
+  UpdatedAtDesc = 'updatedAt_DESC',
+  DeletedAtAsc = 'deletedAt_ASC',
+  DeletedAtDesc = 'deletedAt_DESC',
+  ChannelAsc = 'channel_ASC',
+  ChannelDesc = 'channel_DESC',
+  ChannelIdAsc = 'channelId_ASC',
+  ChannelIdDesc = 'channelId_DESC',
+  CategoryAsc = 'category_ASC',
+  CategoryDesc = 'category_DESC',
+  CategoryIdAsc = 'categoryId_ASC',
+  CategoryIdDesc = 'categoryId_DESC',
+  TitleAsc = 'title_ASC',
+  TitleDesc = 'title_DESC',
+  DescriptionAsc = 'description_ASC',
+  DescriptionDesc = 'description_DESC',
+  DurationAsc = 'duration_ASC',
+  DurationDesc = 'duration_DESC',
+  ThumbnailPhotoDataObjectAsc = 'thumbnailPhotoDataObject_ASC',
+  ThumbnailPhotoDataObjectDesc = 'thumbnailPhotoDataObject_DESC',
+  ThumbnailPhotoDataObjectIdAsc = 'thumbnailPhotoDataObjectId_ASC',
+  ThumbnailPhotoDataObjectIdDesc = 'thumbnailPhotoDataObjectId_DESC',
+  ThumbnailPhotoAvailabilityAsc = 'thumbnailPhotoAvailability_ASC',
+  ThumbnailPhotoAvailabilityDesc = 'thumbnailPhotoAvailability_DESC',
+  LanguageAsc = 'language_ASC',
+  LanguageDesc = 'language_DESC',
+  LanguageIdAsc = 'languageId_ASC',
+  LanguageIdDesc = 'languageId_DESC',
+  HasMarketingAsc = 'hasMarketing_ASC',
+  HasMarketingDesc = 'hasMarketing_DESC',
+  PublishedBeforeJoystreamAsc = 'publishedBeforeJoystream_ASC',
+  PublishedBeforeJoystreamDesc = 'publishedBeforeJoystream_DESC',
+  IsPublicAsc = 'isPublic_ASC',
+  IsPublicDesc = 'isPublic_DESC',
+  IsCensoredAsc = 'isCensored_ASC',
+  IsCensoredDesc = 'isCensored_DESC',
+  IsExplicitAsc = 'isExplicit_ASC',
+  IsExplicitDesc = 'isExplicit_DESC',
+  LicenseAsc = 'license_ASC',
+  LicenseDesc = 'license_DESC',
+  LicenseIdAsc = 'licenseId_ASC',
+  LicenseIdDesc = 'licenseId_DESC',
+  MediaDataObjectAsc = 'mediaDataObject_ASC',
+  MediaDataObjectDesc = 'mediaDataObject_DESC',
+  MediaDataObjectIdAsc = 'mediaDataObjectId_ASC',
+  MediaDataObjectIdDesc = 'mediaDataObjectId_DESC',
+  MediaAvailabilityAsc = 'mediaAvailability_ASC',
+  MediaAvailabilityDesc = 'mediaAvailability_DESC',
+  MediaMetadataAsc = 'mediaMetadata_ASC',
+  MediaMetadataDesc = 'mediaMetadata_DESC',
+  MediaMetadataIdAsc = 'mediaMetadataId_ASC',
+  MediaMetadataIdDesc = 'mediaMetadataId_DESC',
+  CreatedInBlockAsc = 'createdInBlock_ASC',
+  CreatedInBlockDesc = 'createdInBlock_DESC',
+  IsFeaturedAsc = 'isFeatured_ASC',
+  IsFeaturedDesc = 'isFeatured_DESC',
+}
+
+export type VideoUpdateInput = {
+  channel?: Maybe<Scalars['ID']>
+  channelId?: Maybe<Scalars['ID']>
+  category?: Maybe<Scalars['ID']>
+  categoryId?: Maybe<Scalars['ID']>
+  title?: Maybe<Scalars['String']>
+  description?: Maybe<Scalars['String']>
+  duration?: Maybe<Scalars['Float']>
+  thumbnailPhotoDataObject?: Maybe<Scalars['ID']>
+  thumbnailPhotoDataObjectId?: Maybe<Scalars['ID']>
+  thumbnailPhotoUrls?: Maybe<Array<Scalars['String']>>
+  thumbnailPhotoAvailability?: Maybe<AssetAvailability>
+  language?: Maybe<Scalars['ID']>
+  languageId?: Maybe<Scalars['ID']>
+  hasMarketing?: Maybe<Scalars['Boolean']>
+  publishedBeforeJoystream?: Maybe<Scalars['DateTime']>
+  isPublic?: Maybe<Scalars['Boolean']>
+  isCensored?: Maybe<Scalars['Boolean']>
+  isExplicit?: Maybe<Scalars['Boolean']>
+  license?: Maybe<Scalars['ID']>
+  licenseId?: Maybe<Scalars['ID']>
+  mediaDataObject?: Maybe<Scalars['ID']>
+  mediaDataObjectId?: Maybe<Scalars['ID']>
+  mediaUrls?: Maybe<Array<Scalars['String']>>
+  mediaAvailability?: Maybe<AssetAvailability>
+  mediaMetadata?: Maybe<Scalars['ID']>
+  mediaMetadataId?: Maybe<Scalars['ID']>
+  createdInBlock?: Maybe<Scalars['Float']>
+  isFeatured?: Maybe<Scalars['Boolean']>
+}
+
+export type VideoWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  channelId_eq?: Maybe<Scalars['ID']>
+  channelId_in?: Maybe<Array<Scalars['ID']>>
+  categoryId_eq?: Maybe<Scalars['ID']>
+  categoryId_in?: Maybe<Array<Scalars['ID']>>
+  title_eq?: Maybe<Scalars['String']>
+  title_contains?: Maybe<Scalars['String']>
+  title_startsWith?: Maybe<Scalars['String']>
+  title_endsWith?: Maybe<Scalars['String']>
+  title_in?: Maybe<Array<Scalars['String']>>
+  description_eq?: Maybe<Scalars['String']>
+  description_contains?: Maybe<Scalars['String']>
+  description_startsWith?: Maybe<Scalars['String']>
+  description_endsWith?: Maybe<Scalars['String']>
+  description_in?: Maybe<Array<Scalars['String']>>
+  duration_eq?: Maybe<Scalars['Int']>
+  duration_gt?: Maybe<Scalars['Int']>
+  duration_gte?: Maybe<Scalars['Int']>
+  duration_lt?: Maybe<Scalars['Int']>
+  duration_lte?: Maybe<Scalars['Int']>
+  duration_in?: Maybe<Array<Scalars['Int']>>
+  thumbnailPhotoDataObjectId_eq?: Maybe<Scalars['ID']>
+  thumbnailPhotoDataObjectId_in?: Maybe<Array<Scalars['ID']>>
+  thumbnailPhotoUrls_containsAll?: Maybe<Array<Scalars['String']>>
+  thumbnailPhotoUrls_containsNone?: Maybe<Array<Scalars['String']>>
+  thumbnailPhotoUrls_containsAny?: Maybe<Array<Scalars['String']>>
+  thumbnailPhotoAvailability_eq?: Maybe<AssetAvailability>
+  thumbnailPhotoAvailability_in?: Maybe<Array<AssetAvailability>>
+  languageId_eq?: Maybe<Scalars['ID']>
+  languageId_in?: Maybe<Array<Scalars['ID']>>
+  hasMarketing_eq?: Maybe<Scalars['Boolean']>
+  hasMarketing_in?: Maybe<Array<Scalars['Boolean']>>
+  publishedBeforeJoystream_eq?: Maybe<Scalars['DateTime']>
+  publishedBeforeJoystream_lt?: Maybe<Scalars['DateTime']>
+  publishedBeforeJoystream_lte?: Maybe<Scalars['DateTime']>
+  publishedBeforeJoystream_gt?: Maybe<Scalars['DateTime']>
+  publishedBeforeJoystream_gte?: Maybe<Scalars['DateTime']>
+  isPublic_eq?: Maybe<Scalars['Boolean']>
+  isPublic_in?: Maybe<Array<Scalars['Boolean']>>
+  isCensored_eq?: Maybe<Scalars['Boolean']>
+  isCensored_in?: Maybe<Array<Scalars['Boolean']>>
+  isExplicit_eq?: Maybe<Scalars['Boolean']>
+  isExplicit_in?: Maybe<Array<Scalars['Boolean']>>
+  licenseId_eq?: Maybe<Scalars['ID']>
+  licenseId_in?: Maybe<Array<Scalars['ID']>>
+  mediaDataObjectId_eq?: Maybe<Scalars['ID']>
+  mediaDataObjectId_in?: Maybe<Array<Scalars['ID']>>
+  mediaUrls_containsAll?: Maybe<Array<Scalars['String']>>
+  mediaUrls_containsNone?: Maybe<Array<Scalars['String']>>
+  mediaUrls_containsAny?: Maybe<Array<Scalars['String']>>
+  mediaAvailability_eq?: Maybe<AssetAvailability>
+  mediaAvailability_in?: Maybe<Array<AssetAvailability>>
+  mediaMetadataId_eq?: Maybe<Scalars['ID']>
+  mediaMetadataId_in?: Maybe<Array<Scalars['ID']>>
+  createdInBlock_eq?: Maybe<Scalars['Int']>
+  createdInBlock_gt?: Maybe<Scalars['Int']>
+  createdInBlock_gte?: Maybe<Scalars['Int']>
+  createdInBlock_lt?: Maybe<Scalars['Int']>
+  createdInBlock_lte?: Maybe<Scalars['Int']>
+  createdInBlock_in?: Maybe<Array<Scalars['Int']>>
+  isFeatured_eq?: Maybe<Scalars['Boolean']>
+  isFeatured_in?: Maybe<Array<Scalars['Boolean']>>
+  channel?: Maybe<ChannelWhereInput>
+  category?: Maybe<VideoCategoryWhereInput>
+  thumbnailPhotoDataObject?: Maybe<DataObjectWhereInput>
+  language?: Maybe<LanguageWhereInput>
+  license?: Maybe<LicenseWhereInput>
+  mediaDataObject?: Maybe<DataObjectWhereInput>
+  mediaMetadata?: Maybe<VideoMediaMetadataWhereInput>
+  AND?: Maybe<Array<VideoWhereInput>>
+  OR?: Maybe<Array<VideoWhereInput>>
+}
+
+export type VideoWhereUniqueInput = {
+  id: Scalars['ID']
+}
+
+export type Worker = BaseGraphQlObject & {
+  id: Scalars['ID']
+  createdAt: Scalars['DateTime']
+  createdById: Scalars['String']
+  updatedAt?: Maybe<Scalars['DateTime']>
+  updatedById?: Maybe<Scalars['String']>
+  deletedAt?: Maybe<Scalars['DateTime']>
+  deletedById?: Maybe<Scalars['String']>
+  version: Scalars['Int']
+  /** Sign of worker still being active */
+  isActive: Scalars['Boolean']
+  /** Runtime identifier */
+  workerId: Scalars['String']
+  /** Associated working group */
+  type: WorkerType
+  /** Custom metadata set by provider */
+  metadata?: Maybe<Scalars['String']>
+  dataObjects: Array<DataObject>
+}
+
+export type WorkerConnection = {
+  totalCount: Scalars['Int']
+  edges: Array<WorkerEdge>
+  pageInfo: PageInfo
+}
+
+export type WorkerCreateInput = {
+  isActive: Scalars['Boolean']
+  workerId: Scalars['String']
+  type: WorkerType
+  metadata?: Maybe<Scalars['String']>
+}
+
+export type WorkerEdge = {
+  node: Worker
+  cursor: Scalars['String']
+}
+
+export enum WorkerOrderByInput {
+  CreatedAtAsc = 'createdAt_ASC',
+  CreatedAtDesc = 'createdAt_DESC',
+  UpdatedAtAsc = 'updatedAt_ASC',
+  UpdatedAtDesc = 'updatedAt_DESC',
+  DeletedAtAsc = 'deletedAt_ASC',
+  DeletedAtDesc = 'deletedAt_DESC',
+  IsActiveAsc = 'isActive_ASC',
+  IsActiveDesc = 'isActive_DESC',
+  WorkerIdAsc = 'workerId_ASC',
+  WorkerIdDesc = 'workerId_DESC',
+  TypeAsc = 'type_ASC',
+  TypeDesc = 'type_DESC',
+  MetadataAsc = 'metadata_ASC',
+  MetadataDesc = 'metadata_DESC',
+}
+
+export enum WorkerType {
+  Gateway = 'GATEWAY',
+  Storage = 'STORAGE',
+}
+
+export type WorkerUpdateInput = {
+  isActive?: Maybe<Scalars['Boolean']>
+  workerId?: Maybe<Scalars['String']>
+  type?: Maybe<WorkerType>
+  metadata?: Maybe<Scalars['String']>
+}
+
+export type WorkerWhereInput = {
+  id_eq?: Maybe<Scalars['ID']>
+  id_in?: Maybe<Array<Scalars['ID']>>
+  createdAt_eq?: Maybe<Scalars['DateTime']>
+  createdAt_lt?: Maybe<Scalars['DateTime']>
+  createdAt_lte?: Maybe<Scalars['DateTime']>
+  createdAt_gt?: Maybe<Scalars['DateTime']>
+  createdAt_gte?: Maybe<Scalars['DateTime']>
+  createdById_eq?: Maybe<Scalars['ID']>
+  createdById_in?: Maybe<Array<Scalars['ID']>>
+  updatedAt_eq?: Maybe<Scalars['DateTime']>
+  updatedAt_lt?: Maybe<Scalars['DateTime']>
+  updatedAt_lte?: Maybe<Scalars['DateTime']>
+  updatedAt_gt?: Maybe<Scalars['DateTime']>
+  updatedAt_gte?: Maybe<Scalars['DateTime']>
+  updatedById_eq?: Maybe<Scalars['ID']>
+  updatedById_in?: Maybe<Array<Scalars['ID']>>
+  deletedAt_all?: Maybe<Scalars['Boolean']>
+  deletedAt_eq?: Maybe<Scalars['DateTime']>
+  deletedAt_lt?: Maybe<Scalars['DateTime']>
+  deletedAt_lte?: Maybe<Scalars['DateTime']>
+  deletedAt_gt?: Maybe<Scalars['DateTime']>
+  deletedAt_gte?: Maybe<Scalars['DateTime']>
+  deletedById_eq?: Maybe<Scalars['ID']>
+  deletedById_in?: Maybe<Array<Scalars['ID']>>
+  isActive_eq?: Maybe<Scalars['Boolean']>
+  isActive_in?: Maybe<Array<Scalars['Boolean']>>
+  workerId_eq?: Maybe<Scalars['String']>
+  workerId_contains?: Maybe<Scalars['String']>
+  workerId_startsWith?: Maybe<Scalars['String']>
+  workerId_endsWith?: Maybe<Scalars['String']>
+  workerId_in?: Maybe<Array<Scalars['String']>>
+  type_eq?: Maybe<WorkerType>
+  type_in?: Maybe<Array<WorkerType>>
+  metadata_eq?: Maybe<Scalars['String']>
+  metadata_contains?: Maybe<Scalars['String']>
+  metadata_startsWith?: Maybe<Scalars['String']>
+  metadata_endsWith?: Maybe<Scalars['String']>
+  metadata_in?: Maybe<Array<Scalars['String']>>
+  dataObjects_none?: Maybe<DataObjectWhereInput>
+  dataObjects_some?: Maybe<DataObjectWhereInput>
+  dataObjects_every?: Maybe<DataObjectWhereInput>
+  AND?: Maybe<Array<WorkerWhereInput>>
+  OR?: Maybe<Array<WorkerWhereInput>>
+}
+
+export type WorkerWhereUniqueInput = {
+  id: Scalars['ID']
+}

+ 122 - 0
utils/migration-scripts/src/sumer-giza/sumer-query-node/queries/queries.graphql

@@ -0,0 +1,122 @@
+fragment VideoCategoryFields on VideoCategory {
+  id
+  name
+}
+
+fragment ChannelCategoryFields on ChannelCategory {
+  id
+  name
+}
+
+fragment DataObjectFields on DataObject {
+  id
+  joystreamContentId
+  size
+  liaisonJudgement
+}
+
+fragment VideoFields on Video {
+  id
+  categoryId
+  title
+  description
+  duration
+  thumbnailPhotoDataObject {
+    ...DataObjectFields
+  }
+  language {
+    iso
+  }
+  hasMarketing
+  publishedBeforeJoystream
+  isPublic
+  isCensored
+  isExplicit
+  license {
+    code
+    attribution
+    customText
+  }
+  mediaDataObject {
+    ...DataObjectFields
+  }
+  mediaMetadata {
+    encoding {
+      codecName
+      container
+      mimeMediaType
+    }
+    pixelWidth
+    pixelHeight
+    size
+  }
+  isFeatured
+  channel {
+    id
+    ownerMember {
+      id
+      controllerAccount
+    }
+  }
+}
+
+fragment ChannelFields on Channel {
+  id
+  ownerMember {
+    id
+    controllerAccount
+  }
+  categoryId
+  rewardAccount
+  title
+  description
+  coverPhotoDataObject {
+    ...DataObjectFields
+  }
+  avatarPhotoDataObject {
+    ...DataObjectFields
+  }
+  isPublic
+  isCensored
+  language {
+    iso
+  }
+  videos {
+    id
+  }
+}
+
+fragment WorkerFields on Worker {
+  id
+  metadata
+}
+
+query getChannelsByIds($ids: [ID!]) {
+  channels(where: { id_in: $ids }, limit: 1000) {
+    ...ChannelFields
+  }
+}
+
+query getVideosByIds($ids: [ID!]) {
+  videos(where: { id_in: $ids }, limit: 1000) {
+    ...VideoFields
+  }
+}
+
+query getVideoCategories {
+  videoCategories {
+    ...VideoCategoryFields
+  }
+}
+
+query getChannelsCategories {
+  channelCategories {
+    ...ChannelCategoryFields
+  }
+}
+
+query getStorageWorkers {
+  workers(where: { type_eq: STORAGE }) {
+    ...WorkerFields
+  }
+}

+ 21 - 0
utils/migration-scripts/tsconfig.json

@@ -0,0 +1,21 @@
+{
+  "compilerOptions": {
+    "declaration": true,
+    "importHelpers": true,
+    "module": "commonjs",
+    "outDir": "lib",
+    "rootDir": "src",
+    "strict": true,
+    "target": "es2017",
+    "esModuleInterop": true,
+    "types": ["node"],
+    "noUnusedLocals": true,
+    "baseUrl": "./",
+    "paths": {
+      "@polkadot/types/augment": ["../../types/augment-codec/augment-types.ts"],
+      "@polkadot/api/augment": ["../../types/augment-codec/augment-api.ts"]
+    },
+    "skipLibCheck": true
+  },
+  "include": ["src/**/*"]
+}

+ 95 - 17
yarn.lock

@@ -4182,6 +4182,22 @@
     widest-line "^3.1.0"
     wrap-ansi "^4.0.0"
 
+"@oclif/plugin-help@^3.2.3":
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/@oclif/plugin-help/-/plugin-help-3.2.3.tgz#cd24010e7eb326782843d3aa6d6b5a4affebb2c3"
+  integrity sha512-l2Pd0lbOMq4u/7xsl9hqISFqyR9gWEz/8+05xmrXFr67jXyS6EUCQB+mFBa0wepltrmJu0sAFg9AvA2mLaMMqQ==
+  dependencies:
+    "@oclif/command" "^1.5.20"
+    "@oclif/config" "^1.15.1"
+    "@oclif/errors" "^1.2.2"
+    chalk "^4.1.0"
+    indent-string "^4.0.0"
+    lodash.template "^4.4.0"
+    string-width "^4.2.0"
+    strip-ansi "^6.0.0"
+    widest-line "^3.1.0"
+    wrap-ansi "^4.0.0"
+
 "@oclif/plugin-not-found@^1.2.4":
   version "1.2.4"
   resolved "https://registry.yarnpkg.com/@oclif/plugin-not-found/-/plugin-not-found-1.2.4.tgz#160108c82f0aa10f4fb52cee4e0135af34b7220b"
@@ -6266,7 +6282,7 @@
   dependencies:
     node-cache "*"
 
-"@types/node-cleanup@^2.1.1":
+"@types/node-cleanup@^2.1.2":
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/@types/node-cleanup/-/node-cleanup-2.1.2.tgz#545c6909b864df699d46f53ae8d59cabdcb51665"
   integrity sha512-HTksao/sZs9nqxKD/vWOR3WxSrQsyJlBPEFFCgq9lMmhRsuQF+2p6hy+7FaCYn6lOeiDc3ywI8jDQ2bz5y6m8w==
@@ -6336,14 +6352,9 @@
   integrity sha512-gema+apZ6qLQK7k7F0dGkGCWQYsL0qqKORWOQO6tq46q+x+1C0vbOiOqOwRVlh4RAdbQwV/j/ryr3u5NOG1fPQ==
 
 "@types/node@^14":
-  version "14.17.26"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.26.tgz#47a53c7e7804490155a4646d60c8e194816d073c"
-  integrity sha512-eSTNkK/nfmnC7IKpOJZixDgG0W2/eHz1qyFN7o/rwwwIHsVRp+G9nbh4BrQ77kbQ2zPu286AQRxkuRLPcR3gXw==
-
-"@types/node@^8.0.0":
-  version "8.10.66"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.66.tgz#dd035d409df322acc83dff62a602f12a5783bbb3"
-  integrity sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==
+  version "14.17.32"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.32.tgz#2ca61c9ef8c77f6fa1733be9e623ceb0d372ad96"
+  integrity sha512-JcII3D5/OapPGx+eJ+Ik1SQGyt6WvuqdRfh9jUwL6/iHGjmyOriBDciBUu7lEIBTL2ijxwrR70WUnw5AEDmFvQ==
 
 "@types/node@^9.6.4":
   version "9.6.61"
@@ -6619,6 +6630,13 @@
     "@types/mime" "^1"
     "@types/node" "*"
 
+"@types/sharp@^0.29.2":
+  version "0.29.2"
+  resolved "https://registry.yarnpkg.com/@types/sharp/-/sharp-0.29.2.tgz#b4e932e982e258d1013236c8b4bcc14f9883c9a3"
+  integrity sha512-tIbMvtPa8kMyFMKNhpsPT1HO3CgXLuiCAA8bxHAGAZLyALpYvYc4hUu3pu0+3oExQA5LwvHrWp+OilgXCYVQgg==
+  dependencies:
+    "@types/node" "*"
+
 "@types/shortid@^0.0.29":
   version "0.0.29"
   resolved "https://registry.yarnpkg.com/@types/shortid/-/shortid-0.0.29.tgz#8093ee0416a6e2bf2aa6338109114b3fbffa0e9b"
@@ -8730,6 +8748,20 @@ axios@^0.18.0:
     follow-redirects "1.5.10"
     is-buffer "^2.0.2"
 
+axios@^0.21.1:
+  version "0.21.1"
+  resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
+  integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
+  dependencies:
+    follow-redirects "^1.10.0"
+
+axios@^0.24.0:
+  version "0.24.0"
+  resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6"
+  integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==
+  dependencies:
+    follow-redirects "^1.14.4"
+
 babel-code-frame@^6.22.0:
   version "6.26.0"
   resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
@@ -11029,7 +11061,7 @@ color-name@^1.0.0, color-name@~1.1.4:
   resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
   integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
 
-color-string@^1.5.2:
+color-string@^1.5.2, color-string@^1.6.0:
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.6.0.tgz#c3915f61fe267672cb7e1e064c9d692219f6c312"
   integrity sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==
@@ -11061,6 +11093,14 @@ color@^3.0.0, color@^3.1.2:
     color-convert "^1.9.1"
     color-string "^1.5.4"
 
+color@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/color/-/color-4.0.1.tgz#21df44cd10245a91b1ccf5ba031609b0e10e7d67"
+  integrity sha512-rpZjOKN5O7naJxkH2Rx1sZzzBgaiWECc6BYXjeCE6kF0kcASJYbUq02u7JqIHwCb/j3NhV+QhRL2683aICeGZA==
+  dependencies:
+    color-convert "^2.0.1"
+    color-string "^1.6.0"
+
 colorette@^1.2.1, colorette@^1.2.2:
   version "1.2.2"
   resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
@@ -15105,7 +15145,7 @@ follow-redirects@^1.0.0:
   resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.0.tgz#f5d260f95c5f8c105894491feee5dc8993b402fe"
   integrity sha512-0vRwd7RKQBTt+mgu87mtYeofLFZpTas2S9zY+jIeuLJMNvudIgF52nr19q40HOwH5RrhWIPuj9puybzSJiRrVg==
 
-follow-redirects@^1.14.0:
+follow-redirects@^1.14.4:
   version "1.14.4"
   resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379"
   integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==
@@ -22265,7 +22305,7 @@ module-lookup-amd@^6.1.0:
     requirejs "^2.3.5"
     requirejs-config-file "^3.1.1"
 
-moment@^2.10.2, moment@^2.11.2, moment@^2.22.1, moment@^2.24.0:
+moment@^2.10.2, moment@^2.22.1, moment@^2.24.0, moment@^2.29.1:
   version "2.29.1"
   resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
   integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
@@ -22735,6 +22775,11 @@ node-addon-api@^3.0.2:
   resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239"
   integrity "sha1-mLIZMVV0ZsZynlHLd805yWX0Ijk= sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw=="
 
+node-addon-api@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.2.0.tgz#117cbb5a959dff0992e1c586ae0393573e4d2a87"
+  integrity sha512-eazsqzwG2lskuzBqCGPi7Ac2UgOoMz8JVOXVhTvvPDYhthvNpefx8jWD8Np7Gv+2Sz0FlPWZk0nJV0z598Wn8Q==
+
 node-cache@*, node-cache@^5.1.2:
   version "5.1.2"
   resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-5.1.2.tgz#f264dc2ccad0a780e76253a694e9fd0ed19c398d"
@@ -25124,6 +25169,25 @@ prebuild-install@^6.0.0:
     tar-fs "^2.0.0"
     tunnel-agent "^0.6.0"
 
+prebuild-install@^6.1.4:
+  version "6.1.4"
+  resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-6.1.4.tgz#ae3c0142ad611d58570b89af4986088a4937e00f"
+  integrity sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==
+  dependencies:
+    detect-libc "^1.0.3"
+    expand-template "^2.0.3"
+    github-from-package "0.0.0"
+    minimist "^1.2.3"
+    mkdirp-classic "^0.5.3"
+    napi-build-utils "^1.0.1"
+    node-abi "^2.21.0"
+    npmlog "^4.0.1"
+    pump "^3.0.0"
+    rc "^1.2.7"
+    simple-get "^3.0.3"
+    tar-fs "^2.0.0"
+    tunnel-agent "^0.6.0"
+
 precinct@^6.3.1:
   version "6.3.1"
   resolved "https://registry.yarnpkg.com/precinct/-/precinct-6.3.1.tgz#8ad735a8afdfc48b56ed39c9ad3bf999b6b928dc"
@@ -27958,6 +28022,20 @@ shallowequal@^1.0.1, shallowequal@^1.1.0:
   resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
   integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
 
+sharp@^0.29.2:
+  version "0.29.2"
+  resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.29.2.tgz#e8c003cd9cb321585b32dbda6eed3baa7d6f2308"
+  integrity sha512-XWRdiYLIJ3tDUejRyG24KERnJzMfIoyiJBntd2S6/uj3NEeNgRFRLgiBlvPxMa8aml14dKKD98yHinSNKp1xzQ==
+  dependencies:
+    color "^4.0.1"
+    detect-libc "^1.0.3"
+    node-addon-api "^4.2.0"
+    prebuild-install "^6.1.4"
+    semver "^7.3.5"
+    simple-get "^3.1.0"
+    tar-fs "^2.1.1"
+    tunnel-agent "^0.6.0"
+
 shebang-command@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@@ -28102,7 +28180,7 @@ simple-get@^2.7.0:
     once "^1.3.1"
     simple-concat "^1.0.0"
 
-simple-get@^3.0.3:
+simple-get@^3.0.3, simple-get@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.0.tgz#b45be062435e50d159540b576202ceec40b9c6b3"
   integrity "sha1-tFvgYkNeUNFZVAtXYgLO7EC5xrM= sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA=="
@@ -29523,7 +29601,7 @@ tar-fs@^1.13.0:
     pump "^1.0.0"
     tar-stream "^1.1.2"
 
-tar-fs@^2.0.0:
+tar-fs@^2.0.0, tar-fs@^2.1.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784"
   integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==
@@ -30641,9 +30719,9 @@ typescript-tuple@^2.2.1:
     typescript-compare "^0.0.2"
 
 typescript@2.2.2, typescript@^3.0.3, typescript@^3.3, typescript@^3.8.3, typescript@^3.9.5, typescript@^3.9.7, typescript@^4.0.3, typescript@^4.4.3:
-  version "4.4.4"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c"
-  integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==
+  version "4.4.3"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324"
+  integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==
 
 ua-parser-js@^0.7.18:
   version "0.7.28"